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