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