]> git.saurik.com Git - apple/xnu.git/blob - tests/vm_phys_footprint.c
xnu-4903.270.47.tar.gz
[apple/xnu.git] / tests / vm_phys_footprint.c
1 #include <darwintest.h>
2 #include <darwintest_utils.h>
3
4 #include <mach/mach_error.h>
5 #include <mach/mach_init.h>
6 #include <mach/mach_port.h>
7 #include <mach/mach_vm.h>
8 #include <mach/task.h>
9 #include <mach/task_info.h>
10 #include <mach/vm_map.h>
11
12 #include <sys/mman.h>
13
14 #include <Kernel/kern/ledger.h>
15 extern int ledger(int cmd, caddr_t arg1, caddr_t arg2, caddr_t arg3);
16
17 #if ENTITLED && defined(__arm64__)
18 #define LEGACY_FOOTPRINT 1
19 #else /* ENTITLED && __arm64__ */
20 #define LEGACY_FOOTPRINT 0
21 #endif /* ENTITLED && __arm64__ */
22
23 #define MEM_SIZE (100 * 1024 * 1024) /* 100 MB */
24
25 static int64_t ledger_count = -1;
26 static int footprint_index = -1;
27 static int pagetable_index = -1;
28 static struct ledger_entry_info *lei = NULL;
29
30 static void
31 ledger_init(void)
32 {
33 static int ledger_inited = 0;
34 struct ledger_info li;
35 struct ledger_template_info *templateInfo;
36 int64_t templateCnt;
37 int i;
38
39 if (ledger_inited) {
40 return;
41 }
42 ledger_inited = 1;
43
44 T_SETUPBEGIN;
45 T_QUIET;
46 T_WITH_ERRNO;
47 T_ASSERT_EQ(ledger(LEDGER_INFO,
48 (caddr_t)(uintptr_t)getpid(),
49 (caddr_t)&li,
50 NULL),
51 0,
52 "ledger(LEDGER_INFO)");
53
54 templateCnt = li.li_entries;
55 templateInfo = malloc((size_t)li.li_entries * sizeof(struct ledger_template_info));
56 T_QUIET;
57 T_WITH_ERRNO;
58 T_ASSERT_NE(templateInfo, NULL, "malloc()");
59
60 ledger_count = li.li_entries;
61 footprint_index = -1;
62 pagetable_index = -1;
63 T_QUIET;
64 T_WITH_ERRNO;
65 T_ASSERT_GE(ledger(LEDGER_TEMPLATE_INFO,
66 (caddr_t)templateInfo,
67 (caddr_t)&templateCnt,
68 NULL),
69 0,
70 "ledger(LEDGER_TEMPLATE_INFO)");
71 for (i = 0; i < templateCnt; i++) {
72 if (!strncmp(templateInfo[i].lti_name,
73 "phys_footprint",
74 strlen("phys_footprint"))) {
75 footprint_index = i;
76 } else if (!strncmp(templateInfo[i].lti_name,
77 "page_table",
78 strlen("page_table"))) {
79 pagetable_index = i;
80 }
81 }
82 free(templateInfo);
83
84 lei = (struct ledger_entry_info *)
85 malloc((size_t)ledger_count * sizeof(*lei));
86 T_QUIET;
87 T_WITH_ERRNO;
88 T_ASSERT_NE(lei, NULL, "malloc(ledger_entry_info)");
89
90 T_QUIET;
91 T_ASSERT_NE(footprint_index, -1, "no footprint_index");
92 T_QUIET;
93 T_ASSERT_NE(pagetable_index, -1, "no pagetable_index");
94
95 T_SETUPEND;
96 }
97
98 static void
99 get_ledger_info(
100 uint64_t *phys_footprint,
101 uint64_t *page_table)
102 {
103 int64_t count;
104
105 count = ledger_count;
106 T_QUIET;
107 T_WITH_ERRNO;
108 T_ASSERT_GE(ledger(LEDGER_ENTRY_INFO,
109 (caddr_t)(uintptr_t)getpid(),
110 (caddr_t)lei,
111 (caddr_t)&count),
112 0,
113 "ledger(LEDGER_ENTRY_INFO)");
114 T_QUIET;
115 T_ASSERT_GT(count, (int64_t)footprint_index, "no entry for footprint");
116 T_QUIET;
117 T_ASSERT_GT(count, (int64_t)pagetable_index, "no entry for pagetable");
118 if (phys_footprint) {
119 *phys_footprint = (uint64_t)(lei[footprint_index].lei_balance);
120 }
121 if (page_table) {
122 *page_table = (uint64_t)(lei[pagetable_index].lei_balance);
123 }
124 }
125
126 static mach_vm_address_t
127 pre_warm(
128 mach_vm_size_t vm_size)
129 {
130 kern_return_t kr;
131 mach_vm_address_t vm_addr;
132 unsigned char BigBufOnStack[100 * 1024];
133 uint64_t footprint, page_table;
134
135 /* make sure ledgers are ready to be queried */
136 ledger_init();
137
138 T_SETUPBEGIN;
139
140 /*
141 * Touch a few pages ahead on the stack, to make
142 * sure we don't see a footprint increase due to
143 * an extra stack page later.
144 */
145 memset(BigBufOnStack, 0xb, sizeof(BigBufOnStack));
146 T_QUIET;
147 T_EXPECT_EQ(BigBufOnStack[0], 0xb,
148 "BigBufOnStack[0] == 0x%x",
149 BigBufOnStack[0]);
150 T_QUIET;
151 T_EXPECT_EQ(BigBufOnStack[sizeof(BigBufOnStack) - 1], 0xb,
152 "BigBufOnStack[%lu] == 0x%x",
153 sizeof(BigBufOnStack),
154 BigBufOnStack[sizeof(BigBufOnStack) - 1]);
155
156 /*
157 * Pre-allocate, touch and then release the same amount
158 * of memory we'll be allocating later during the test,
159 * to account for any memory overhead (page tables, global
160 * variables, ...).
161 */
162 vm_addr = 0;
163 kr = mach_vm_allocate(mach_task_self(),
164 &vm_addr,
165 vm_size,
166 VM_FLAGS_ANYWHERE);
167 T_QUIET;
168 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%lld) error 0x%x (%s)",
169 vm_size, kr, mach_error_string(kr));
170 memset((char *)(uintptr_t)vm_addr, 'p', (size_t)vm_size);
171 kr = mach_vm_deallocate(mach_task_self(),
172 vm_addr,
173 vm_size);
174 T_QUIET;
175 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
176 kr, mach_error_string(kr));
177
178 /*
179 * Exercise the ledger code to make sure it's ready to run
180 * without any extra memory overhead later.
181 */
182 get_ledger_info(&footprint, &page_table);
183
184 T_SETUPEND;
185
186 /*
187 * Return the start of the virtual range we pre-warmed, so that the
188 * test can check that it's using the same range.
189 */
190 return vm_addr;
191 }
192
193 T_DECL(phys_footprint_anonymous,
194 "phys_footprint for anonymous memory",
195 T_META_NAMESPACE("xnu.vm"),
196 T_META_LTEPHASE(LTE_POSTINIT))
197 {
198 uint64_t footprint_before, pagetable_before;
199 uint64_t footprint_after, pagetable_after;
200 uint64_t footprint_expected;
201 kern_return_t kr;
202 mach_vm_address_t pre_vm_addr, vm_addr;
203 mach_vm_size_t vm_size, dirty_size;
204
205 /* pre-warm to account for page table expansion */
206 pre_vm_addr = pre_warm(MEM_SIZE);
207
208 /* allocating virtual memory... */
209 get_ledger_info(&footprint_before, &pagetable_before);
210 vm_addr = 0;
211 vm_size = MEM_SIZE;
212 kr = mach_vm_allocate(mach_task_self(), &vm_addr, vm_size,
213 VM_FLAGS_ANYWHERE);
214 T_QUIET;
215 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate() error 0x%x (%s)",
216 kr, mach_error_string(kr));
217 T_QUIET;
218 T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
219 /* ... should not change footprint */
220 get_ledger_info(&footprint_after, &pagetable_after);
221 footprint_expected = footprint_before;
222 footprint_expected += (pagetable_after - pagetable_before);
223 T_LOG("virtual allocation does not change phys_footprint");
224 T_EXPECT_EQ(footprint_after, footprint_expected,
225 "virtual allocation of %lld bytes: "
226 "footprint %lld -> %lld expected %lld delta %lld",
227 vm_size, footprint_before, footprint_after,
228 footprint_expected, footprint_after - footprint_expected);
229
230 /* touching memory... */
231 get_ledger_info(&footprint_before, &pagetable_before);
232 dirty_size = vm_size / 2;
233 memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
234 /* ... should increase footprint */
235 get_ledger_info(&footprint_after, &pagetable_after);
236 footprint_expected = footprint_before + dirty_size;
237 footprint_expected += (pagetable_after - pagetable_before);
238 T_LOG("modifying anonymous memory increases phys_footprint");
239 T_EXPECT_EQ(footprint_after, footprint_expected,
240 "touched %lld bytes: "
241 "footprint %lld -> %lld expected %lld delta %lld",
242 dirty_size, footprint_before, footprint_after,
243 footprint_expected, footprint_after - footprint_expected);
244
245 /* deallocating memory... */
246 get_ledger_info(&footprint_before, &pagetable_before);
247 kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
248 T_QUIET;
249 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
250 kr, mach_error_string(kr));
251 /* ... should decrease footprint */
252 get_ledger_info(&footprint_after, &pagetable_after);
253 footprint_expected = footprint_before - dirty_size;
254 footprint_expected += (pagetable_after - pagetable_before);
255 T_LOG("deallocating dirty anonymous memory decreases phys_footprint");
256 T_EXPECT_EQ(footprint_after, footprint_expected,
257 "deallocated %lld dirty bytes: "
258 "footprint %lld -> %lld expected %lld delta %lld",
259 dirty_size, footprint_before, footprint_after,
260 footprint_expected, footprint_after - footprint_expected);
261 }
262
263 #define TEMP_FILE_TEMPLATE "/tmp/phys_footprint_data.XXXXXXXX"
264 #define TEMP_FILE_SIZE (1 * 1024 * 1024)
265
266 T_DECL(phys_footprint_file,
267 "phys_footprint for mapped file",
268 T_META_NAMESPACE("xnu.vm"),
269 T_META_LTEPHASE(LTE_POSTINIT))
270 {
271 uint64_t footprint_before, pagetable_before;
272 uint64_t footprint_after, pagetable_after;
273 uint64_t footprint_expected;
274 mach_vm_address_t pre_vm_addr;
275 int fd;
276 char *map_addr;
277 size_t map_size, dirty_size;
278 ssize_t nbytes;
279 char tmp_file_name[PATH_MAX] = TEMP_FILE_TEMPLATE;
280 char *buf;
281 size_t buf_size;
282
283 T_SETUPBEGIN;
284 buf_size = TEMP_FILE_SIZE;
285 T_QUIET;
286 T_ASSERT_NOTNULL(buf = (char *)malloc(buf_size),
287 "allocate %zu-byte buffer", buf_size);
288 memset(buf, 'f', buf_size);
289 T_WITH_ERRNO;
290 T_QUIET;
291 T_ASSERT_NOTNULL(mktemp(tmp_file_name),
292 "create temporary file name");
293 T_WITH_ERRNO;
294 T_QUIET;
295 T_ASSERT_GE(fd = open(tmp_file_name, O_CREAT | O_RDWR),
296 0,
297 "create temp file");
298 T_WITH_ERRNO;
299 T_QUIET;
300 T_ASSERT_EQ(nbytes = write(fd, buf, buf_size),
301 (ssize_t)buf_size,
302 "write %zu bytes", buf_size);
303 free(buf);
304 T_SETUPEND;
305
306 /* pre-warm to account for page table expansion */
307 pre_vm_addr = pre_warm(TEMP_FILE_SIZE);
308
309 /* mapping a file does not impact footprint... */
310 get_ledger_info(&footprint_before, &pagetable_before);
311 map_size = TEMP_FILE_SIZE;
312 T_WITH_ERRNO;
313 T_QUIET;
314 T_ASSERT_NOTNULL(map_addr = (char *)mmap(NULL, map_size,
315 PROT_READ | PROT_WRITE,
316 MAP_FILE | MAP_SHARED, fd, 0),
317 "mmap()");
318 T_QUIET;
319 T_EXPECT_EQ((mach_vm_address_t)map_addr, pre_vm_addr,
320 "pre-warm mishap");
321 /* ... should not change footprint */
322 get_ledger_info(&footprint_after, &pagetable_after);
323 footprint_expected = footprint_before;
324 footprint_expected += (pagetable_after - pagetable_before);
325 T_LOG("mapping file does not change phys_footprint");
326 T_EXPECT_EQ(footprint_after, footprint_expected,
327 "mapping file with %zu bytes: "
328 "footprint %lld -> %lld expected %lld delta %lld",
329 map_size, footprint_before, footprint_after,
330 footprint_expected, footprint_after - footprint_expected);
331
332 /* touching file-backed memory... */
333 get_ledger_info(&footprint_before, &pagetable_before);
334 dirty_size = map_size / 2;
335 memset(map_addr, 'F', dirty_size);
336 /* ... should not impact footprint */
337 get_ledger_info(&footprint_after, &pagetable_after);
338 footprint_expected = footprint_before;
339 footprint_expected += (pagetable_after - pagetable_before);
340 T_LOG("modifying file-backed memory does not impact phys_footprint");
341 T_EXPECT_EQ(footprint_after, footprint_expected,
342 "touched %zu bytes: "
343 "footprint %lld -> %lld expected %lld delta %lld",
344 dirty_size, footprint_before, footprint_after,
345 footprint_expected, footprint_after - footprint_expected);
346
347 /* deallocating file-backed memory... */
348 get_ledger_info(&footprint_before, &pagetable_before);
349 T_WITH_ERRNO;
350 T_QUIET;
351 T_ASSERT_EQ(munmap(map_addr, map_size),
352 0,
353 "unmap file");
354 /* ... should not impact footprint */
355 get_ledger_info(&footprint_after, &pagetable_after);
356 footprint_expected = footprint_before;
357 footprint_expected += (pagetable_after - pagetable_before);
358 T_LOG("unmapping file-backed memory does not impact phys_footprint");
359 T_EXPECT_EQ(footprint_after, footprint_expected,
360 "unmapped %zu dirty bytes: "
361 "footprint %lld -> %lld expected %lld delta %lld",
362 dirty_size, footprint_before, footprint_after,
363 footprint_expected, footprint_after - footprint_expected);
364 }
365
366 T_DECL(phys_footprint_purgeable,
367 "phys_footprint for purgeable memory",
368 T_META_NAMESPACE("xnu.vm"),
369 T_META_LTEPHASE(LTE_POSTINIT))
370 {
371 uint64_t footprint_before, pagetable_before;
372 uint64_t footprint_after, pagetable_after;
373 uint64_t footprint_expected;
374 kern_return_t kr;
375 mach_vm_address_t pre_vm_addr, vm_addr;
376 mach_vm_size_t vm_size, dirty_size;
377 int state;
378
379 /* pre-warm to account for page table expansion */
380 pre_vm_addr = pre_warm(MEM_SIZE);
381
382 /* allocating purgeable virtual memory... */
383 get_ledger_info(&footprint_before, &pagetable_before);
384 vm_addr = 0;
385 vm_size = MEM_SIZE;
386 kr = mach_vm_allocate(mach_task_self(), &vm_addr, vm_size,
387 VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
388 T_QUIET;
389 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate() error 0x%x (%s)",
390 kr, mach_error_string(kr));
391 T_QUIET;
392 T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
393 /* ... should not change footprint */
394 get_ledger_info(&footprint_after, &pagetable_after);
395 footprint_expected = footprint_before;
396 footprint_expected += (pagetable_after - pagetable_before);
397 T_LOG("purgeable virtual allocation does not change phys_footprint");
398 T_EXPECT_EQ(footprint_after, footprint_expected,
399 "purgeable virtual allocation of %lld bytes: "
400 "footprint %lld -> %lld expected %lld delta %lld",
401 vm_size, footprint_before, footprint_after,
402 footprint_expected, footprint_after - footprint_expected);
403
404 /* touching memory... */
405 get_ledger_info(&footprint_before, &pagetable_before);
406 dirty_size = vm_size / 2;
407 memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
408 /* ... should increase footprint */
409 get_ledger_info(&footprint_after, &pagetable_after);
410 footprint_expected = footprint_before + dirty_size;
411 footprint_expected += (pagetable_after - pagetable_before);
412 T_LOG("modifying anonymous memory increases phys_footprint");
413 T_EXPECT_EQ(footprint_after, footprint_expected,
414 "touched %lld bytes: "
415 "footprint %lld -> %lld expected %lld delta %lld",
416 dirty_size, footprint_before, footprint_after,
417 footprint_expected, footprint_after - footprint_expected);
418
419 /* making it volatile... */
420 get_ledger_info(&footprint_before, &pagetable_before);
421 state = VM_PURGABLE_VOLATILE;
422 T_QUIET;
423 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
424 vm_addr,
425 VM_PURGABLE_SET_STATE,
426 &state),
427 KERN_SUCCESS,
428 "vm_purgable_control(VOLATILE)");
429 T_QUIET;
430 T_ASSERT_EQ(state, VM_PURGABLE_NONVOLATILE,
431 "memory was non-volatile");
432 /* ... should decrease footprint */
433 get_ledger_info(&footprint_after, &pagetable_after);
434 footprint_expected = footprint_before - dirty_size;
435 footprint_expected += (pagetable_after - pagetable_before);
436 T_LOG("making volatile decreases phys_footprint");
437 T_EXPECT_EQ(footprint_after, footprint_expected,
438 "made volatile %lld dirty bytes: "
439 "footprint %lld -> %lld expected %lld delta %lld",
440 dirty_size, footprint_before, footprint_after,
441 footprint_expected, footprint_after - footprint_expected);
442
443 /* making it non-volatile... */
444 get_ledger_info(&footprint_before, &pagetable_before);
445 state = VM_PURGABLE_NONVOLATILE;
446 T_QUIET;
447 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
448 vm_addr,
449 VM_PURGABLE_SET_STATE,
450 &state),
451 KERN_SUCCESS,
452 "vm_purgable_control(NONVOLATILE)");
453 T_QUIET;
454 T_ASSERT_EQ(state, VM_PURGABLE_VOLATILE,
455 "memory was volatile");
456 /* ... should increase footprint */
457 get_ledger_info(&footprint_after, &pagetable_after);
458 footprint_expected = footprint_before + dirty_size;
459 footprint_expected += (pagetable_after - pagetable_before);
460 T_LOG("making non-volatile increases phys_footprint");
461 T_EXPECT_EQ(footprint_after, footprint_expected,
462 "made non-volatile %lld dirty bytes: "
463 "footprint %lld -> %lld expected %lld delta %lld",
464 dirty_size, footprint_before, footprint_after,
465 footprint_expected, footprint_after - footprint_expected);
466
467 /* deallocating memory... */
468 get_ledger_info(&footprint_before, &pagetable_before);
469 kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
470 T_QUIET;
471 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
472 kr, mach_error_string(kr));
473 /* ... should decrease footprint */
474 get_ledger_info(&footprint_after, &pagetable_after);
475 footprint_expected = footprint_before - dirty_size;
476 footprint_expected += (pagetable_after - pagetable_before);
477 T_LOG("deallocating memory decreases phys_footprint");
478 T_EXPECT_EQ(footprint_after, footprint_expected,
479 "deallocated %lld dirty bytes: "
480 "footprint %lld -> %lld expected %lld delta %lld",
481 dirty_size, footprint_before, footprint_after,
482 footprint_expected, footprint_after - footprint_expected);
483 }
484
485 T_DECL(phys_footprint_purgeable_ownership,
486 "phys_footprint for owned purgeable memory",
487 T_META_NAMESPACE("xnu.vm"),
488 T_META_LTEPHASE(LTE_POSTINIT))
489 {
490 uint64_t footprint_before, pagetable_before;
491 uint64_t footprint_after, pagetable_after;
492 uint64_t footprint_expected;
493 kern_return_t kr;
494 mach_vm_address_t pre_vm_addr, vm_addr;
495 mach_vm_size_t vm_size, dirty_size, me_size;
496 int state;
497 mach_port_t me_port;
498
499 /* pre-warm to account for page table expansion */
500 pre_vm_addr = pre_warm(MEM_SIZE);
501
502 /* allocating purgeable virtual memory... */
503 get_ledger_info(&footprint_before, &pagetable_before);
504 vm_addr = 0;
505 vm_size = MEM_SIZE;
506 kr = mach_vm_allocate(mach_task_self(), &vm_addr, vm_size,
507 VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE);
508 T_QUIET;
509 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate() error 0x%x (%s)",
510 kr, mach_error_string(kr));
511 T_QUIET;
512 T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
513 /* ... should not change footprint */
514 get_ledger_info(&footprint_after, &pagetable_after);
515 footprint_expected = footprint_before;
516 footprint_expected += (pagetable_after - pagetable_before);
517 T_LOG("purgeable virtual allocation does not change phys_footprint");
518 T_EXPECT_EQ(footprint_after, footprint_expected,
519 "purgeable virtual allocation of %lld bytes: "
520 "footprint %lld -> %lld expected %lld delta %lld",
521 vm_size, footprint_before, footprint_after,
522 footprint_expected, footprint_after - footprint_expected);
523
524 /* touching memory... */
525 get_ledger_info(&footprint_before, &pagetable_before);
526 dirty_size = vm_size / 2;
527 memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
528 /* ... should increase footprint */
529 get_ledger_info(&footprint_after, &pagetable_after);
530 footprint_expected = footprint_before + dirty_size;
531 footprint_expected += (pagetable_after - pagetable_before);
532 T_LOG("modifying anonymous memory increases phys_footprint");
533 T_EXPECT_EQ(footprint_after, footprint_expected,
534 "touched %lld bytes: "
535 "footprint %lld -> %lld expected %lld delta %lld",
536 dirty_size, footprint_before, footprint_after,
537 footprint_expected, footprint_after - footprint_expected);
538
539 /* making it volatile... */
540 get_ledger_info(&footprint_before, &pagetable_before);
541 state = VM_PURGABLE_VOLATILE;
542 T_QUIET;
543 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
544 vm_addr,
545 VM_PURGABLE_SET_STATE,
546 &state),
547 KERN_SUCCESS,
548 "vm_purgable_control(VOLATILE)");
549 T_QUIET;
550 T_ASSERT_EQ(state, VM_PURGABLE_NONVOLATILE,
551 "memory was non-volatile");
552 /* ... should decrease footprint */
553 get_ledger_info(&footprint_after, &pagetable_after);
554 footprint_expected = footprint_before - dirty_size;
555 footprint_expected += (pagetable_after - pagetable_before);
556 T_LOG("making volatile decreases phys_footprint");
557 T_EXPECT_EQ(footprint_after, footprint_expected,
558 "made volatile %lld dirty bytes: "
559 "footprint %lld -> %lld expected %lld delta %lld",
560 dirty_size, footprint_before, footprint_after,
561 footprint_expected, footprint_after - footprint_expected);
562
563 /* making it non-volatile... */
564 get_ledger_info(&footprint_before, &pagetable_before);
565 state = VM_PURGABLE_NONVOLATILE;
566 T_QUIET;
567 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
568 vm_addr,
569 VM_PURGABLE_SET_STATE,
570 &state),
571 KERN_SUCCESS,
572 "vm_purgable_control(NONVOLATILE)");
573 T_QUIET;
574 T_ASSERT_EQ(state, VM_PURGABLE_VOLATILE,
575 "memory was volatile");
576 /* ... should increase footprint */
577 get_ledger_info(&footprint_after, &pagetable_after);
578 footprint_expected = footprint_before + dirty_size;
579 footprint_expected += (pagetable_after - pagetable_before);
580 T_LOG("making non-volatile increases phys_footprint");
581 T_EXPECT_EQ(footprint_after, footprint_expected,
582 "made non-volatile %lld dirty bytes: "
583 "footprint %lld -> %lld expected %lld delta %lld",
584 dirty_size, footprint_before, footprint_after,
585 footprint_expected, footprint_after - footprint_expected);
586
587 /* making a memory entry... */
588 get_ledger_info(&footprint_before, &pagetable_before);
589 me_size = vm_size;
590 me_port = MACH_PORT_NULL;
591 kr = mach_make_memory_entry_64(mach_task_self(),
592 &me_size,
593 vm_addr,
594 VM_PROT_READ | VM_PROT_WRITE,
595 &me_port,
596 MACH_PORT_NULL);
597 T_QUIET;
598 T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
599 kr, mach_error_string(kr));
600 T_QUIET;
601 T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
602 /* ... should not change footprint */
603 get_ledger_info(&footprint_after, &pagetable_after);
604 footprint_expected = footprint_before;
605 footprint_expected += (pagetable_after - pagetable_before);
606 T_LOG("making a memory entry does not change phys_footprint");
607 T_EXPECT_EQ(footprint_after, footprint_expected,
608 "making a memory entry of %lld bytes: "
609 "footprint %lld -> %lld expected %lld delta %lld",
610 vm_size, footprint_before, footprint_after,
611 footprint_expected, footprint_after - footprint_expected);
612
613 /* deallocating memory while holding memory entry... */
614 get_ledger_info(&footprint_before, &pagetable_before);
615 kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
616 T_QUIET;
617 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
618 kr, mach_error_string(kr));
619 /* ... should not change footprint */
620 get_ledger_info(&footprint_after, &pagetable_after);
621 footprint_expected = footprint_before;
622 footprint_expected += (pagetable_after - pagetable_before);
623 T_LOG("deallocating owned memory while holding memory entry "
624 "does not change phys_footprint");
625 T_EXPECT_EQ(footprint_after, footprint_expected,
626 "deallocated %lld dirty bytes: "
627 "footprint %lld -> %lld expected %lld delta %lld",
628 dirty_size, footprint_before, footprint_after,
629 footprint_expected, footprint_after - footprint_expected);
630
631 /* releasing the memory entry... */
632 kr = mach_port_deallocate(mach_task_self(), me_port);
633 T_QUIET;
634 T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
635 kr, mach_error_string(kr));
636 /* ... should decrease footprint */
637 get_ledger_info(&footprint_after, &pagetable_after);
638 footprint_expected = footprint_before - dirty_size;
639 footprint_expected += (pagetable_after - pagetable_before);
640 T_LOG("releasing memory entry decreases phys_footprint");
641 T_EXPECT_EQ(footprint_after, footprint_expected,
642 "made volatile %lld dirty bytes: "
643 "footprint %lld -> %lld expected %lld delta %lld",
644 dirty_size, footprint_before, footprint_after,
645 footprint_expected, footprint_after - footprint_expected);
646 }
647
648 #ifdef MAP_MEM_LEDGER_TAGGED
649 T_DECL(phys_footprint_ledger_purgeable_owned,
650 "phys_footprint for ledger-tagged purgeable memory ownership",
651 T_META_NAMESPACE("xnu.vm"),
652 T_META_LTEPHASE(LTE_POSTINIT))
653 {
654 uint64_t footprint_before, pagetable_before;
655 uint64_t footprint_after, pagetable_after;
656 uint64_t footprint_expected;
657 kern_return_t kr;
658 mach_vm_address_t pre_vm_addr, vm_addr;
659 mach_vm_size_t vm_size, dirty_size, me_size;
660 int state;
661 mach_port_t me_port;
662
663 /* pre-warm to account for page table expansion */
664 pre_vm_addr = pre_warm(MEM_SIZE);
665
666 /* making a memory entry... */
667 get_ledger_info(&footprint_before, &pagetable_before);
668 vm_size = MEM_SIZE;
669 me_size = vm_size;
670 me_port = MACH_PORT_NULL;
671 kr = mach_make_memory_entry_64(mach_task_self(),
672 &me_size,
673 0,
674 (MAP_MEM_NAMED_CREATE |
675 MAP_MEM_LEDGER_TAGGED |
676 MAP_MEM_PURGABLE |
677 VM_PROT_READ | VM_PROT_WRITE),
678 &me_port,
679 MACH_PORT_NULL);
680 T_QUIET;
681 T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
682 kr, mach_error_string(kr));
683 T_QUIET;
684 T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
685 /* ... should not change footprint */
686 get_ledger_info(&footprint_after, &pagetable_after);
687 footprint_expected = footprint_before;
688 footprint_expected += (pagetable_after - pagetable_before);
689 T_LOG("making a memory entry does not change phys_footprint");
690 T_EXPECT_EQ(footprint_after, footprint_expected,
691 "making a memory entry of %lld bytes: "
692 "footprint %lld -> %lld expected %lld delta %lld",
693 vm_size, footprint_before, footprint_after,
694 footprint_expected, footprint_after - footprint_expected);
695
696 /* mapping ledger-tagged virtual memory... */
697 get_ledger_info(&footprint_before, &pagetable_before);
698 vm_addr = 0;
699 kr = mach_vm_map(mach_task_self(), &vm_addr, vm_size,
700 0, /* mask */
701 VM_FLAGS_ANYWHERE,
702 me_port,
703 0, /* offset */
704 FALSE, /* copy */
705 VM_PROT_READ | VM_PROT_WRITE,
706 VM_PROT_READ | VM_PROT_WRITE,
707 VM_INHERIT_DEFAULT);
708 T_QUIET;
709 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_map() error 0x%x (%s)",
710 kr, mach_error_string(kr));
711 T_QUIET;
712 T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
713 /* ... should not change footprint */
714 get_ledger_info(&footprint_after, &pagetable_after);
715 footprint_expected = footprint_before;
716 footprint_expected += (pagetable_after - pagetable_before);
717 T_LOG("mapping ledger-tagged memory does not change phys_footprint");
718 T_EXPECT_EQ(footprint_after, footprint_expected,
719 "ledger-tagged mapping of %lld bytes: "
720 "footprint %lld -> %lld expected %lld delta %lld",
721 vm_size, footprint_before, footprint_after,
722 footprint_expected, footprint_after - footprint_expected);
723
724 /* touching memory... */
725 get_ledger_info(&footprint_before, &pagetable_before);
726 dirty_size = vm_size / 2;
727 memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
728 /* ... should increase footprint */
729 get_ledger_info(&footprint_after, &pagetable_after);
730 footprint_expected = footprint_before + dirty_size;
731 footprint_expected += (pagetable_after - pagetable_before);
732 T_LOG("modifying ledger-tagged memory increases phys_footprint");
733 T_EXPECT_EQ(footprint_after, footprint_expected,
734 "touched %lld bytes: "
735 "footprint %lld -> %lld expected %lld delta %lld",
736 dirty_size, footprint_before, footprint_after,
737 footprint_expected, footprint_after - footprint_expected);
738
739 /* making it volatile... */
740 get_ledger_info(&footprint_before, &pagetable_before);
741 state = VM_PURGABLE_VOLATILE;
742 T_QUIET;
743 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
744 vm_addr,
745 VM_PURGABLE_SET_STATE,
746 &state),
747 KERN_SUCCESS,
748 "vm_purgable_control(VOLATILE)");
749 T_QUIET;
750 T_ASSERT_EQ(state, VM_PURGABLE_NONVOLATILE,
751 "memory was non-volatile");
752 /* ... should decrease footprint */
753 get_ledger_info(&footprint_after, &pagetable_after);
754 footprint_expected = footprint_before - dirty_size;
755 footprint_expected += (pagetable_after - pagetable_before);
756 T_LOG("making volatile decreases phys_footprint");
757 T_EXPECT_EQ(footprint_after, footprint_expected,
758 "made volatile %lld dirty bytes: "
759 "footprint %lld -> %lld expected %lld delta %lld",
760 dirty_size, footprint_before, footprint_after,
761 footprint_expected, footprint_after - footprint_expected);
762
763 /* making it non-volatile... */
764 get_ledger_info(&footprint_before, &pagetable_before);
765 state = VM_PURGABLE_NONVOLATILE;
766 T_QUIET;
767 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
768 vm_addr,
769 VM_PURGABLE_SET_STATE,
770 &state),
771 KERN_SUCCESS,
772 "vm_purgable_control(NONVOLATILE)");
773 T_QUIET;
774 T_ASSERT_EQ(state, VM_PURGABLE_VOLATILE,
775 "memory was volatile");
776 /* ... should increase footprint */
777 get_ledger_info(&footprint_after, &pagetable_after);
778 footprint_expected = footprint_before + dirty_size;
779 footprint_expected += (pagetable_after - pagetable_before);
780 T_LOG("making non-volatile increases phys_footprint");
781 T_EXPECT_EQ(footprint_after, footprint_expected,
782 "made non-volatile %lld dirty bytes: "
783 "footprint %lld -> %lld expected %lld delta %lld",
784 dirty_size, footprint_before, footprint_after,
785 footprint_expected, footprint_after - footprint_expected);
786
787 /* deallocating memory while holding memory entry... */
788 get_ledger_info(&footprint_before, &pagetable_before);
789 kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
790 T_QUIET;
791 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
792 kr, mach_error_string(kr));
793 /* ... should not change footprint */
794 get_ledger_info(&footprint_after, &pagetable_after);
795 footprint_expected = footprint_before;
796 footprint_expected += (pagetable_after - pagetable_before);
797 T_LOG("deallocating owned memory while holding memory entry "
798 "does not change phys_footprint");
799 T_EXPECT_EQ(footprint_after, footprint_expected,
800 "deallocated %lld dirty bytes: "
801 "footprint %lld -> %lld expected %lld delta %lld",
802 dirty_size, footprint_before, footprint_after,
803 footprint_expected, footprint_after - footprint_expected);
804
805 /* releasing the memory entry... */
806 kr = mach_port_deallocate(mach_task_self(), me_port);
807 T_QUIET;
808 T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
809 kr, mach_error_string(kr));
810 /* ... should decrease footprint */
811 get_ledger_info(&footprint_after, &pagetable_after);
812 footprint_expected = footprint_before - dirty_size;
813 footprint_expected += (pagetable_after - pagetable_before);
814 T_LOG("releasing memory entry decreases phys_footprint");
815 T_EXPECT_EQ(footprint_after, footprint_expected,
816 "made volatile %lld dirty bytes: "
817 "footprint %lld -> %lld expected %lld delta %lld",
818 dirty_size, footprint_before, footprint_after,
819 footprint_expected, footprint_after - footprint_expected);
820 }
821
822 T_DECL(phys_footprint_ledger_owned,
823 "phys_footprint for ledger-tagged memory ownership",
824 T_META_NAMESPACE("xnu.vm"),
825 T_META_LTEPHASE(LTE_POSTINIT))
826 {
827 uint64_t footprint_before, pagetable_before;
828 uint64_t footprint_after, pagetable_after;
829 uint64_t footprint_expected;
830 kern_return_t kr;
831 mach_vm_address_t pre_vm_addr, vm_addr;
832 mach_vm_size_t vm_size, dirty_size, me_size;
833 int state;
834 mach_port_t me_port;
835
836 /* pre-warm to account for page table expansion */
837 pre_vm_addr = pre_warm(MEM_SIZE);
838
839 /* making a memory entry... */
840 get_ledger_info(&footprint_before, &pagetable_before);
841 vm_size = MEM_SIZE;
842 me_size = vm_size;
843 me_port = MACH_PORT_NULL;
844 kr = mach_make_memory_entry_64(mach_task_self(),
845 &me_size,
846 0,
847 (MAP_MEM_NAMED_CREATE |
848 MAP_MEM_LEDGER_TAGGED |
849 VM_PROT_READ | VM_PROT_WRITE),
850 &me_port,
851 MACH_PORT_NULL);
852 T_QUIET;
853 T_EXPECT_EQ(kr, KERN_SUCCESS, "make_memory_entry() error 0x%x (%s)",
854 kr, mach_error_string(kr));
855 T_QUIET;
856 T_EXPECT_EQ(me_size, vm_size, "memory entry size mismatch");
857 /* ... should not change footprint */
858 get_ledger_info(&footprint_after, &pagetable_after);
859 footprint_expected = footprint_before;
860 footprint_expected += (pagetable_after - pagetable_before);
861 T_LOG("making a memory entry does not change phys_footprint");
862 T_EXPECT_EQ(footprint_after, footprint_expected,
863 "making a memory entry of %lld bytes: "
864 "footprint %lld -> %lld expected %lld delta %lld",
865 vm_size, footprint_before, footprint_after,
866 footprint_expected, footprint_after - footprint_expected);
867
868 /* mapping ledger-tagged virtual memory... */
869 get_ledger_info(&footprint_before, &pagetable_before);
870 vm_addr = 0;
871 kr = mach_vm_map(mach_task_self(), &vm_addr, vm_size,
872 0, /* mask */
873 VM_FLAGS_ANYWHERE,
874 me_port,
875 0, /* offset */
876 FALSE, /* copy */
877 VM_PROT_READ | VM_PROT_WRITE,
878 VM_PROT_READ | VM_PROT_WRITE,
879 VM_INHERIT_DEFAULT);
880 T_QUIET;
881 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_map() error 0x%x (%s)",
882 kr, mach_error_string(kr));
883 T_QUIET;
884 T_EXPECT_EQ(vm_addr, pre_vm_addr, "pre-warm mishap");
885 /* ... should not change footprint */
886 get_ledger_info(&footprint_after, &pagetable_after);
887 footprint_expected = footprint_before;
888 footprint_expected += (pagetable_after - pagetable_before);
889 T_LOG("mapping ledger-tagged memory does not change phys_footprint");
890 T_EXPECT_EQ(footprint_after, footprint_expected,
891 "ledger-tagged mapping of %lld bytes: "
892 "footprint %lld -> %lld expected %lld delta %lld",
893 vm_size, footprint_before, footprint_after,
894 footprint_expected, footprint_after - footprint_expected);
895
896 /* touching memory... */
897 get_ledger_info(&footprint_before, &pagetable_before);
898 dirty_size = vm_size / 2;
899 memset((char *)(uintptr_t)vm_addr, 'x', (size_t)dirty_size);
900 /* ... should increase footprint */
901 get_ledger_info(&footprint_after, &pagetable_after);
902 footprint_expected = footprint_before + dirty_size;
903 footprint_expected += (pagetable_after - pagetable_before);
904 T_LOG("modifying ledger-tagged memory increases phys_footprint");
905 T_EXPECT_EQ(footprint_after, footprint_expected,
906 "touched %lld bytes: "
907 "footprint %lld -> %lld expected %lld delta %lld",
908 dirty_size, footprint_before, footprint_after,
909 footprint_expected, footprint_after - footprint_expected);
910
911 /* deallocating memory while holding memory entry... */
912 get_ledger_info(&footprint_before, &pagetable_before);
913 kr = mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
914 T_QUIET;
915 T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate() error 0x%x (%s)",
916 kr, mach_error_string(kr));
917 /* ... should not change footprint */
918 get_ledger_info(&footprint_after, &pagetable_after);
919 footprint_expected = footprint_before;
920 footprint_expected += (pagetable_after - pagetable_before);
921 T_LOG("deallocating owned memory while holding memory entry "
922 "does not change phys_footprint");
923 T_EXPECT_EQ(footprint_after, footprint_expected,
924 "deallocated %lld dirty bytes: "
925 "footprint %lld -> %lld expected %lld delta %lld",
926 dirty_size, footprint_before, footprint_after,
927 footprint_expected, footprint_after - footprint_expected);
928
929 /* releasing the memory entry... */
930 kr = mach_port_deallocate(mach_task_self(), me_port);
931 T_QUIET;
932 T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_port_deallocate() error 0x%x (%s)",
933 kr, mach_error_string(kr));
934 /* ... should decrease footprint */
935 get_ledger_info(&footprint_after, &pagetable_after);
936 footprint_expected = footprint_before - dirty_size;
937 footprint_expected += (pagetable_after - pagetable_before);
938 T_LOG("releasing memory entry decreases phys_footprint");
939 T_EXPECT_EQ(footprint_after, footprint_expected,
940 "made volatile %lld dirty bytes: "
941 "footprint %lld -> %lld expected %lld delta %lld",
942 dirty_size, footprint_before, footprint_after,
943 footprint_expected, footprint_after - footprint_expected);
944 }
945 #endif /* MAP_MEM_LEDGER_TAGGED */
946
947 /* IOSurface code from: CoreImage/CoreImageTests/CIRender/SurfaceUtils.c */
948 #include <CoreFoundation/CoreFoundation.h>
949 #include <IOSurface/IOSurface.h>
950 #include <IOSurface/IOSurfacePrivate.h>
951 static size_t
952 bytes_per_element(uint32_t format)
953 {
954 size_t bpe = 0;
955 switch (format) {
956 case 32: // kCVPixelFormatType_32ARGB (ARGB8)
957 bpe = 4;
958 break;
959 default:
960 bpe = 0;
961 break;
962 }
963 return bpe;
964 }
965 static size_t
966 bytes_per_pixel(uint32_t format)
967 {
968 size_t bpe = 0;
969 switch (format) {
970 case 32: // kCVPixelFormatType_32ARGB (ARGB8)
971 bpe = 4;
972 break;
973 default:
974 bpe = 0;
975 break;
976 }
977 return bpe;
978 }
979 static inline size_t
980 roundSizeToMultiple(size_t size, size_t mult)
981 {
982 return ((size + mult - 1) / mult) * mult;
983 }
984 static inline void
985 setIntValue(CFMutableDictionaryRef dict, const CFStringRef key, int value)
986 {
987 CFNumberRef number = CFNumberCreate(0, kCFNumberIntType, &value);
988 CFDictionarySetValue(dict, key, number);
989 CFRelease(number);
990 }
991 typedef void (^SurfacePlaneBlock)(void *data, size_t planeIndex, size_t width, size_t height, size_t rowbytes);
992 static IOReturn
993 SurfaceApplyPlaneBlock(IOSurfaceRef surface, SurfacePlaneBlock block)
994 {
995 if (surface == nil || block == nil) {
996 return kIOReturnBadArgument;
997 }
998
999 IOReturn result = kIOReturnSuccess;
1000 size_t planeCount = IOSurfaceGetPlaneCount(surface);
1001
1002 if (planeCount == 0) {
1003 result = IOSurfaceLock(surface, 0, NULL);
1004 if (result != kIOReturnSuccess) {
1005 return result;
1006 }
1007
1008 void* base = IOSurfaceGetBaseAddress(surface);
1009 size_t rb = IOSurfaceGetBytesPerRow(surface);
1010 size_t w = IOSurfaceGetWidth(surface);
1011 size_t h = IOSurfaceGetHeight(surface);
1012
1013 if (base && rb && w && h) {
1014 block(base, 0, w, h, rb);
1015 }
1016
1017 IOSurfaceUnlock(surface, 0, NULL);
1018 } else if (planeCount == 2) {
1019 for (size_t i = 0; i < planeCount; i++) {
1020 result = IOSurfaceLock(surface, 0, NULL);
1021 if (result != kIOReturnSuccess) {
1022 return result;
1023 }
1024
1025 void* base = IOSurfaceGetBaseAddressOfPlane(surface, i);
1026 size_t rb = IOSurfaceGetBytesPerRowOfPlane(surface, i);
1027 size_t w = IOSurfaceGetWidthOfPlane(surface, i);
1028 size_t h = IOSurfaceGetHeightOfPlane(surface, i);
1029
1030 if (base && rb && w && h) {
1031 block(base, i, w, h, rb);
1032 }
1033
1034 IOSurfaceUnlock(surface, 0, NULL);
1035 }
1036 }
1037 return result;
1038 }
1039 static void
1040 ClearSurface(IOSurfaceRef surface)
1041 {
1042 const int zero = 0;
1043 (void) SurfaceApplyPlaneBlock(surface, ^(void *p, size_t i, __unused size_t w, size_t h, size_t rb)
1044 {
1045 if (i == 0) {
1046 memset(p, zero, rb * h);
1047 } else {
1048 memset(p, 128, rb * h);
1049 }
1050 });
1051 }
1052 static IOSurfaceRef
1053 CreateSurface(uint32_t pixelsWide, uint32_t pixelsHigh, uint32_t rowBytesAlignment, uint32_t fmt, bool purgeable, bool clear)
1054 {
1055 IOSurfaceRef surface = nil;
1056
1057 if (pixelsWide < 1 || pixelsHigh < 1 || fmt == 0) {
1058 return nil;
1059 }
1060
1061 size_t bpp = bytes_per_pixel(fmt);
1062 size_t bpe = bytes_per_element(fmt);
1063 if (bpp == 0 || bpe == 0) {
1064 return nil;
1065 }
1066
1067 size_t rowbytes = pixelsWide * bpp;
1068 if (rowBytesAlignment == 0) {
1069 rowBytesAlignment = 16;
1070 }
1071 rowbytes = roundSizeToMultiple(rowbytes, rowBytesAlignment);
1072
1073 CFMutableDictionaryRef props = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1074 setIntValue(props, kIOSurfaceBytesPerRow, (int)rowbytes);
1075 setIntValue(props, kIOSurfaceWidth, (int)pixelsWide);
1076 setIntValue(props, kIOSurfaceHeight, (int)pixelsHigh);
1077 setIntValue(props, kIOSurfacePixelFormat, (int)fmt);
1078 #if TARGET_OS_IPHONE
1079 setIntValue(props, kIOSurfaceNonPurgeable, purgeable);
1080 #else /* TARGET_OS_IPHONE */
1081 (void)purgeable;
1082 #endif /* TARGET_OS_IPHONE */
1083 {
1084 if (bpe != bpp) { // i.e. a 422 format such as 'yuvf' etc.
1085 setIntValue(props, kIOSurfaceElementWidth, 2);
1086 setIntValue(props, kIOSurfaceElementHeight, 1);
1087 }
1088 setIntValue(props, kIOSurfaceBytesPerElement, (int)bpe);
1089 }
1090
1091 surface = IOSurfaceCreate(props);
1092
1093 if (clear) {
1094 ClearSurface(surface);
1095 }
1096
1097 CFRelease(props);
1098 return surface;
1099 }
1100 T_DECL(phys_footprint_purgeable_iokit,
1101 "phys_footprint for purgeable IOKit memory",
1102 T_META_NAMESPACE("xnu.vm"),
1103 T_META_LTEPHASE(LTE_POSTINIT))
1104 {
1105 uint64_t footprint_before, pagetable_before;
1106 uint64_t footprint_after, pagetable_after;
1107 uint64_t footprint_expected;
1108 IOSurfaceRef surface;
1109 uint32_t old_state;
1110 uint64_t surface_size;
1111
1112 T_SETUPBEGIN;
1113 ledger_init();
1114 surface = CreateSurface(1024, 1024, 0, 32, true, true);
1115 IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableVolatile, &old_state);
1116 IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableNonVolatile, &old_state);
1117 CFRelease(surface);
1118 T_SETUPEND;
1119
1120 surface_size = 1024 * 1024 * 4;
1121
1122 /* create IOsurface: footprint grows */
1123 get_ledger_info(&footprint_before, &pagetable_before);
1124 surface = CreateSurface(1024, 1024, 0, 32, true, true);
1125 get_ledger_info(&footprint_after, &pagetable_after);
1126 #if LEGACY_FOOTPRINT
1127 footprint_expected = footprint_before;
1128 footprint_expected += (pagetable_after - pagetable_before);
1129 T_LOG("LEGACY FOOTPRINT: creating IOSurface: no footprint impact");
1130 T_EXPECT_EQ(footprint_after, footprint_expected,
1131 "create IOSurface %lld bytes: "
1132 "footprint %lld -> %lld expected %lld delta %lld",
1133 surface_size, footprint_before, footprint_after,
1134 footprint_expected, footprint_after - footprint_expected);
1135 #else /* LEGACY_FOOTPRINT */
1136 footprint_expected = footprint_before + surface_size;
1137 footprint_expected += (pagetable_after - pagetable_before);
1138 T_LOG("creating IOSurface increases phys_footprint");
1139 T_EXPECT_EQ(footprint_after, footprint_expected,
1140 "create IOSurface %lld bytes: "
1141 "footprint %lld -> %lld expected %lld delta %lld",
1142 surface_size, footprint_before, footprint_after,
1143 footprint_expected, footprint_after - footprint_expected);
1144 #endif /* LEGACY_FOOTPRINT */
1145
1146 /* make IOSurface volatile: footprint shrinks */
1147 get_ledger_info(&footprint_before, &pagetable_before);
1148 IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableVolatile, &old_state);
1149 get_ledger_info(&footprint_after, &pagetable_after);
1150 #if LEGACY_FOOTPRINT
1151 footprint_expected = footprint_before;
1152 footprint_expected += (pagetable_after - pagetable_before);
1153 T_LOG("LEGACY FOOTPRINT: volatile IOSurface: no footprint impact");
1154 T_EXPECT_EQ(footprint_after, footprint_expected,
1155 "volatile IOSurface %lld bytes: "
1156 "footprint %lld -> %lld expected %lld delta %lld",
1157 surface_size, footprint_before, footprint_after,
1158 footprint_expected, footprint_after - footprint_expected);
1159 #else /* LEGACY_FOOTPRINT */
1160 footprint_expected = footprint_before - surface_size;
1161 footprint_expected += (pagetable_after - pagetable_before);
1162 T_LOG("making IOSurface volatile decreases phys_footprint");
1163 T_EXPECT_EQ(footprint_after, footprint_expected,
1164 "made volatile %lld bytes: "
1165 "footprint %lld -> %lld expected %lld delta %lld",
1166 surface_size, footprint_before, footprint_after,
1167 footprint_expected, footprint_after - footprint_expected);
1168 #endif /* LEGACY_FOOTPRINT */
1169
1170 /* make IOSurface non-volatile: footprint grows */
1171 get_ledger_info(&footprint_before, &pagetable_before);
1172 IOSurfaceSetPurgeable(surface, kIOSurfacePurgeableNonVolatile, &old_state);
1173 get_ledger_info(&footprint_after, &pagetable_after);
1174 #if LEGACY_FOOTPRINT
1175 footprint_expected = footprint_before;
1176 footprint_expected += (pagetable_after - pagetable_before);
1177 T_LOG("LEGACY FOOTPRINT: non-volatile IOSurface: no footprint impact");
1178 T_EXPECT_EQ(footprint_after, footprint_expected,
1179 "non-volatile IOSurface %lld bytes: "
1180 "footprint %lld -> %lld expected %lld delta %lld",
1181 surface_size, footprint_before, footprint_after,
1182 footprint_expected, footprint_after - footprint_expected);
1183 #else /* LEGACY_FOOTPRINT */
1184 footprint_expected = footprint_before + surface_size;
1185 footprint_expected += (pagetable_after - pagetable_before);
1186 T_LOG("making IOSurface non-volatile increases phys_footprint");
1187 T_EXPECT_EQ(footprint_after, footprint_expected,
1188 "made non-volatile %lld bytes: "
1189 "footprint %lld -> %lld expected %lld delta %lld",
1190 surface_size, footprint_before, footprint_after,
1191 footprint_expected, footprint_after - footprint_expected);
1192 #endif /* LEGACY_FOOTPRINT */
1193
1194 /* accessing IOSurface re-mapping: no footprint impact */
1195
1196 /* deallocating IOSurface re-mapping: no footprint impact */
1197
1198 /* release IOSurface: footprint shrinks */
1199 get_ledger_info(&footprint_before, &pagetable_before);
1200 CFRelease(surface);
1201 get_ledger_info(&footprint_after, &pagetable_after);
1202 #if LEGACY_FOOTPRINT
1203 footprint_expected = footprint_before;
1204 footprint_expected += (pagetable_after - pagetable_before);
1205 T_LOG("LEGACY FOOTPRINT: release IOSurface: no footprint impact");
1206 T_EXPECT_EQ(footprint_after, footprint_expected,
1207 "releasing IOSurface %lld bytes: "
1208 "footprint %lld -> %lld expected %lld delta %lld",
1209 surface_size, footprint_before, footprint_after,
1210 footprint_expected, footprint_after - footprint_expected);
1211 #else /* LEGACY_FOOTPRINT */
1212 footprint_expected = footprint_before - surface_size;
1213 footprint_expected += (pagetable_after - pagetable_before);
1214 T_LOG("releasing IOSurface decreases phys_footprint");
1215 T_EXPECT_EQ(footprint_after, footprint_expected,
1216 "released IOSurface %lld bytes: "
1217 "footprint %lld -> %lld expected %lld delta %lld",
1218 surface_size, footprint_before, footprint_after,
1219 footprint_expected, footprint_after - footprint_expected);
1220 #endif /* LEGACY_FOOTPRINT */
1221 }