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