Loading...
tests/perf_compressor.c xnu-12377.121.6 /dev/null
--- xnu/xnu-12377.121.6/tests/perf_compressor.c
+++ /dev/null
@@ -1,455 +0,0 @@
-#include <stdio.h>
-#include <signal.h>
-#include <sys/sysctl.h>
-#include <sys/kern_memorystatus.h>
-#include <mach-o/dyld.h>
-#include <perfcheck_keys.h>
-
-#ifdef T_NAMESPACE
-#undef T_NAMESPACE
-#endif
-#include <darwintest.h>
-#include <darwintest_utils.h>
-
-T_GLOBAL_META(
-	T_META_NAMESPACE("xnu.vm.perf"),
-	T_META_RADAR_COMPONENT_NAME("xnu"),
-	T_META_RADAR_COMPONENT_VERSION("VM"),
-	T_META_CHECK_LEAKS(false),
-	T_META_TAG_PERF,
-	T_META_ENABLED(false) /* rdar://84443533 */
-	);
-
-enum {
-	ALL_ZEROS,
-	MOSTLY_ZEROS,
-	RANDOM,
-	TYPICAL
-};
-
-#define CREATE_LIST(X) \
-	X(SUCCESS) \
-	X(TOO_FEW_ARGUMENTS) \
-	X(SYSCTL_VM_PAGESIZE_FAILED) \
-	X(VM_PAGESIZE_IS_ZERO) \
-	X(UNKNOWN_PAGE_TYPE) \
-	X(DISPATCH_SOURCE_CREATE_FAILED) \
-	X(INITIAL_SIGNAL_TO_PARENT_FAILED) \
-	X(SIGNAL_TO_PARENT_FAILED) \
-	X(MEMORYSTATUS_CONTROL_FAILED) \
-	X(IS_FREEZABLE_NOT_AS_EXPECTED) \
-	X(EXIT_CODE_MAX)
-
-#define EXIT_CODES_ENUM(VAR) VAR,
-enum exit_codes_num {
-	CREATE_LIST(EXIT_CODES_ENUM)
-};
-
-#define EXIT_CODES_STRING(VAR) #VAR,
-static const char *exit_codes_str[] = {
-	CREATE_LIST(EXIT_CODES_STRING)
-};
-
-#define SYSCTL_FREEZE_TO_MEMORY         "kern.memorystatus_freeze_to_memory=1"
-
-static pid_t pid = -1;
-static dt_stat_t ratio;
-static dt_stat_time_t compr_time;
-static dt_stat_time_t decompr_time;
-
-void allocate_zero_pages(char **buf, int num_pages, int vmpgsize);
-void allocate_mostly_zero_pages(char **buf, int num_pages, int vmpgsize);
-void allocate_random_pages(char **buf, int num_pages, int vmpgsize);
-void allocate_representative_pages(char **buf, int num_pages, int vmpgsize);
-void run_compressor_test(int size_mb, int page_type);
-void freeze_helper_process(void);
-void cleanup(void);
-
-void
-allocate_zero_pages(char **buf, int num_pages, int vmpgsize)
-{
-	int i;
-
-	for (i = 0; i < num_pages; i++) {
-		buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
-		memset(buf[i], 0, vmpgsize);
-	}
-}
-
-void
-allocate_mostly_zero_pages(char **buf, int num_pages, int vmpgsize)
-{
-	int i, j;
-
-	for (i = 0; i < num_pages; i++) {
-		buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
-		memset(buf[i], 0, vmpgsize);
-		for (j = 0; j < 40; j++) {
-			buf[i][j] = (char)(j + 1);
-		}
-	}
-}
-
-void
-allocate_random_pages(char **buf, int num_pages, int vmpgsize)
-{
-	int i;
-
-	for (i = 0; i < num_pages; i++) {
-		buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
-		arc4random_buf((void*)buf[i], (size_t)vmpgsize);
-	}
-}
-
-// Gives us the compression ratio we see in the typical case (~2.7)
-void
-allocate_representative_pages(char **buf, int num_pages, int vmpgsize)
-{
-	int i, j;
-	char val;
-
-	for (j = 0; j < num_pages; j++) {
-		buf[j] = (char*)malloc((size_t)vmpgsize * sizeof(char));
-		val = 0;
-		for (i = 0; i < vmpgsize; i += 16) {
-			memset(&buf[j][i], val, 16);
-			if (i < 3400 * (vmpgsize / 4096)) {
-				val++;
-			}
-		}
-	}
-}
-
-void
-freeze_helper_process(void)
-{
-	int ret, freeze_enabled;
-	int64_t compressed_before, compressed_after, input_before, input_after;
-	size_t length;
-	int errno_sysctl_freeze;
-
-	length = sizeof(compressed_before);
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_compressed_bytes", &compressed_before, &length, NULL, 0),
-	    "failed to query vm.compressor_compressed_bytes");
-	length = sizeof(input_before);
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_input_bytes", &input_before, &length, NULL, 0),
-	    "failed to query vm.compressor_input_bytes");
-
-	T_STAT_MEASURE(compr_time) {
-		ret = sysctlbyname("kern.memorystatus_freeze", NULL, NULL, &pid, sizeof(pid));
-		errno_sysctl_freeze = errno;
-	};
-
-	length = sizeof(compressed_after);
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_compressed_bytes", &compressed_after, &length, NULL, 0),
-	    "failed to query vm.compressor_compressed_bytes");
-	length = sizeof(input_after);
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_input_bytes", &input_after, &length, NULL, 0),
-	    "failed to query vm.compressor_input_bytes");
-
-	length = sizeof(freeze_enabled);
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.freeze_enabled", &freeze_enabled, &length, NULL, 0),
-	    "failed to query vm.freeze_enabled");
-	if (freeze_enabled) {
-		errno = errno_sysctl_freeze;
-		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl kern.memorystatus_freeze failed");
-	} else {
-		/* If freezer is disabled, skip the test. This can happen due to disk space shortage. */
-		T_LOG("Freeze has been disabled. Terminating early.");
-		T_END;
-	}
-
-	dt_stat_add(ratio, (double)(input_after - input_before) / (double)(compressed_after - compressed_before));
-
-	ret = sysctlbyname("kern.memorystatus_thaw", NULL, NULL, &pid, sizeof(pid));
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl kern.memorystatus_thaw failed");
-
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGUSR1), "failed to send SIGUSR1 to child process");
-}
-
-void
-cleanup(void)
-{
-	/* No helper process. */
-	if (pid == -1) {
-		return;
-	}
-	/* Kill the helper process. */
-	kill(pid, SIGKILL);
-}
-
-void
-run_compressor_test(int size_mb, int page_type)
-{
-	int ret;
-	char sz_str[50];
-	char pt_str[50];
-	char **launch_tool_args;
-	char testpath[PATH_MAX];
-	uint32_t testpath_buf_size;
-	dispatch_source_t ds_freeze, ds_proc, ds_decompr;
-	int freeze_enabled;
-	size_t length;
-	__block bool decompr_latency_is_stable = false;
-
-	length = sizeof(freeze_enabled);
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.freeze_enabled", &freeze_enabled, &length, NULL, 0),
-	    "failed to query vm.freeze_enabled");
-	if (!freeze_enabled) {
-		/* If freezer is disabled, skip the test. This can happen due to disk space shortage. */
-		T_SKIP("Freeze has been disabled. Skipping test.");
-	}
-
-	T_ATEND(cleanup);
-
-	ratio = dt_stat_create("(input bytes / compressed bytes)", "compression_ratio");
-	compr_time = dt_stat_time_create("compressor_latency");
-
-	// This sets the A/B failure threshold at 50% of baseline for compressor_latency
-	dt_stat_set_variable((struct dt_stat *)compr_time, kPCFailureThresholdPctVar, 50.0);
-
-	signal(SIGUSR2, SIG_IGN);
-	ds_decompr = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR2, 0, dispatch_get_main_queue());
-	T_QUIET; T_ASSERT_NOTNULL(ds_decompr, "dispatch_source_create (ds_decompr)");
-
-	dispatch_source_set_event_handler(ds_decompr, ^{
-		decompr_latency_is_stable = true;
-	});
-	dispatch_activate(ds_decompr);
-
-	signal(SIGUSR1, SIG_IGN);
-	ds_freeze = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dispatch_get_main_queue());
-	T_QUIET; T_ASSERT_NOTNULL(ds_freeze, "dispatch_source_create (ds_freeze)");
-
-	dispatch_source_set_event_handler(ds_freeze, ^{
-		if (!(dt_stat_stable(compr_time) && decompr_latency_is_stable)) {
-		        freeze_helper_process();
-		} else {
-		        dt_stat_finalize(compr_time);
-		        dt_stat_finalize(ratio);
-
-		        kill(pid, SIGKILL);
-		        dispatch_source_cancel(ds_freeze);
-		        dispatch_source_cancel(ds_decompr);
-		}
-	});
-	dispatch_activate(ds_freeze);
-
-	testpath_buf_size = sizeof(testpath);
-	ret = _NSGetExecutablePath(testpath, &testpath_buf_size);
-	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "_NSGetExecutablePath");
-	T_LOG("Executable path: %s", testpath);
-
-	sprintf(sz_str, "%d", size_mb);
-	sprintf(pt_str, "%d", page_type);
-	launch_tool_args = (char *[]){
-		testpath,
-		"-n",
-		"allocate_pages",
-		"--",
-		sz_str,
-		pt_str,
-		NULL
-	};
-
-	/* Spawn the child process. Suspend after launch until the exit proc handler has been set up. */
-	ret = dt_launch_tool(&pid, launch_tool_args, true, NULL, NULL);
-	if (ret != 0) {
-		T_LOG("dt_launch tool returned %d with error code %d", ret, errno);
-	}
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "dt_launch_tool");
-
-	ds_proc = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, (uintptr_t)pid, DISPATCH_PROC_EXIT, dispatch_get_main_queue());
-	T_QUIET; T_ASSERT_NOTNULL(ds_proc, "dispatch_source_create (ds_proc)");
-
-	dispatch_source_set_event_handler(ds_proc, ^{
-		int status = 0, code = 0;
-		pid_t rc = waitpid(pid, &status, 0);
-		T_QUIET; T_ASSERT_EQ(rc, pid, "waitpid");
-		code = WEXITSTATUS(status);
-
-		if (code == 0) {
-		        T_END;
-		} else if (code > 0 && code < EXIT_CODE_MAX) {
-		        T_ASSERT_FAIL("Child exited with %s", exit_codes_str[code]);
-		} else {
-		        T_ASSERT_FAIL("Child exited with unknown exit code %d", code);
-		}
-	});
-	dispatch_activate(ds_proc);
-
-	T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGCONT), "failed to send SIGCONT to child process");
-	dispatch_main();
-}
-
-T_HELPER_DECL(allocate_pages, "allocates pages to compress") {
-	int i, j, ret, size_mb, page_type, vmpgsize, freezable_state;
-	size_t vmpgsize_length;
-	__block int num_pages;
-	__block char **buf;
-	dispatch_source_t ds_signal;
-
-	vmpgsize_length = sizeof(vmpgsize);
-	ret = sysctlbyname("vm.pagesize", &vmpgsize, &vmpgsize_length, NULL, 0);
-	if (ret != 0) {
-		exit(SYSCTL_VM_PAGESIZE_FAILED);
-	}
-	if (vmpgsize == 0) {
-		exit(VM_PAGESIZE_IS_ZERO);
-	}
-
-	if (argc < 2) {
-		exit(TOO_FEW_ARGUMENTS);
-	}
-
-	size_mb = atoi(argv[0]);
-	page_type = atoi(argv[1]);
-	num_pages = size_mb * 1024 * 1024 / vmpgsize;
-	buf = (char**)malloc(sizeof(char*) * (size_t)num_pages);
-
-	// Switch on the type of page requested
-	switch (page_type) {
-	case ALL_ZEROS:
-		allocate_zero_pages(buf, num_pages, vmpgsize);
-		break;
-	case MOSTLY_ZEROS:
-		allocate_mostly_zero_pages(buf, num_pages, vmpgsize);
-		break;
-	case RANDOM:
-		allocate_random_pages(buf, num_pages, vmpgsize);
-		break;
-	case TYPICAL:
-		allocate_representative_pages(buf, num_pages, vmpgsize);
-		break;
-	default:
-		exit(UNKNOWN_PAGE_TYPE);
-	}
-
-	for (j = 0; j < num_pages; j++) {
-		i = buf[j][0];
-	}
-
-	decompr_time = dt_stat_time_create("decompression_latency");
-
-	/* Opt in to freezing. */
-	printf("[%d] Setting state to freezable\n", getpid());
-	if (memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_FREEZABLE, getpid(), 1, NULL, 0) != KERN_SUCCESS) {
-		exit(MEMORYSTATUS_CONTROL_FAILED);
-	}
-
-	/* Verify that the state has been set correctly */
-	freezable_state = memorystatus_control(MEMORYSTATUS_CMD_GET_PROCESS_IS_FREEZABLE, getpid(), 0, NULL, 0);
-	if (freezable_state != 1) {
-		exit(IS_FREEZABLE_NOT_AS_EXPECTED);
-	}
-
-	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{
-		/* Signal to the parent that we're done allocating and it's ok to freeze us */
-		printf("[%d] Sending initial signal to parent to begin freezing\n", getpid());
-		if (kill(getppid(), SIGUSR1) != 0) {
-		        exit(INITIAL_SIGNAL_TO_PARENT_FAILED);
-		}
-	});
-
-	signal(SIGUSR1, SIG_IGN);
-	ds_signal = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dispatch_get_main_queue());
-	if (ds_signal == NULL) {
-		exit(DISPATCH_SOURCE_CREATE_FAILED);
-	}
-
-	__block bool collect_dt_stat_measurements = true;
-
-	dispatch_source_set_event_handler(ds_signal, ^{
-		volatile int tmp;
-		uint64_t decompr_start_time, decompr_end_time;
-
-		decompr_start_time = mach_absolute_time();
-
-		/* Make sure all the pages are accessed before trying to freeze again */
-		for (int x = 0; x < num_pages; x++) {
-		        tmp = buf[x][0];
-		}
-
-		decompr_end_time = mach_absolute_time();
-
-		if (collect_dt_stat_measurements) {
-			if (dt_stat_stable(decompr_time)) {
-				collect_dt_stat_measurements = false;
-				dt_stat_finalize(decompr_time);
-				if (kill(getppid(), SIGUSR2) != 0) {
-					exit(SIGNAL_TO_PARENT_FAILED);
-				}
-			} else {
-				dt_stat_mach_time_add(decompr_time, decompr_end_time - decompr_start_time);
-			}
-		}
-
-		if (kill(getppid(), SIGUSR1) != 0) {
-		        exit(SIGNAL_TO_PARENT_FAILED);
-		}
-	});
-	dispatch_activate(ds_signal);
-
-	dispatch_main();
-}
-
-// Numbers for 10MB and above are fairly reproducible. Anything smaller shows a lot of variation.
-
-// Keeping just the 100MB version for iOSMark
-#ifndef DT_IOSMARK
-T_DECL(compr_10MB_zero,
-    "Compression latency for 10MB - zero pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(10, ALL_ZEROS);
-}
-
-T_DECL(compr_10MB_mostly_zero,
-    "Compression latency for 10MB - mostly zero pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(10, MOSTLY_ZEROS);
-}
-
-T_DECL(compr_10MB_random,
-    "Compression latency for 10MB - random pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(10, RANDOM);
-}
-
-T_DECL(compr_10MB_typical,
-    "Compression latency for 10MB - typical pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(10, TYPICAL);
-}
-
-T_DECL(compr_100MB_zero,
-    "Compression latency for 100MB - zero pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(100, ALL_ZEROS);
-}
-
-T_DECL(compr_100MB_mostly_zero,
-    "Compression latency for 100MB - mostly zero pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(100, MOSTLY_ZEROS);
-}
-
-T_DECL(compr_100MB_random,
-    "Compression latency for 100MB - random pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(100, RANDOM);
-}
-#endif
-
-T_DECL(compr_100MB_typical,
-    "Compression latency for 100MB - typical pages",
-    T_META_ASROOT(true),
-    T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY), T_META_TAG_VM_NOT_ELIGIBLE) {
-	run_compressor_test(100, TYPICAL);
-}