printf("Supported <test type>:\n" " -M (page merging)\n" " -Z (zero pages merging)\n" " -N (merging of pages in different NUMA nodes)\n" " -U (page unmerging)\n" " -P evaluate merging time and speed.\n" " For this test, the size of duplicated memory area (in MiB)\n" " must be provided using -s option\n" " -H evaluate merging time and speed of area allocated mostly with huge pages\n" " For this test, the size of duplicated memory area (in MiB)\n" " must be provided using -s option\n" " -D evaluate unmerging time and speed when disabling KSM.\n" " For this test, the size of duplicated memory area (in MiB)\n" " must be provided using -s option\n" " -C evaluate the time required to break COW of merged pages.\n\n");
printf(" -a: specify the access protections of pages.\n" " <prot> must be of the form [rwx].\n" " Default: %s\n", KSM_PROT_STR_DEFAULT);
printf(" -p: specify the number of pages to test.\n" " Default: %ld\n", KSM_PAGE_COUNT_DEFAULT);
printf(" -l: limit the maximum running time (in seconds) for a test.\n" " Default: %d seconds\n", KSM_SCAN_LIMIT_SEC_DEFAULT);
printf(" -z: change use_zero_pages tunable\n" " Default: %d\n", KSM_USE_ZERO_PAGES_DEFAULT);
printf(" -m: change merge_across_nodes tunable\n" " Default: %d\n", KSM_MERGE_ACROSS_NODES_DEFAULT);
printf(" -d: turn debugging output on\n");
printf(" -s: the size of duplicated memory area (in MiB)\n");
printf(" -t: KSM merge type\n" " Default: 0\n" " 0: madvise merging\n" " 1: prctl merging\n");
staticint check_ksm_merge(int merge_type, int mapping, int prot, long page_count, int timeout, size_t page_size)
{ void *map_ptr; struct timespec start_time;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
perror("clock_gettime"); return KSFT_FAIL;
}
/* fill pages with the same data and merge them */
map_ptr = allocate_memory(NULL, prot, mapping, '*', page_size * page_count); if (!map_ptr) return KSFT_FAIL;
if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) goto err_out;
/* verify that the right number of pages are merged */ if (assert_ksm_pages_count(page_count)) {
printf("OK\n");
munmap(map_ptr, page_size * page_count); if (merge_type == KSM_MERGE_PRCTL)
prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); return KSFT_PASS;
}
staticint check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout, size_t page_size)
{ void *map_ptr; struct timespec start_time; int page_count = 2;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
perror("clock_gettime"); return KSFT_FAIL;
}
/* fill pages with the same data and merge them */
map_ptr = allocate_memory(NULL, prot, mapping, '*', page_size * page_count); if (!map_ptr) return KSFT_FAIL;
if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) goto err_out;
/* change 1 byte in each of the 2 pages -- KSM must automatically unmerge them */
memset(map_ptr, '-', 1);
memset(map_ptr + page_size, '+', 1);
/* get at least 1 scan, so KSM can detect that the pages were modified */ if (ksm_do_scan(1, start_time, timeout)) goto err_out;
/* check that unmerging was successful and 0 pages are currently merged */ if (assert_ksm_pages_count(0)) {
printf("OK\n");
munmap(map_ptr, page_size * page_count); return KSFT_PASS;
}
staticint check_ksm_zero_page_merge(int merge_type, int mapping, int prot, long page_count, int timeout, bool use_zero_pages, size_t page_size)
{ void *map_ptr; struct timespec start_time;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
perror("clock_gettime"); return KSFT_FAIL;
}
if (ksm_write_sysfs(KSM_FP("use_zero_pages"), use_zero_pages)) return KSFT_FAIL;
/* fill pages with zero and try to merge them */
map_ptr = allocate_memory(NULL, prot, mapping, 0, page_size * page_count); if (!map_ptr) return KSFT_FAIL;
if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) goto err_out;
staticint check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeout, bool merge_across_nodes, size_t page_size)
{ void *numa1_map_ptr, *numa2_map_ptr; struct timespec start_time; int page_count = 2; int first_node;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
perror("clock_gettime"); return KSFT_FAIL;
}
if (numa_available() < 0) {
perror("NUMA support not enabled"); return KSFT_SKIP;
} if (numa_num_configured_nodes() <= 1) {
printf("At least 2 NUMA nodes must be available\n"); return KSFT_SKIP;
} if (ksm_write_sysfs(KSM_FP("merge_across_nodes"), merge_across_nodes)) return KSFT_FAIL;
/* allocate 2 pages in 2 different NUMA nodes and fill them with the same data */
first_node = get_first_mem_node();
numa1_map_ptr = numa_alloc_onnode(page_size, first_node);
numa2_map_ptr = numa_alloc_onnode(page_size, get_next_mem_node(first_node)); if (!numa1_map_ptr || !numa2_map_ptr) {
perror("numa_alloc_onnode"); return KSFT_FAIL;
}
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
perror("clock_gettime"); return KSFT_FAIL;
} for (size_t i = 0; i < page_count - 1; i = i + 2)
memset(map_ptr + page_size * i, '-', 1); if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_time)) {
perror("clock_gettime"); return KSFT_FAIL;
}
/* Create 2000 pairs of duplicate pages */ for (size_t i = 0; i < page_count - 1; i = i + 2) {
memset(map_ptr + page_size * i, '+', i / 2 + 1);
memset(map_ptr + page_size * (i + 1), '+', i / 2 + 1);
} if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) goto err_out;
if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) {
perror("clock_gettime"); goto err_out;
} for (size_t i = 0; i < page_count - 1; i = i + 2)
memset(map_ptr + page_size * i, '-', 1); if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_time)) {
perror("clock_gettime"); goto err_out;
}
switch (test_name) { case CHECK_KSM_MERGE:
ret = check_ksm_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count,
ksm_scan_limit_sec, page_size); break; case CHECK_KSM_UNMERGE:
ret = check_ksm_unmerge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, page_size); break; case CHECK_KSM_ZERO_PAGE_MERGE:
ret = check_ksm_zero_page_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
page_count, ksm_scan_limit_sec, use_zero_pages,
page_size); break; case CHECK_KSM_NUMA_MERGE:
ret = check_ksm_numa_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, merge_across_nodes, page_size); break; case KSM_MERGE_TIME: if (size_MB == 0) {
printf("Option '-s' is required.\n"); return KSFT_FAIL;
}
ret = ksm_merge_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, size_MB); break; case KSM_MERGE_TIME_HUGE_PAGES: if (size_MB == 0) {
printf("Option '-s' is required.\n"); return KSFT_FAIL;
}
ret = ksm_merge_hugepages_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, size_MB); break; case KSM_UNMERGE_TIME: if (size_MB == 0) {
printf("Option '-s' is required.\n"); return KSFT_FAIL;
}
ret = ksm_unmerge_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, size_MB); break; case KSM_COW_TIME:
ret = ksm_cow_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot,
ksm_scan_limit_sec, page_size); break;
}
if (ksm_restore(&ksm_sysfs_old)) {
printf("Cannot restore default tunables\n"); return KSFT_FAIL;
}
return ret;
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.18Bemerkung:
(vorverarbeitet am 2026-10-12)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.