1 #include <darwintest.h>
2 #include <darwintest_utils.h>
4 #include <mach/mach_error.h>
5 #include <mach/mach_init.h>
6 #include <mach/mach_port.h>
7 #include <mach/mach_vm.h>
9 #include <mach/task_info.h>
10 #include <mach/vm_map.h>
13 #include <sys/types.h>
14 #include <sys/sysctl.h>
16 #include <TargetConditionals.h>
18 #include <Kernel/kern/ledger.h>
19 extern int ledger(int cmd
, caddr_t arg1
, caddr_t arg2
, caddr_t arg3
);
21 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
22 boolean_t legacy_footprint
;
24 #if LEGACY_FOOTPRINT_ENTITLED && defined(__arm64__)
25 #define TEST_VM_NAMESPACE "xnu.vm_legacy"
26 #else /* ENTITLED && __arm64__ */
27 #define TEST_VM_NAMESPACE "xnu.vm"
28 #endif /* ENTITLED && __arm64__ */
30 #define MEM_SIZE (100 * 1024 * 1024) /* 100 MB */
32 static int64_t ledger_count
= -1;
33 static int footprint_index
= -1;
34 static int pagetable_index
= -1;
35 static struct ledger_entry_info
*lei
= NULL
;
40 static int ledger_inited
= 0;
41 struct ledger_info li
;
42 struct ledger_template_info
*templateInfo
;
45 int legacy_footprint_entitlement_mode
;
55 legacy_footprint
= FALSE
;
56 #if LEGACY_FOOTPRINT_ENTITLED
61 oldlen
= sizeof(legacy_footprint_entitlement_mode
);
62 ret
= sysctlbyname("kern.legacy_footprint_entitlement_mode",
63 &legacy_footprint_entitlement_mode
,
67 if (ret
== 0 && legacy_footprint_entitlement_mode
== 2) {
68 legacy_footprint
= TRUE
;
70 #endif /* LEGACY_FOOTPRINT_ENTITLED */
74 T_ASSERT_EQ(ledger(LEDGER_INFO
,
75 (caddr_t
)(uintptr_t)getpid(),
79 "ledger(LEDGER_INFO)");
81 templateCnt
= li
.li_entries
;
82 templateInfo
= malloc((size_t)li
.li_entries
* sizeof(struct ledger_template_info
));
85 T_ASSERT_NE(templateInfo
, NULL
, "malloc()");
87 ledger_count
= li
.li_entries
;
92 T_ASSERT_GE(ledger(LEDGER_TEMPLATE_INFO
,
93 (caddr_t
)templateInfo
,
94 (caddr_t
)&templateCnt
,
97 "ledger(LEDGER_TEMPLATE_INFO)");
98 for (i
= 0; i
< templateCnt
; i
++) {
99 if (!strncmp(templateInfo
[i
].lti_name
,
101 strlen("phys_footprint"))) {
103 } else if (!strncmp(templateInfo
[i
].lti_name
,
105 strlen("page_table"))) {
111 lei
= (struct ledger_entry_info
*)
112 malloc((size_t)ledger_count
* sizeof(*lei
));
115 T_ASSERT_NE(lei
, NULL
, "malloc(ledger_entry_info)");
118 T_ASSERT_NE(footprint_index
, -1, "no footprint_index");
120 T_ASSERT_NE(pagetable_index
, -1, "no pagetable_index");
127 uint64_t *phys_footprint
,
128 uint64_t *page_table
)
132 count
= ledger_count
;
135 T_ASSERT_GE(ledger(LEDGER_ENTRY_INFO
,
136 (caddr_t
)(uintptr_t)getpid(),
140 "ledger(LEDGER_ENTRY_INFO)");
142 T_ASSERT_GT(count
, (int64_t)footprint_index
, "no entry for footprint");
144 T_ASSERT_GT(count
, (int64_t)pagetable_index
, "no entry for pagetable");
145 if (phys_footprint
) {
146 *phys_footprint
= (uint64_t)(lei
[footprint_index
].lei_balance
);
149 *page_table
= (uint64_t)(lei
[pagetable_index
].lei_balance
);
153 static mach_vm_address_t
155 mach_vm_size_t vm_size
)
158 mach_vm_address_t vm_addr
;
159 unsigned char BigBufOnStack
[100 * 1024];
160 uint64_t footprint
, page_table
;
162 /* make sure ledgers are ready to be queried */
168 * Touch a few pages ahead on the stack, to make
169 * sure we don't see a footprint increase due to
170 * an extra stack page later.
172 memset(BigBufOnStack
, 0xb, sizeof(BigBufOnStack
));
174 T_EXPECT_EQ(BigBufOnStack
[0], 0xb,
175 "BigBufOnStack[0] == 0x%x",
178 T_EXPECT_EQ(BigBufOnStack
[sizeof(BigBufOnStack
) - 1], 0xb,
179 "BigBufOnStack[%lu] == 0x%x",
180 sizeof(BigBufOnStack
),
181 BigBufOnStack
[sizeof(BigBufOnStack
) - 1]);
184 * Pre-allocate, touch and then release the same amount
185 * of memory we'll be allocating later during the test,
186 * to account for any memory overhead (page tables, global
190 kr
= mach_vm_allocate(mach_task_self(),
195 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_allocate(%lld) error 0x%x (%s)",
196 vm_size
, kr
, mach_error_string(kr
));
197 memset((char *)(uintptr_t)vm_addr
, 'p', (size_t)vm_size
);
198 kr
= mach_vm_deallocate(mach_task_self(),
202 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
203 kr
, mach_error_string(kr
));
206 * Exercise the ledger code to make sure it's ready to run
207 * without any extra memory overhead later.
209 get_ledger_info(&footprint
, &page_table
);
214 * Return the start of the virtual range we pre-warmed, so that the
215 * test can check that it's using the same range.
220 T_DECL(phys_footprint_anonymous
,
221 "phys_footprint for anonymous memory",
222 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
223 T_META_LTEPHASE(LTE_POSTINIT
))
225 uint64_t footprint_before
, pagetable_before
;
226 uint64_t footprint_after
, pagetable_after
;
227 uint64_t footprint_expected
;
229 mach_vm_address_t pre_vm_addr
, vm_addr
;
230 mach_vm_size_t vm_size
, dirty_size
;
232 /* pre-warm to account for page table expansion */
233 pre_vm_addr
= pre_warm(MEM_SIZE
);
235 /* allocating virtual memory... */
236 get_ledger_info(&footprint_before
, &pagetable_before
);
239 kr
= mach_vm_allocate(mach_task_self(), &vm_addr
, vm_size
,
242 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_allocate() error 0x%x (%s)",
243 kr
, mach_error_string(kr
));
245 T_EXPECT_EQ(vm_addr
, pre_vm_addr
, "pre-warm mishap");
246 /* ... should not change footprint */
247 get_ledger_info(&footprint_after
, &pagetable_after
);
248 footprint_expected
= footprint_before
;
249 footprint_expected
+= (pagetable_after
- pagetable_before
);
250 T_LOG("virtual allocation does not change phys_footprint");
251 T_EXPECT_EQ(footprint_after
, footprint_expected
,
252 "virtual allocation of %lld bytes: "
253 "footprint %lld -> %lld expected %lld delta %lld",
254 vm_size
, footprint_before
, footprint_after
,
255 footprint_expected
, footprint_after
- footprint_expected
);
257 /* touching memory... */
258 get_ledger_info(&footprint_before
, &pagetable_before
);
259 dirty_size
= vm_size
/ 2;
260 memset((char *)(uintptr_t)vm_addr
, 'x', (size_t)dirty_size
);
261 /* ... should increase footprint */
262 get_ledger_info(&footprint_after
, &pagetable_after
);
263 footprint_expected
= footprint_before
+ dirty_size
;
264 footprint_expected
+= (pagetable_after
- pagetable_before
);
265 T_LOG("modifying anonymous memory increases phys_footprint");
266 T_EXPECT_EQ(footprint_after
, footprint_expected
,
267 "touched %lld bytes: "
268 "footprint %lld -> %lld expected %lld delta %lld",
269 dirty_size
, footprint_before
, footprint_after
,
270 footprint_expected
, footprint_after
- footprint_expected
);
272 /* deallocating memory... */
273 get_ledger_info(&footprint_before
, &pagetable_before
);
274 kr
= mach_vm_deallocate(mach_task_self(), vm_addr
, vm_size
);
276 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
277 kr
, mach_error_string(kr
));
278 /* ... should decrease footprint */
279 get_ledger_info(&footprint_after
, &pagetable_after
);
280 footprint_expected
= footprint_before
- dirty_size
;
281 footprint_expected
+= (pagetable_after
- pagetable_before
);
282 T_LOG("deallocating dirty anonymous memory decreases phys_footprint");
283 T_EXPECT_EQ(footprint_after
, footprint_expected
,
284 "deallocated %lld dirty bytes: "
285 "footprint %lld -> %lld expected %lld delta %lld",
286 dirty_size
, footprint_before
, footprint_after
,
287 footprint_expected
, footprint_after
- footprint_expected
);
290 #define TEMP_FILE_TEMPLATE "/tmp/phys_footprint_data.XXXXXXXX"
291 #define TEMP_FILE_SIZE (1 * 1024 * 1024)
293 T_DECL(phys_footprint_file
,
294 "phys_footprint for mapped file",
295 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
296 T_META_LTEPHASE(LTE_POSTINIT
))
298 uint64_t footprint_before
, pagetable_before
;
299 uint64_t footprint_after
, pagetable_after
;
300 uint64_t footprint_expected
;
301 mach_vm_address_t pre_vm_addr
;
304 size_t map_size
, dirty_size
;
306 char tmp_file_name
[PATH_MAX
] = TEMP_FILE_TEMPLATE
;
311 buf_size
= TEMP_FILE_SIZE
;
313 T_ASSERT_NOTNULL(buf
= (char *)malloc(buf_size
),
314 "allocate %zu-byte buffer", buf_size
);
315 memset(buf
, 'f', buf_size
);
318 T_ASSERT_NOTNULL(mktemp(tmp_file_name
),
319 "create temporary file name");
322 T_ASSERT_GE(fd
= open(tmp_file_name
, O_CREAT
| O_RDWR
),
327 T_ASSERT_EQ(nbytes
= write(fd
, buf
, buf_size
),
329 "write %zu bytes", buf_size
);
333 /* pre-warm to account for page table expansion */
334 pre_vm_addr
= pre_warm(TEMP_FILE_SIZE
);
336 /* mapping a file does not impact footprint... */
337 get_ledger_info(&footprint_before
, &pagetable_before
);
338 map_size
= TEMP_FILE_SIZE
;
341 T_ASSERT_NOTNULL(map_addr
= (char *)mmap(NULL
, map_size
,
342 PROT_READ
| PROT_WRITE
,
343 MAP_FILE
| MAP_SHARED
, fd
, 0),
346 T_EXPECT_EQ((mach_vm_address_t
)map_addr
, pre_vm_addr
,
348 /* ... should not change footprint */
349 get_ledger_info(&footprint_after
, &pagetable_after
);
350 footprint_expected
= footprint_before
;
351 footprint_expected
+= (pagetable_after
- pagetable_before
);
352 T_LOG("mapping file does not change phys_footprint");
353 T_EXPECT_EQ(footprint_after
, footprint_expected
,
354 "mapping file with %zu bytes: "
355 "footprint %lld -> %lld expected %lld delta %lld",
356 map_size
, footprint_before
, footprint_after
,
357 footprint_expected
, footprint_after
- footprint_expected
);
359 /* touching file-backed memory... */
360 get_ledger_info(&footprint_before
, &pagetable_before
);
361 dirty_size
= map_size
/ 2;
362 memset(map_addr
, 'F', dirty_size
);
363 /* ... should not impact footprint */
364 get_ledger_info(&footprint_after
, &pagetable_after
);
365 footprint_expected
= footprint_before
;
366 footprint_expected
+= (pagetable_after
- pagetable_before
);
367 T_LOG("modifying file-backed memory does not impact phys_footprint");
368 T_EXPECT_EQ(footprint_after
, footprint_expected
,
369 "touched %zu bytes: "
370 "footprint %lld -> %lld expected %lld delta %lld",
371 dirty_size
, footprint_before
, footprint_after
,
372 footprint_expected
, footprint_after
- footprint_expected
);
374 /* deallocating file-backed memory... */
375 get_ledger_info(&footprint_before
, &pagetable_before
);
378 T_ASSERT_EQ(munmap(map_addr
, map_size
),
381 /* ... should not impact footprint */
382 get_ledger_info(&footprint_after
, &pagetable_after
);
383 footprint_expected
= footprint_before
;
384 footprint_expected
+= (pagetable_after
- pagetable_before
);
385 T_LOG("unmapping file-backed memory does not impact phys_footprint");
386 T_EXPECT_EQ(footprint_after
, footprint_expected
,
387 "unmapped %zu dirty bytes: "
388 "footprint %lld -> %lld expected %lld delta %lld",
389 dirty_size
, footprint_before
, footprint_after
,
390 footprint_expected
, footprint_after
- footprint_expected
);
393 T_DECL(phys_footprint_purgeable
,
394 "phys_footprint for purgeable memory",
395 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
396 T_META_LTEPHASE(LTE_POSTINIT
))
398 uint64_t footprint_before
, pagetable_before
;
399 uint64_t footprint_after
, pagetable_after
;
400 uint64_t footprint_expected
;
402 mach_vm_address_t pre_vm_addr
, vm_addr
;
403 mach_vm_size_t vm_size
, dirty_size
;
406 /* pre-warm to account for page table expansion */
407 pre_vm_addr
= pre_warm(MEM_SIZE
);
409 /* allocating purgeable virtual memory... */
410 get_ledger_info(&footprint_before
, &pagetable_before
);
413 kr
= mach_vm_allocate(mach_task_self(), &vm_addr
, vm_size
,
414 VM_FLAGS_ANYWHERE
| VM_FLAGS_PURGABLE
);
416 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_allocate() error 0x%x (%s)",
417 kr
, mach_error_string(kr
));
419 T_EXPECT_EQ(vm_addr
, pre_vm_addr
, "pre-warm mishap");
420 /* ... should not change footprint */
421 get_ledger_info(&footprint_after
, &pagetable_after
);
422 footprint_expected
= footprint_before
;
423 footprint_expected
+= (pagetable_after
- pagetable_before
);
424 T_LOG("purgeable virtual allocation does not change phys_footprint");
425 T_EXPECT_EQ(footprint_after
, footprint_expected
,
426 "purgeable virtual allocation of %lld bytes: "
427 "footprint %lld -> %lld expected %lld delta %lld",
428 vm_size
, footprint_before
, footprint_after
,
429 footprint_expected
, footprint_after
- footprint_expected
);
431 /* touching memory... */
432 get_ledger_info(&footprint_before
, &pagetable_before
);
433 dirty_size
= vm_size
/ 2;
434 memset((char *)(uintptr_t)vm_addr
, 'x', (size_t)dirty_size
);
435 /* ... should increase footprint */
436 get_ledger_info(&footprint_after
, &pagetable_after
);
437 footprint_expected
= footprint_before
+ dirty_size
;
438 footprint_expected
+= (pagetable_after
- pagetable_before
);
439 T_LOG("modifying anonymous memory increases phys_footprint");
440 T_EXPECT_EQ(footprint_after
, footprint_expected
,
441 "touched %lld bytes: "
442 "footprint %lld -> %lld expected %lld delta %lld",
443 dirty_size
, footprint_before
, footprint_after
,
444 footprint_expected
, footprint_after
- footprint_expected
);
446 /* making it volatile... */
447 get_ledger_info(&footprint_before
, &pagetable_before
);
448 state
= VM_PURGABLE_VOLATILE
;
450 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
452 VM_PURGABLE_SET_STATE
,
455 "vm_purgable_control(VOLATILE)");
457 T_ASSERT_EQ(state
, VM_PURGABLE_NONVOLATILE
,
458 "memory was non-volatile");
459 /* ... should decrease footprint */
460 get_ledger_info(&footprint_after
, &pagetable_after
);
461 footprint_expected
= footprint_before
- dirty_size
;
462 footprint_expected
+= (pagetable_after
- pagetable_before
);
463 T_LOG("making volatile decreases phys_footprint");
464 T_EXPECT_EQ(footprint_after
, footprint_expected
,
465 "made volatile %lld dirty bytes: "
466 "footprint %lld -> %lld expected %lld delta %lld",
467 dirty_size
, footprint_before
, footprint_after
,
468 footprint_expected
, footprint_after
- footprint_expected
);
470 /* making it non-volatile... */
471 get_ledger_info(&footprint_before
, &pagetable_before
);
472 state
= VM_PURGABLE_NONVOLATILE
;
474 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
476 VM_PURGABLE_SET_STATE
,
479 "vm_purgable_control(NONVOLATILE)");
481 T_ASSERT_EQ(state
, VM_PURGABLE_VOLATILE
,
482 "memory was volatile");
483 /* ... should increase footprint */
484 get_ledger_info(&footprint_after
, &pagetable_after
);
485 footprint_expected
= footprint_before
+ dirty_size
;
486 footprint_expected
+= (pagetable_after
- pagetable_before
);
487 T_LOG("making non-volatile increases phys_footprint");
488 T_EXPECT_EQ(footprint_after
, footprint_expected
,
489 "made non-volatile %lld dirty bytes: "
490 "footprint %lld -> %lld expected %lld delta %lld",
491 dirty_size
, footprint_before
, footprint_after
,
492 footprint_expected
, footprint_after
- footprint_expected
);
494 /* deallocating memory... */
495 get_ledger_info(&footprint_before
, &pagetable_before
);
496 kr
= mach_vm_deallocate(mach_task_self(), vm_addr
, vm_size
);
498 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
499 kr
, mach_error_string(kr
));
500 /* ... should decrease footprint */
501 get_ledger_info(&footprint_after
, &pagetable_after
);
502 footprint_expected
= footprint_before
- dirty_size
;
503 footprint_expected
+= (pagetable_after
- pagetable_before
);
504 T_LOG("deallocating memory decreases phys_footprint");
505 T_EXPECT_EQ(footprint_after
, footprint_expected
,
506 "deallocated %lld dirty bytes: "
507 "footprint %lld -> %lld expected %lld delta %lld",
508 dirty_size
, footprint_before
, footprint_after
,
509 footprint_expected
, footprint_after
- footprint_expected
);
512 T_DECL(phys_footprint_purgeable_ownership
,
513 "phys_footprint for owned purgeable memory",
514 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
515 T_META_LTEPHASE(LTE_POSTINIT
))
517 uint64_t footprint_before
, pagetable_before
;
518 uint64_t footprint_after
, pagetable_after
;
519 uint64_t footprint_expected
;
521 mach_vm_address_t pre_vm_addr
, vm_addr
;
522 mach_vm_size_t vm_size
, dirty_size
, me_size
;
526 /* pre-warm to account for page table expansion */
527 pre_vm_addr
= pre_warm(MEM_SIZE
);
529 /* allocating purgeable virtual memory... */
530 get_ledger_info(&footprint_before
, &pagetable_before
);
533 kr
= mach_vm_allocate(mach_task_self(), &vm_addr
, vm_size
,
534 VM_FLAGS_ANYWHERE
| VM_FLAGS_PURGABLE
);
536 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_allocate() error 0x%x (%s)",
537 kr
, mach_error_string(kr
));
539 T_EXPECT_EQ(vm_addr
, pre_vm_addr
, "pre-warm mishap");
540 /* ... should not change footprint */
541 get_ledger_info(&footprint_after
, &pagetable_after
);
542 footprint_expected
= footprint_before
;
543 footprint_expected
+= (pagetable_after
- pagetable_before
);
544 T_LOG("purgeable virtual allocation does not change phys_footprint");
545 T_EXPECT_EQ(footprint_after
, footprint_expected
,
546 "purgeable virtual allocation of %lld bytes: "
547 "footprint %lld -> %lld expected %lld delta %lld",
548 vm_size
, footprint_before
, footprint_after
,
549 footprint_expected
, footprint_after
- footprint_expected
);
551 /* touching memory... */
552 get_ledger_info(&footprint_before
, &pagetable_before
);
553 dirty_size
= vm_size
/ 2;
554 memset((char *)(uintptr_t)vm_addr
, 'x', (size_t)dirty_size
);
555 /* ... should increase footprint */
556 get_ledger_info(&footprint_after
, &pagetable_after
);
557 footprint_expected
= footprint_before
+ dirty_size
;
558 footprint_expected
+= (pagetable_after
- pagetable_before
);
559 T_LOG("modifying anonymous memory increases phys_footprint");
560 T_EXPECT_EQ(footprint_after
, footprint_expected
,
561 "touched %lld bytes: "
562 "footprint %lld -> %lld expected %lld delta %lld",
563 dirty_size
, footprint_before
, footprint_after
,
564 footprint_expected
, footprint_after
- footprint_expected
);
566 /* making it volatile... */
567 get_ledger_info(&footprint_before
, &pagetable_before
);
568 state
= VM_PURGABLE_VOLATILE
;
570 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
572 VM_PURGABLE_SET_STATE
,
575 "vm_purgable_control(VOLATILE)");
577 T_ASSERT_EQ(state
, VM_PURGABLE_NONVOLATILE
,
578 "memory was non-volatile");
579 /* ... should decrease footprint */
580 get_ledger_info(&footprint_after
, &pagetable_after
);
581 footprint_expected
= footprint_before
- dirty_size
;
582 footprint_expected
+= (pagetable_after
- pagetable_before
);
583 T_LOG("making volatile decreases phys_footprint");
584 T_EXPECT_EQ(footprint_after
, footprint_expected
,
585 "made volatile %lld dirty bytes: "
586 "footprint %lld -> %lld expected %lld delta %lld",
587 dirty_size
, footprint_before
, footprint_after
,
588 footprint_expected
, footprint_after
- footprint_expected
);
590 /* making it non-volatile... */
591 get_ledger_info(&footprint_before
, &pagetable_before
);
592 state
= VM_PURGABLE_NONVOLATILE
;
594 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
596 VM_PURGABLE_SET_STATE
,
599 "vm_purgable_control(NONVOLATILE)");
601 T_ASSERT_EQ(state
, VM_PURGABLE_VOLATILE
,
602 "memory was volatile");
603 /* ... should increase footprint */
604 get_ledger_info(&footprint_after
, &pagetable_after
);
605 footprint_expected
= footprint_before
+ dirty_size
;
606 footprint_expected
+= (pagetable_after
- pagetable_before
);
607 T_LOG("making non-volatile increases phys_footprint");
608 T_EXPECT_EQ(footprint_after
, footprint_expected
,
609 "made non-volatile %lld dirty bytes: "
610 "footprint %lld -> %lld expected %lld delta %lld",
611 dirty_size
, footprint_before
, footprint_after
,
612 footprint_expected
, footprint_after
- footprint_expected
);
614 /* making a memory entry... */
615 get_ledger_info(&footprint_before
, &pagetable_before
);
617 me_port
= MACH_PORT_NULL
;
618 kr
= mach_make_memory_entry_64(mach_task_self(),
621 VM_PROT_READ
| VM_PROT_WRITE
,
625 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "make_memory_entry() error 0x%x (%s)",
626 kr
, mach_error_string(kr
));
628 T_EXPECT_EQ(me_size
, vm_size
, "memory entry size mismatch");
629 /* ... should not change footprint */
630 get_ledger_info(&footprint_after
, &pagetable_after
);
631 footprint_expected
= footprint_before
;
632 footprint_expected
+= (pagetable_after
- pagetable_before
);
633 T_LOG("making a memory entry does not change phys_footprint");
634 T_EXPECT_EQ(footprint_after
, footprint_expected
,
635 "making a memory entry of %lld bytes: "
636 "footprint %lld -> %lld expected %lld delta %lld",
637 vm_size
, footprint_before
, footprint_after
,
638 footprint_expected
, footprint_after
- footprint_expected
);
640 /* deallocating memory while holding memory entry... */
641 get_ledger_info(&footprint_before
, &pagetable_before
);
642 kr
= mach_vm_deallocate(mach_task_self(), vm_addr
, vm_size
);
644 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
645 kr
, mach_error_string(kr
));
646 /* ... should not change footprint */
647 get_ledger_info(&footprint_after
, &pagetable_after
);
648 footprint_expected
= footprint_before
;
649 footprint_expected
+= (pagetable_after
- pagetable_before
);
650 T_LOG("deallocating owned memory while holding memory entry "
651 "does not change phys_footprint");
652 T_EXPECT_EQ(footprint_after
, footprint_expected
,
653 "deallocated %lld dirty bytes: "
654 "footprint %lld -> %lld expected %lld delta %lld",
655 dirty_size
, footprint_before
, footprint_after
,
656 footprint_expected
, footprint_after
- footprint_expected
);
658 /* releasing the memory entry... */
659 kr
= mach_port_deallocate(mach_task_self(), me_port
);
661 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "mach_port_deallocate() error 0x%x (%s)",
662 kr
, mach_error_string(kr
));
663 /* ... should decrease footprint */
664 get_ledger_info(&footprint_after
, &pagetable_after
);
665 footprint_expected
= footprint_before
- dirty_size
;
666 footprint_expected
+= (pagetable_after
- pagetable_before
);
667 T_LOG("releasing memory entry decreases phys_footprint");
668 T_EXPECT_EQ(footprint_after
, footprint_expected
,
669 "made volatile %lld dirty bytes: "
670 "footprint %lld -> %lld expected %lld delta %lld",
671 dirty_size
, footprint_before
, footprint_after
,
672 footprint_expected
, footprint_after
- footprint_expected
);
675 #ifdef MAP_MEM_LEDGER_TAGGED
676 T_DECL(phys_footprint_ledger_purgeable_owned
,
677 "phys_footprint for ledger-tagged purgeable memory ownership",
678 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
679 T_META_LTEPHASE(LTE_POSTINIT
))
681 uint64_t footprint_before
, pagetable_before
;
682 uint64_t footprint_after
, pagetable_after
;
683 uint64_t footprint_expected
;
685 mach_vm_address_t pre_vm_addr
, vm_addr
;
686 mach_vm_size_t vm_size
, dirty_size
, me_size
;
690 /* pre-warm to account for page table expansion */
691 pre_vm_addr
= pre_warm(MEM_SIZE
);
693 /* making a memory entry... */
694 get_ledger_info(&footprint_before
, &pagetable_before
);
697 me_port
= MACH_PORT_NULL
;
698 kr
= mach_make_memory_entry_64(mach_task_self(),
701 (MAP_MEM_NAMED_CREATE
|
702 MAP_MEM_LEDGER_TAGGED
|
704 VM_PROT_READ
| VM_PROT_WRITE
),
708 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "make_memory_entry() error 0x%x (%s)",
709 kr
, mach_error_string(kr
));
711 T_EXPECT_EQ(me_size
, vm_size
, "memory entry size mismatch");
712 /* ... should not change footprint */
713 get_ledger_info(&footprint_after
, &pagetable_after
);
714 footprint_expected
= footprint_before
;
715 footprint_expected
+= (pagetable_after
- pagetable_before
);
716 T_LOG("making a memory entry does not change phys_footprint");
717 T_EXPECT_EQ(footprint_after
, footprint_expected
,
718 "making a memory entry of %lld bytes: "
719 "footprint %lld -> %lld expected %lld delta %lld",
720 vm_size
, footprint_before
, footprint_after
,
721 footprint_expected
, footprint_after
- footprint_expected
);
723 /* mapping ledger-tagged virtual memory... */
724 get_ledger_info(&footprint_before
, &pagetable_before
);
726 kr
= mach_vm_map(mach_task_self(), &vm_addr
, vm_size
,
732 VM_PROT_READ
| VM_PROT_WRITE
,
733 VM_PROT_READ
| VM_PROT_WRITE
,
736 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_map() error 0x%x (%s)",
737 kr
, mach_error_string(kr
));
739 T_EXPECT_EQ(vm_addr
, pre_vm_addr
, "pre-warm mishap");
740 /* ... should not change footprint */
741 get_ledger_info(&footprint_after
, &pagetable_after
);
742 footprint_expected
= footprint_before
;
743 footprint_expected
+= (pagetable_after
- pagetable_before
);
744 T_LOG("mapping ledger-tagged memory does not change phys_footprint");
745 T_EXPECT_EQ(footprint_after
, footprint_expected
,
746 "ledger-tagged mapping of %lld bytes: "
747 "footprint %lld -> %lld expected %lld delta %lld",
748 vm_size
, footprint_before
, footprint_after
,
749 footprint_expected
, footprint_after
- footprint_expected
);
751 /* touching memory... */
752 get_ledger_info(&footprint_before
, &pagetable_before
);
753 dirty_size
= vm_size
/ 2;
754 memset((char *)(uintptr_t)vm_addr
, 'x', (size_t)dirty_size
);
755 /* ... should increase footprint */
756 get_ledger_info(&footprint_after
, &pagetable_after
);
757 footprint_expected
= footprint_before
+ dirty_size
;
758 footprint_expected
+= (pagetable_after
- pagetable_before
);
759 T_LOG("modifying ledger-tagged memory increases phys_footprint");
760 T_EXPECT_EQ(footprint_after
, footprint_expected
,
761 "touched %lld bytes: "
762 "footprint %lld -> %lld expected %lld delta %lld",
763 dirty_size
, footprint_before
, footprint_after
,
764 footprint_expected
, footprint_after
- footprint_expected
);
766 /* making it volatile... */
767 get_ledger_info(&footprint_before
, &pagetable_before
);
768 state
= VM_PURGABLE_VOLATILE
;
770 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
772 VM_PURGABLE_SET_STATE
,
775 "vm_purgable_control(VOLATILE)");
777 T_ASSERT_EQ(state
, VM_PURGABLE_NONVOLATILE
,
778 "memory was non-volatile");
779 /* ... should decrease footprint */
780 get_ledger_info(&footprint_after
, &pagetable_after
);
781 footprint_expected
= footprint_before
- dirty_size
;
782 footprint_expected
+= (pagetable_after
- pagetable_before
);
783 T_LOG("making volatile decreases phys_footprint");
784 T_EXPECT_EQ(footprint_after
, footprint_expected
,
785 "made volatile %lld dirty bytes: "
786 "footprint %lld -> %lld expected %lld delta %lld",
787 dirty_size
, footprint_before
, footprint_after
,
788 footprint_expected
, footprint_after
- footprint_expected
);
790 /* making it non-volatile... */
791 get_ledger_info(&footprint_before
, &pagetable_before
);
792 state
= VM_PURGABLE_NONVOLATILE
;
794 T_ASSERT_EQ(mach_vm_purgable_control(mach_task_self(),
796 VM_PURGABLE_SET_STATE
,
799 "vm_purgable_control(NONVOLATILE)");
801 T_ASSERT_EQ(state
, VM_PURGABLE_VOLATILE
,
802 "memory was volatile");
803 /* ... should increase footprint */
804 get_ledger_info(&footprint_after
, &pagetable_after
);
805 footprint_expected
= footprint_before
+ dirty_size
;
806 footprint_expected
+= (pagetable_after
- pagetable_before
);
807 T_LOG("making non-volatile increases phys_footprint");
808 T_EXPECT_EQ(footprint_after
, footprint_expected
,
809 "made non-volatile %lld dirty bytes: "
810 "footprint %lld -> %lld expected %lld delta %lld",
811 dirty_size
, footprint_before
, footprint_after
,
812 footprint_expected
, footprint_after
- footprint_expected
);
814 /* deallocating memory while holding memory entry... */
815 get_ledger_info(&footprint_before
, &pagetable_before
);
816 kr
= mach_vm_deallocate(mach_task_self(), vm_addr
, vm_size
);
818 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
819 kr
, mach_error_string(kr
));
820 /* ... should not change footprint */
821 get_ledger_info(&footprint_after
, &pagetable_after
);
822 footprint_expected
= footprint_before
;
823 footprint_expected
+= (pagetable_after
- pagetable_before
);
824 T_LOG("deallocating owned memory while holding memory entry "
825 "does not change phys_footprint");
826 T_EXPECT_EQ(footprint_after
, footprint_expected
,
827 "deallocated %lld dirty bytes: "
828 "footprint %lld -> %lld expected %lld delta %lld",
829 dirty_size
, footprint_before
, footprint_after
,
830 footprint_expected
, footprint_after
- footprint_expected
);
832 /* releasing the memory entry... */
833 kr
= mach_port_deallocate(mach_task_self(), me_port
);
835 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "mach_port_deallocate() error 0x%x (%s)",
836 kr
, mach_error_string(kr
));
837 /* ... should decrease footprint */
838 get_ledger_info(&footprint_after
, &pagetable_after
);
839 footprint_expected
= footprint_before
- dirty_size
;
840 footprint_expected
+= (pagetable_after
- pagetable_before
);
841 T_LOG("releasing memory entry decreases phys_footprint");
842 T_EXPECT_EQ(footprint_after
, footprint_expected
,
843 "made volatile %lld dirty bytes: "
844 "footprint %lld -> %lld expected %lld delta %lld",
845 dirty_size
, footprint_before
, footprint_after
,
846 footprint_expected
, footprint_after
- footprint_expected
);
849 T_DECL(phys_footprint_ledger_owned
,
850 "phys_footprint for ledger-tagged memory ownership",
851 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
852 T_META_LTEPHASE(LTE_POSTINIT
))
854 uint64_t footprint_before
, pagetable_before
;
855 uint64_t footprint_after
, pagetable_after
;
856 uint64_t footprint_expected
;
858 mach_vm_address_t pre_vm_addr
, vm_addr
;
859 mach_vm_size_t vm_size
, dirty_size
, me_size
;
862 /* pre-warm to account for page table expansion */
863 pre_vm_addr
= pre_warm(MEM_SIZE
);
865 /* making a memory entry... */
866 get_ledger_info(&footprint_before
, &pagetable_before
);
869 me_port
= MACH_PORT_NULL
;
870 kr
= mach_make_memory_entry_64(mach_task_self(),
873 (MAP_MEM_NAMED_CREATE
|
874 MAP_MEM_LEDGER_TAGGED
|
875 VM_PROT_READ
| VM_PROT_WRITE
),
879 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "make_memory_entry() error 0x%x (%s)",
880 kr
, mach_error_string(kr
));
882 T_EXPECT_EQ(me_size
, vm_size
, "memory entry size mismatch");
883 /* ... should not change footprint */
884 get_ledger_info(&footprint_after
, &pagetable_after
);
885 footprint_expected
= footprint_before
;
886 footprint_expected
+= (pagetable_after
- pagetable_before
);
887 T_LOG("making a memory entry does not change phys_footprint");
888 T_EXPECT_EQ(footprint_after
, footprint_expected
,
889 "making a memory entry of %lld bytes: "
890 "footprint %lld -> %lld expected %lld delta %lld",
891 vm_size
, footprint_before
, footprint_after
,
892 footprint_expected
, footprint_after
- footprint_expected
);
894 /* mapping ledger-tagged virtual memory... */
895 get_ledger_info(&footprint_before
, &pagetable_before
);
897 kr
= mach_vm_map(mach_task_self(), &vm_addr
, vm_size
,
903 VM_PROT_READ
| VM_PROT_WRITE
,
904 VM_PROT_READ
| VM_PROT_WRITE
,
907 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_map() error 0x%x (%s)",
908 kr
, mach_error_string(kr
));
910 T_EXPECT_EQ(vm_addr
, pre_vm_addr
, "pre-warm mishap");
911 /* ... should not change footprint */
912 get_ledger_info(&footprint_after
, &pagetable_after
);
913 footprint_expected
= footprint_before
;
914 footprint_expected
+= (pagetable_after
- pagetable_before
);
915 T_LOG("mapping ledger-tagged memory does not change phys_footprint");
916 T_EXPECT_EQ(footprint_after
, footprint_expected
,
917 "ledger-tagged mapping of %lld bytes: "
918 "footprint %lld -> %lld expected %lld delta %lld",
919 vm_size
, footprint_before
, footprint_after
,
920 footprint_expected
, footprint_after
- footprint_expected
);
922 /* touching memory... */
923 get_ledger_info(&footprint_before
, &pagetable_before
);
924 dirty_size
= vm_size
/ 2;
925 memset((char *)(uintptr_t)vm_addr
, 'x', (size_t)dirty_size
);
926 /* ... should increase footprint */
927 get_ledger_info(&footprint_after
, &pagetable_after
);
928 footprint_expected
= footprint_before
+ dirty_size
;
929 footprint_expected
+= (pagetable_after
- pagetable_before
);
930 T_LOG("modifying ledger-tagged memory increases phys_footprint");
931 T_EXPECT_EQ(footprint_after
, footprint_expected
,
932 "touched %lld bytes: "
933 "footprint %lld -> %lld expected %lld delta %lld",
934 dirty_size
, footprint_before
, footprint_after
,
935 footprint_expected
, footprint_after
- footprint_expected
);
937 /* deallocating memory while holding memory entry... */
938 get_ledger_info(&footprint_before
, &pagetable_before
);
939 kr
= mach_vm_deallocate(mach_task_self(), vm_addr
, vm_size
);
941 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
942 kr
, mach_error_string(kr
));
943 /* ... should not change footprint */
944 get_ledger_info(&footprint_after
, &pagetable_after
);
945 footprint_expected
= footprint_before
;
946 footprint_expected
+= (pagetable_after
- pagetable_before
);
947 T_LOG("deallocating owned memory while holding memory entry "
948 "does not change phys_footprint");
949 T_EXPECT_EQ(footprint_after
, footprint_expected
,
950 "deallocated %lld dirty bytes: "
951 "footprint %lld -> %lld expected %lld delta %lld",
952 dirty_size
, footprint_before
, footprint_after
,
953 footprint_expected
, footprint_after
- footprint_expected
);
955 /* releasing the memory entry... */
956 kr
= mach_port_deallocate(mach_task_self(), me_port
);
958 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "mach_port_deallocate() error 0x%x (%s)",
959 kr
, mach_error_string(kr
));
960 /* ... should decrease footprint */
961 get_ledger_info(&footprint_after
, &pagetable_after
);
962 footprint_expected
= footprint_before
- dirty_size
;
963 footprint_expected
+= (pagetable_after
- pagetable_before
);
964 T_LOG("releasing memory entry decreases phys_footprint");
965 T_EXPECT_EQ(footprint_after
, footprint_expected
,
966 "made volatile %lld dirty bytes: "
967 "footprint %lld -> %lld expected %lld delta %lld",
968 dirty_size
, footprint_before
, footprint_after
,
969 footprint_expected
, footprint_after
- footprint_expected
);
971 #endif /* MAP_MEM_LEDGER_TAGGED */
973 /* IOSurface code from: CoreImage/CoreImageTests/CIRender/SurfaceUtils.c */
974 #include <CoreFoundation/CoreFoundation.h>
975 #include <IOSurface/IOSurface.h>
976 #include <IOSurface/IOSurfacePrivate.h>
978 bytes_per_element(uint32_t format
)
982 case 32: // kCVPixelFormatType_32ARGB (ARGB8)
992 bytes_per_pixel(uint32_t format
)
996 case 32: // kCVPixelFormatType_32ARGB (ARGB8)
1005 static inline size_t
1006 roundSizeToMultiple(size_t size
, size_t mult
)
1008 return ((size
+ mult
- 1) / mult
) * mult
;
1011 setIntValue(CFMutableDictionaryRef dict
, const CFStringRef key
, int value
)
1013 CFNumberRef number
= CFNumberCreate(0, kCFNumberIntType
, &value
);
1014 CFDictionarySetValue(dict
, key
, number
);
1018 setBoolValue(CFMutableDictionaryRef dict
, const CFStringRef key
, bool value
)
1020 CFDictionarySetValue(dict
, key
, value
? kCFBooleanTrue
: kCFBooleanFalse
);
1022 typedef void (^SurfacePlaneBlock
)(void *data
, size_t planeIndex
, size_t width
, size_t height
, size_t rowbytes
);
1024 SurfaceApplyPlaneBlock(IOSurfaceRef surface
, SurfacePlaneBlock block
)
1026 if (surface
== nil
|| block
== nil
) {
1027 return kIOReturnBadArgument
;
1030 IOReturn result
= kIOReturnSuccess
;
1031 size_t planeCount
= IOSurfaceGetPlaneCount(surface
);
1033 if (planeCount
== 0) {
1034 result
= IOSurfaceLock(surface
, 0, NULL
);
1035 if (result
!= kIOReturnSuccess
) {
1039 void* base
= IOSurfaceGetBaseAddress(surface
);
1040 size_t rb
= IOSurfaceGetBytesPerRow(surface
);
1041 size_t w
= IOSurfaceGetWidth(surface
);
1042 size_t h
= IOSurfaceGetHeight(surface
);
1044 if (base
&& rb
&& w
&& h
) {
1045 block(base
, 0, w
, h
, rb
);
1048 IOSurfaceUnlock(surface
, 0, NULL
);
1049 } else if (planeCount
== 2) {
1050 for (size_t i
= 0; i
< planeCount
; i
++) {
1051 result
= IOSurfaceLock(surface
, 0, NULL
);
1052 if (result
!= kIOReturnSuccess
) {
1056 void* base
= IOSurfaceGetBaseAddressOfPlane(surface
, i
);
1057 size_t rb
= IOSurfaceGetBytesPerRowOfPlane(surface
, i
);
1058 size_t w
= IOSurfaceGetWidthOfPlane(surface
, i
);
1059 size_t h
= IOSurfaceGetHeightOfPlane(surface
, i
);
1061 if (base
&& rb
&& w
&& h
) {
1062 block(base
, i
, w
, h
, rb
);
1065 IOSurfaceUnlock(surface
, 0, NULL
);
1071 ClearSurface(IOSurfaceRef surface
)
1074 (void) SurfaceApplyPlaneBlock(surface
, ^(void *p
, size_t i
, __unused
size_t w
, size_t h
, size_t rb
)
1077 memset(p
, zero
, rb
* h
);
1079 memset(p
, 128, rb
* h
);
1084 SurfaceGetMemorySize(IOSurfaceRef surface
)
1086 size_t planeCount
= IOSurfaceGetPlaneCount(surface
);
1088 if (planeCount
== 0) {
1089 size_t rb
= IOSurfaceGetBytesPerRow(surface
);
1090 size_t h
= IOSurfaceGetHeight(surface
);
1092 } else if (planeCount
== 2) {
1093 size_t rb0
= IOSurfaceGetBytesPerRowOfPlane(surface
, 0);
1094 size_t h0
= IOSurfaceGetHeightOfPlane(surface
, 0);
1095 size_t rb1
= IOSurfaceGetBytesPerRowOfPlane(surface
, 1);
1096 size_t h1
= IOSurfaceGetHeightOfPlane(surface
, 1);
1097 return rb0
* h0
+ rb1
* h1
;
1102 CreateSurface(uint32_t pixelsWide
, uint32_t pixelsHigh
, uint32_t rowBytesAlignment
, uint32_t fmt
, bool purgeable
, bool clear
)
1104 IOSurfaceRef surface
= nil
;
1106 if (pixelsWide
< 1 || pixelsHigh
< 1 || fmt
== 0) {
1110 size_t bpp
= bytes_per_pixel(fmt
);
1111 size_t bpe
= bytes_per_element(fmt
);
1112 if (bpp
== 0 || bpe
== 0) {
1116 size_t rowbytes
= pixelsWide
* bpp
;
1117 if (rowBytesAlignment
== 0) {
1118 rowBytesAlignment
= 16;
1120 rowbytes
= roundSizeToMultiple(rowbytes
, rowBytesAlignment
);
1122 CFMutableDictionaryRef props
= CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1123 setIntValue(props
, kIOSurfaceBytesPerRow
, (int)rowbytes
);
1124 setIntValue(props
, kIOSurfaceWidth
, (int)pixelsWide
);
1125 setIntValue(props
, kIOSurfaceHeight
, (int)pixelsHigh
);
1126 setIntValue(props
, kIOSurfacePixelFormat
, (int)fmt
);
1127 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1128 setBoolValue(props
, kIOSurfaceNonPurgeable
, !purgeable
);
1129 #else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1131 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
1133 if (bpe
!= bpp
) { // i.e. a 422 format such as 'yuvf' etc.
1134 setIntValue(props
, kIOSurfaceElementWidth
, 2);
1135 setIntValue(props
, kIOSurfaceElementHeight
, 1);
1137 setIntValue(props
, kIOSurfaceBytesPerElement
, (int)bpe
);
1140 surface
= IOSurfaceCreate(props
);
1143 ClearSurface(surface
);
1149 T_DECL(phys_footprint_purgeable_iokit
,
1150 "phys_footprint for purgeable IOKit memory",
1151 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
1152 T_META_LTEPHASE(LTE_POSTINIT
))
1154 uint64_t footprint_before
, pagetable_before
;
1155 uint64_t footprint_after
, pagetable_after
;
1156 uint64_t footprint_expected
, footprint_delta_slop
;
1157 int64_t footprint_delta
;
1158 IOSurfaceRef surface
;
1160 uint64_t surface_size
;
1163 footprint_delta_slop
= 8 * vm_kernel_page_size
;
1165 surface
= CreateSurface(1024, 1024, 0, 32, true, true);
1166 IOSurfaceSetPurgeable(surface
, kIOSurfacePurgeableVolatile
, &old_state
);
1167 IOSurfaceSetPurgeable(surface
, kIOSurfacePurgeableNonVolatile
, &old_state
);
1171 surface_size
= 1024 * 1024 * 4;
1173 /* create IOsurface: footprint grows */
1174 get_ledger_info(&footprint_before
, &pagetable_before
);
1175 surface
= CreateSurface(1024, 1024, 0, 32, true, true);
1176 get_ledger_info(&footprint_after
, &pagetable_after
);
1177 if (legacy_footprint
) {
1178 footprint_expected
= footprint_before
;
1179 footprint_expected
+= (pagetable_after
- pagetable_before
);
1180 footprint_delta
= (int64_t)(footprint_after
- footprint_expected
);
1181 T_LOG("LEGACY FOOTPRINT: creating purgeable IOSurface: no footprint impact");
1182 T_EXPECT_LE((uint64_t)llabs(footprint_delta
), footprint_delta_slop
,
1183 "create purgeable IOSurface %lld bytes: "
1184 "footprint %lld -> %lld expected %lld delta %lld",
1185 surface_size
, footprint_before
, footprint_after
,
1186 footprint_expected
, footprint_delta
);
1188 footprint_expected
= footprint_before
+ surface_size
;
1189 footprint_expected
+= (pagetable_after
- pagetable_before
);
1190 footprint_delta
= (int64_t)(footprint_after
- footprint_expected
);
1191 T_LOG("creating purgeable IOSurface increases phys_footprint");
1192 T_EXPECT_LE((uint64_t)llabs(footprint_delta
), footprint_delta_slop
,
1193 "create purgeable IOSurface %lld bytes: "
1194 "footprint %lld -> %lld expected %lld delta %lld",
1195 surface_size
, footprint_before
, footprint_after
,
1196 footprint_expected
, footprint_delta
);
1199 /* make IOSurface volatile: footprint shrinks */
1200 get_ledger_info(&footprint_before
, &pagetable_before
);
1201 IOSurfaceSetPurgeable(surface
, kIOSurfacePurgeableVolatile
, &old_state
);
1202 get_ledger_info(&footprint_after
, &pagetable_after
);
1203 if (legacy_footprint
) {
1204 footprint_expected
= footprint_before
;
1205 footprint_expected
+= (pagetable_after
- pagetable_before
);
1206 T_LOG("LEGACY FOOTPRINT: volatile IOSurface: no footprint impact");
1207 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1208 "volatile IOSurface %lld bytes: "
1209 "footprint %lld -> %lld expected %lld delta %lld",
1210 surface_size
, footprint_before
, footprint_after
,
1211 footprint_expected
, footprint_after
- footprint_expected
);
1213 footprint_expected
= footprint_before
- surface_size
;
1214 footprint_expected
+= (pagetable_after
- pagetable_before
);
1215 T_LOG("making IOSurface volatile decreases phys_footprint");
1216 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1217 "made volatile %lld bytes: "
1218 "footprint %lld -> %lld expected %lld delta %lld",
1219 surface_size
, footprint_before
, footprint_after
,
1220 footprint_expected
, footprint_after
- footprint_expected
);
1223 /* make IOSurface non-volatile: footprint grows */
1224 get_ledger_info(&footprint_before
, &pagetable_before
);
1225 IOSurfaceSetPurgeable(surface
, kIOSurfacePurgeableNonVolatile
, &old_state
);
1226 get_ledger_info(&footprint_after
, &pagetable_after
);
1227 if (legacy_footprint
) {
1228 footprint_expected
= footprint_before
;
1229 footprint_expected
+= (pagetable_after
- pagetable_before
);
1230 T_LOG("LEGACY FOOTPRINT: non-volatile IOSurface: no footprint impact");
1231 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1232 "non-volatile IOSurface %lld bytes: "
1233 "footprint %lld -> %lld expected %lld delta %lld",
1234 surface_size
, footprint_before
, footprint_after
,
1235 footprint_expected
, footprint_after
- footprint_expected
);
1237 footprint_expected
= footprint_before
+ surface_size
;
1238 footprint_expected
+= (pagetable_after
- pagetable_before
);
1239 T_LOG("making IOSurface non-volatile increases phys_footprint");
1240 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1241 "made non-volatile %lld bytes: "
1242 "footprint %lld -> %lld expected %lld delta %lld",
1243 surface_size
, footprint_before
, footprint_after
,
1244 footprint_expected
, footprint_after
- footprint_expected
);
1247 /* accessing IOSurface re-mapping: no footprint impact */
1249 /* deallocating IOSurface re-mapping: no footprint impact */
1251 /* release IOSurface: footprint shrinks */
1252 get_ledger_info(&footprint_before
, &pagetable_before
);
1254 get_ledger_info(&footprint_after
, &pagetable_after
);
1255 if (legacy_footprint
) {
1256 footprint_expected
= footprint_before
;
1257 footprint_expected
+= (pagetable_after
- pagetable_before
);
1258 T_LOG("LEGACY FOOTPRINT: release IOSurface: no footprint impact");
1259 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1260 "releasing IOSurface %lld bytes: "
1261 "footprint %lld -> %lld expected %lld delta %lld",
1262 surface_size
, footprint_before
, footprint_after
,
1263 footprint_expected
, footprint_after
- footprint_expected
);
1265 footprint_expected
= footprint_before
- surface_size
;
1266 footprint_expected
+= (pagetable_after
- pagetable_before
);
1267 T_LOG("releasing IOSurface decreases phys_footprint");
1268 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1269 "released IOSurface %lld bytes: "
1270 "footprint %lld -> %lld expected %lld delta %lld",
1271 surface_size
, footprint_before
, footprint_after
,
1272 footprint_expected
, footprint_after
- footprint_expected
);
1276 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
1277 T_DECL(phys_footprint_nonpurgeable_iokit
,
1278 "phys_footprint for non-purgeable IOKit memory",
1279 T_META_NAMESPACE(TEST_VM_NAMESPACE
),
1280 T_META_LTEPHASE(LTE_POSTINIT
))
1282 uint64_t footprint_before
, pagetable_before
;
1283 uint64_t footprint_after
, pagetable_after
;
1284 uint64_t footprint_expected
, footprint_delta_slop
;
1285 int64_t footprint_delta
;
1286 IOSurfaceRef surface
;
1287 uint64_t surface_size
;
1290 mach_vm_address_t remap_addr
;
1292 vm_prot_t cur_prot
, max_prot
;
1298 surface
= CreateSurface(1024, 1024, 0, 32, false, true);
1300 footprint_delta_slop
= 8 * vm_kernel_page_size
;
1303 surface_size
= 1024 * 1024 * 4;
1305 /* create IOsurface: footprint grows */
1306 get_ledger_info(&footprint_before
, &pagetable_before
);
1307 surface
= CreateSurface(1024, 1024, 0, 32, false, true);
1308 get_ledger_info(&footprint_after
, &pagetable_after
);
1309 footprint_expected
= footprint_before
+ surface_size
;
1310 footprint_expected
+= (pagetable_after
- pagetable_before
);
1311 footprint_delta
= (int64_t)(footprint_after
- footprint_expected
);
1312 T_LOG("creating non-purgeable IOSurface increases phys_footprint");
1313 T_EXPECT_LE((uint64_t)llabs(footprint_delta
), footprint_delta_slop
,
1314 "create non-purgeable IOSurface %lld bytes: "
1315 "footprint %lld -> %lld expected %lld delta %lld",
1316 surface_size
, footprint_before
, footprint_after
,
1317 footprint_expected
, footprint_delta
);
1319 /* make IOSurface volatile: fail and no footprint impact */
1320 get_ledger_info(&footprint_before
, &pagetable_before
);
1321 IOSurfaceSetPurgeable(surface
, kIOSurfacePurgeableVolatile
, &old_state
);
1322 get_ledger_info(&footprint_after
, &pagetable_after
);
1323 footprint_expected
= footprint_before
;
1324 footprint_expected
+= (pagetable_after
- pagetable_before
);
1325 T_LOG("making non-purgeable IOSurface volatile: no footprint impact");
1326 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1327 "made volatile %lld non-purgeable bytes: "
1328 "footprint %lld -> %lld expected %lld delta %lld",
1329 surface_size
, footprint_before
, footprint_after
,
1330 footprint_expected
, footprint_after
- footprint_expected
);
1332 /* re-mapping IOSurface: no footprint impact */
1333 get_ledger_info(&footprint_before
, &pagetable_before
);
1334 map_base
= IOSurfaceGetBaseAddress(surface
);
1335 map_size
= SurfaceGetMemorySize(surface
);
1336 // T_EXPECT_EQ(map_size, surface_size, "map_size %lld surface_size %lld",
1337 // map_size, surface_size);
1339 kr
= mach_vm_remap(mach_task_self(),
1341 (mach_vm_size_t
)surface_size
,
1345 (mach_vm_address_t
)map_base
,
1349 VM_INHERIT_DEFAULT
);
1351 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_remap() error 0x%x (%s)",
1352 kr
, mach_error_string(kr
));
1353 get_ledger_info(&footprint_after
, &pagetable_after
);
1354 footprint_expected
= footprint_before
;
1355 footprint_expected
+= (pagetable_after
- pagetable_before
);
1356 T_LOG("re-mapping IOSurface does not impact phys_footprint");
1357 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1358 "remapping IOSurface %lld bytes: "
1359 "footprint %lld -> %lld expected %lld delta %lld",
1360 surface_size
, footprint_before
, footprint_after
,
1361 footprint_expected
, footprint_after
- footprint_expected
);
1363 /* accessing IOSurface re-mapping: footprint grows */
1364 get_ledger_info(&footprint_before
, &pagetable_before
);
1365 memset((char *)(uintptr_t)remap_addr
, 'p', (size_t)surface_size
);
1366 get_ledger_info(&footprint_after
, &pagetable_after
);
1367 footprint_expected
= footprint_before
+ surface_size
;
1368 footprint_expected
+= (pagetable_after
- pagetable_before
);
1369 T_LOG("accessing re-mapped IOSurface grows phys_footprint");
1370 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1371 "accessing remapped IOSurface %lld bytes: "
1372 "footprint %lld -> %lld expected %lld delta %lld",
1373 surface_size
, footprint_before
, footprint_after
,
1374 footprint_expected
, footprint_after
- footprint_expected
);
1376 /* deallocating IOSurface re-mapping: footprint shrinks */
1377 get_ledger_info(&footprint_before
, &pagetable_before
);
1378 kr
= mach_vm_deallocate(mach_task_self(),
1380 (mach_vm_size_t
)surface_size
);
1382 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate() error 0x%x (%s)",
1383 kr
, mach_error_string(kr
));
1384 get_ledger_info(&footprint_after
, &pagetable_after
);
1385 footprint_expected
= footprint_before
- surface_size
;
1386 footprint_expected
+= (pagetable_after
- pagetable_before
);
1387 T_LOG("deallocating re-mapping of IOSurface shrinks phys_footprint");
1388 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1389 "deallocating remapped IOSurface %lld bytes: "
1390 "footprint %lld -> %lld expected %lld delta %lld",
1391 surface_size
, footprint_before
, footprint_after
,
1392 footprint_expected
, footprint_after
- footprint_expected
);
1394 /* release IOSurface: footprint shrinks */
1395 get_ledger_info(&footprint_before
, &pagetable_before
);
1397 get_ledger_info(&footprint_after
, &pagetable_after
);
1398 footprint_expected
= footprint_before
- surface_size
;
1399 footprint_expected
+= (pagetable_after
- pagetable_before
);
1400 T_LOG("releasing IOSurface decreases phys_footprint");
1401 T_EXPECT_EQ(footprint_after
, footprint_expected
,
1402 "released IOSurface %lld bytes: "
1403 "footprint %lld -> %lld expected %lld delta %lld",
1404 surface_size
, footprint_before
, footprint_after
,
1405 footprint_expected
, footprint_after
- footprint_expected
);
1407 #endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */