xref: /xnu-10063.101.15/tools/tests/superpages/measure_tlbs.c (revision 94d3b452840153a99b38a3a9659680b2a006908e)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4 #include <setjmp.h>
5 #include <mach/mach.h>
6 #include <mach/mach_vm.h>
7 #include <time.h>
8 
9 #define SUPERPAGE_SIZE (2*1024*1024)
10 #define SUPERPAGE_MASK (-SUPERPAGE_SIZE)
11 #define SUPERPAGE_ROUND_UP(a) ((a + SUPERPAGE_SIZE-1) & SUPERPAGE_MASK)
12 
13 #define RUNS0 100000
14 #define STEP 4 /* KB */
15 #define START STEP
16 #define MAX (1024*1024) /* KB */
17 
18 #define RUNS1 RUNS0
19 #define RUNS2 (RUNS0/20)
20 
21 clock_t
testt(boolean_t superpages,int mode,int write,int kb)22 testt(boolean_t superpages, int mode, int write, int kb)
23 {
24 	static int sum;
25 	char *data;
26 	unsigned int run, p, p2, i, res;
27 	mach_vm_address_t addr = 0;
28 	int pages = kb / 4;
29 	mach_vm_size_t  size = SUPERPAGE_ROUND_UP(pages * PAGE_SIZE); /* allocate full superpages */
30 	int kr;
31 
32 	kr = mach_vm_allocate(mach_task_self(), &addr, size, VM_FLAGS_ANYWHERE | (superpages? VM_FLAGS_SUPERPAGE_SIZE_2MB : VM_FLAGS_SUPERPAGE_NONE));
33 
34 	if (!addr) {
35 		return 0;
36 	}
37 
38 	data = (char*)(long)addr;
39 
40 	/* touch every base page to make sure everything is mapped and zero-filled */
41 	for (p = 0; p < pages; p++) {
42 		sum += data[p * PAGE_SIZE];
43 	}
44 
45 	clock_t a = clock(); /* start timing */
46 	switch (mode) {
47 	case 0:         /* one byte every 4096 */
48 		if (write) {
49 			for (run = 0; run < RUNS0; run++) {
50 				for (p = 0; p < pages; p++) {
51 					data[p * PAGE_SIZE] = run & 0xFF;
52 				}
53 			}
54 		} else {
55 			for (run = 0; run < RUNS0; run++) {
56 				for (p = 0; p < pages; p++) {
57 					sum += data[p * PAGE_SIZE];
58 				}
59 			}
60 		}
61 		break;
62 	case 1:         /* every byte */
63 		if (write) {
64 			for (run = 0; run < RUNS1 / PAGE_SIZE; run++) {
65 				for (i = 0; i < pages * PAGE_SIZE; i++) {
66 					data[i] = run & 0xFF;
67 				}
68 			}
69 		} else {
70 			for (run = 0; run < RUNS1 / PAGE_SIZE; run++) {
71 				for (i = 0; i < pages * PAGE_SIZE; i++) {
72 					sum += data[i];
73 				}
74 			}
75 		}
76 		break;
77 	case 2:         /* random */
78 #define PRIME 15485863
79 #define NODE_SIZE 128           /* bytes per node */
80 #define NODE_ACCESSES 16        /* accesses per node */
81 		p = 0;
82 		if (write) {
83 			for (run = 0; run < RUNS2 * pages; run++) {
84 				p += PRIME;
85 				p2 = p % (pages * PAGE_SIZE / NODE_SIZE);
86 //printf("p2 = %d\n", p2);
87 				for (i = 0; i < NODE_ACCESSES; i++) {
88 					data[p2 * NODE_SIZE + i] = run & 0xFF;
89 				}
90 			}
91 		} else {
92 			for (run = 0; run < RUNS2 * pages; run++) {
93 				p += PRIME;
94 				p2 = p % (pages * PAGE_SIZE / NODE_SIZE);
95 				for (i = 0; i < NODE_ACCESSES; i++) {
96 					sum += data[p2 * NODE_SIZE + i];
97 				}
98 			}
99 		}
100 		break;
101 	}
102 	clock_t b = clock(); /* stop timing */
103 	mach_vm_deallocate(mach_task_self(), addr, size);
104 	res = b - a;
105 	res /= pages;
106 	return res;
107 }
108 
109 int
main(int argc,char ** argv)110 main(int argc, char **argv)
111 {
112 	int kb;
113 	uint64_t time1, time2, time3, time4;
114 
115 	int mode;
116 
117 	printf("; m0 r s; m0 r b; m0 w s; m0 w b; m1 r s; m1 r b; m1 w s; m1 w b; m2 r s; m2 r b; m2 w s; m2 w b\n");
118 	for (kb = START; kb < MAX; kb += STEP) {
119 		printf("%d", kb);
120 		for (mode = 0; mode <= 2; mode++) {
121 			time1 = time2 = time3 = time4 = -1;
122 			time1 = testt(TRUE, mode, 0, kb);       // read super
123 			time2 = testt(FALSE, mode, 0, kb);      // read base
124 			time3 = testt(TRUE, mode, 1, kb);       // write super
125 			time4 = testt(FALSE, mode, 1, kb);      // write base
126 			printf("; %lld; %lld; %lld; %lld", time1, time2, time3, time4);
127 			fflush(stdout);
128 		}
129 		printf("\n");
130 	}
131 
132 	return 0;
133 }
134