Re: [LTP] [PATCH 09/13] testcases/kernel/mem: Move KSM bits to ksm tests

Li Wang
2024-12-19T02:53:00Z

On Thu, Dec 19, 2024 at 2:48 AM Cyril Hrubis <chrubis@suse.cz> wrote:

> Moves the ksm helpers into a ksm/ksm_test.h since these are not used by
> any other but ksm tests.
>
> Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
> ---
> testcases/kernel/mem/include/mem.h | 5 -
> testcases/kernel/mem/ksm/Makefile | 2 +-
> testcases/kernel/mem/ksm/ksm01.c | 2 +-
> testcases/kernel/mem/ksm/ksm02.c | 2 +-
> testcases/kernel/mem/ksm/ksm03.c | 2 +-
> testcases/kernel/mem/ksm/ksm04.c | 2 +-
> testcases/kernel/mem/ksm/ksm05.c | 2 +-
> testcases/kernel/mem/ksm/ksm06.c | 4 +-
> testcases/kernel/mem/ksm/ksm07.c | 3 +-
> testcases/kernel/mem/ksm/ksm_common.h | 3 +-
> testcases/kernel/mem/ksm/ksm_test.h | 299 ++++++++++++++++++++++++++
>

We do have another tst_helper.h under testcases/kernel/include/,
maybe we can combine it with ksm_test.h together?

> testcases/kernel/mem/lib/mem.c | 287 ------------------------
> 12 files changed, 312 insertions(+), 301 deletions(-)
> create mode 100644 testcases/kernel/mem/ksm/ksm_test.h
>
> diff --git a/testcases/kernel/mem/include/mem.h
> b/testcases/kernel/mem/include/mem.h
> index 5ebedc175..25389f34c 100644
> --- a/testcases/kernel/mem/include/mem.h
> +++ b/testcases/kernel/mem/include/mem.h
> @@ -16,11 +16,6 @@
>
> /* KSM */
>
> -void create_same_memory(int size, int num, int unit);
> -void test_ksm_merge_across_nodes(unsigned long nr_pages);
> -void ksm_group_check(int run, int pg_shared, int pg_sharing, int
> pg_volatile,
> - int pg_unshared, int sleep_msecs, int pages_to_scan);
> -
> /* HUGETLB */
>
> #define PATH_SHMMAX "/proc/sys/kernel/shmmax"
> diff --git a/testcases/kernel/mem/ksm/Makefile
> b/testcases/kernel/mem/ksm/Makefile
> index 6aba73e61..2af02a274 100644
> --- a/testcases/kernel/mem/ksm/Makefile
> +++ b/testcases/kernel/mem/ksm/Makefile
> @@ -7,5 +7,5 @@ LTPLIBS = numa
> ksm06: LTPLDLIBS = -lltpnuma
>
> include $(top_srcdir)/include/mk/testcases.mk
> -include $(top_srcdir)/testcases/kernel/mem/include/libmem.mk
> +include $(top_srcdir)/testcases/kernel/include/lib.mk
> include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/mem/ksm/ksm01.c
> b/testcases/kernel/mem/ksm/ksm01.c
> index e2d3d9e00..a22e4830f 100644
> --- a/testcases/kernel/mem/ksm/ksm01.c
> +++ b/testcases/kernel/mem/ksm/ksm01.c
> @@ -56,7 +56,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> -#include "mem.h"
> +#include "tst_test.h"
> #include "ksm_common.h"
>
> static void verify_ksm(void)
> diff --git a/testcases/kernel/mem/ksm/ksm02.c
> b/testcases/kernel/mem/ksm/ksm02.c
> index a388e82ab..4d1306045 100644
> --- a/testcases/kernel/mem/ksm/ksm02.c
> +++ b/testcases/kernel/mem/ksm/ksm02.c
> @@ -53,7 +53,7 @@
> #include <signal.h>
> #include <stdio.h>
> #include <unistd.h>
> -#include "mem.h"
> +#include "tst_test.h"
> #include "ksm_common.h"
>
> #ifdef HAVE_NUMA_V2
> diff --git a/testcases/kernel/mem/ksm/ksm03.c
> b/testcases/kernel/mem/ksm/ksm03.c
> index cff74700d..78844b30e 100644
> --- a/testcases/kernel/mem/ksm/ksm03.c
> +++ b/testcases/kernel/mem/ksm/ksm03.c
> @@ -56,7 +56,7 @@
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> -#include "mem.h"
> +#include "tst_test.h"
> #include "ksm_common.h"
>
> static void verify_ksm(void)
> diff --git a/testcases/kernel/mem/ksm/ksm04.c
> b/testcases/kernel/mem/ksm/ksm04.c
> index 31f3ff2eb..8465ee230 100644
> --- a/testcases/kernel/mem/ksm/ksm04.c
> +++ b/testcases/kernel/mem/ksm/ksm04.c
> @@ -38,7 +38,7 @@
> #include <signal.h>
> #include <stdio.h>
> #include <unistd.h>
> -#include "mem.h"
> +#include "tst_test.h"
> #include "ksm_common.h"
>
> #ifdef HAVE_NUMA_V2
> diff --git a/testcases/kernel/mem/ksm/ksm05.c
> b/testcases/kernel/mem/ksm/ksm05.c
> index 1d9d9699a..025dffc09 100644
> --- a/testcases/kernel/mem/ksm/ksm05.c
> +++ b/testcases/kernel/mem/ksm/ksm05.c
> @@ -39,7 +39,7 @@
> #include <stdlib.h>
> #include <errno.h>
> #include "tst_test.h"
> -#include "mem.h"
> +#include "ksm_helper.h"
>
> #ifdef HAVE_DECL_MADV_MERGEABLE
>
> diff --git a/testcases/kernel/mem/ksm/ksm06.c
> b/testcases/kernel/mem/ksm/ksm06.c
> index 80fdf1e47..09a54fd18 100644
> --- a/testcases/kernel/mem/ksm/ksm06.c
> +++ b/testcases/kernel/mem/ksm/ksm06.c
> @@ -33,8 +33,10 @@
> #include <unistd.h>
> #include <limits.h>
>
> -#include "mem.h"
> +#include "tst_test.h"
> #include "tst_numa.h"
> +#include "ksm_helper.h"
> +#include "ksm_test.h"
>
> #ifdef HAVE_NUMA_V2
> # include <numa.h>
> diff --git a/testcases/kernel/mem/ksm/ksm07.c
> b/testcases/kernel/mem/ksm/ksm07.c
> index 619bd7b55..24b393283 100644
> --- a/testcases/kernel/mem/ksm/ksm07.c
> +++ b/testcases/kernel/mem/ksm/ksm07.c
> @@ -23,7 +23,8 @@
> */
>
> #include <sys/wait.h>
> -#include "mem.h"
> +#include "tst_test.h"
> +#include "ksm_helper.h"
>
> /* This test allocates one page, fills the page with a's, captures the
> * full_scan and pages_skipped counters. Then it makes sure at least 3
> diff --git a/testcases/kernel/mem/ksm/ksm_common.h
> b/testcases/kernel/mem/ksm/ksm_common.h
> index 43ea8f8c2..d677b224d 100644
> --- a/testcases/kernel/mem/ksm/ksm_common.h
> +++ b/testcases/kernel/mem/ksm/ksm_common.h
> @@ -11,7 +11,9 @@
> #define KSM_COMMON_H__
>
> #include "tst_test.h"
> +#include "ksm_helper.h"
> #include "numa_helper.h"
> +#include "ksm_test.h"
>
> #define DEFAULT_MEMSIZE 128
>
> @@ -67,5 +69,4 @@ static inline unsigned int get_a_numa_node(void)
> abort();
> }
>
> -
> #endif /* KSM_COMMON_H__ */
> diff --git a/testcases/kernel/mem/ksm/ksm_test.h
> b/testcases/kernel/mem/ksm/ksm_test.h
> new file mode 100644
> index 000000000..ebce8197c
> --- /dev/null
> +++ b/testcases/kernel/mem/ksm/ksm_test.h
> @@ -0,0 +1,299 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) Linux Test Project, 2011-2021
> + * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2024
> + */
> +#ifndef KSM_TEST_
> +#define KSM_TEST_
> +
> +#include <sys/wait.h>
> +
> +static inline void check(char *path, long int value)
> +{
> + char fullpath[BUFSIZ];
> + long actual_val;
> +
> + snprintf(fullpath, BUFSIZ, PATH_KSM "%s", path);
> + SAFE_FILE_SCANF(fullpath, "%ld", &actual_val);
> +
> + if (actual_val != value)
> + tst_res(TFAIL, "%s is not %ld but %ld.", path, value,
> + actual_val);
> + else
> + tst_res(TPASS, "%s is %ld.", path, actual_val);
> +}
> +
> +static inline void final_group_check(int run, int pages_shared, int
> pages_sharing,
> + int pages_volatile, int pages_unshared,
> + int sleep_millisecs, int pages_to_scan)
> +{
> + int ksm_run_orig;
> +
> + tst_res(TINFO, "check!");
> + check("run", run);
> +
> + /*
> + * Temporarily stop the KSM scan during the checks: during the
> + * KSM scan the rmap_items in the stale unstable tree of the
> + * old pass are removed from it and are later reinserted in
> + * the new unstable tree of the current pass. So if the checks
> + * run in the race window between removal and re-insertion, it
> + * can lead to unexpected false positives where page_volatile
> + * is elevated and page_unshared is recessed.
> + */
> + SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
> + SAFE_FILE_PRINTF(PATH_KSM "run", "0");
> +
> + check("pages_shared", pages_shared);
> + check("pages_sharing", pages_sharing);
> + check("pages_volatile", pages_volatile);
> + check("pages_unshared", pages_unshared);
> + check("sleep_millisecs", sleep_millisecs);
> + check("pages_to_scan", pages_to_scan);
> +
> + SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
> +}
> +
> +static inline void ksm_group_check(int run, int pages_shared, int
> pages_sharing,
> + int pages_volatile, int pages_unshared,
> + int sleep_millisecs, int pages_to_scan)
> +{
> + if (run != 1) {
> + tst_res(TFAIL, "group_check run is not 1, %d.", run);
> + } else {
> + /* wait for ksm daemon to scan all mergeable pages. */
> + wait_ksmd_full_scan();
> + }
> +
> + final_group_check(run, pages_shared, pages_sharing,
> + pages_volatile, pages_unshared,
> + sleep_millisecs, pages_to_scan);
> +}
> +
> +static inline void verify(char **memory, char value, int proc,
> + int start, int end, int start2, int end2)
> +{
> + int i, j;
> + void *s = NULL;
> +
> + s = SAFE_MALLOC((end - start) * (end2 - start2));
> +
> + tst_res(TINFO, "child %d verifies memory content.", proc);
> + memset(s, value, (end - start) * (end2 - start2));
> + if (memcmp(memory[start], s, (end - start) * (end2 - start2))
> + != 0)
> + for (j = start; j < end; j++)
> + for (i = start2; i < end2; i++)
> + if (memory[j][i] != value)
> + tst_res(TFAIL, "child %d has %c at
> "
> + "%d,%d,%d.",
> + proc, memory[j][i], proc,
> + j, i);
> + free(s);
> +}
> +
> +struct ksm_merge_data {
> + char data;
> + unsigned int mergeable_size;
> +};
> +
> +static inline void ksm_child_memset(int child_num, int size, int
> total_unit,
> + struct ksm_merge_data ksm_merge_data, char **memory)
> +{
> + int i = 0, j;
> + int unit = size / total_unit;
> +
> + tst_res(TINFO, "child %d continues...", child_num);
> +
> + if (ksm_merge_data.mergeable_size == size * TST_MB) {
> + tst_res(TINFO, "child %d allocates %d TST_MB filled with
> '%c'",
> + child_num, size, ksm_merge_data.data);
> +
> + } else {
> + tst_res(TINFO, "child %d allocates %d TST_MB filled with
> '%c'"
> + " except one page with 'e'",
> + child_num, size, ksm_merge_data.data);
> + }
> +
> + for (j = 0; j < total_unit; j++) {
> + for (i = 0; (unsigned int)i < unit * TST_MB; i++)
> + memory[j][i] = ksm_merge_data.data;
> + }
> +
> + /* if it contains unshared page, then set 'e' char
> + * at the end of the last page
> + */
> + if (ksm_merge_data.mergeable_size < size * TST_MB)
> + memory[j-1][i-1] = 'e';
> +}
> +
> +static inline void create_ksm_child(int child_num, int size, int unit,
> + struct ksm_merge_data *ksm_merge_data)
> +{
> + int j, total_unit;
> + char **memory;
> +
> + /* The total units in all */
> + total_unit = size / unit;
> +
> + /* Apply for the space for memory */
> + memory = SAFE_MALLOC(total_unit * sizeof(char *));
> + for (j = 0; j < total_unit; j++) {
> + memory[j] = SAFE_MMAP(NULL, unit * TST_MB,
> PROT_READ|PROT_WRITE,
> + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
> +#ifdef HAVE_DECL_MADV_MERGEABLE
> + if (madvise(memory[j], unit * TST_MB, MADV_MERGEABLE) ==
> -1)
> + tst_brk(TBROK|TERRNO, "madvise");
> +#endif
> + }
> +
> + tst_res(TINFO, "child %d stops.", child_num);
> + if (raise(SIGSTOP) == -1)
> + tst_brk(TBROK|TERRNO, "kill");
> + fflush(stdout);
> +
> + for (j = 0; j < 4; j++) {
> +
> + ksm_child_memset(child_num, size, total_unit,
> + ksm_merge_data[j], memory);
> +
> + fflush(stdout);
> +
> + tst_res(TINFO, "child %d stops.", child_num);
> + if (raise(SIGSTOP) == -1)
> + tst_brk(TBROK|TERRNO, "kill");
> +
> + if (ksm_merge_data[j].mergeable_size < size * TST_MB) {
> + verify(memory, 'e', child_num, total_unit - 1,
> + total_unit, unit * TST_MB - 1, unit *
> TST_MB);
> + verify(memory, ksm_merge_data[j].data, child_num,
> + 0, total_unit, 0, unit * TST_MB - 1);
> + } else {
> + verify(memory, ksm_merge_data[j].data, child_num,
> + 0, total_unit, 0, unit * TST_MB);
> + }
> + }
> +
> + tst_res(TINFO, "child %d finished.", child_num);
> +}
> +
> +static inline void stop_ksm_children(int *child, int num)
> +{
> + int k, status;
> +
> + tst_res(TINFO, "wait for all children to stop.");
> + for (k = 0; k < num; k++) {
> + SAFE_WAITPID(child[k], &status, WUNTRACED);
> + if (!WIFSTOPPED(status))
> + tst_brk(TBROK, "child %d was not stopped", k);
> + }
> +}
> +
> +static inline void resume_ksm_children(int *child, int num)
> +{
> + int k;
> +
> + tst_res(TINFO, "resume all children.");
> + for (k = 0; k < num; k++)
> + SAFE_KILL(child[k], SIGCONT);
> +
> + fflush(stdout);
> +}
> +
> +static inline void create_same_memory(int size, int num, int unit)
> +{
> + int i, j, status, *child;
> + unsigned long ps, pages;
> + struct ksm_merge_data **ksm_data;
> +
> + struct ksm_merge_data ksm_data0[] = {
> + {'c', size*TST_MB}, {'c', size*TST_MB}, {'d', size*TST_MB},
> {'d', size*TST_MB},
> + };
> + struct ksm_merge_data ksm_data1[] = {
> + {'a', size*TST_MB}, {'b', size*TST_MB}, {'d', size*TST_MB},
> {'d', size*TST_MB-1},
> + };
> + struct ksm_merge_data ksm_data2[] = {
> + {'a', size*TST_MB}, {'a', size*TST_MB}, {'d', size*TST_MB},
> {'d', size*TST_MB},
> + };
> +
> + ps = sysconf(_SC_PAGE_SIZE);
> + pages = TST_MB / ps;
> +
> + ksm_data = malloc((num - 3) * sizeof(struct ksm_merge_data *));
> + /* Since from third child, the data is same with the first child's
> */
> + for (i = 0; i < num - 3; i++) {
> + ksm_data[i] = malloc(4 * sizeof(struct ksm_merge_data));
> + for (j = 0; j < 4; j++) {
> + ksm_data[i][j].data = ksm_data0[j].data;
> + ksm_data[i][j].mergeable_size =
> + ksm_data0[j].mergeable_size;
> + }
> + }
> +
> + child = SAFE_MALLOC(num * sizeof(int));
> +
> + for (i = 0; i < num; i++) {
> + fflush(stdout);
> + switch (child[i] = SAFE_FORK()) {
> + case 0:
> + if (i == 0) {
> + create_ksm_child(i, size, unit, ksm_data0);
> + exit(0);
> + } else if (i == 1) {
> + create_ksm_child(i, size, unit, ksm_data1);
> + exit(0);
> + } else if (i == 2) {
> + create_ksm_child(i, size, unit, ksm_data2);
> + exit(0);
> + } else {
> + create_ksm_child(i, size, unit,
> ksm_data[i-3]);
> + exit(0);
> + }
> + }
> + }
> +
> + stop_ksm_children(child, num);
> +
> + tst_res(TINFO, "KSM merging...");
> + if (access(PATH_KSM "max_page_sharing", F_OK) == 0) {
> + SAFE_FILE_PRINTF(PATH_KSM "run", "2");
> + SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", "%ld", size
> * pages * num);
> + }
> +
> + SAFE_FILE_PRINTF(PATH_KSM "run", "1");
> + SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", size * pages *
> num);
> + SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0");
> +
> + resume_ksm_children(child, num);
> + stop_ksm_children(child, num);
> + ksm_group_check(1, 2, size * num * pages - 2, 0, 0, 0, size *
> pages * num);
> +
> + resume_ksm_children(child, num);
> + stop_ksm_children(child, num);
> + ksm_group_check(1, 3, size * num * pages - 3, 0, 0, 0, size *
> pages * num);
> +
> + resume_ksm_children(child, num);
> + stop_ksm_children(child, num);
> + ksm_group_check(1, 1, size * num * pages - 1, 0, 0, 0, size *
> pages * num);
> +
> + resume_ksm_children(child, num);
> + stop_ksm_children(child, num);
> + ksm_group_check(1, 1, size * num * pages - 2, 0, 1, 0, size *
> pages * num);
> +
> + tst_res(TINFO, "KSM unmerging...");
> + SAFE_FILE_PRINTF(PATH_KSM "run", "2");
> +
> + resume_ksm_children(child, num);
> + final_group_check(2, 0, 0, 0, 0, 0, size * pages * num);
> +
> + tst_res(TINFO, "stop KSM.");
> + SAFE_FILE_PRINTF(PATH_KSM "run", "0");
> + final_group_check(0, 0, 0, 0, 0, 0, size * pages * num);
> +
> + while (waitpid(-1, &status, 0) > 0)
> + if (WEXITSTATUS(status) != 0)
> + tst_res(TFAIL, "child exit status is %d",
> + WEXITSTATUS(status));
> +}
> +
> +#endif /* KSM_TEST_ */
> diff --git a/testcases/kernel/mem/lib/mem.c
> b/testcases/kernel/mem/lib/mem.c
> index f3b844994..4e5c0b873 100644
> --- a/testcases/kernel/mem/lib/mem.c
> +++ b/testcases/kernel/mem/lib/mem.c
> @@ -28,290 +28,3 @@
>
> /* KSM */
>
> -static void check(char *path, long int value)
> -{
> - char fullpath[BUFSIZ];
> - long actual_val;
> -
> - snprintf(fullpath, BUFSIZ, PATH_KSM "%s", path);
> - SAFE_FILE_SCANF(fullpath, "%ld", &actual_val);
> -
> - if (actual_val != value)
> - tst_res(TFAIL, "%s is not %ld but %ld.", path, value,
> - actual_val);
> - else
> - tst_res(TPASS, "%s is %ld.", path, actual_val);
> -}
> -
> -static void final_group_check(int run, int pages_shared, int
> pages_sharing,
> - int pages_volatile, int pages_unshared,
> - int sleep_millisecs, int pages_to_scan)
> -{
> - int ksm_run_orig;
> -
> - tst_res(TINFO, "check!");
> - check("run", run);
> -
> - /*
> - * Temporarily stop the KSM scan during the checks: during the
> - * KSM scan the rmap_items in the stale unstable tree of the
> - * old pass are removed from it and are later reinserted in
> - * the new unstable tree of the current pass. So if the checks
> - * run in the race window between removal and re-insertion, it
> - * can lead to unexpected false positives where page_volatile
> - * is elevated and page_unshared is recessed.
> - */
> - SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
> - SAFE_FILE_PRINTF(PATH_KSM "run", "0");
> -
> - check("pages_shared", pages_shared);
> - check("pages_sharing", pages_sharing);
> - check("pages_volatile", pages_volatile);
> - check("pages_unshared", pages_unshared);
> - check("sleep_millisecs", sleep_millisecs);
> - check("pages_to_scan", pages_to_scan);
> -
> - SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
> -}
> -
> -void ksm_group_check(int run, int pages_shared, int pages_sharing,
> - int pages_volatile, int pages_unshared,
> - int sleep_millisecs, int pages_to_scan)
> -{
> - if (run != 1) {
> - tst_res(TFAIL, "group_check run is not 1, %d.", run);
> - } else {
> - /* wait for ksm daemon to scan all mergeable pages. */
> - wait_ksmd_full_scan();
> - }
> -
> - final_group_check(run, pages_shared, pages_sharing,
> - pages_volatile, pages_unshared,
> - sleep_millisecs, pages_to_scan);
> -}
> -
> -static void verify(char **memory, char value, int proc,
> - int start, int end, int start2, int end2)
> -{
> - int i, j;
> - void *s = NULL;
> -
> - s = SAFE_MALLOC((end - start) * (end2 - start2));
> -
> - tst_res(TINFO, "child %d verifies memory content.", proc);
> - memset(s, value, (end - start) * (end2 - start2));
> - if (memcmp(memory[start], s, (end - start) * (end2 - start2))
> - != 0)
> - for (j = start; j < end; j++)
> - for (i = start2; i < end2; i++)
> - if (memory[j][i] != value)
> - tst_res(TFAIL, "child %d has %c at
> "
> - "%d,%d,%d.",
> - proc, memory[j][i], proc,
> - j, i);
> - free(s);
> -}
> -
> -struct ksm_merge_data {
> - char data;
> - unsigned int mergeable_size;
> -};
> -
> -static void ksm_child_memset(int child_num, int size, int total_unit,
> - struct ksm_merge_data ksm_merge_data, char **memory)
> -{
> - int i = 0, j;
> - int unit = size / total_unit;
> -
> - tst_res(TINFO, "child %d continues...", child_num);
> -
> - if (ksm_merge_data.mergeable_size == size * MB) {
> - tst_res(TINFO, "child %d allocates %d MB filled with '%c'",
> - child_num, size, ksm_merge_data.data);
> -
> - } else {
> - tst_res(TINFO, "child %d allocates %d MB filled with '%c'"
> - " except one page with 'e'",
> - child_num, size, ksm_merge_data.data);
> - }
> -
> - for (j = 0; j < total_unit; j++) {
> - for (i = 0; (unsigned int)i < unit * MB; i++)
> - memory[j][i] = ksm_merge_data.data;
> - }
> -
> - /* if it contains unshared page, then set 'e' char
> - * at the end of the last page
> - */
> - if (ksm_merge_data.mergeable_size < size * MB)
> - memory[j-1][i-1] = 'e';
> -}
> -
> -static void create_ksm_child(int child_num, int size, int unit,
> - struct ksm_merge_data *ksm_merge_data)
> -{
> - int j, total_unit;
> - char **memory;
> -
> - /* The total units in all */
> - total_unit = size / unit;
> -
> - /* Apply for the space for memory */
> - memory = SAFE_MALLOC(total_unit * sizeof(char *));
> - for (j = 0; j < total_unit; j++) {
> - memory[j] = SAFE_MMAP(NULL, unit * MB,
> PROT_READ|PROT_WRITE,
> - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
> -#ifdef HAVE_DECL_MADV_MERGEABLE
> - if (madvise(memory[j], unit * MB, MADV_MERGEABLE) == -1)
> - tst_brk(TBROK|TERRNO, "madvise");
> -#endif
> - }
> -
> - tst_res(TINFO, "child %d stops.", child_num);
> - if (raise(SIGSTOP) == -1)
> - tst_brk(TBROK|TERRNO, "kill");
> - fflush(stdout);
> -
> - for (j = 0; j < 4; j++) {
> -
> - ksm_child_memset(child_num, size, total_unit,
> - ksm_merge_data[j], memory);
> -
> - fflush(stdout);
> -
> - tst_res(TINFO, "child %d stops.", child_num);
> - if (raise(SIGSTOP) == -1)
> - tst_brk(TBROK|TERRNO, "kill");
> -
> - if (ksm_merge_data[j].mergeable_size < size * MB) {
> - verify(memory, 'e', child_num, total_unit - 1,
> - total_unit, unit * MB - 1, unit * MB);
> - verify(memory, ksm_merge_data[j].data, child_num,
> - 0, total_unit, 0, unit * MB - 1);
> - } else {
> - verify(memory, ksm_merge_data[j].data, child_num,
> - 0, total_unit, 0, unit * MB);
> - }
> - }
> -
> - tst_res(TINFO, "child %d finished.", child_num);
> -}
> -
> -static void stop_ksm_children(int *child, int num)
> -{
> - int k, status;
> -
> - tst_res(TINFO, "wait for all children to stop.");
> - for (k = 0; k < num; k++) {
> - SAFE_WAITPID(child[k], &status, WUNTRACED);
> - if (!WIFSTOPPED(status))
> - tst_brk(TBROK, "child %d was not stopped", k);
> - }
> -}
> -
> -static void resume_ksm_children(int *child, int num)
> -{
> - int k;
> -
> - tst_res(TINFO, "resume all children.");
> - for (k = 0; k < num; k++)
> - SAFE_KILL(child[k], SIGCONT);
> -
> - fflush(stdout);
> -}
> -
> -void create_same_memory(int size, int num, int unit)
> -{
> - int i, j, status, *child;
> - unsigned long ps, pages;
> - struct ksm_merge_data **ksm_data;
> -
> - struct ksm_merge_data ksm_data0[] = {
> - {'c', size*MB}, {'c', size*MB}, {'d', size*MB}, {'d',
> size*MB},
> - };
> - struct ksm_merge_data ksm_data1[] = {
> - {'a', size*MB}, {'b', size*MB}, {'d', size*MB}, {'d',
> size*MB-1},
> - };
> - struct ksm_merge_data ksm_data2[] = {
> - {'a', size*MB}, {'a', size*MB}, {'d', size*MB}, {'d',
> size*MB},
> - };
> -
> - ps = sysconf(_SC_PAGE_SIZE);
> - pages = MB / ps;
> -
> - ksm_data = malloc((num - 3) * sizeof(struct ksm_merge_data *));
> - /* Since from third child, the data is same with the first child's
> */
> - for (i = 0; i < num - 3; i++) {
> - ksm_data[i] = malloc(4 * sizeof(struct ksm_merge_data));
> - for (j = 0; j < 4; j++) {
> - ksm_data[i][j].data = ksm_data0[j].data;
> - ksm_data[i][j].mergeable_size =
> - ksm_data0[j].mergeable_size;
> - }
> - }
> -
> - child = SAFE_MALLOC(num * sizeof(int));
> -
> - for (i = 0; i < num; i++) {
> - fflush(stdout);
> - switch (child[i] = SAFE_FORK()) {
> - case 0:
> - if (i == 0) {
> - create_ksm_child(i, size, unit, ksm_data0);
> - exit(0);
> - } else if (i == 1) {
> - create_ksm_child(i, size, unit, ksm_data1);
> - exit(0);
> - } else if (i == 2) {
> - create_ksm_child(i, size, unit, ksm_data2);
> - exit(0);
> - } else {
> - create_ksm_child(i, size, unit,
> ksm_data[i-3]);
> - exit(0);
> - }
> - }
> - }
> -
> - stop_ksm_children(child, num);
> -
> - tst_res(TINFO, "KSM merging...");
> - if (access(PATH_KSM "max_page_sharing", F_OK) == 0) {
> - SAFE_FILE_PRINTF(PATH_KSM "run", "2");
> - SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", "%ld", size
> * pages * num);
> - }
> -
> - SAFE_FILE_PRINTF(PATH_KSM "run", "1");
> - SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", size * pages *
> num);
> - SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0");
> -
> - resume_ksm_children(child, num);
> - stop_ksm_children(child, num);
> - ksm_group_check(1, 2, size * num * pages - 2, 0, 0, 0, size *
> pages * num);
> -
> - resume_ksm_children(child, num);
> - stop_ksm_children(child, num);
> - ksm_group_check(1, 3, size * num * pages - 3, 0, 0, 0, size *
> pages * num);
> -
> - resume_ksm_children(child, num);
> - stop_ksm_children(child, num);
> - ksm_group_check(1, 1, size * num * pages - 1, 0, 0, 0, size *
> pages * num);
> -
> - resume_ksm_children(child, num);
> - stop_ksm_children(child, num);
> - ksm_group_check(1, 1, size * num * pages - 2, 0, 1, 0, size *
> pages * num);
> -
> - tst_res(TINFO, "KSM unmerging...");
> - SAFE_FILE_PRINTF(PATH_KSM "run", "2");
> -
> - resume_ksm_children(child, num);
> - final_group_check(2, 0, 0, 0, 0, 0, size * pages * num);
> -
> - tst_res(TINFO, "stop KSM.");
> - SAFE_FILE_PRINTF(PATH_KSM "run", "0");
> - final_group_check(0, 0, 0, 0, 0, 0, size * pages * num);
> -
> - while (waitpid(-1, &status, 0) > 0)
> - if (WEXITSTATUS(status) != 0)
> - tst_res(TFAIL, "child exit status is %d",
> - WEXITSTATUS(status));
> -}
> --
> 2.45.2
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp
>
>

--
Regards,
Li Wang