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