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