xref: /xnu-12377.81.4/tests/vm/corpse_footprint.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 #include <darwintest.h>
29 #include <darwintest_perf.h>
30 #include <darwintest_utils.h>
31 #include <mach/error.h>
32 #include <mach/mach.h>
33 #include <mach/task.h>
34 #include <stdbool.h>
35 #include <signal.h>
36 #include <spawn.h>
37 #include <spawn_private.h>
38 
39 T_GLOBAL_META(
40 	T_META_NAMESPACE("xnu.vm.corpse"),
41 	T_META_RADAR_COMPONENT_NAME("xnu"),
42 	T_META_RADAR_COMPONENT_VERSION("VM"),
43 	T_META_CHECK_LEAKS(false));
44 
45 static pid_t
spawn_munch(size_t footprint)46 spawn_munch(size_t footprint)
47 {
48 	char **launch_tool_args;
49 	pid_t child_pid;
50 	int ret;
51 
52 	char size_arg[64];
53 
54 	T_LOG("Spawning munch with size %lu MiB", footprint >> 20);
55 
56 	T_QUIET; T_ASSERT_POSIX_SUCCESS(
57 		snprintf(size_arg, sizeof(size_arg), "--lim-size=%lub", footprint),
58 		"snprintf()");
59 
60 	launch_tool_args = (char *[]){
61 		"/usr/local/bin/munch",
62 		"--cfg-inprocess",
63 		"--fill-cr=2.5",
64 		"--type=malloc",
65 		size_arg,
66 		NULL
67 	};
68 
69 	/* Spawn the child process. */
70 	ret = dt_launch_tool(&child_pid, launch_tool_args, false, NULL, NULL);
71 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dt_launch_tool");
72 	T_QUIET; T_ASSERT_GT(child_pid, 0, "child pid");
73 
74 	return child_pid;
75 }
76 
77 static pid_t munch_pid = 0;
78 
79 static void
perf_fork_corpse_teardown(void)80 perf_fork_corpse_teardown(void)
81 {
82 	int ret;
83 	bool exited;
84 
85 	ret = kill(munch_pid, SIGINT);
86 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kill()");
87 
88 	exited = dt_waitpid(munch_pid, NULL, NULL, 30);
89 	T_QUIET; T_ASSERT_TRUE(exited, "dt_wait_pid()");
90 }
91 
92 T_DECL(perf_fork_corpse,
93     "Performance test for forking corpses",
94     // T_META_ENABLED(!(TARGET_OS_WATCH || TARGET_OS_BRIDGE || TARGET_OS_TV)),
95     T_META_ENABLED(false), /* rdar://148736982 */
96     T_META_BOOTARGS_SET("amfi_unrestrict_task_for_pid=1"),
97     T_META_TAG_PERF,
98     T_META_TAG_VM_NOT_PREFERRED,
99     T_META_RUN_CONCURRENTLY(false))
100 {
101 	size_t footprint = 512 << 20; // 512 MiB
102 	mach_port_t corpse_port;
103 	mach_port_t task_port;
104 	kern_return_t kr;
105 
106 	pid_t pid = spawn_munch(footprint);
107 
108 	T_ATEND(perf_fork_corpse_teardown);
109 
110 	kr = task_for_pid(mach_task_self(), pid, &task_port);
111 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_for_pid()");
112 	T_QUIET; T_ASSERT_NE(task_port, MACH_PORT_NULL, "task_for_pid");
113 
114 	dt_stat_time_t stat = dt_stat_time_create("duration");
115 
116 	T_LOG("Collecting measurements...");
117 	while (!dt_stat_stable(stat)) {
T_STAT_MEASURE(stat)118 		T_STAT_MEASURE(stat) {
119 			kr = task_generate_corpse(task_port, &corpse_port);
120 		}
121 		if (kr != KERN_SUCCESS) {
122 			T_SKIP("Unable to generate a corpse (%d | %s)", kr, mach_error_string(kr));
123 		}
124 
125 		mach_port_deallocate(mach_task_self(), corpse_port);
126 	}
127 	dt_stat_finalize(stat);
128 }
129