xref: /xnu-8019.80.24/tests/perf_compressor.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1*a325d9c4SApple OSS Distributions #include <stdio.h>
2*a325d9c4SApple OSS Distributions #include <signal.h>
3*a325d9c4SApple OSS Distributions #include <sys/sysctl.h>
4*a325d9c4SApple OSS Distributions #include <sys/kern_memorystatus.h>
5*a325d9c4SApple OSS Distributions #include <mach-o/dyld.h>
6*a325d9c4SApple OSS Distributions #include <perfcheck_keys.h>
7*a325d9c4SApple OSS Distributions 
8*a325d9c4SApple OSS Distributions #ifdef T_NAMESPACE
9*a325d9c4SApple OSS Distributions #undef T_NAMESPACE
10*a325d9c4SApple OSS Distributions #endif
11*a325d9c4SApple OSS Distributions #include <darwintest.h>
12*a325d9c4SApple OSS Distributions #include <darwintest_utils.h>
13*a325d9c4SApple OSS Distributions 
14*a325d9c4SApple OSS Distributions T_GLOBAL_META(
15*a325d9c4SApple OSS Distributions 	T_META_NAMESPACE("xnu.vm.perf"),
16*a325d9c4SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
17*a325d9c4SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"),
18*a325d9c4SApple OSS Distributions 	T_META_CHECK_LEAKS(false),
19*a325d9c4SApple OSS Distributions 	T_META_TAG_PERF
20*a325d9c4SApple OSS Distributions 	);
21*a325d9c4SApple OSS Distributions 
22*a325d9c4SApple OSS Distributions enum {
23*a325d9c4SApple OSS Distributions 	ALL_ZEROS,
24*a325d9c4SApple OSS Distributions 	MOSTLY_ZEROS,
25*a325d9c4SApple OSS Distributions 	RANDOM,
26*a325d9c4SApple OSS Distributions 	TYPICAL
27*a325d9c4SApple OSS Distributions };
28*a325d9c4SApple OSS Distributions 
29*a325d9c4SApple OSS Distributions #define CREATE_LIST(X) \
30*a325d9c4SApple OSS Distributions 	X(SUCCESS) \
31*a325d9c4SApple OSS Distributions 	X(TOO_FEW_ARGUMENTS) \
32*a325d9c4SApple OSS Distributions 	X(SYSCTL_VM_PAGESIZE_FAILED) \
33*a325d9c4SApple OSS Distributions 	X(VM_PAGESIZE_IS_ZERO) \
34*a325d9c4SApple OSS Distributions 	X(UNKNOWN_PAGE_TYPE) \
35*a325d9c4SApple OSS Distributions 	X(DISPATCH_SOURCE_CREATE_FAILED) \
36*a325d9c4SApple OSS Distributions 	X(INITIAL_SIGNAL_TO_PARENT_FAILED) \
37*a325d9c4SApple OSS Distributions 	X(SIGNAL_TO_PARENT_FAILED) \
38*a325d9c4SApple OSS Distributions 	X(MEMORYSTATUS_CONTROL_FAILED) \
39*a325d9c4SApple OSS Distributions 	X(IS_FREEZABLE_NOT_AS_EXPECTED) \
40*a325d9c4SApple OSS Distributions 	X(EXIT_CODE_MAX)
41*a325d9c4SApple OSS Distributions 
42*a325d9c4SApple OSS Distributions #define EXIT_CODES_ENUM(VAR) VAR,
43*a325d9c4SApple OSS Distributions enum exit_codes_num {
44*a325d9c4SApple OSS Distributions 	CREATE_LIST(EXIT_CODES_ENUM)
45*a325d9c4SApple OSS Distributions };
46*a325d9c4SApple OSS Distributions 
47*a325d9c4SApple OSS Distributions #define EXIT_CODES_STRING(VAR) #VAR,
48*a325d9c4SApple OSS Distributions static const char *exit_codes_str[] = {
49*a325d9c4SApple OSS Distributions 	CREATE_LIST(EXIT_CODES_STRING)
50*a325d9c4SApple OSS Distributions };
51*a325d9c4SApple OSS Distributions 
52*a325d9c4SApple OSS Distributions #define SYSCTL_FREEZE_TO_MEMORY         "kern.memorystatus_freeze_to_memory=1"
53*a325d9c4SApple OSS Distributions 
54*a325d9c4SApple OSS Distributions static pid_t pid = -1;
55*a325d9c4SApple OSS Distributions static dt_stat_t ratio;
56*a325d9c4SApple OSS Distributions static dt_stat_time_t compr_time;
57*a325d9c4SApple OSS Distributions static dt_stat_time_t decompr_time;
58*a325d9c4SApple OSS Distributions 
59*a325d9c4SApple OSS Distributions void allocate_zero_pages(char **buf, int num_pages, int vmpgsize);
60*a325d9c4SApple OSS Distributions void allocate_mostly_zero_pages(char **buf, int num_pages, int vmpgsize);
61*a325d9c4SApple OSS Distributions void allocate_random_pages(char **buf, int num_pages, int vmpgsize);
62*a325d9c4SApple OSS Distributions void allocate_representative_pages(char **buf, int num_pages, int vmpgsize);
63*a325d9c4SApple OSS Distributions void run_compressor_test(int size_mb, int page_type);
64*a325d9c4SApple OSS Distributions void freeze_helper_process(void);
65*a325d9c4SApple OSS Distributions void cleanup(void);
66*a325d9c4SApple OSS Distributions 
67*a325d9c4SApple OSS Distributions void
allocate_zero_pages(char ** buf,int num_pages,int vmpgsize)68*a325d9c4SApple OSS Distributions allocate_zero_pages(char **buf, int num_pages, int vmpgsize)
69*a325d9c4SApple OSS Distributions {
70*a325d9c4SApple OSS Distributions 	int i;
71*a325d9c4SApple OSS Distributions 
72*a325d9c4SApple OSS Distributions 	for (i = 0; i < num_pages; i++) {
73*a325d9c4SApple OSS Distributions 		buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
74*a325d9c4SApple OSS Distributions 		memset(buf[i], 0, vmpgsize);
75*a325d9c4SApple OSS Distributions 	}
76*a325d9c4SApple OSS Distributions }
77*a325d9c4SApple OSS Distributions 
78*a325d9c4SApple OSS Distributions void
allocate_mostly_zero_pages(char ** buf,int num_pages,int vmpgsize)79*a325d9c4SApple OSS Distributions allocate_mostly_zero_pages(char **buf, int num_pages, int vmpgsize)
80*a325d9c4SApple OSS Distributions {
81*a325d9c4SApple OSS Distributions 	int i, j;
82*a325d9c4SApple OSS Distributions 
83*a325d9c4SApple OSS Distributions 	for (i = 0; i < num_pages; i++) {
84*a325d9c4SApple OSS Distributions 		buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
85*a325d9c4SApple OSS Distributions 		memset(buf[i], 0, vmpgsize);
86*a325d9c4SApple OSS Distributions 		for (j = 0; j < 40; j++) {
87*a325d9c4SApple OSS Distributions 			buf[i][j] = (char)(j + 1);
88*a325d9c4SApple OSS Distributions 		}
89*a325d9c4SApple OSS Distributions 	}
90*a325d9c4SApple OSS Distributions }
91*a325d9c4SApple OSS Distributions 
92*a325d9c4SApple OSS Distributions void
allocate_random_pages(char ** buf,int num_pages,int vmpgsize)93*a325d9c4SApple OSS Distributions allocate_random_pages(char **buf, int num_pages, int vmpgsize)
94*a325d9c4SApple OSS Distributions {
95*a325d9c4SApple OSS Distributions 	int i;
96*a325d9c4SApple OSS Distributions 
97*a325d9c4SApple OSS Distributions 	for (i = 0; i < num_pages; i++) {
98*a325d9c4SApple OSS Distributions 		buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
99*a325d9c4SApple OSS Distributions 		arc4random_buf((void*)buf[i], (size_t)vmpgsize);
100*a325d9c4SApple OSS Distributions 	}
101*a325d9c4SApple OSS Distributions }
102*a325d9c4SApple OSS Distributions 
103*a325d9c4SApple OSS Distributions // Gives us the compression ratio we see in the typical case (~2.7)
104*a325d9c4SApple OSS Distributions void
allocate_representative_pages(char ** buf,int num_pages,int vmpgsize)105*a325d9c4SApple OSS Distributions allocate_representative_pages(char **buf, int num_pages, int vmpgsize)
106*a325d9c4SApple OSS Distributions {
107*a325d9c4SApple OSS Distributions 	int i, j;
108*a325d9c4SApple OSS Distributions 	char val;
109*a325d9c4SApple OSS Distributions 
110*a325d9c4SApple OSS Distributions 	for (j = 0; j < num_pages; j++) {
111*a325d9c4SApple OSS Distributions 		buf[j] = (char*)malloc((size_t)vmpgsize * sizeof(char));
112*a325d9c4SApple OSS Distributions 		val = 0;
113*a325d9c4SApple OSS Distributions 		for (i = 0; i < vmpgsize; i += 16) {
114*a325d9c4SApple OSS Distributions 			memset(&buf[j][i], val, 16);
115*a325d9c4SApple OSS Distributions 			if (i < 3400 * (vmpgsize / 4096)) {
116*a325d9c4SApple OSS Distributions 				val++;
117*a325d9c4SApple OSS Distributions 			}
118*a325d9c4SApple OSS Distributions 		}
119*a325d9c4SApple OSS Distributions 	}
120*a325d9c4SApple OSS Distributions }
121*a325d9c4SApple OSS Distributions 
122*a325d9c4SApple OSS Distributions void
freeze_helper_process(void)123*a325d9c4SApple OSS Distributions freeze_helper_process(void)
124*a325d9c4SApple OSS Distributions {
125*a325d9c4SApple OSS Distributions 	int ret, freeze_enabled;
126*a325d9c4SApple OSS Distributions 	int64_t compressed_before, compressed_after, input_before, input_after;
127*a325d9c4SApple OSS Distributions 	size_t length;
128*a325d9c4SApple OSS Distributions 	int errno_sysctl_freeze;
129*a325d9c4SApple OSS Distributions 
130*a325d9c4SApple OSS Distributions 	length = sizeof(compressed_before);
131*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_compressed_bytes", &compressed_before, &length, NULL, 0),
132*a325d9c4SApple OSS Distributions 	    "failed to query vm.compressor_compressed_bytes");
133*a325d9c4SApple OSS Distributions 	length = sizeof(input_before);
134*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_input_bytes", &input_before, &length, NULL, 0),
135*a325d9c4SApple OSS Distributions 	    "failed to query vm.compressor_input_bytes");
136*a325d9c4SApple OSS Distributions 
137*a325d9c4SApple OSS Distributions 	T_STAT_MEASURE(compr_time) {
138*a325d9c4SApple OSS Distributions 		ret = sysctlbyname("kern.memorystatus_freeze", NULL, NULL, &pid, sizeof(pid));
139*a325d9c4SApple OSS Distributions 		errno_sysctl_freeze = errno;
140*a325d9c4SApple OSS Distributions 	};
141*a325d9c4SApple OSS Distributions 
142*a325d9c4SApple OSS Distributions 	length = sizeof(compressed_after);
143*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_compressed_bytes", &compressed_after, &length, NULL, 0),
144*a325d9c4SApple OSS Distributions 	    "failed to query vm.compressor_compressed_bytes");
145*a325d9c4SApple OSS Distributions 	length = sizeof(input_after);
146*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_input_bytes", &input_after, &length, NULL, 0),
147*a325d9c4SApple OSS Distributions 	    "failed to query vm.compressor_input_bytes");
148*a325d9c4SApple OSS Distributions 
149*a325d9c4SApple OSS Distributions 	length = sizeof(freeze_enabled);
150*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.freeze_enabled", &freeze_enabled, &length, NULL, 0),
151*a325d9c4SApple OSS Distributions 	    "failed to query vm.freeze_enabled");
152*a325d9c4SApple OSS Distributions 	if (freeze_enabled) {
153*a325d9c4SApple OSS Distributions 		errno = errno_sysctl_freeze;
154*a325d9c4SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl kern.memorystatus_freeze failed");
155*a325d9c4SApple OSS Distributions 	} else {
156*a325d9c4SApple OSS Distributions 		/* If freezer is disabled, skip the test. This can happen due to disk space shortage. */
157*a325d9c4SApple OSS Distributions 		T_LOG("Freeze has been disabled. Terminating early.");
158*a325d9c4SApple OSS Distributions 		T_END;
159*a325d9c4SApple OSS Distributions 	}
160*a325d9c4SApple OSS Distributions 
161*a325d9c4SApple OSS Distributions 	dt_stat_add(ratio, (double)(input_after - input_before) / (double)(compressed_after - compressed_before));
162*a325d9c4SApple OSS Distributions 
163*a325d9c4SApple OSS Distributions 	ret = sysctlbyname("kern.memorystatus_thaw", NULL, NULL, &pid, sizeof(pid));
164*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl kern.memorystatus_thaw failed");
165*a325d9c4SApple OSS Distributions 
166*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGUSR1), "failed to send SIGUSR1 to child process");
167*a325d9c4SApple OSS Distributions }
168*a325d9c4SApple OSS Distributions 
169*a325d9c4SApple OSS Distributions void
cleanup(void)170*a325d9c4SApple OSS Distributions cleanup(void)
171*a325d9c4SApple OSS Distributions {
172*a325d9c4SApple OSS Distributions 	/* No helper process. */
173*a325d9c4SApple OSS Distributions 	if (pid == -1) {
174*a325d9c4SApple OSS Distributions 		return;
175*a325d9c4SApple OSS Distributions 	}
176*a325d9c4SApple OSS Distributions 	/* Kill the helper process. */
177*a325d9c4SApple OSS Distributions 	kill(pid, SIGKILL);
178*a325d9c4SApple OSS Distributions }
179*a325d9c4SApple OSS Distributions 
180*a325d9c4SApple OSS Distributions void
run_compressor_test(int size_mb,int page_type)181*a325d9c4SApple OSS Distributions run_compressor_test(int size_mb, int page_type)
182*a325d9c4SApple OSS Distributions {
183*a325d9c4SApple OSS Distributions 	int ret;
184*a325d9c4SApple OSS Distributions 	char sz_str[50];
185*a325d9c4SApple OSS Distributions 	char pt_str[50];
186*a325d9c4SApple OSS Distributions 	char **launch_tool_args;
187*a325d9c4SApple OSS Distributions 	char testpath[PATH_MAX];
188*a325d9c4SApple OSS Distributions 	uint32_t testpath_buf_size;
189*a325d9c4SApple OSS Distributions 	dispatch_source_t ds_freeze, ds_proc, ds_decompr;
190*a325d9c4SApple OSS Distributions 	int freeze_enabled;
191*a325d9c4SApple OSS Distributions 	size_t length;
192*a325d9c4SApple OSS Distributions 	__block bool decompr_latency_is_stable = false;
193*a325d9c4SApple OSS Distributions 
194*a325d9c4SApple OSS Distributions 	length = sizeof(freeze_enabled);
195*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.freeze_enabled", &freeze_enabled, &length, NULL, 0),
196*a325d9c4SApple OSS Distributions 	    "failed to query vm.freeze_enabled");
197*a325d9c4SApple OSS Distributions 	if (!freeze_enabled) {
198*a325d9c4SApple OSS Distributions 		/* If freezer is disabled, skip the test. This can happen due to disk space shortage. */
199*a325d9c4SApple OSS Distributions 		T_SKIP("Freeze has been disabled. Skipping test.");
200*a325d9c4SApple OSS Distributions 	}
201*a325d9c4SApple OSS Distributions 
202*a325d9c4SApple OSS Distributions 	T_ATEND(cleanup);
203*a325d9c4SApple OSS Distributions 
204*a325d9c4SApple OSS Distributions 	ratio = dt_stat_create("(input bytes / compressed bytes)", "compression_ratio");
205*a325d9c4SApple OSS Distributions 	compr_time = dt_stat_time_create("compressor_latency");
206*a325d9c4SApple OSS Distributions 
207*a325d9c4SApple OSS Distributions 	// This sets the A/B failure threshold at 50% of baseline for compressor_latency
208*a325d9c4SApple OSS Distributions 	dt_stat_set_variable((struct dt_stat *)compr_time, kPCFailureThresholdPctVar, 50.0);
209*a325d9c4SApple OSS Distributions 
210*a325d9c4SApple OSS Distributions 	signal(SIGUSR2, SIG_IGN);
211*a325d9c4SApple OSS Distributions 	ds_decompr = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR2, 0, dispatch_get_main_queue());
212*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(ds_decompr, "dispatch_source_create (ds_decompr)");
213*a325d9c4SApple OSS Distributions 
214*a325d9c4SApple OSS Distributions 	dispatch_source_set_event_handler(ds_decompr, ^{
215*a325d9c4SApple OSS Distributions 		decompr_latency_is_stable = true;
216*a325d9c4SApple OSS Distributions 	});
217*a325d9c4SApple OSS Distributions 	dispatch_activate(ds_decompr);
218*a325d9c4SApple OSS Distributions 
219*a325d9c4SApple OSS Distributions 	signal(SIGUSR1, SIG_IGN);
220*a325d9c4SApple OSS Distributions 	ds_freeze = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dispatch_get_main_queue());
221*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(ds_freeze, "dispatch_source_create (ds_freeze)");
222*a325d9c4SApple OSS Distributions 
223*a325d9c4SApple OSS Distributions 	dispatch_source_set_event_handler(ds_freeze, ^{
224*a325d9c4SApple OSS Distributions 		if (!(dt_stat_stable(compr_time) && decompr_latency_is_stable)) {
225*a325d9c4SApple OSS Distributions 		        freeze_helper_process();
226*a325d9c4SApple OSS Distributions 		} else {
227*a325d9c4SApple OSS Distributions 		        dt_stat_finalize(compr_time);
228*a325d9c4SApple OSS Distributions 		        dt_stat_finalize(ratio);
229*a325d9c4SApple OSS Distributions 
230*a325d9c4SApple OSS Distributions 		        kill(pid, SIGKILL);
231*a325d9c4SApple OSS Distributions 		        dispatch_source_cancel(ds_freeze);
232*a325d9c4SApple OSS Distributions 		        dispatch_source_cancel(ds_decompr);
233*a325d9c4SApple OSS Distributions 		}
234*a325d9c4SApple OSS Distributions 	});
235*a325d9c4SApple OSS Distributions 	dispatch_activate(ds_freeze);
236*a325d9c4SApple OSS Distributions 
237*a325d9c4SApple OSS Distributions 	testpath_buf_size = sizeof(testpath);
238*a325d9c4SApple OSS Distributions 	ret = _NSGetExecutablePath(testpath, &testpath_buf_size);
239*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "_NSGetExecutablePath");
240*a325d9c4SApple OSS Distributions 	T_LOG("Executable path: %s", testpath);
241*a325d9c4SApple OSS Distributions 
242*a325d9c4SApple OSS Distributions 	sprintf(sz_str, "%d", size_mb);
243*a325d9c4SApple OSS Distributions 	sprintf(pt_str, "%d", page_type);
244*a325d9c4SApple OSS Distributions 	launch_tool_args = (char *[]){
245*a325d9c4SApple OSS Distributions 		testpath,
246*a325d9c4SApple OSS Distributions 		"-n",
247*a325d9c4SApple OSS Distributions 		"allocate_pages",
248*a325d9c4SApple OSS Distributions 		"--",
249*a325d9c4SApple OSS Distributions 		sz_str,
250*a325d9c4SApple OSS Distributions 		pt_str,
251*a325d9c4SApple OSS Distributions 		NULL
252*a325d9c4SApple OSS Distributions 	};
253*a325d9c4SApple OSS Distributions 
254*a325d9c4SApple OSS Distributions 	/* Spawn the child process. Suspend after launch until the exit proc handler has been set up. */
255*a325d9c4SApple OSS Distributions 	ret = dt_launch_tool(&pid, launch_tool_args, true, NULL, NULL);
256*a325d9c4SApple OSS Distributions 	if (ret != 0) {
257*a325d9c4SApple OSS Distributions 		T_LOG("dt_launch tool returned %d with error code %d", ret, errno);
258*a325d9c4SApple OSS Distributions 	}
259*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "dt_launch_tool");
260*a325d9c4SApple OSS Distributions 
261*a325d9c4SApple OSS Distributions 	ds_proc = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, (uintptr_t)pid, DISPATCH_PROC_EXIT, dispatch_get_main_queue());
262*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(ds_proc, "dispatch_source_create (ds_proc)");
263*a325d9c4SApple OSS Distributions 
264*a325d9c4SApple OSS Distributions 	dispatch_source_set_event_handler(ds_proc, ^{
265*a325d9c4SApple OSS Distributions 		int status = 0, code = 0;
266*a325d9c4SApple OSS Distributions 		pid_t rc = waitpid(pid, &status, 0);
267*a325d9c4SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(rc, pid, "waitpid");
268*a325d9c4SApple OSS Distributions 		code = WEXITSTATUS(status);
269*a325d9c4SApple OSS Distributions 
270*a325d9c4SApple OSS Distributions 		if (code == 0) {
271*a325d9c4SApple OSS Distributions 		        T_END;
272*a325d9c4SApple OSS Distributions 		} else if (code > 0 && code < EXIT_CODE_MAX) {
273*a325d9c4SApple OSS Distributions 		        T_ASSERT_FAIL("Child exited with %s", exit_codes_str[code]);
274*a325d9c4SApple OSS Distributions 		} else {
275*a325d9c4SApple OSS Distributions 		        T_ASSERT_FAIL("Child exited with unknown exit code %d", code);
276*a325d9c4SApple OSS Distributions 		}
277*a325d9c4SApple OSS Distributions 	});
278*a325d9c4SApple OSS Distributions 	dispatch_activate(ds_proc);
279*a325d9c4SApple OSS Distributions 
280*a325d9c4SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(kill(pid, SIGCONT), "failed to send SIGCONT to child process");
281*a325d9c4SApple OSS Distributions 	dispatch_main();
282*a325d9c4SApple OSS Distributions }
283*a325d9c4SApple OSS Distributions 
284*a325d9c4SApple OSS Distributions T_HELPER_DECL(allocate_pages, "allocates pages to compress") {
285*a325d9c4SApple OSS Distributions 	int i, j, ret, size_mb, page_type, vmpgsize, freezable_state;
286*a325d9c4SApple OSS Distributions 	size_t vmpgsize_length;
287*a325d9c4SApple OSS Distributions 	__block int num_pages;
288*a325d9c4SApple OSS Distributions 	__block char **buf;
289*a325d9c4SApple OSS Distributions 	dispatch_source_t ds_signal;
290*a325d9c4SApple OSS Distributions 
291*a325d9c4SApple OSS Distributions 	vmpgsize_length = sizeof(vmpgsize);
292*a325d9c4SApple OSS Distributions 	ret = sysctlbyname("vm.pagesize", &vmpgsize, &vmpgsize_length, NULL, 0);
293*a325d9c4SApple OSS Distributions 	if (ret != 0) {
294*a325d9c4SApple OSS Distributions 		exit(SYSCTL_VM_PAGESIZE_FAILED);
295*a325d9c4SApple OSS Distributions 	}
296*a325d9c4SApple OSS Distributions 	if (vmpgsize == 0) {
297*a325d9c4SApple OSS Distributions 		exit(VM_PAGESIZE_IS_ZERO);
298*a325d9c4SApple OSS Distributions 	}
299*a325d9c4SApple OSS Distributions 
300*a325d9c4SApple OSS Distributions 	if (argc < 2) {
301*a325d9c4SApple OSS Distributions 		exit(TOO_FEW_ARGUMENTS);
302*a325d9c4SApple OSS Distributions 	}
303*a325d9c4SApple OSS Distributions 
304*a325d9c4SApple OSS Distributions 	size_mb = atoi(argv[0]);
305*a325d9c4SApple OSS Distributions 	page_type = atoi(argv[1]);
306*a325d9c4SApple OSS Distributions 	num_pages = size_mb * 1024 * 1024 / vmpgsize;
307*a325d9c4SApple OSS Distributions 	buf = (char**)malloc(sizeof(char*) * (size_t)num_pages);
308*a325d9c4SApple OSS Distributions 
309*a325d9c4SApple OSS Distributions 	// Switch on the type of page requested
310*a325d9c4SApple OSS Distributions 	switch (page_type) {
311*a325d9c4SApple OSS Distributions 	case ALL_ZEROS:
312*a325d9c4SApple OSS Distributions 		allocate_zero_pages(buf, num_pages, vmpgsize);
313*a325d9c4SApple OSS Distributions 		break;
314*a325d9c4SApple OSS Distributions 	case MOSTLY_ZEROS:
315*a325d9c4SApple OSS Distributions 		allocate_mostly_zero_pages(buf, num_pages, vmpgsize);
316*a325d9c4SApple OSS Distributions 		break;
317*a325d9c4SApple OSS Distributions 	case RANDOM:
318*a325d9c4SApple OSS Distributions 		allocate_random_pages(buf, num_pages, vmpgsize);
319*a325d9c4SApple OSS Distributions 		break;
320*a325d9c4SApple OSS Distributions 	case TYPICAL:
321*a325d9c4SApple OSS Distributions 		allocate_representative_pages(buf, num_pages, vmpgsize);
322*a325d9c4SApple OSS Distributions 		break;
323*a325d9c4SApple OSS Distributions 	default:
324*a325d9c4SApple OSS Distributions 		exit(UNKNOWN_PAGE_TYPE);
325*a325d9c4SApple OSS Distributions 	}
326*a325d9c4SApple OSS Distributions 
327*a325d9c4SApple OSS Distributions 	for (j = 0; j < num_pages; j++) {
328*a325d9c4SApple OSS Distributions 		i = buf[j][0];
329*a325d9c4SApple OSS Distributions 	}
330*a325d9c4SApple OSS Distributions 
331*a325d9c4SApple OSS Distributions 	decompr_time = dt_stat_time_create("decompression_latency");
332*a325d9c4SApple OSS Distributions 
333*a325d9c4SApple OSS Distributions 	/* Opt in to freezing. */
334*a325d9c4SApple OSS Distributions 	printf("[%d] Setting state to freezable\n", getpid());
335*a325d9c4SApple OSS Distributions 	if (memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_FREEZABLE, getpid(), 1, NULL, 0) != KERN_SUCCESS) {
336*a325d9c4SApple OSS Distributions 		exit(MEMORYSTATUS_CONTROL_FAILED);
337*a325d9c4SApple OSS Distributions 	}
338*a325d9c4SApple OSS Distributions 
339*a325d9c4SApple OSS Distributions 	/* Verify that the state has been set correctly */
340*a325d9c4SApple OSS Distributions 	freezable_state = memorystatus_control(MEMORYSTATUS_CMD_GET_PROCESS_IS_FREEZABLE, getpid(), 0, NULL, 0);
341*a325d9c4SApple OSS Distributions 	if (freezable_state != 1) {
342*a325d9c4SApple OSS Distributions 		exit(IS_FREEZABLE_NOT_AS_EXPECTED);
343*a325d9c4SApple OSS Distributions 	}
344*a325d9c4SApple OSS Distributions 
345*a325d9c4SApple OSS Distributions 	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC), dispatch_get_main_queue(), ^{
346*a325d9c4SApple OSS Distributions 		/* Signal to the parent that we're done allocating and it's ok to freeze us */
347*a325d9c4SApple OSS Distributions 		printf("[%d] Sending initial signal to parent to begin freezing\n", getpid());
348*a325d9c4SApple OSS Distributions 		if (kill(getppid(), SIGUSR1) != 0) {
349*a325d9c4SApple OSS Distributions 		        exit(INITIAL_SIGNAL_TO_PARENT_FAILED);
350*a325d9c4SApple OSS Distributions 		}
351*a325d9c4SApple OSS Distributions 	});
352*a325d9c4SApple OSS Distributions 
353*a325d9c4SApple OSS Distributions 	signal(SIGUSR1, SIG_IGN);
354*a325d9c4SApple OSS Distributions 	ds_signal = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1, 0, dispatch_get_main_queue());
355*a325d9c4SApple OSS Distributions 	if (ds_signal == NULL) {
356*a325d9c4SApple OSS Distributions 		exit(DISPATCH_SOURCE_CREATE_FAILED);
357*a325d9c4SApple OSS Distributions 	}
358*a325d9c4SApple OSS Distributions 
359*a325d9c4SApple OSS Distributions 	__block bool collect_dt_stat_measurements = true;
360*a325d9c4SApple OSS Distributions 
361*a325d9c4SApple OSS Distributions 	dispatch_source_set_event_handler(ds_signal, ^{
362*a325d9c4SApple OSS Distributions 		volatile int tmp;
363*a325d9c4SApple OSS Distributions 		uint64_t decompr_start_time, decompr_end_time;
364*a325d9c4SApple OSS Distributions 
365*a325d9c4SApple OSS Distributions 		decompr_start_time = mach_absolute_time();
366*a325d9c4SApple OSS Distributions 
367*a325d9c4SApple OSS Distributions 		/* Make sure all the pages are accessed before trying to freeze again */
368*a325d9c4SApple OSS Distributions 		for (int x = 0; x < num_pages; x++) {
369*a325d9c4SApple OSS Distributions 		        tmp = buf[x][0];
370*a325d9c4SApple OSS Distributions 		}
371*a325d9c4SApple OSS Distributions 
372*a325d9c4SApple OSS Distributions 		decompr_end_time = mach_absolute_time();
373*a325d9c4SApple OSS Distributions 
374*a325d9c4SApple OSS Distributions 		if (collect_dt_stat_measurements) {
375*a325d9c4SApple OSS Distributions 			if (dt_stat_stable(decompr_time)) {
376*a325d9c4SApple OSS Distributions 				collect_dt_stat_measurements = false;
377*a325d9c4SApple OSS Distributions 				dt_stat_finalize(decompr_time);
378*a325d9c4SApple OSS Distributions 				if (kill(getppid(), SIGUSR2) != 0) {
379*a325d9c4SApple OSS Distributions 					exit(SIGNAL_TO_PARENT_FAILED);
380*a325d9c4SApple OSS Distributions 				}
381*a325d9c4SApple OSS Distributions 			} else {
382*a325d9c4SApple OSS Distributions 				dt_stat_mach_time_add(decompr_time, decompr_end_time - decompr_start_time);
383*a325d9c4SApple OSS Distributions 			}
384*a325d9c4SApple OSS Distributions 		}
385*a325d9c4SApple OSS Distributions 
386*a325d9c4SApple OSS Distributions 		if (kill(getppid(), SIGUSR1) != 0) {
387*a325d9c4SApple OSS Distributions 		        exit(SIGNAL_TO_PARENT_FAILED);
388*a325d9c4SApple OSS Distributions 		}
389*a325d9c4SApple OSS Distributions 	});
390*a325d9c4SApple OSS Distributions 	dispatch_activate(ds_signal);
391*a325d9c4SApple OSS Distributions 
392*a325d9c4SApple OSS Distributions 	dispatch_main();
393*a325d9c4SApple OSS Distributions }
394*a325d9c4SApple OSS Distributions 
395*a325d9c4SApple OSS Distributions // Numbers for 10MB and above are fairly reproducible. Anything smaller shows a lot of variation.
396*a325d9c4SApple OSS Distributions 
397*a325d9c4SApple OSS Distributions // Keeping just the 100MB version for iOSMark
398*a325d9c4SApple OSS Distributions #ifndef DT_IOSMARK
399*a325d9c4SApple OSS Distributions T_DECL(compr_10MB_zero,
400*a325d9c4SApple OSS Distributions     "Compression latency for 10MB - zero pages",
401*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
402*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
403*a325d9c4SApple OSS Distributions 	run_compressor_test(10, ALL_ZEROS);
404*a325d9c4SApple OSS Distributions }
405*a325d9c4SApple OSS Distributions 
406*a325d9c4SApple OSS Distributions T_DECL(compr_10MB_mostly_zero,
407*a325d9c4SApple OSS Distributions     "Compression latency for 10MB - mostly zero pages",
408*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
409*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
410*a325d9c4SApple OSS Distributions 	run_compressor_test(10, MOSTLY_ZEROS);
411*a325d9c4SApple OSS Distributions }
412*a325d9c4SApple OSS Distributions 
413*a325d9c4SApple OSS Distributions T_DECL(compr_10MB_random,
414*a325d9c4SApple OSS Distributions     "Compression latency for 10MB - random pages",
415*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
416*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
417*a325d9c4SApple OSS Distributions 	run_compressor_test(10, RANDOM);
418*a325d9c4SApple OSS Distributions }
419*a325d9c4SApple OSS Distributions 
420*a325d9c4SApple OSS Distributions T_DECL(compr_10MB_typical,
421*a325d9c4SApple OSS Distributions     "Compression latency for 10MB - typical pages",
422*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
423*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
424*a325d9c4SApple OSS Distributions 	run_compressor_test(10, TYPICAL);
425*a325d9c4SApple OSS Distributions }
426*a325d9c4SApple OSS Distributions 
427*a325d9c4SApple OSS Distributions T_DECL(compr_100MB_zero,
428*a325d9c4SApple OSS Distributions     "Compression latency for 100MB - zero pages",
429*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
430*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
431*a325d9c4SApple OSS Distributions 	run_compressor_test(100, ALL_ZEROS);
432*a325d9c4SApple OSS Distributions }
433*a325d9c4SApple OSS Distributions 
434*a325d9c4SApple OSS Distributions T_DECL(compr_100MB_mostly_zero,
435*a325d9c4SApple OSS Distributions     "Compression latency for 100MB - mostly zero pages",
436*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
437*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
438*a325d9c4SApple OSS Distributions 	run_compressor_test(100, MOSTLY_ZEROS);
439*a325d9c4SApple OSS Distributions }
440*a325d9c4SApple OSS Distributions 
441*a325d9c4SApple OSS Distributions T_DECL(compr_100MB_random,
442*a325d9c4SApple OSS Distributions     "Compression latency for 100MB - random pages",
443*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
444*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
445*a325d9c4SApple OSS Distributions 	run_compressor_test(100, RANDOM);
446*a325d9c4SApple OSS Distributions }
447*a325d9c4SApple OSS Distributions #endif
448*a325d9c4SApple OSS Distributions 
449*a325d9c4SApple OSS Distributions T_DECL(compr_100MB_typical,
450*a325d9c4SApple OSS Distributions     "Compression latency for 100MB - typical pages",
451*a325d9c4SApple OSS Distributions     T_META_ASROOT(true),
452*a325d9c4SApple OSS Distributions     T_META_SYSCTL_INT(SYSCTL_FREEZE_TO_MEMORY)) {
453*a325d9c4SApple OSS Distributions 	run_compressor_test(100, TYPICAL);
454*a325d9c4SApple OSS Distributions }
455