printf("Supported :\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" " 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");
if (ksm_read_sysfs(KSM_FP("pages_shared"), &pages_shared) ||
ksm_read_sysfs(KSM_FP("pages_sharing"), &pages_sharing) ||
ksm_read_sysfs(KSM_FP("max_page_sharing"), &max_page_sharing)) returnfalse;
if (debug) {
ksm_print_sysfs();
ksm_print_procfs();
}
/* * Since there must be at least 2 pages for merging and 1 page can be * shared with the limited number of pages (max_page_sharing), sometimes * there are 'leftover' pages that cannot be merged. For example, if there * are 11 pages and max_page_sharing = 10, then only 10 pages will be * merged and the 11th page won't be affected. As a result, when the number * of duplicate pages is divided by max_page_sharing and the remainder is 1, * pages_shared and pages_sharing values will be equal between dupl_page_count * and dupl_page_count - 1.
*/ if (dupl_page_count % max_page_sharing == 1 || dupl_page_count % max_page_sharing == 0) { if (pages_shared == dupl_page_count / max_page_sharing &&
pages_sharing == pages_shared * (max_page_sharing - 1)) returntrue;
} else { if (pages_shared == (dupl_page_count / max_page_sharing + 1) &&
pages_sharing == dupl_page_count - pages_shared) returntrue;
}
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;
/* * verify that the right number of pages are merged: * 1) if use_zero_pages is set to 1, empty pages are merged * with the kernel zero page instead of with each other; * 2) if use_zero_pages is set to 0, empty pages are not treated specially * and merged as usual.
*/ if (use_zero_pages && !assert_ksm_pages_count(0)) goto err_out; elseif (!use_zero_pages && !assert_ksm_pages_count(page_count)) 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;
}
/* try to merge the pages */ if (ksm_merge_pages(merge_type, numa1_map_ptr, page_size, start_time, timeout) ||
ksm_merge_pages(merge_type, numa2_map_ptr, page_size, start_time, timeout)) goto err_out;
/* * verify that the right number of pages are merged: * 1) if merge_across_nodes was enabled, 2 duplicate pages will be merged; * 2) if merge_across_nodes = 0, there must be 0 merged pages, since there is * only 1 unique page in each node and they can't be shared.
*/ if (merge_across_nodes && !assert_ksm_pages_count(page_count)) goto err_out; elseif (!merge_across_nodes && !assert_ksm_pages_count(0)) goto err_out;
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;
}
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.