1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino * MBWTEST.C
3*86d7f5d3SJohn Marino *
4*86d7f5d3SJohn Marino * (c)Copyright 2003 Matthew Dillon. This code is hereby placed in the public
5*86d7f5d3SJohn Marino * domain.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * Attempt to figure out the L1 and L2 cache sizes and measure memory
8*86d7f5d3SJohn Marino * bandwidth for the L1 and L2 cache and for non-cache memory.
9*86d7f5d3SJohn Marino *
10*86d7f5d3SJohn Marino * $DragonFly: src/test/sysperf/mbwtest.c,v 1.1 2003/11/13 07:10:36 dillon Exp $
11*86d7f5d3SJohn Marino */
12*86d7f5d3SJohn Marino
13*86d7f5d3SJohn Marino #include <sys/file.h>
14*86d7f5d3SJohn Marino #include <sys/time.h>
15*86d7f5d3SJohn Marino #include <stdio.h>
16*86d7f5d3SJohn Marino #include <stdlib.h>
17*86d7f5d3SJohn Marino #include <unistd.h>
18*86d7f5d3SJohn Marino #include <string.h>
19*86d7f5d3SJohn Marino
20*86d7f5d3SJohn Marino #define MAXBYTES (16*1024*1024)
21*86d7f5d3SJohn Marino
22*86d7f5d3SJohn Marino static int bandwidth_test(char *buf, int loops, int bytes, char *msg);
23*86d7f5d3SJohn Marino static void start_timing(void);
24*86d7f5d3SJohn Marino static int stop_timing(char *str, long long bytes);
25*86d7f5d3SJohn Marino
26*86d7f5d3SJohn Marino int
main(int ac,char ** av)27*86d7f5d3SJohn Marino main(int ac, char **av)
28*86d7f5d3SJohn Marino {
29*86d7f5d3SJohn Marino char *buf;
30*86d7f5d3SJohn Marino int loops;
31*86d7f5d3SJohn Marino int us1;
32*86d7f5d3SJohn Marino int us2;
33*86d7f5d3SJohn Marino long long count1;
34*86d7f5d3SJohn Marino long long count2;
35*86d7f5d3SJohn Marino long long count3;
36*86d7f5d3SJohn Marino long long count4;
37*86d7f5d3SJohn Marino int bytes1;
38*86d7f5d3SJohn Marino int bytes2;
39*86d7f5d3SJohn Marino int bytes3;
40*86d7f5d3SJohn Marino int bytes4;
41*86d7f5d3SJohn Marino
42*86d7f5d3SJohn Marino buf = malloc(MAXBYTES * 2);
43*86d7f5d3SJohn Marino bzero(buf, MAXBYTES * 2);
44*86d7f5d3SJohn Marino
45*86d7f5d3SJohn Marino /*
46*86d7f5d3SJohn Marino * Get a baseline for 1/4 second L1 cache timing maximizing the number
47*86d7f5d3SJohn Marino * of loops. The minimum L1 cache size is 4K.
48*86d7f5d3SJohn Marino */
49*86d7f5d3SJohn Marino start_timing();
50*86d7f5d3SJohn Marino us1 = bandwidth_test(buf, 1000, 4096, NULL); /* uS per 1000 loops */
51*86d7f5d3SJohn Marino loops = 1000000LL * 1000 / 4 / us1; /* loops for 1/4 sec */
52*86d7f5d3SJohn Marino count1 = loops * 4096LL;
53*86d7f5d3SJohn Marino start_timing();
54*86d7f5d3SJohn Marino us1 = bandwidth_test(buf, loops, 4096, NULL); /* best case timing */
55*86d7f5d3SJohn Marino printf("."); fflush(stdout); usleep(1000000 / 4);
56*86d7f5d3SJohn Marino
57*86d7f5d3SJohn Marino /*
58*86d7f5d3SJohn Marino * Search for the L1 cache size. Look for a 20% difference in bandwidth
59*86d7f5d3SJohn Marino */
60*86d7f5d3SJohn Marino bzero(buf, 4096);
61*86d7f5d3SJohn Marino start_timing();
62*86d7f5d3SJohn Marino us1 = bandwidth_test(buf, count1 / 4096 + 20, 4096, NULL);
63*86d7f5d3SJohn Marino for (bytes1 = 8192; bytes1 < MAXBYTES; bytes1 <<= 1) {
64*86d7f5d3SJohn Marino start_timing();
65*86d7f5d3SJohn Marino us2 = bandwidth_test(buf, count1 / bytes1 + 20, bytes1, NULL);
66*86d7f5d3SJohn Marino if (us2 > us1 + us1 / 5)
67*86d7f5d3SJohn Marino break;
68*86d7f5d3SJohn Marino }
69*86d7f5d3SJohn Marino bytes1 >>= 1; /* actual L1 cache size */
70*86d7f5d3SJohn Marino count2 = count1 * us1 / us2;
71*86d7f5d3SJohn Marino printf("."); fflush(stdout); usleep(1000000 / 4);
72*86d7f5d3SJohn Marino
73*86d7f5d3SJohn Marino bytes2 = bytes1 << 1;
74*86d7f5d3SJohn Marino bzero(buf, bytes2);
75*86d7f5d3SJohn Marino start_timing();
76*86d7f5d3SJohn Marino us1 = bandwidth_test(buf, count2 / bytes2 + 20, bytes2, NULL);
77*86d7f5d3SJohn Marino for (bytes2 <<= 1; bytes2 < MAXBYTES; bytes2 <<= 1) {
78*86d7f5d3SJohn Marino start_timing();
79*86d7f5d3SJohn Marino us2 = bandwidth_test(buf, count2 / bytes2 + 20, bytes2, NULL);
80*86d7f5d3SJohn Marino if (us2 > us1 + us1 / 5)
81*86d7f5d3SJohn Marino break;
82*86d7f5d3SJohn Marino }
83*86d7f5d3SJohn Marino count3 = count2 * us1 / us2;
84*86d7f5d3SJohn Marino bytes2 >>= 1; /* actual L2 cache size */
85*86d7f5d3SJohn Marino
86*86d7f5d3SJohn Marino bytes3 = bytes2 << 1;
87*86d7f5d3SJohn Marino bzero(buf, bytes3);
88*86d7f5d3SJohn Marino start_timing();
89*86d7f5d3SJohn Marino us1 = bandwidth_test(buf, count3 / bytes3 + 20, bytes3, NULL);
90*86d7f5d3SJohn Marino for (bytes3 <<= 1; bytes3 < MAXBYTES; bytes3 <<= 1) {
91*86d7f5d3SJohn Marino start_timing();
92*86d7f5d3SJohn Marino us2 = bandwidth_test(buf, count3 / bytes3 + 20, bytes3, NULL);
93*86d7f5d3SJohn Marino if (us2 > us1 + us1 / 5)
94*86d7f5d3SJohn Marino break;
95*86d7f5d3SJohn Marino }
96*86d7f5d3SJohn Marino count4 = count3 * us1 / us2;
97*86d7f5d3SJohn Marino bytes3 >>= 1; /* actual L3 cache size */
98*86d7f5d3SJohn Marino
99*86d7f5d3SJohn Marino /*
100*86d7f5d3SJohn Marino * Final run to generate output
101*86d7f5d3SJohn Marino */
102*86d7f5d3SJohn Marino printf("\nL1 cache size: %d\n", bytes1);
103*86d7f5d3SJohn Marino
104*86d7f5d3SJohn Marino if (bytes2 == MAXBYTES)
105*86d7f5d3SJohn Marino printf("L2 cache size: No L2 cache found\n");
106*86d7f5d3SJohn Marino else
107*86d7f5d3SJohn Marino printf("L2 cache size: %d\n", bytes2);
108*86d7f5d3SJohn Marino
109*86d7f5d3SJohn Marino if (bytes3 == MAXBYTES)
110*86d7f5d3SJohn Marino printf("L3 cache size: No L3 cache found\n");
111*86d7f5d3SJohn Marino else
112*86d7f5d3SJohn Marino printf("L3 cache size: %d\n", bytes3);
113*86d7f5d3SJohn Marino
114*86d7f5d3SJohn Marino sleep(1);
115*86d7f5d3SJohn Marino start_timing();
116*86d7f5d3SJohn Marino bandwidth_test(buf, count1 / bytes1 + 20, bytes1, "L1 cache bandwidth");
117*86d7f5d3SJohn Marino if (bytes2 != MAXBYTES) {
118*86d7f5d3SJohn Marino start_timing();
119*86d7f5d3SJohn Marino bandwidth_test(buf, count2 / bytes2 + 20, bytes2,
120*86d7f5d3SJohn Marino "L2 cache bandwidth");
121*86d7f5d3SJohn Marino }
122*86d7f5d3SJohn Marino if (bytes3 != MAXBYTES) {
123*86d7f5d3SJohn Marino start_timing();
124*86d7f5d3SJohn Marino bandwidth_test(buf, count3 / bytes3 + 20, bytes3,
125*86d7f5d3SJohn Marino "L3 cache bandwidth");
126*86d7f5d3SJohn Marino }
127*86d7f5d3SJohn Marino
128*86d7f5d3SJohn Marino /*
129*86d7f5d3SJohn Marino * Set bytes2 to exceed the L2 cache size
130*86d7f5d3SJohn Marino */
131*86d7f5d3SJohn Marino bytes4 = bytes3 << 1;
132*86d7f5d3SJohn Marino if (bytes4 < MAXBYTES)
133*86d7f5d3SJohn Marino bytes4 <<= 1;
134*86d7f5d3SJohn Marino start_timing();
135*86d7f5d3SJohn Marino bandwidth_test(buf, count4 / bytes4 + 20, bytes4, "non-cache bandwidth");
136*86d7f5d3SJohn Marino return(0);
137*86d7f5d3SJohn Marino }
138*86d7f5d3SJohn Marino
139*86d7f5d3SJohn Marino struct timeval tv1;
140*86d7f5d3SJohn Marino struct timeval tv2;
141*86d7f5d3SJohn Marino
142*86d7f5d3SJohn Marino static
143*86d7f5d3SJohn Marino int
bandwidth_test(char * buf,int loops,int bytes,char * msg)144*86d7f5d3SJohn Marino bandwidth_test(char *buf, int loops, int bytes, char *msg)
145*86d7f5d3SJohn Marino {
146*86d7f5d3SJohn Marino register char *bptr;
147*86d7f5d3SJohn Marino register char *lptr;
148*86d7f5d3SJohn Marino register int v;
149*86d7f5d3SJohn Marino int j;
150*86d7f5d3SJohn Marino int us;
151*86d7f5d3SJohn Marino
152*86d7f5d3SJohn Marino lptr = buf + bytes;
153*86d7f5d3SJohn Marino for (j = 0; j < loops; ++j) {
154*86d7f5d3SJohn Marino for (bptr = buf; bptr < lptr; bptr += 32) {
155*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 0);
156*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 4);
157*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 8);
158*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 12);
159*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 16);
160*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 20);
161*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 24);
162*86d7f5d3SJohn Marino v = *(volatile int *)(bptr + 28);
163*86d7f5d3SJohn Marino }
164*86d7f5d3SJohn Marino }
165*86d7f5d3SJohn Marino us = stop_timing(msg, (long long)bytes * loops);
166*86d7f5d3SJohn Marino return(us);
167*86d7f5d3SJohn Marino }
168*86d7f5d3SJohn Marino
169*86d7f5d3SJohn Marino static
170*86d7f5d3SJohn Marino void
start_timing(void)171*86d7f5d3SJohn Marino start_timing(void)
172*86d7f5d3SJohn Marino {
173*86d7f5d3SJohn Marino gettimeofday(&tv1, NULL);
174*86d7f5d3SJohn Marino }
175*86d7f5d3SJohn Marino
176*86d7f5d3SJohn Marino static
177*86d7f5d3SJohn Marino int
stop_timing(char * str,long long bytes)178*86d7f5d3SJohn Marino stop_timing(char *str, long long bytes)
179*86d7f5d3SJohn Marino {
180*86d7f5d3SJohn Marino int us;
181*86d7f5d3SJohn Marino
182*86d7f5d3SJohn Marino gettimeofday(&tv2, NULL);
183*86d7f5d3SJohn Marino
184*86d7f5d3SJohn Marino us = tv2.tv_usec + 1000000 - tv1.tv_usec +
185*86d7f5d3SJohn Marino (tv2.tv_sec - tv1.tv_sec - 1) * 1000000;
186*86d7f5d3SJohn Marino if (str) {
187*86d7f5d3SJohn Marino printf("%s: %4.2f Mbytes/sec\n",
188*86d7f5d3SJohn Marino str,
189*86d7f5d3SJohn Marino (double)bytes * 1000000.0 / ((double)us * 1024.0 * 1024.0));
190*86d7f5d3SJohn Marino }
191*86d7f5d3SJohn Marino return(us);
192*86d7f5d3SJohn Marino }
193*86d7f5d3SJohn Marino
194