if (!group_name) return NULL; if (cg_create(group_name)) goto fail; if (cg_write(group_name, "memory.max", "1M")) {
cg_destroy(group_name); goto fail;
} return group_name;
fail:
free(group_name); return NULL;
}
/* *Sanitytesttocheckthatpagesarewrittenintozswap.
*/ staticint test_zswap_usage(constchar *root)
{ long zswpout_before, zswpout_after; int ret = KSFT_FAIL; char *test_group;
test_group = cg_name(root, "no_shrink_test"); if (!test_group) goto out; if (cg_create(test_group)) goto out; if (cg_write(test_group, "memory.max", "1M")) goto out;
zswpout_before = get_zswpout(test_group); if (zswpout_before < 0) {
ksft_print_msg("Failed to get zswpout\n"); goto out;
}
/* Allocate more than memory.max to push memory into zswap */ if (cg_run(test_group, allocate_bytes, (void *)MB(4))) goto out;
/* Verify that pages come into zswap */
zswpout_after = get_zswpout(test_group); if (zswpout_after <= zswpout_before) {
ksft_print_msg("zswpout does not increase after test program\n"); goto out;
}
ret = KSFT_PASS;
/* *Checkthatwhenmemory.zswap.max=0,nopagescangotothezswappoolfor *thecgroup.
*/ staticint test_swapin_nozswap(constchar *root)
{ int ret = KSFT_FAIL; char *test_group; long swap_peak, zswpout;
test_group = cg_name(root, "no_zswap_test"); if (!test_group) goto out; if (cg_create(test_group)) goto out; if (cg_write(test_group, "memory.max", "8M")) goto out; if (cg_write(test_group, "memory.zswap.max", "0")) goto out;
/* Allocate and read more than memory.max to trigger swapin */ if (cg_run(test_group, allocate_and_read_bytes, (void *)MB(32))) goto out;
/* Verify that pages are swapped out, but no zswap happened */
swap_peak = cg_read_long(test_group, "memory.swap.peak"); if (swap_peak < 0) {
ksft_print_msg("failed to get cgroup's swap_peak\n"); goto out;
}
if (swap_peak < MB(24)) {
ksft_print_msg("at least 24MB of memory should be swapped out\n"); goto out;
}
zswpout = get_zswpout(test_group); if (zswpout < 0) {
ksft_print_msg("failed to get zswpout\n"); goto out;
}
if (zswpout > 0) {
ksft_print_msg("zswapout > 0 when memory.zswap.max = 0\n"); goto out;
}
mem = (char *)malloc(memsize); if (!mem) return ret;
/* *Fillhalfofeachpagewithincreasingdata,andkeepother *halfempty,thiswillresultindatathatisstillcompressible *andendsupinzswap,withmaterialzswapusage.
*/ for (int i = 0; i < pagesize; i++)
buf[i] = i < pagesize/2 ? (char) i : 0;
for (int i = 0; i < memsize; i += pagesize)
memcpy(&mem[i], buf, pagesize);
/* Try and reclaim allocated memory */ if (cg_write_numeric(cgroup, "memory.reclaim", memsize)) {
ksft_print_msg("Failed to reclaim all of the requested memory\n"); goto out;
}
/* zswpin */ for (int i = 0; i < memsize; i += pagesize) { if (memcmp(&mem[i], buf, pagesize)) {
ksft_print_msg("invalid memory\n"); goto out;
}
}
if (cg_write_numeric(cgroup, "memory.zswap.max", zswap_usage/2)) goto out;
/* *Ifwritebackisenabled,tryingtoreclaimmemorynowwilltriggera *writebackaszswap.maxishalfofwhatwasneededwhenreclaimranthefirsttime. *Ifwritebackisdisabled,memoryreclaimwillfailaszswapislimitedand *itcan'twritebacktoswap.
*/
ret = cg_write_numeric(cgroup, "memory.reclaim", memsize); if (!wb_enabled)
ret = (ret == -EAGAIN) ? 0 : -1;
out:
free(mem); return ret;
}
staticint test_zswap_writeback_one(constchar *cgroup, bool wb)
{ long zswpwb_before, zswpwb_after;
zswpwb_before = get_cg_wb_count(cgroup); if (zswpwb_before != 0) {
ksft_print_msg("zswpwb_before = %ld instead of 0\n", zswpwb_before); return -1;
}
if (cg_run(cgroup, attempt_writeback, (void *) &wb)) return -1;
/* Verify that zswap writeback occurred only if writeback was enabled */
zswpwb_after = get_cg_wb_count(cgroup); if (zswpwb_after < 0) return -1;
if (wb != !!zswpwb_after) {
ksft_print_msg("zswpwb_after is %ld while wb is %s\n",
zswpwb_after, wb ? "enabled" : "disabled"); return -1;
}
return0;
}
/* Test to verify the zswap writeback path */ staticint test_zswap_writeback(constchar *root, bool wb)
{ int ret = KSFT_FAIL; char *test_group, *test_group_child = NULL;
if (cg_read_strcmp(root, "memory.zswap.writeback", "1")) return KSFT_SKIP;
test_group = cg_name(root, "zswap_writeback_test"); if (!test_group) goto out; if (cg_create(test_group)) goto out; if (cg_write(test_group, "memory.zswap.writeback", wb ? "1" : "0")) goto out;
if (test_zswap_writeback_one(test_group, wb)) goto out;
/* Reset memory.zswap.max to max (modified by attempt_writeback), and *setupchildcgroup,whosememory.zswap.writebackishardcodedto1.
* Thus, the parent's setting shall be what's in effect. */ if (cg_write(test_group, "memory.zswap.max", "max")) goto out; if (cg_write(test_group, "cgroup.subtree_control", "+memory")) goto out;
test_group_child = cg_name(test_group, "zswap_writeback_test_child"); if (!test_group_child) goto out; if (cg_create(test_group_child)) goto out; if (cg_write(test_group_child, "memory.zswap.writeback", "1")) goto out;
if (test_zswap_writeback_one(test_group_child, wb)) goto out;
wb_group = setup_test_group_1M(root, "per_memcg_wb_test1"); if (!wb_group) return KSFT_FAIL; if (cg_write(wb_group, "memory.zswap.max", "10K")) goto out;
control_group = setup_test_group_1M(root, "per_memcg_wb_test2"); if (!control_group) goto out;
/* Push some test_group2 memory into zswap */ if (cg_enter_current(control_group)) goto out;
control_allocation = malloc(control_allocation_size); for (int i = 0; i < control_allocation_size; i += 4095)
control_allocation[i] = 'a'; if (cg_read_key_long(control_group, "memory.stat", "zswapped") < 1) goto out;
/* Allocate 10x memory.max to push wb_group memory into zswap and trigger wb */ if (cg_run(wb_group, allocate_bytes, (void *)MB(10))) goto out;
/* Verify that only zswapped memory from gwb_group has been written back */ if (get_cg_wb_count(wb_group) > 0 && get_cg_wb_count(control_group) == 0)
ret = KSFT_PASS;
out:
cg_enter_current(root); if (control_group) {
cg_destroy(control_group);
free(control_group);
}
cg_destroy(wb_group);
free(wb_group); if (control_allocation)
free(control_allocation); return ret;
}
/* Set up test memcg */
test_group = cg_name(root, "kmem_bypass_test"); if (!test_group) goto out;
/* Spawn memcg child and wait for it to allocate */
set_min_free_kb(min_free_kb_low); if (cg_create(test_group)) goto out;
values->child_allocated = false;
child_pid = cg_run_nowait(test_group, no_kmem_bypass_child, values); if (child_pid < 0) goto out; while (!values->child_allocated && wait_child_iteration++ < 10000)
usleep(1000);
/* Try to wakeup kswapd and let it push child memory to zswap */
set_min_free_kb(min_free_kb_high); for (int i = 0; i < 20; i++) {
size_t stored_pages; char *trigger_allocation = malloc(trigger_allocation_size);
if (!trigger_allocation) break; for (int i = 0; i < trigger_allocation_size; i += 4095)
trigger_allocation[i] = 'b';
usleep(100000);
free(trigger_allocation); if (get_zswap_stored_pages(&stored_pages)) break; if (stored_pages < 0) break; /* If memory was pushed to zswap, verify it belongs to memcg */ if (stored_pages > stored_pages_threshold) { int zswapped = cg_read_key_long(test_group, "memory.stat", "zswapped "); int delta = stored_pages * 4096 - zswapped; int result_ok = delta < stored_pages * 4096 / 4;
ret = result_ok ? KSFT_PASS : KSFT_FAIL; break;
}
}
if (cg_read_strstr(root, "cgroup.subtree_control", "memory")) if (cg_write(root, "cgroup.subtree_control", "+memory"))
ksft_exit_skip("Failed to set memory controller\n");
for (i = 0; i < ARRAY_SIZE(tests); i++) { switch (tests[i].fn(root)) { case KSFT_PASS:
ksft_test_result_pass("%s\n", tests[i].name); break; case KSFT_SKIP:
ksft_test_result_skip("%s\n", tests[i].name); break; default:
ret = EXIT_FAILURE;
ksft_test_result_fail("%s\n", tests[i].name); break;
}
}
return ret;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-10-11)
¤
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.