]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/darwintests/perf_compressor.c
xnu-4570.41.2.tar.gz
[apple/xnu.git] / tools / tests / darwintests / perf_compressor.c
1 #ifdef T_NAMESPACE
2 #undef T_NAMESPACE
3 #endif
4 #include <darwintest.h>
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/sysctl.h>
11
12 T_GLOBAL_META(
13 T_META_NAMESPACE("xnu.vm.perf"),
14 T_META_CHECK_LEAKS(false)
15 );
16
17 enum {
18 ALL_ZEROS,
19 MOSTLY_ZEROS,
20 RANDOM,
21 TYPICAL
22 };
23
24 void allocate_zero_pages(char **buf, int num_pages, int vmpgsize);
25 void allocate_mostly_zero_pages(char **buf, int num_pages, int vmpgsize);
26 void allocate_random_pages(char **buf, int num_pages, int vmpgsize);
27 void allocate_representative_pages(char **buf, int num_pages, int vmpgsize);
28 void allocate_pages(int size_mb, int page_type);
29 void run_compressor_test(int size_mb, int page_type);
30
31 void allocate_zero_pages(char **buf, int num_pages, int vmpgsize) {
32 int i;
33
34 for (i = 0; i < num_pages; i++) {
35 buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
36 memset(buf[i], 0, vmpgsize);
37 }
38 }
39
40 void allocate_mostly_zero_pages(char **buf, int num_pages, int vmpgsize) {
41 int i, j;
42
43 for (i = 0; i < num_pages; i++) {
44 buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
45 memset(buf[i], 0, vmpgsize);
46 for (j = 0; j < 40; j++) {
47 buf[i][j] = (char)(j+1);
48 }
49 }
50 }
51
52 void allocate_random_pages(char **buf, int num_pages, int vmpgsize) {
53 int i;
54
55 for (i = 0; i < num_pages; i++) {
56 buf[i] = (char*)malloc((size_t)vmpgsize * sizeof(char));
57 arc4random_buf((void*)buf[i], (size_t)vmpgsize);
58 }
59 }
60
61 // Gives us the compression ratio we see in the typical case (~2.7)
62 void allocate_representative_pages(char **buf, int num_pages, int vmpgsize) {
63 int i, j;
64 char val;
65
66 for (j = 0; j < num_pages; j++) {
67 buf[j] = (char*)malloc((size_t)vmpgsize * sizeof(char));
68 val = 0;
69 for (i = 0; i < vmpgsize; i += 16) {
70 memset(&buf[j][i], val, 16);
71 if (i < 3700 * (vmpgsize / 4096)) {
72 val++;
73 }
74 }
75 }
76 }
77
78 void allocate_pages(int size_mb, int page_type) {
79 int num_pages = 0;
80 int vmpgsize, i, j;
81 char **buf;
82 size_t vmpgsize_length;
83
84 vmpgsize_length = sizeof(vmpgsize);
85 T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.pagesize", &vmpgsize, &vmpgsize_length, NULL, 0),
86 "failed to query vm.pagesize");
87 if (vmpgsize == 0) {
88 T_FAIL("vm.pagesize set to zero");
89 }
90
91 num_pages = size_mb * 1024 * 1024 / vmpgsize;
92 buf = (char**)malloc(sizeof(char*) * (size_t)num_pages);
93
94 // Switch on the type of page requested
95 switch(page_type) {
96 case ALL_ZEROS:
97 allocate_zero_pages(buf, num_pages, vmpgsize);
98 break;
99 case MOSTLY_ZEROS:
100 allocate_mostly_zero_pages(buf, num_pages, vmpgsize);
101 break;
102 case RANDOM:
103 allocate_random_pages(buf, num_pages, vmpgsize);
104 break;
105 case TYPICAL:
106 allocate_representative_pages(buf, num_pages, vmpgsize);
107 break;
108 default:
109 T_FAIL("unknown page type");
110 break;
111 }
112
113 for(j = 0; j < num_pages; j++) {
114 i = buf[j][1];
115 }
116 }
117
118
119 void run_compressor_test(int size_mb, int page_type) {
120
121 #ifndef CONFIG_FREEZE
122 T_SKIP("Task freeze not supported.");
123 #endif
124
125 dt_stat_t r = dt_stat_create("(input bytes / compressed bytes)", "compression_ratio");
126 dt_stat_time_t s = dt_stat_time_create("compressor_latency");
127
128 while (!dt_stat_stable(s)) {
129 pid_t pid;
130 int parent_pipe[2], child_pipe[2];
131
132 T_QUIET; T_ASSERT_POSIX_SUCCESS(pipe(parent_pipe), "pipe failed");
133 T_QUIET; T_ASSERT_POSIX_SUCCESS(pipe(child_pipe), "pipe failed");
134
135 pid = fork();
136 T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "fork failed with %d", errno);
137
138 if (pid == 0) {
139 int val = 1;
140
141 close(child_pipe[0]);
142 close(parent_pipe[1]);
143 allocate_pages(size_mb, page_type);
144
145 // Indicates to the parent that the child has finished allocating pages
146 write(child_pipe[1], &val, sizeof(val));
147
148 // Parent is done with the freeze, ok to exit now
149 read(parent_pipe[0], &val, sizeof(val));
150 if (val != 2) {
151 T_FAIL("pipe read error");
152 }
153 close(child_pipe[1]);
154 close(parent_pipe[0]);
155 exit(0);
156
157 } else {
158 int val, ret;
159 int64_t compressed_before, compressed_after, input_before, input_after;
160 dt_stat_token start_token;
161 size_t length = sizeof(compressed_before);
162
163 close(child_pipe[1]);
164 close(parent_pipe[0]);
165
166 // Wait for the child to finish allocating pages
167 read(child_pipe[0], &val, sizeof(val));
168 if (val != 1) {
169 T_FAIL("pipe read error");
170 }
171 // Just to be extra sure that the child has finished allocating all of its pages
172 usleep(100);
173
174 T_LOG("attempting to freeze pid %d\n", pid);
175
176 T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_compressed_bytes", &compressed_before, &length, NULL, 0),
177 "failed to query vm.compressor_compressed_bytes");
178 T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_input_bytes", &input_before, &length, NULL, 0),
179 "failed to query vm.compressor_input_bytes");
180
181 start_token = dt_stat_time_begin(s);
182 ret = sysctlbyname("kern.memorystatus_freeze", NULL, NULL, &pid, (size_t)sizeof(int));
183 dt_stat_time_end(s, start_token);
184
185 T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_compressed_bytes", &compressed_after, &length, NULL, 0),
186 "failed to query vm.compressor_compressed_bytes");
187 T_QUIET; T_ASSERT_POSIX_SUCCESS(sysctlbyname("vm.compressor_input_bytes", &input_after, &length, NULL, 0),
188 "failed to query vm.compressor_input_bytes");
189
190 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl kern.memorystatus_freeze failed on pid %d", pid);
191
192 dt_stat_add(r, (double)(input_after - input_before)/(double)(compressed_after - compressed_before));
193
194 val = 2;
195 // Ok for the child to exit now
196 write(parent_pipe[1], &val, sizeof(val));
197 usleep(100);
198
199 close(child_pipe[0]);
200 close(parent_pipe[1]);
201 }
202 }
203
204 dt_stat_finalize(s);
205 dt_stat_finalize(r);
206 }
207
208 // Numbers for 10MB and above are fairly reproducible. Anything smaller shows a lot of variation.
209 T_DECL(compr_10MB_zero, "Compressor latencies") {
210 run_compressor_test(10, ALL_ZEROS);
211 }
212
213 T_DECL(compr_10MB_mostly_zero, "Compressor latencies") {
214 run_compressor_test(10, MOSTLY_ZEROS);
215 }
216
217 T_DECL(compr_10MB_random, "Compressor latencies") {
218 run_compressor_test(10, RANDOM);
219 }
220
221 T_DECL(compr_10MB_typical, "Compressor latencies") {
222 run_compressor_test(10, TYPICAL);
223 }
224
225 T_DECL(compr_100MB_zero, "Compressor latencies") {
226 run_compressor_test(100, ALL_ZEROS);
227 }
228
229 T_DECL(compr_100MB_mostly_zero, "Compressor latencies") {
230 run_compressor_test(100, MOSTLY_ZEROS);
231 }
232
233 T_DECL(compr_100MB_random, "Compressor latencies") {
234 run_compressor_test(100, RANDOM);
235 }
236
237 T_DECL(compr_100MB_typical, "Compressor latencies") {
238 run_compressor_test(100, TYPICAL);
239 }
240