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