xref: /xnu-12377.81.4/tests/vm/vm_mte_reclamation_withmte.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2025 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 
29 /*
30  * The only difference between this file and vm_mte_reclamation.c is that
31  * this file runs with MTE turned on.
32  */
33 
34 #include <ctype.h>
35 #include <darwintest.h>
36 #include <darwintest_utils.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/sysctl.h>
41 #include <signal.h>
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <unistd.h>
45 
46 #include "arm_mte_utilities.h"
47 #include "test_utils.h"
48 
49 #if __arm64__
50 T_GLOBAL_META(
51 	T_META_NAMESPACE("xnu.vm.mteinfo"),
52 	T_META_RADAR_COMPONENT_NAME("xnu"),
53 	T_META_RADAR_COMPONENT_VERSION("VM"),
54 	T_META_RUN_CONCURRENTLY(true),
55 	T_META_TAG_VM_PREFERRED);
56 
57 static void
tear_down(void)58 tear_down(void)
59 {
60 	/* Terminate munch */
61 	T_QUIET; T_EXPECT_POSIX_SUCCESS(system("killall -9 munch"),
62 	    "terminated munch");
63 }
64 
65 void
run_munch(void)66 run_munch(void)
67 {
68 	/*
69 	 * Allocates anonymous memory using the 'munch' tool to create
70 	 * memory pressure in the system, so that we can compress to free up
71 	 * some pages (triggers compressor)
72 	 */
73 	char *munch_args[] =
74 	{
75 		"/usr/local/bin/munch",
76 		"--lim-jetsam=idle",
77 		"--type=wired",
78 		"--cfg-background",
79 		NULL
80 	};
81 	posix_spawn_then_perform_action_from_process(munch_args,
82 	    MTE_SPAWN_USE_LEGACY_API, 0);
83 	sleep(30);/* Let the system stabilize */
84 }
85 
86 void
run_munch_mte(void)87 run_munch_mte(void)
88 {
89 	/*
90 	 * Allocates tagged memory using the 'munch' tool
91 	 * to trigger tag storage page relocations
92 	 */
93 
94 	pid_t pid = fork();
95 	if (pid == 0) {
96 		execl("/bin/sh",
97 		    "sh",
98 		    "-c",
99 		    "taskpolicy -S explicit-enable-inherit munch "
100 		    "--block=1 --type=malloc 10g",
101 		    (char*)NULL);
102 		perror("execl");
103 		exit(EXIT_FAILURE);
104 	} else if (pid < 0) {
105 		perror("fork");
106 		exit(EXIT_FAILURE);
107 	}
108 	sleep(30);
109 	kill(pid, SIGTERM);
110 	sleep(10);
111 	kill(pid, SIGKILL);
112 	waitpid(pid, NULL, 0);
113 }
114 
115 T_DECL(vm_mte_ts_for_tagged_malloc,
116     "Make sure we don't use tag storage page for tagged malloc heap",
117     T_META_BOOTARGS_SET("mte_ts_vm_tag=1_4,7_9,11_12"),
118     T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE2", 1),
119     T_META_ASROOT(true),
120     XNU_T_META_SOC_SPECIFIC)
121 {
122 	struct {
123 		uint32_t vm_tag;
124 		bool mte;
125 		bool expect_ts;
126 	} args = {VM_MEMORY_MALLOC_SMALL, true, false};
127 	T_EXPECT_EQ_INT(1,
128 	    (int)run_sysctl_test("vm_mte_tag_storage_for_vm_tag", (int64_t)(&args)),
129 	    "didn't get tag storage page for allocation");
130 }
131 
132 T_DECL(test_mte_tag_storage_reclamation,
133     "test verifies correct allocation and reclamation of tag storage pages"
134     "in the compressor pool controlled by a boot-arg."
135     "For test, we take initial readings of vm.mte.compress_ts_pages_used,"
136     "vm.mte.cell.inactive,and vm.mte.tag_storage.compressor_relocations."
137     "Then we allocate anonymous memory to trigger compressor via munch usage"
138     "(vm.mte.compress_ts_pages_used  should increase;"
139     "vm.mte.cell.inactive should decrease). Then we add tagged memory pressure"
140     "to initiate the fill thread (vm.mte.tag_storage.compressor_relocations"
141     "and vm.mte.cell.active should increase,"
142     "vm.mte.compress_ts_pages_used should decrease ).",
143     T_META_BOOTARGS_SET("mte_ts_vmtag=2,7,11"),
144     T_META_BOOTARGS_SET("mte_ts_compressor=1"),
145     T_META_REQUIRES_SYSCTL_EQ("hw.optional.arm.FEAT_MTE2", 1),
146     XNU_T_META_SOC_SPECIFIC,
147     T_META_ASROOT(true),
148     T_META_ENABLED(!TARGET_OS_XR) /* rdar://165838166 */)
149 {
150 	T_ATEND(tear_down);
151 	/*
152 	 * Allocate a significant amount of wired memory to trigger compressor use,
153 	 * Check if the compressor is actively compressing pages,
154 	 * "vm.mte.compress_ts_pages_used" is increasing,
155 	 * vm.mte.cell.inactive" is decreasing
156 	 */
157 	int64_t compress_to_pages_used_initial =
158 	    sysctl_get_Q("vm.mte.compress_ts_pages_used");
159 	int64_t  inactive_pages_initial  = sysctl_get_Q("vm.mte.cell.inactive");
160 	int64_t  relocation_pages_initial =
161 	    sysctl_get_Q("vm.mte.tag_storage.compressor_relocations");
162 
163 	run_munch();
164 
165 	int64_t compress_to_pages_used_final_1 =
166 	    sysctl_get_Q("vm.mte.compress_ts_pages_used");
167 	T_QUIET; T_EXPECT_GT(compress_to_pages_used_final_1,
168 	    compress_to_pages_used_initial,
169 	    "vm.mte.compress_ts_pages_used is behaving as expected (increasing)");
170 	sleep(15);
171 	int64_t  inactive_pages_final = sysctl_get_Q("vm.mte.cell.inactive");
172 	T_QUIET; T_EXPECT_LT(inactive_pages_final, inactive_pages_initial,
173 	    "vm.mte.cell.inactive is behaving as expected (decreasing)");
174 
175 	/*
176 	 * Track active page counts pre- and post-tagged allocation to
177 	 * compare for increase
178 	 */
179 	int64_t  active_pages_initial  = sysctl_get_Q("vm.mte.cell.active");
180 
181 	/*
182 	 * Allocate heavy tagged memory to trigger fill thread,
183 	 * vm.mte.tag_storage.compressor_relocations to increase
184 	 */
185 	run_munch_mte();
186 
187 	int64_t  relocation_pages_final =
188 	    sysctl_get_Q("vm.mte.tag_storage.compressor_relocations");
189 	T_QUIET; T_EXPECT_GT(relocation_pages_final, relocation_pages_initial,
190 	    "vm.mte.cell.relocation is behaving as expected (increasing)");
191 	int64_t  active_pages_final = sysctl_get_Q("vm.mte.cell.active");
192 	T_QUIET; T_EXPECT_GT(active_pages_final, active_pages_initial,
193 	    "vm.mte.cell.active is behaving as expected (increasing)");
194 }
195 #endif /* __arm64__ */
196