xref: /xnu-8792.81.2/tests/perf_vmfault.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1*19c3b8c2SApple OSS Distributions #include <unistd.h>
2*19c3b8c2SApple OSS Distributions #include <stdlib.h>
3*19c3b8c2SApple OSS Distributions #include <sys/mman.h>
4*19c3b8c2SApple OSS Distributions #include <sys/sysctl.h>
5*19c3b8c2SApple OSS Distributions #include <mach/mach.h>
6*19c3b8c2SApple OSS Distributions #include <mach/vm_map.h>
7*19c3b8c2SApple OSS Distributions #include <darwintest.h>
8*19c3b8c2SApple OSS Distributions #include <TargetConditionals.h>
9*19c3b8c2SApple OSS Distributions #include <perfcheck_keys.h>
10*19c3b8c2SApple OSS Distributions 
11*19c3b8c2SApple OSS Distributions #include "benchmark/helpers.h"
12*19c3b8c2SApple OSS Distributions #include "test_utils.h"
13*19c3b8c2SApple OSS Distributions 
14*19c3b8c2SApple OSS Distributions T_GLOBAL_META(
15*19c3b8c2SApple OSS Distributions 	T_META_NAMESPACE("xnu.vm.perf"),
16*19c3b8c2SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
17*19c3b8c2SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"),
18*19c3b8c2SApple OSS Distributions 	T_META_CHECK_LEAKS(false),
19*19c3b8c2SApple OSS Distributions 	T_META_TAG_PERF
20*19c3b8c2SApple OSS Distributions 	);
21*19c3b8c2SApple OSS Distributions 
22*19c3b8c2SApple OSS Distributions #ifdef DT_IOSMARK
23*19c3b8c2SApple OSS Distributions #define MEMSIZE                 (1UL<<29)       /* 512 MB */
24*19c3b8c2SApple OSS Distributions #else
25*19c3b8c2SApple OSS Distributions #define MEMSIZE                 (1UL<<27)       /* 128 MB */
26*19c3b8c2SApple OSS Distributions #endif
27*19c3b8c2SApple OSS Distributions 
28*19c3b8c2SApple OSS Distributions #define VM_TAG1                 100
29*19c3b8c2SApple OSS Distributions #define VM_TAG2                 101
30*19c3b8c2SApple OSS Distributions 
31*19c3b8c2SApple OSS Distributions enum {
32*19c3b8c2SApple OSS Distributions 	SOFT_FAULT,
33*19c3b8c2SApple OSS Distributions 	ZERO_FILL,
34*19c3b8c2SApple OSS Distributions 	NUM_FAULT_TYPES
35*19c3b8c2SApple OSS Distributions };
36*19c3b8c2SApple OSS Distributions 
37*19c3b8c2SApple OSS Distributions enum {
38*19c3b8c2SApple OSS Distributions 	VARIANT_DEFAULT = 1,
39*19c3b8c2SApple OSS Distributions 	VARIANT_SINGLE_REGION,
40*19c3b8c2SApple OSS Distributions 	VARIANT_MULTIPLE_REGIONS,
41*19c3b8c2SApple OSS Distributions 	NUM_MAPPING_VARIANTS
42*19c3b8c2SApple OSS Distributions };
43*19c3b8c2SApple OSS Distributions 
44*19c3b8c2SApple OSS Distributions static char *variant_str[] = {
45*19c3b8c2SApple OSS Distributions 	"none",
46*19c3b8c2SApple OSS Distributions 	"default",
47*19c3b8c2SApple OSS Distributions 	"single-region",
48*19c3b8c2SApple OSS Distributions 	"multiple-regions"
49*19c3b8c2SApple OSS Distributions };
50*19c3b8c2SApple OSS Distributions 
51*19c3b8c2SApple OSS Distributions 
52*19c3b8c2SApple OSS Distributions typedef struct {
53*19c3b8c2SApple OSS Distributions 	char *region_addr;
54*19c3b8c2SApple OSS Distributions 	char *shared_region_addr;
55*19c3b8c2SApple OSS Distributions 	size_t region_len;
56*19c3b8c2SApple OSS Distributions } memregion_config;
57*19c3b8c2SApple OSS Distributions 
58*19c3b8c2SApple OSS Distributions static memregion_config *memregion_config_per_thread;
59*19c3b8c2SApple OSS Distributions 
60*19c3b8c2SApple OSS Distributions static size_t pgsize;
61*19c3b8c2SApple OSS Distributions static int num_threads;
62*19c3b8c2SApple OSS Distributions static int ready_thread_count;
63*19c3b8c2SApple OSS Distributions static int finished_thread_count;
64*19c3b8c2SApple OSS Distributions static dt_stat_time_t runtime;
65*19c3b8c2SApple OSS Distributions static pthread_cond_t start_cvar;
66*19c3b8c2SApple OSS Distributions static pthread_cond_t threads_ready_cvar;
67*19c3b8c2SApple OSS Distributions static pthread_cond_t threads_finished_cvar;
68*19c3b8c2SApple OSS Distributions static pthread_mutex_t ready_thread_count_lock;
69*19c3b8c2SApple OSS Distributions static pthread_mutex_t finished_thread_count_lock;
70*19c3b8c2SApple OSS Distributions 
71*19c3b8c2SApple OSS Distributions static void map_mem_regions_default(int fault_type, size_t memsize);
72*19c3b8c2SApple OSS Distributions static void map_mem_regions_single(int fault_type, size_t memsize);
73*19c3b8c2SApple OSS Distributions static void map_mem_regions_multiple(int fault_type, size_t memsize);
74*19c3b8c2SApple OSS Distributions static void map_mem_regions(int fault_type, int mapping_variant, size_t memsize);
75*19c3b8c2SApple OSS Distributions static void unmap_mem_regions(int mapping_variant, size_t memsize);
76*19c3b8c2SApple OSS Distributions static void setup_per_thread_regions(char *memblock, char *memblock_share, int fault_type, size_t memsize);
77*19c3b8c2SApple OSS Distributions static void fault_pages(int thread_id);
78*19c3b8c2SApple OSS Distributions static void execute_threads(void);
79*19c3b8c2SApple OSS Distributions static void *thread_setup(void *arg);
80*19c3b8c2SApple OSS Distributions static void run_test(int fault_type, int mapping_variant, size_t memsize);
81*19c3b8c2SApple OSS Distributions static void setup_and_run_test(int test, int threads);
82*19c3b8c2SApple OSS Distributions 
83*19c3b8c2SApple OSS Distributions /* Allocates memory using the default mmap behavior. Each VM region created is capped at 128 MB. */
84*19c3b8c2SApple OSS Distributions static void
map_mem_regions_default(int fault_type,size_t memsize)85*19c3b8c2SApple OSS Distributions map_mem_regions_default(int fault_type, size_t memsize)
86*19c3b8c2SApple OSS Distributions {
87*19c3b8c2SApple OSS Distributions 	volatile char val;
88*19c3b8c2SApple OSS Distributions 	vm_prot_t curprot, maxprot;
89*19c3b8c2SApple OSS Distributions 	char *ptr, *memblock, *memblock_share = NULL;
90*19c3b8c2SApple OSS Distributions 
91*19c3b8c2SApple OSS Distributions 	memblock = (char *)mmap(NULL, memsize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
92*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_NE((void *)memblock, MAP_FAILED, "mmap");
93*19c3b8c2SApple OSS Distributions 
94*19c3b8c2SApple OSS Distributions 	if (fault_type == SOFT_FAULT) {
95*19c3b8c2SApple OSS Distributions 		/* Fault in all the pages of the original region. */
96*19c3b8c2SApple OSS Distributions 		for (ptr = memblock; ptr < memblock + memsize; ptr += pgsize) {
97*19c3b8c2SApple OSS Distributions 			val = *ptr;
98*19c3b8c2SApple OSS Distributions 		}
99*19c3b8c2SApple OSS Distributions 		/* Remap the region so that subsequent accesses result in read soft faults. */
100*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(vm_remap(mach_task_self(), (vm_address_t *)&memblock_share,
101*19c3b8c2SApple OSS Distributions 		    memsize, 0, VM_FLAGS_ANYWHERE, mach_task_self(), (vm_address_t)memblock, FALSE,
102*19c3b8c2SApple OSS Distributions 		    &curprot, &maxprot, VM_INHERIT_DEFAULT), "vm_remap");
103*19c3b8c2SApple OSS Distributions 	}
104*19c3b8c2SApple OSS Distributions 	setup_per_thread_regions(memblock, memblock_share, fault_type, memsize);
105*19c3b8c2SApple OSS Distributions }
106*19c3b8c2SApple OSS Distributions 
107*19c3b8c2SApple OSS Distributions /* Creates a single VM region by mapping in a named memory entry. */
108*19c3b8c2SApple OSS Distributions static void
map_mem_regions_single(int fault_type,size_t memsize)109*19c3b8c2SApple OSS Distributions map_mem_regions_single(int fault_type, size_t memsize)
110*19c3b8c2SApple OSS Distributions {
111*19c3b8c2SApple OSS Distributions 	volatile char val;
112*19c3b8c2SApple OSS Distributions 	vm_prot_t curprot, maxprot;
113*19c3b8c2SApple OSS Distributions 	char *ptr, *memblock = NULL, *memblock_share = NULL;
114*19c3b8c2SApple OSS Distributions 	vm_size_t size = memsize;
115*19c3b8c2SApple OSS Distributions 	vm_offset_t addr1 = 0;
116*19c3b8c2SApple OSS Distributions 	mach_port_t mem_handle = MACH_PORT_NULL;
117*19c3b8c2SApple OSS Distributions 
118*19c3b8c2SApple OSS Distributions 	/* Allocate a region and fault in all the pages. */
119*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(vm_allocate(mach_task_self(), &addr1, size, VM_FLAGS_ANYWHERE), "vm_allocate");
120*19c3b8c2SApple OSS Distributions 	for (ptr = (char *)addr1; ptr < (char *)addr1 + memsize; ptr += pgsize) {
121*19c3b8c2SApple OSS Distributions 		val = *ptr;
122*19c3b8c2SApple OSS Distributions 	}
123*19c3b8c2SApple OSS Distributions 
124*19c3b8c2SApple OSS Distributions 	/* Create a named memory entry from the region allocated above, and de-allocate said region. */
125*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(mach_make_memory_entry(mach_task_self(), &size, addr1, VM_PROT_ALL | MAP_MEM_NAMED_CREATE,
126*19c3b8c2SApple OSS Distributions 	    &mem_handle, MACH_PORT_NULL), "mach_make_memory_entry");
127*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(vm_deallocate(mach_task_self(), addr1, size), "vm_deallocate");
128*19c3b8c2SApple OSS Distributions 
129*19c3b8c2SApple OSS Distributions 	/* Map in the named entry and deallocate it. */
130*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(vm_map(mach_task_self(), (vm_address_t *)&memblock, size, 0, VM_FLAGS_ANYWHERE, mem_handle, 0,
131*19c3b8c2SApple OSS Distributions 	    FALSE, VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_NONE), "vm_map");
132*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(mach_port_deallocate(mach_task_self(), mem_handle), "mach_port_deallocate");
133*19c3b8c2SApple OSS Distributions 
134*19c3b8c2SApple OSS Distributions 	if (fault_type == SOFT_FAULT) {
135*19c3b8c2SApple OSS Distributions 		/* Fault in all the pages of the original region. */
136*19c3b8c2SApple OSS Distributions 		for (ptr = memblock; ptr < memblock + memsize; ptr += pgsize) {
137*19c3b8c2SApple OSS Distributions 			val = *ptr;
138*19c3b8c2SApple OSS Distributions 		}
139*19c3b8c2SApple OSS Distributions 		/* Remap the region so that subsequent accesses result in read soft faults. */
140*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(vm_remap(mach_task_self(), (vm_address_t *)&memblock_share,
141*19c3b8c2SApple OSS Distributions 		    memsize, 0, VM_FLAGS_ANYWHERE, mach_task_self(), (vm_address_t)memblock, FALSE,
142*19c3b8c2SApple OSS Distributions 		    &curprot, &maxprot, VM_INHERIT_DEFAULT), "vm_remap");
143*19c3b8c2SApple OSS Distributions 	}
144*19c3b8c2SApple OSS Distributions 	setup_per_thread_regions(memblock, memblock_share, fault_type, memsize);
145*19c3b8c2SApple OSS Distributions }
146*19c3b8c2SApple OSS Distributions 
147*19c3b8c2SApple OSS Distributions /* Allocates a separate VM region for each thread. */
148*19c3b8c2SApple OSS Distributions static void
map_mem_regions_multiple(int fault_type,size_t memsize)149*19c3b8c2SApple OSS Distributions map_mem_regions_multiple(int fault_type, size_t memsize)
150*19c3b8c2SApple OSS Distributions {
151*19c3b8c2SApple OSS Distributions 	int i;
152*19c3b8c2SApple OSS Distributions 	size_t region_len, num_pages;
153*19c3b8c2SApple OSS Distributions 	volatile char val;
154*19c3b8c2SApple OSS Distributions 	char *ptr, *memblock, *memblock_share;
155*19c3b8c2SApple OSS Distributions 	vm_prot_t curprot, maxprot;
156*19c3b8c2SApple OSS Distributions 
157*19c3b8c2SApple OSS Distributions 	num_pages = memsize / pgsize;
158*19c3b8c2SApple OSS Distributions 
159*19c3b8c2SApple OSS Distributions 	for (i = 0; i < num_threads; i++) {
160*19c3b8c2SApple OSS Distributions 		memblock = NULL;
161*19c3b8c2SApple OSS Distributions 
162*19c3b8c2SApple OSS Distributions 		region_len = num_pages / (size_t)num_threads;
163*19c3b8c2SApple OSS Distributions 		if ((size_t)i < num_pages % (size_t)num_threads) {
164*19c3b8c2SApple OSS Distributions 			region_len++;
165*19c3b8c2SApple OSS Distributions 		}
166*19c3b8c2SApple OSS Distributions 		region_len *= pgsize;
167*19c3b8c2SApple OSS Distributions 
168*19c3b8c2SApple OSS Distributions 		int fd = VM_MAKE_TAG((i % 2)? VM_TAG1 : VM_TAG2);
169*19c3b8c2SApple OSS Distributions 		memblock = (char *)mmap(NULL, region_len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, fd, 0);
170*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_NE((void *)memblock, MAP_FAILED, "mmap");
171*19c3b8c2SApple OSS Distributions 		memregion_config_per_thread[i].region_addr = memblock;
172*19c3b8c2SApple OSS Distributions 		memregion_config_per_thread[i].shared_region_addr = 0;
173*19c3b8c2SApple OSS Distributions 		memregion_config_per_thread[i].region_len = region_len;
174*19c3b8c2SApple OSS Distributions 
175*19c3b8c2SApple OSS Distributions 		if (fault_type == SOFT_FAULT) {
176*19c3b8c2SApple OSS Distributions 			/* Fault in all the pages of the original region. */
177*19c3b8c2SApple OSS Distributions 			for (ptr = memblock; ptr < memblock + region_len; ptr += pgsize) {
178*19c3b8c2SApple OSS Distributions 				val = *ptr;
179*19c3b8c2SApple OSS Distributions 			}
180*19c3b8c2SApple OSS Distributions 			memblock_share = NULL;
181*19c3b8c2SApple OSS Distributions 			/* Remap the region so that subsequent accesses result in read soft faults. */
182*19c3b8c2SApple OSS Distributions 			T_QUIET; T_ASSERT_MACH_SUCCESS(vm_remap(mach_task_self(), (vm_address_t *)&memblock_share,
183*19c3b8c2SApple OSS Distributions 			    region_len, 0, VM_FLAGS_ANYWHERE, mach_task_self(), (vm_address_t)memblock, FALSE,
184*19c3b8c2SApple OSS Distributions 			    &curprot, &maxprot, VM_INHERIT_DEFAULT), "vm_remap");
185*19c3b8c2SApple OSS Distributions 			memregion_config_per_thread[i].shared_region_addr = memblock_share;
186*19c3b8c2SApple OSS Distributions 		}
187*19c3b8c2SApple OSS Distributions 	}
188*19c3b8c2SApple OSS Distributions }
189*19c3b8c2SApple OSS Distributions 
190*19c3b8c2SApple OSS Distributions static void
map_mem_regions(int fault_type,int mapping_variant,size_t memsize)191*19c3b8c2SApple OSS Distributions map_mem_regions(int fault_type, int mapping_variant, size_t memsize)
192*19c3b8c2SApple OSS Distributions {
193*19c3b8c2SApple OSS Distributions 	memregion_config_per_thread = (memregion_config *)malloc(sizeof(*memregion_config_per_thread) * (size_t)num_threads);
194*19c3b8c2SApple OSS Distributions 	switch (mapping_variant) {
195*19c3b8c2SApple OSS Distributions 	case VARIANT_SINGLE_REGION:
196*19c3b8c2SApple OSS Distributions 		map_mem_regions_single(fault_type, memsize);
197*19c3b8c2SApple OSS Distributions 		break;
198*19c3b8c2SApple OSS Distributions 	case VARIANT_MULTIPLE_REGIONS:
199*19c3b8c2SApple OSS Distributions 		map_mem_regions_multiple(fault_type, memsize);
200*19c3b8c2SApple OSS Distributions 		break;
201*19c3b8c2SApple OSS Distributions 	case VARIANT_DEFAULT:
202*19c3b8c2SApple OSS Distributions 	default:
203*19c3b8c2SApple OSS Distributions 		map_mem_regions_default(fault_type, memsize);
204*19c3b8c2SApple OSS Distributions 	}
205*19c3b8c2SApple OSS Distributions }
206*19c3b8c2SApple OSS Distributions 
207*19c3b8c2SApple OSS Distributions static void
setup_per_thread_regions(char * memblock,char * memblock_share,int fault_type,size_t memsize)208*19c3b8c2SApple OSS Distributions setup_per_thread_regions(char *memblock, char *memblock_share, int fault_type, size_t memsize)
209*19c3b8c2SApple OSS Distributions {
210*19c3b8c2SApple OSS Distributions 	int i;
211*19c3b8c2SApple OSS Distributions 	size_t region_len, region_start, num_pages;
212*19c3b8c2SApple OSS Distributions 
213*19c3b8c2SApple OSS Distributions 	num_pages = memsize / pgsize;
214*19c3b8c2SApple OSS Distributions 	for (i = 0; i < num_threads; i++) {
215*19c3b8c2SApple OSS Distributions 		region_len = num_pages / (size_t)num_threads;
216*19c3b8c2SApple OSS Distributions 		region_start = region_len * (size_t)i;
217*19c3b8c2SApple OSS Distributions 
218*19c3b8c2SApple OSS Distributions 		if ((size_t)i < num_pages % (size_t)num_threads) {
219*19c3b8c2SApple OSS Distributions 			region_start += (size_t)i;
220*19c3b8c2SApple OSS Distributions 			region_len++;
221*19c3b8c2SApple OSS Distributions 		} else {
222*19c3b8c2SApple OSS Distributions 			region_start += num_pages % (size_t)num_threads;
223*19c3b8c2SApple OSS Distributions 		}
224*19c3b8c2SApple OSS Distributions 
225*19c3b8c2SApple OSS Distributions 		region_start *= pgsize;
226*19c3b8c2SApple OSS Distributions 		region_len *= pgsize;
227*19c3b8c2SApple OSS Distributions 
228*19c3b8c2SApple OSS Distributions 		memregion_config_per_thread[i].region_addr = memblock + region_start;
229*19c3b8c2SApple OSS Distributions 		memregion_config_per_thread[i].shared_region_addr = ((fault_type == SOFT_FAULT) ?
230*19c3b8c2SApple OSS Distributions 		    memblock_share + region_start : 0);
231*19c3b8c2SApple OSS Distributions 		memregion_config_per_thread[i].region_len = region_len;
232*19c3b8c2SApple OSS Distributions 	}
233*19c3b8c2SApple OSS Distributions }
234*19c3b8c2SApple OSS Distributions 
235*19c3b8c2SApple OSS Distributions static void
unmap_mem_regions(int mapping_variant,size_t memsize)236*19c3b8c2SApple OSS Distributions unmap_mem_regions(int mapping_variant, size_t memsize)
237*19c3b8c2SApple OSS Distributions {
238*19c3b8c2SApple OSS Distributions 	if (mapping_variant == VARIANT_MULTIPLE_REGIONS) {
239*19c3b8c2SApple OSS Distributions 		int i;
240*19c3b8c2SApple OSS Distributions 		for (i = 0; i < num_threads; i++) {
241*19c3b8c2SApple OSS Distributions 			if (memregion_config_per_thread[i].shared_region_addr != 0) {
242*19c3b8c2SApple OSS Distributions 				T_QUIET; T_ASSERT_MACH_SUCCESS(munmap(memregion_config_per_thread[i].shared_region_addr,
243*19c3b8c2SApple OSS Distributions 				    memregion_config_per_thread[i].region_len), "munmap");
244*19c3b8c2SApple OSS Distributions 			}
245*19c3b8c2SApple OSS Distributions 			T_QUIET; T_ASSERT_MACH_SUCCESS(munmap(memregion_config_per_thread[i].region_addr,
246*19c3b8c2SApple OSS Distributions 			    memregion_config_per_thread[i].region_len), "munmap");
247*19c3b8c2SApple OSS Distributions 		}
248*19c3b8c2SApple OSS Distributions 	} else {
249*19c3b8c2SApple OSS Distributions 		if (memregion_config_per_thread[0].shared_region_addr != 0) {
250*19c3b8c2SApple OSS Distributions 			T_QUIET; T_ASSERT_MACH_SUCCESS(munmap(memregion_config_per_thread[0].shared_region_addr, memsize), "munmap");
251*19c3b8c2SApple OSS Distributions 		}
252*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(munmap(memregion_config_per_thread[0].region_addr, memsize), "munmap");
253*19c3b8c2SApple OSS Distributions 	}
254*19c3b8c2SApple OSS Distributions }
255*19c3b8c2SApple OSS Distributions 
256*19c3b8c2SApple OSS Distributions static void
fault_pages(int thread_id)257*19c3b8c2SApple OSS Distributions fault_pages(int thread_id)
258*19c3b8c2SApple OSS Distributions {
259*19c3b8c2SApple OSS Distributions 	char *ptr, *block;
260*19c3b8c2SApple OSS Distributions 	volatile char val;
261*19c3b8c2SApple OSS Distributions 
262*19c3b8c2SApple OSS Distributions 	block = memregion_config_per_thread[thread_id].shared_region_addr ?
263*19c3b8c2SApple OSS Distributions 	    memregion_config_per_thread[thread_id].shared_region_addr :
264*19c3b8c2SApple OSS Distributions 	    memregion_config_per_thread[thread_id].region_addr;
265*19c3b8c2SApple OSS Distributions 	for (ptr = block; ptr < block + memregion_config_per_thread[thread_id].region_len; ptr += pgsize) {
266*19c3b8c2SApple OSS Distributions 		val = *ptr;
267*19c3b8c2SApple OSS Distributions 	}
268*19c3b8c2SApple OSS Distributions }
269*19c3b8c2SApple OSS Distributions 
270*19c3b8c2SApple OSS Distributions static void *
thread_setup(void * arg)271*19c3b8c2SApple OSS Distributions thread_setup(void *arg)
272*19c3b8c2SApple OSS Distributions {
273*19c3b8c2SApple OSS Distributions 	int my_index = *((int *)arg);
274*19c3b8c2SApple OSS Distributions 
275*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&ready_thread_count_lock), "pthread_mutex_lock");
276*19c3b8c2SApple OSS Distributions 	ready_thread_count++;
277*19c3b8c2SApple OSS Distributions 	if (ready_thread_count == num_threads) {
278*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_signal(&threads_ready_cvar), "pthread_cond_signal");
279*19c3b8c2SApple OSS Distributions 	}
280*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_wait(&start_cvar, &ready_thread_count_lock), "pthread_cond_wait");
281*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&ready_thread_count_lock), "pthread_mutex_unlock");
282*19c3b8c2SApple OSS Distributions 
283*19c3b8c2SApple OSS Distributions 	fault_pages(my_index);
284*19c3b8c2SApple OSS Distributions 
285*19c3b8c2SApple OSS Distributions 	/* Up the finished count */
286*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&finished_thread_count_lock), "pthread_mutex_lock");
287*19c3b8c2SApple OSS Distributions 	finished_thread_count++;
288*19c3b8c2SApple OSS Distributions 	if (finished_thread_count == num_threads) {
289*19c3b8c2SApple OSS Distributions 		/* All the threads are done. Wake up the main thread */
290*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_signal(&threads_finished_cvar), "pthread_cond_signal");
291*19c3b8c2SApple OSS Distributions 	}
292*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&finished_thread_count_lock), "pthread_mutex_unlock");
293*19c3b8c2SApple OSS Distributions 	return NULL;
294*19c3b8c2SApple OSS Distributions }
295*19c3b8c2SApple OSS Distributions 
296*19c3b8c2SApple OSS Distributions static void
execute_threads(void)297*19c3b8c2SApple OSS Distributions execute_threads(void)
298*19c3b8c2SApple OSS Distributions {
299*19c3b8c2SApple OSS Distributions 	int thread_index, thread_retval;
300*19c3b8c2SApple OSS Distributions 	int *thread_indices;
301*19c3b8c2SApple OSS Distributions 	void *thread_retval_ptr = &thread_retval;
302*19c3b8c2SApple OSS Distributions 	pthread_t* threads;
303*19c3b8c2SApple OSS Distributions 
304*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_init(&threads_ready_cvar, NULL), "pthread_cond_init");
305*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_init(&start_cvar, NULL), "pthread_cond_init");
306*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_init(&ready_thread_count_lock, NULL), "pthread_mutex_init");
307*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_init(&threads_finished_cvar, NULL), "pthread_cond_init");
308*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_init(&finished_thread_count_lock, NULL), "pthread_mutex_init");
309*19c3b8c2SApple OSS Distributions 	ready_thread_count = 0;
310*19c3b8c2SApple OSS Distributions 	finished_thread_count = 0;
311*19c3b8c2SApple OSS Distributions 
312*19c3b8c2SApple OSS Distributions 	threads = (pthread_t *)malloc(sizeof(*threads) * (size_t)num_threads);
313*19c3b8c2SApple OSS Distributions 	thread_indices = (int *)malloc(sizeof(*thread_indices) * (size_t)num_threads);
314*19c3b8c2SApple OSS Distributions 	for (thread_index = 0; thread_index < num_threads; thread_index++) {
315*19c3b8c2SApple OSS Distributions 		thread_indices[thread_index] = thread_index;
316*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_create(&threads[thread_index], NULL,
317*19c3b8c2SApple OSS Distributions 		    thread_setup, (void *)&thread_indices[thread_index]), "pthread_create");
318*19c3b8c2SApple OSS Distributions 	}
319*19c3b8c2SApple OSS Distributions 
320*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&ready_thread_count_lock), "pthread_mutex_lock");
321*19c3b8c2SApple OSS Distributions 	while (ready_thread_count != num_threads) {
322*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_wait(&threads_ready_cvar, &ready_thread_count_lock),
323*19c3b8c2SApple OSS Distributions 		    "pthread_cond_wait");
324*19c3b8c2SApple OSS Distributions 	}
325*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_unlock(&ready_thread_count_lock), "pthread_mutex_unlock");
326*19c3b8c2SApple OSS Distributions 
327*19c3b8c2SApple OSS Distributions 	T_STAT_MEASURE(runtime) {
328*19c3b8c2SApple OSS Distributions 		/* Ungate the threads */
329*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_broadcast(&start_cvar), "pthread_cond_broadcast");
330*19c3b8c2SApple OSS Distributions 		/* Wait for the threads to finish */
331*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_mutex_lock(&finished_thread_count_lock), "pthread_mutex_lock");
332*19c3b8c2SApple OSS Distributions 		while (finished_thread_count != num_threads) {
333*19c3b8c2SApple OSS Distributions 			T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_cond_wait(&threads_finished_cvar, &finished_thread_count_lock), "pthread_cond_wait");
334*19c3b8c2SApple OSS Distributions 		}
335*19c3b8c2SApple OSS Distributions 	};
336*19c3b8c2SApple OSS Distributions 
337*19c3b8c2SApple OSS Distributions 	/* Join the threads */
338*19c3b8c2SApple OSS Distributions 	for (thread_index = 0; thread_index < num_threads; thread_index++) {
339*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_SUCCESS(pthread_join(threads[thread_index], &thread_retval_ptr),
340*19c3b8c2SApple OSS Distributions 		    "pthread_join");
341*19c3b8c2SApple OSS Distributions 	}
342*19c3b8c2SApple OSS Distributions 
343*19c3b8c2SApple OSS Distributions 	free(threads);
344*19c3b8c2SApple OSS Distributions 	free(thread_indices);
345*19c3b8c2SApple OSS Distributions }
346*19c3b8c2SApple OSS Distributions 
347*19c3b8c2SApple OSS Distributions static void
run_test(int fault_type,int mapping_variant,size_t memsize)348*19c3b8c2SApple OSS Distributions run_test(int fault_type, int mapping_variant, size_t memsize)
349*19c3b8c2SApple OSS Distributions {
350*19c3b8c2SApple OSS Distributions 	char metric_str[32];
351*19c3b8c2SApple OSS Distributions 	size_t num_pages;
352*19c3b8c2SApple OSS Distributions 	size_t sysctl_size = sizeof(pgsize);
353*19c3b8c2SApple OSS Distributions 	int ret = sysctlbyname("vm.pagesize", &pgsize, &sysctl_size, NULL, 0);
354*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "sysctl vm.pagesize failed");
355*19c3b8c2SApple OSS Distributions 
356*19c3b8c2SApple OSS Distributions 	num_pages = memsize / pgsize;
357*19c3b8c2SApple OSS Distributions 
358*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_LT(fault_type, NUM_FAULT_TYPES, "invalid test type");
359*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_LT(mapping_variant, NUM_MAPPING_VARIANTS, "invalid mapping variant");
360*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_GT(num_threads, 0, "num_threads <= 0");
361*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_GT((int)num_pages / num_threads, 0, "num_pages/num_threads <= 0");
362*19c3b8c2SApple OSS Distributions 
363*19c3b8c2SApple OSS Distributions 	T_LOG("No. of cpus:     %d", get_ncpu());
364*19c3b8c2SApple OSS Distributions 	T_LOG("No. of threads:  %d", num_threads);
365*19c3b8c2SApple OSS Distributions 	T_LOG("No. of pages:    %ld", num_pages);
366*19c3b8c2SApple OSS Distributions 	T_LOG("Pagesize:        %ld", pgsize);
367*19c3b8c2SApple OSS Distributions 	T_LOG("Allocation size: %ld MB", memsize / (1024 * 1024));
368*19c3b8c2SApple OSS Distributions 	T_LOG("Mapping variant: %s", variant_str[mapping_variant]);
369*19c3b8c2SApple OSS Distributions 
370*19c3b8c2SApple OSS Distributions 	snprintf(metric_str, 32, "Runtime-%s", variant_str[mapping_variant]);
371*19c3b8c2SApple OSS Distributions 	runtime = dt_stat_time_create(metric_str);
372*19c3b8c2SApple OSS Distributions 
373*19c3b8c2SApple OSS Distributions 	while (!dt_stat_stable(runtime)) {
374*19c3b8c2SApple OSS Distributions 		map_mem_regions(fault_type, mapping_variant, memsize);
375*19c3b8c2SApple OSS Distributions 		execute_threads();
376*19c3b8c2SApple OSS Distributions 		unmap_mem_regions(mapping_variant, memsize);
377*19c3b8c2SApple OSS Distributions 	}
378*19c3b8c2SApple OSS Distributions 
379*19c3b8c2SApple OSS Distributions 	dt_stat_finalize(runtime);
380*19c3b8c2SApple OSS Distributions 	T_LOG("Throughput-%s (MB/s): %lf\n\n", variant_str[mapping_variant], (double)memsize / (1024 * 1024) / dt_stat_mean((dt_stat_t)runtime));
381*19c3b8c2SApple OSS Distributions }
382*19c3b8c2SApple OSS Distributions 
383*19c3b8c2SApple OSS Distributions static void
setup_and_run_test(int fault_type,int threads)384*19c3b8c2SApple OSS Distributions setup_and_run_test(int fault_type, int threads)
385*19c3b8c2SApple OSS Distributions {
386*19c3b8c2SApple OSS Distributions 	int i, mapping_variant;
387*19c3b8c2SApple OSS Distributions 	size_t memsize;
388*19c3b8c2SApple OSS Distributions 	char *e;
389*19c3b8c2SApple OSS Distributions 
390*19c3b8c2SApple OSS Distributions 	mapping_variant = VARIANT_DEFAULT;
391*19c3b8c2SApple OSS Distributions 	memsize = MEMSIZE;
392*19c3b8c2SApple OSS Distributions 	num_threads = threads;
393*19c3b8c2SApple OSS Distributions 
394*19c3b8c2SApple OSS Distributions 	if ((e = getenv("NTHREADS"))) {
395*19c3b8c2SApple OSS Distributions 		if (threads == 1) {
396*19c3b8c2SApple OSS Distributions 			T_SKIP("Custom environment variables specified. Skipping single threaded version.");
397*19c3b8c2SApple OSS Distributions 		}
398*19c3b8c2SApple OSS Distributions 		num_threads = (int)strtol(e, NULL, 0);
399*19c3b8c2SApple OSS Distributions 	}
400*19c3b8c2SApple OSS Distributions 
401*19c3b8c2SApple OSS Distributions 	if ((e = getenv("MEMSIZEMB"))) {
402*19c3b8c2SApple OSS Distributions 		memsize = (size_t)strtol(e, NULL, 0) * 1024 * 1024;
403*19c3b8c2SApple OSS Distributions 	}
404*19c3b8c2SApple OSS Distributions 
405*19c3b8c2SApple OSS Distributions 	if ((e = getenv("VARIANT"))) {
406*19c3b8c2SApple OSS Distributions 		mapping_variant = (int)strtol(e, NULL, 0);
407*19c3b8c2SApple OSS Distributions 		run_test(fault_type, mapping_variant, memsize);
408*19c3b8c2SApple OSS Distributions 	} else {
409*19c3b8c2SApple OSS Distributions 		for (i = VARIANT_DEFAULT; i < NUM_MAPPING_VARIANTS; i++) {
410*19c3b8c2SApple OSS Distributions 			run_test(fault_type, i, memsize);
411*19c3b8c2SApple OSS Distributions 		}
412*19c3b8c2SApple OSS Distributions 	}
413*19c3b8c2SApple OSS Distributions 
414*19c3b8c2SApple OSS Distributions 	T_END;
415*19c3b8c2SApple OSS Distributions }
416*19c3b8c2SApple OSS Distributions 
417*19c3b8c2SApple OSS Distributions T_DECL(read_soft_fault,
418*19c3b8c2SApple OSS Distributions     "Read soft faults (single thread)")
419*19c3b8c2SApple OSS Distributions {
420*19c3b8c2SApple OSS Distributions 	setup_and_run_test(SOFT_FAULT, 1);
421*19c3b8c2SApple OSS Distributions }
422*19c3b8c2SApple OSS Distributions 
423*19c3b8c2SApple OSS Distributions T_DECL(read_soft_fault_multithreaded,
424*19c3b8c2SApple OSS Distributions     "Read soft faults (multi-threaded)")
425*19c3b8c2SApple OSS Distributions {
426*19c3b8c2SApple OSS Distributions 	char *e;
427*19c3b8c2SApple OSS Distributions 	int nthreads;
428*19c3b8c2SApple OSS Distributions 
429*19c3b8c2SApple OSS Distributions 	/* iOSMark passes in the no. of threads via an env. variable */
430*19c3b8c2SApple OSS Distributions 	if ((e = getenv("DT_STAT_NTHREADS"))) {
431*19c3b8c2SApple OSS Distributions 		nthreads = (int)strtol(e, NULL, 0);
432*19c3b8c2SApple OSS Distributions 	} else {
433*19c3b8c2SApple OSS Distributions 		nthreads = get_ncpu();
434*19c3b8c2SApple OSS Distributions 		if (nthreads == 1) {
435*19c3b8c2SApple OSS Distributions 			T_SKIP("Skipping multi-threaded test on single core device.");
436*19c3b8c2SApple OSS Distributions 		}
437*19c3b8c2SApple OSS Distributions 	}
438*19c3b8c2SApple OSS Distributions 	setup_and_run_test(SOFT_FAULT, nthreads);
439*19c3b8c2SApple OSS Distributions }
440*19c3b8c2SApple OSS Distributions 
441*19c3b8c2SApple OSS Distributions T_DECL(zero_fill_fault,
442*19c3b8c2SApple OSS Distributions     "Zero fill faults (single thread)")
443*19c3b8c2SApple OSS Distributions {
444*19c3b8c2SApple OSS Distributions 	setup_and_run_test(ZERO_FILL, 1);
445*19c3b8c2SApple OSS Distributions }
446*19c3b8c2SApple OSS Distributions 
447*19c3b8c2SApple OSS Distributions T_DECL(zero_fill_fault_multithreaded,
448*19c3b8c2SApple OSS Distributions     "Zero fill faults (multi-threaded)",
449*19c3b8c2SApple OSS Distributions     XNU_T_META_SOC_SPECIFIC)
450*19c3b8c2SApple OSS Distributions {
451*19c3b8c2SApple OSS Distributions 	char *e;
452*19c3b8c2SApple OSS Distributions 	int nthreads;
453*19c3b8c2SApple OSS Distributions 
454*19c3b8c2SApple OSS Distributions 	/* iOSMark passes in the no. of threads via an env. variable */
455*19c3b8c2SApple OSS Distributions 	if ((e = getenv("DT_STAT_NTHREADS"))) {
456*19c3b8c2SApple OSS Distributions 		nthreads = (int)strtol(e, NULL, 0);
457*19c3b8c2SApple OSS Distributions 	} else {
458*19c3b8c2SApple OSS Distributions 		nthreads = get_ncpu();
459*19c3b8c2SApple OSS Distributions 		if (nthreads == 1) {
460*19c3b8c2SApple OSS Distributions 			T_SKIP("Skipping multi-threaded test on single core device.");
461*19c3b8c2SApple OSS Distributions 		}
462*19c3b8c2SApple OSS Distributions 	}
463*19c3b8c2SApple OSS Distributions 	setup_and_run_test(ZERO_FILL, nthreads);
464*19c3b8c2SApple OSS Distributions }
465