xref: /dflybsd-src/test/sysperf/mbwtest.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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