1*09a53ad8SAndrew Turner /*
2*09a53ad8SAndrew Turner  * Copyright (c) 2011, Linaro Limited
3*09a53ad8SAndrew Turner  * All rights reserved.
4*09a53ad8SAndrew Turner  *
5*09a53ad8SAndrew Turner  * Redistribution and use in source and binary forms, with or without
6*09a53ad8SAndrew Turner  * modification, are permitted provided that the following conditions are met:
7*09a53ad8SAndrew Turner  *     * Redistributions of source code must retain the above copyright
8*09a53ad8SAndrew Turner  *       notice, this list of conditions and the following disclaimer.
9*09a53ad8SAndrew Turner  *     * Redistributions in binary form must reproduce the above copyright
10*09a53ad8SAndrew Turner  *       notice, this list of conditions and the following disclaimer in the
11*09a53ad8SAndrew Turner  *       documentation and/or other materials provided with the distribution.
12*09a53ad8SAndrew Turner  *     * Neither the name of the Linaro nor the
13*09a53ad8SAndrew Turner  *       names of its contributors may be used to endorse or promote products
14*09a53ad8SAndrew Turner  *       derived from this software without specific prior written permission.
15*09a53ad8SAndrew Turner  *
16*09a53ad8SAndrew Turner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*09a53ad8SAndrew Turner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*09a53ad8SAndrew Turner  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*09a53ad8SAndrew Turner  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
20*09a53ad8SAndrew Turner  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*09a53ad8SAndrew Turner  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*09a53ad8SAndrew Turner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*09a53ad8SAndrew Turner  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*09a53ad8SAndrew Turner  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*09a53ad8SAndrew Turner  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*09a53ad8SAndrew Turner  */
27*09a53ad8SAndrew Turner 
28*09a53ad8SAndrew Turner /** A simple harness that times how long a string function takes to
29*09a53ad8SAndrew Turner  * run.
30*09a53ad8SAndrew Turner  */
31*09a53ad8SAndrew Turner 
32*09a53ad8SAndrew Turner /* PENDING: Add EPL */
33*09a53ad8SAndrew Turner 
34*09a53ad8SAndrew Turner #include <string.h>
35*09a53ad8SAndrew Turner #include <time.h>
36*09a53ad8SAndrew Turner #include <stdint.h>
37*09a53ad8SAndrew Turner #include <stdlib.h>
38*09a53ad8SAndrew Turner #include <stdio.h>
39*09a53ad8SAndrew Turner #include <stdbool.h>
40*09a53ad8SAndrew Turner #include <assert.h>
41*09a53ad8SAndrew Turner #include <unistd.h>
42*09a53ad8SAndrew Turner #include <errno.h>
43*09a53ad8SAndrew Turner 
44*09a53ad8SAndrew Turner #define NUM_ELEMS(_x) (sizeof(_x) / sizeof((_x)[0]))
45*09a53ad8SAndrew Turner 
46*09a53ad8SAndrew Turner #ifndef VERSION
47*09a53ad8SAndrew Turner #define VERSION "(unknown version)"
48*09a53ad8SAndrew Turner #endif
49*09a53ad8SAndrew Turner 
50*09a53ad8SAndrew Turner /** Make sure a function is called by using the return value */
51*09a53ad8SAndrew Turner #define SPOIL(_x)  volatile long x = (long)(_x); (void)x
52*09a53ad8SAndrew Turner 
53*09a53ad8SAndrew Turner /** Type of functions that can be tested */
54*09a53ad8SAndrew Turner typedef void (*stub_t)(void *dest, void *src, size_t n);
55*09a53ad8SAndrew Turner 
56*09a53ad8SAndrew Turner /** Meta data about one test */
57*09a53ad8SAndrew Turner struct test
58*09a53ad8SAndrew Turner {
59*09a53ad8SAndrew Turner   /** Test name */
60*09a53ad8SAndrew Turner   const char *name;
61*09a53ad8SAndrew Turner   /** Function to test */
62*09a53ad8SAndrew Turner   stub_t stub;
63*09a53ad8SAndrew Turner };
64*09a53ad8SAndrew Turner 
65*09a53ad8SAndrew Turner /** Flush the cache by reading a chunk of memory */
empty(volatile char * against)66*09a53ad8SAndrew Turner static void empty(volatile char *against)
67*09a53ad8SAndrew Turner {
68*09a53ad8SAndrew Turner   /* We know that there's a 16 k cache with 64 byte lines giving
69*09a53ad8SAndrew Turner      a total of 256 lines.  Read randomly from 256*5 places should
70*09a53ad8SAndrew Turner      flush everything */
71*09a53ad8SAndrew Turner   int offset = (1024 - 256)*1024;
72*09a53ad8SAndrew Turner 
73*09a53ad8SAndrew Turner   for (int i = offset; i < offset + 16*1024*3; i += 64)
74*09a53ad8SAndrew Turner     {
75*09a53ad8SAndrew Turner       against[i];
76*09a53ad8SAndrew Turner     }
77*09a53ad8SAndrew Turner }
78*09a53ad8SAndrew Turner 
79*09a53ad8SAndrew Turner /** Stub that does nothing.  Used for calibrating */
xbounce(void * dest,void * src,size_t n)80*09a53ad8SAndrew Turner static void xbounce(void *dest, void *src, size_t n)
81*09a53ad8SAndrew Turner {
82*09a53ad8SAndrew Turner   SPOIL(0);
83*09a53ad8SAndrew Turner }
84*09a53ad8SAndrew Turner 
85*09a53ad8SAndrew Turner /** Stub that calls memcpy */
xmemcpy(void * dest,void * src,size_t n)86*09a53ad8SAndrew Turner static void xmemcpy(void *dest, void *src, size_t n)
87*09a53ad8SAndrew Turner {
88*09a53ad8SAndrew Turner   SPOIL(memcpy(dest, src, n));
89*09a53ad8SAndrew Turner }
90*09a53ad8SAndrew Turner 
91*09a53ad8SAndrew Turner /** Stub that calls memset */
xmemset(void * dest,void * src,size_t n)92*09a53ad8SAndrew Turner static void xmemset(void *dest, void *src, size_t n)
93*09a53ad8SAndrew Turner {
94*09a53ad8SAndrew Turner   SPOIL(memset(dest, 0, n));
95*09a53ad8SAndrew Turner }
96*09a53ad8SAndrew Turner 
97*09a53ad8SAndrew Turner /** Stub that calls memcmp */
xmemcmp(void * dest,void * src,size_t n)98*09a53ad8SAndrew Turner static void xmemcmp(void *dest, void *src, size_t n)
99*09a53ad8SAndrew Turner {
100*09a53ad8SAndrew Turner   SPOIL(memcmp(dest, src, n));
101*09a53ad8SAndrew Turner }
102*09a53ad8SAndrew Turner 
103*09a53ad8SAndrew Turner /** Stub that calls strcpy */
xstrcpy(void * dest,void * src,size_t n)104*09a53ad8SAndrew Turner static void xstrcpy(void *dest, void *src, size_t n)
105*09a53ad8SAndrew Turner {
106*09a53ad8SAndrew Turner   SPOIL(strcpy(dest, src));
107*09a53ad8SAndrew Turner }
108*09a53ad8SAndrew Turner 
109*09a53ad8SAndrew Turner /** Stub that calls strlen */
xstrlen(void * dest,void * src,size_t n)110*09a53ad8SAndrew Turner static void xstrlen(void *dest, void *src, size_t n)
111*09a53ad8SAndrew Turner {
112*09a53ad8SAndrew Turner   SPOIL(strlen(dest));
113*09a53ad8SAndrew Turner }
114*09a53ad8SAndrew Turner 
115*09a53ad8SAndrew Turner /** Stub that calls strcmp */
xstrcmp(void * dest,void * src,size_t n)116*09a53ad8SAndrew Turner static void xstrcmp(void *dest, void *src, size_t n)
117*09a53ad8SAndrew Turner {
118*09a53ad8SAndrew Turner   SPOIL(strcmp(dest, src));
119*09a53ad8SAndrew Turner }
120*09a53ad8SAndrew Turner 
121*09a53ad8SAndrew Turner /** Stub that calls strchr */
xstrchr(void * dest,void * src,size_t n)122*09a53ad8SAndrew Turner static void xstrchr(void *dest, void *src, size_t n)
123*09a53ad8SAndrew Turner {
124*09a53ad8SAndrew Turner   /* Put the character at the end of the string and before the null */
125*09a53ad8SAndrew Turner   ((char *)src)[n-1] = 32;
126*09a53ad8SAndrew Turner   SPOIL(strchr(src, 32));
127*09a53ad8SAndrew Turner }
128*09a53ad8SAndrew Turner 
129*09a53ad8SAndrew Turner /** Stub that calls memchr */
xmemchr(void * dest,void * src,size_t n)130*09a53ad8SAndrew Turner static void xmemchr(void *dest, void *src, size_t n)
131*09a53ad8SAndrew Turner {
132*09a53ad8SAndrew Turner   /* Put the character at the end of the block */
133*09a53ad8SAndrew Turner   ((char *)src)[n-1] = 32;
134*09a53ad8SAndrew Turner   SPOIL(memchr(src, 32, n));
135*09a53ad8SAndrew Turner }
136*09a53ad8SAndrew Turner 
137*09a53ad8SAndrew Turner /** All functions that can be tested */
138*09a53ad8SAndrew Turner static const struct test tests[] =
139*09a53ad8SAndrew Turner   {
140*09a53ad8SAndrew Turner     { "bounce", xbounce },
141*09a53ad8SAndrew Turner     { "memchr", xmemchr },
142*09a53ad8SAndrew Turner     { "memcpy", xmemcpy },
143*09a53ad8SAndrew Turner     { "memset", xmemset },
144*09a53ad8SAndrew Turner     { "memcmp", xmemcmp },
145*09a53ad8SAndrew Turner     { "strchr", xstrchr },
146*09a53ad8SAndrew Turner     { "strcmp", xstrcmp },
147*09a53ad8SAndrew Turner     { "strcpy", xstrcpy },
148*09a53ad8SAndrew Turner     { "strlen", xstrlen },
149*09a53ad8SAndrew Turner     { NULL }
150*09a53ad8SAndrew Turner   };
151*09a53ad8SAndrew Turner 
152*09a53ad8SAndrew Turner /** Show basic usage */
usage(const char * name)153*09a53ad8SAndrew Turner static void usage(const char* name)
154*09a53ad8SAndrew Turner {
155*09a53ad8SAndrew Turner   printf("%s %s: run a string related benchmark.\n"
156*09a53ad8SAndrew Turner          "usage: %s [-c block-size] [-l loop-count] [-a alignment|src_alignment:dst_alignment] [-f] [-t test-name] [-r run-id]\n"
157*09a53ad8SAndrew Turner          , name, VERSION, name);
158*09a53ad8SAndrew Turner 
159*09a53ad8SAndrew Turner   printf("Tests:");
160*09a53ad8SAndrew Turner 
161*09a53ad8SAndrew Turner   for (const struct test *ptest = tests; ptest->name != NULL; ptest++)
162*09a53ad8SAndrew Turner     {
163*09a53ad8SAndrew Turner       printf(" %s", ptest->name);
164*09a53ad8SAndrew Turner     }
165*09a53ad8SAndrew Turner 
166*09a53ad8SAndrew Turner   printf("\n");
167*09a53ad8SAndrew Turner 
168*09a53ad8SAndrew Turner   exit(-1);
169*09a53ad8SAndrew Turner }
170*09a53ad8SAndrew Turner 
171*09a53ad8SAndrew Turner /** Find the test by name */
find_test(const char * name)172*09a53ad8SAndrew Turner static const struct test *find_test(const char *name)
173*09a53ad8SAndrew Turner {
174*09a53ad8SAndrew Turner   if (name == NULL)
175*09a53ad8SAndrew Turner     {
176*09a53ad8SAndrew Turner       return tests + 0;
177*09a53ad8SAndrew Turner     }
178*09a53ad8SAndrew Turner   else
179*09a53ad8SAndrew Turner     {
180*09a53ad8SAndrew Turner       for (const struct test *p = tests; p->name != NULL; p++)
181*09a53ad8SAndrew Turner 	{
182*09a53ad8SAndrew Turner           if (strcmp(p->name, name) == 0)
183*09a53ad8SAndrew Turner 	    {
184*09a53ad8SAndrew Turner               return p;
185*09a53ad8SAndrew Turner 	    }
186*09a53ad8SAndrew Turner 	}
187*09a53ad8SAndrew Turner     }
188*09a53ad8SAndrew Turner 
189*09a53ad8SAndrew Turner   return NULL;
190*09a53ad8SAndrew Turner }
191*09a53ad8SAndrew Turner 
192*09a53ad8SAndrew Turner #define MIN_BUFFER_SIZE 1024*1024
193*09a53ad8SAndrew Turner #define MAX_ALIGNMENT	256
194*09a53ad8SAndrew Turner 
195*09a53ad8SAndrew Turner /** Take a pointer and ensure that the lower bits == alignment */
realign(char * p,int alignment)196*09a53ad8SAndrew Turner static char *realign(char *p, int alignment)
197*09a53ad8SAndrew Turner {
198*09a53ad8SAndrew Turner   uintptr_t pp = (uintptr_t)p;
199*09a53ad8SAndrew Turner   pp = (pp + (MAX_ALIGNMENT - 1)) & ~(MAX_ALIGNMENT - 1);
200*09a53ad8SAndrew Turner   pp += alignment;
201*09a53ad8SAndrew Turner 
202*09a53ad8SAndrew Turner   return (char *)pp;
203*09a53ad8SAndrew Turner }
204*09a53ad8SAndrew Turner 
parse_int_arg(const char * arg,const char * exe_name)205*09a53ad8SAndrew Turner static int parse_int_arg(const char *arg, const char *exe_name)
206*09a53ad8SAndrew Turner {
207*09a53ad8SAndrew Turner   long int ret;
208*09a53ad8SAndrew Turner 
209*09a53ad8SAndrew Turner   errno = 0;
210*09a53ad8SAndrew Turner   ret = strtol(arg, NULL, 0);
211*09a53ad8SAndrew Turner 
212*09a53ad8SAndrew Turner   if (errno)
213*09a53ad8SAndrew Turner     {
214*09a53ad8SAndrew Turner       usage(exe_name);
215*09a53ad8SAndrew Turner     }
216*09a53ad8SAndrew Turner 
217*09a53ad8SAndrew Turner   return (int)ret;
218*09a53ad8SAndrew Turner }
219*09a53ad8SAndrew Turner 
parse_alignment_arg(const char * arg,const char * exe_name,int * src_alignment,int * dst_alignment)220*09a53ad8SAndrew Turner static void parse_alignment_arg(const char *arg, const char *exe_name,
221*09a53ad8SAndrew Turner 				int *src_alignment, int *dst_alignment)
222*09a53ad8SAndrew Turner {
223*09a53ad8SAndrew Turner   long int ret;
224*09a53ad8SAndrew Turner   char *endptr;
225*09a53ad8SAndrew Turner 
226*09a53ad8SAndrew Turner   errno = 0;
227*09a53ad8SAndrew Turner   ret = strtol(arg, &endptr, 0);
228*09a53ad8SAndrew Turner 
229*09a53ad8SAndrew Turner   if (errno)
230*09a53ad8SAndrew Turner     {
231*09a53ad8SAndrew Turner       usage(exe_name);
232*09a53ad8SAndrew Turner     }
233*09a53ad8SAndrew Turner 
234*09a53ad8SAndrew Turner   *src_alignment = (int)ret;
235*09a53ad8SAndrew Turner 
236*09a53ad8SAndrew Turner   if (ret > 256 || ret < 1)
237*09a53ad8SAndrew Turner     {
238*09a53ad8SAndrew Turner       printf("Alignment should be in the range [1, 256].\n");
239*09a53ad8SAndrew Turner       usage(exe_name);
240*09a53ad8SAndrew Turner     }
241*09a53ad8SAndrew Turner 
242*09a53ad8SAndrew Turner   if (ret == 256)
243*09a53ad8SAndrew Turner     ret = 0;
244*09a53ad8SAndrew Turner 
245*09a53ad8SAndrew Turner   if (endptr && *endptr == ':')
246*09a53ad8SAndrew Turner     {
247*09a53ad8SAndrew Turner       errno = 0;
248*09a53ad8SAndrew Turner       ret = strtol(endptr + 1, NULL, 0);
249*09a53ad8SAndrew Turner 
250*09a53ad8SAndrew Turner       if (errno)
251*09a53ad8SAndrew Turner 	{
252*09a53ad8SAndrew Turner 	  usage(exe_name);
253*09a53ad8SAndrew Turner 	}
254*09a53ad8SAndrew Turner 
255*09a53ad8SAndrew Turner       if (ret > 256 || ret < 1)
256*09a53ad8SAndrew Turner 	{
257*09a53ad8SAndrew Turner 	  printf("Alignment should be in the range [1, 256].\n");
258*09a53ad8SAndrew Turner 	  usage(exe_name);
259*09a53ad8SAndrew Turner 	}
260*09a53ad8SAndrew Turner 
261*09a53ad8SAndrew Turner       if (ret == 256)
262*09a53ad8SAndrew Turner 	ret = 0;
263*09a53ad8SAndrew Turner     }
264*09a53ad8SAndrew Turner 
265*09a53ad8SAndrew Turner   *dst_alignment = (int)ret;
266*09a53ad8SAndrew Turner }
267*09a53ad8SAndrew Turner 
268*09a53ad8SAndrew Turner /** Setup and run a test */
main(int argc,char ** argv)269*09a53ad8SAndrew Turner int main(int argc, char **argv)
270*09a53ad8SAndrew Turner {
271*09a53ad8SAndrew Turner   /* Size of src and dest buffers */
272*09a53ad8SAndrew Turner   size_t buffer_size = MIN_BUFFER_SIZE;
273*09a53ad8SAndrew Turner 
274*09a53ad8SAndrew Turner   /* Number of bytes per call */
275*09a53ad8SAndrew Turner   int count = 31;
276*09a53ad8SAndrew Turner   /* Number of times to run */
277*09a53ad8SAndrew Turner   int loops = 10000000;
278*09a53ad8SAndrew Turner   /* True to flush the cache each time */
279*09a53ad8SAndrew Turner   int flush = 0;
280*09a53ad8SAndrew Turner   /* Name of the test */
281*09a53ad8SAndrew Turner   const char *name = NULL;
282*09a53ad8SAndrew Turner   /* Alignment of buffers */
283*09a53ad8SAndrew Turner   int src_alignment = 8;
284*09a53ad8SAndrew Turner   int dst_alignment = 8;
285*09a53ad8SAndrew Turner   /* Name of the run */
286*09a53ad8SAndrew Turner   const char *run_id = "0";
287*09a53ad8SAndrew Turner 
288*09a53ad8SAndrew Turner   int opt;
289*09a53ad8SAndrew Turner 
290*09a53ad8SAndrew Turner   while ((opt = getopt(argc, argv, "c:l:ft:r:hva:")) > 0)
291*09a53ad8SAndrew Turner     {
292*09a53ad8SAndrew Turner       switch (opt)
293*09a53ad8SAndrew Turner 	{
294*09a53ad8SAndrew Turner 	case 'c':
295*09a53ad8SAndrew Turner           count = parse_int_arg(optarg, argv[0]);
296*09a53ad8SAndrew Turner           break;
297*09a53ad8SAndrew Turner 	case 'l':
298*09a53ad8SAndrew Turner           loops = parse_int_arg(optarg, argv[0]);
299*09a53ad8SAndrew Turner           break;
300*09a53ad8SAndrew Turner 	case 'a':
301*09a53ad8SAndrew Turner           parse_alignment_arg(optarg, argv[0], &src_alignment, &dst_alignment);
302*09a53ad8SAndrew Turner           break;
303*09a53ad8SAndrew Turner 	case 'f':
304*09a53ad8SAndrew Turner           flush = 1;
305*09a53ad8SAndrew Turner           break;
306*09a53ad8SAndrew Turner 	case 't':
307*09a53ad8SAndrew Turner           name = strdup(optarg);
308*09a53ad8SAndrew Turner           break;
309*09a53ad8SAndrew Turner 	case 'r':
310*09a53ad8SAndrew Turner           run_id = strdup(optarg);
311*09a53ad8SAndrew Turner           break;
312*09a53ad8SAndrew Turner 	case 'h':
313*09a53ad8SAndrew Turner           usage(argv[0]);
314*09a53ad8SAndrew Turner           break;
315*09a53ad8SAndrew Turner 	default:
316*09a53ad8SAndrew Turner           usage(argv[0]);
317*09a53ad8SAndrew Turner           break;
318*09a53ad8SAndrew Turner 	}
319*09a53ad8SAndrew Turner     }
320*09a53ad8SAndrew Turner 
321*09a53ad8SAndrew Turner   /* Find the test by name */
322*09a53ad8SAndrew Turner   const struct test *ptest = find_test(name);
323*09a53ad8SAndrew Turner 
324*09a53ad8SAndrew Turner   if (ptest == NULL)
325*09a53ad8SAndrew Turner     {
326*09a53ad8SAndrew Turner       usage(argv[0]);
327*09a53ad8SAndrew Turner     }
328*09a53ad8SAndrew Turner 
329*09a53ad8SAndrew Turner   if (count + MAX_ALIGNMENT * 2 > MIN_BUFFER_SIZE)
330*09a53ad8SAndrew Turner     {
331*09a53ad8SAndrew Turner       buffer_size = count + MAX_ALIGNMENT * 2;
332*09a53ad8SAndrew Turner     }
333*09a53ad8SAndrew Turner 
334*09a53ad8SAndrew Turner   /* Buffers to read and write from */
335*09a53ad8SAndrew Turner   char *src = malloc(buffer_size);
336*09a53ad8SAndrew Turner   char *dest = malloc(buffer_size);
337*09a53ad8SAndrew Turner 
338*09a53ad8SAndrew Turner   assert(src != NULL && dest != NULL);
339*09a53ad8SAndrew Turner 
340*09a53ad8SAndrew Turner   src = realign(src, src_alignment);
341*09a53ad8SAndrew Turner   dest = realign(dest, dst_alignment);
342*09a53ad8SAndrew Turner 
343*09a53ad8SAndrew Turner   /* Fill the buffer with non-zero, reproducable random data */
344*09a53ad8SAndrew Turner   srandom(1539);
345*09a53ad8SAndrew Turner 
346*09a53ad8SAndrew Turner   for (int i = 0; i < buffer_size; i++)
347*09a53ad8SAndrew Turner     {
348*09a53ad8SAndrew Turner       src[i] = (char)random() | 1;
349*09a53ad8SAndrew Turner       dest[i] = src[i];
350*09a53ad8SAndrew Turner     }
351*09a53ad8SAndrew Turner 
352*09a53ad8SAndrew Turner   /* Make sure the buffers are null terminated for any string tests */
353*09a53ad8SAndrew Turner   src[count] = 0;
354*09a53ad8SAndrew Turner   dest[count] = 0;
355*09a53ad8SAndrew Turner 
356*09a53ad8SAndrew Turner   struct timespec start, end;
357*09a53ad8SAndrew Turner   int err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
358*09a53ad8SAndrew Turner   assert(err == 0);
359*09a53ad8SAndrew Turner 
360*09a53ad8SAndrew Turner   /* Preload */
361*09a53ad8SAndrew Turner   stub_t stub = ptest->stub;
362*09a53ad8SAndrew Turner 
363*09a53ad8SAndrew Turner   /* Run two variants to reduce the cost of testing for the flush */
364*09a53ad8SAndrew Turner   if (flush == 0)
365*09a53ad8SAndrew Turner     {
366*09a53ad8SAndrew Turner       for (int i = 0; i < loops; i++)
367*09a53ad8SAndrew Turner 	{
368*09a53ad8SAndrew Turner 	  (*stub)(dest, src, count);
369*09a53ad8SAndrew Turner 	}
370*09a53ad8SAndrew Turner     }
371*09a53ad8SAndrew Turner   else
372*09a53ad8SAndrew Turner     {
373*09a53ad8SAndrew Turner       for (int i = 0; i < loops; i++)
374*09a53ad8SAndrew Turner 	{
375*09a53ad8SAndrew Turner 	  (*stub)(dest, src, count);
376*09a53ad8SAndrew Turner 	  empty(dest);
377*09a53ad8SAndrew Turner 	}
378*09a53ad8SAndrew Turner     }
379*09a53ad8SAndrew Turner 
380*09a53ad8SAndrew Turner   err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
381*09a53ad8SAndrew Turner   assert(err == 0);
382*09a53ad8SAndrew Turner 
383*09a53ad8SAndrew Turner   /* Drop any leading path and pull the variant name out of the executable */
384*09a53ad8SAndrew Turner   char *variant = strrchr(argv[0], '/');
385*09a53ad8SAndrew Turner 
386*09a53ad8SAndrew Turner   if (variant == NULL)
387*09a53ad8SAndrew Turner     {
388*09a53ad8SAndrew Turner       variant = argv[0];
389*09a53ad8SAndrew Turner     }
390*09a53ad8SAndrew Turner 
391*09a53ad8SAndrew Turner   variant = strstr(variant, "try-");
392*09a53ad8SAndrew Turner   assert(variant != NULL);
393*09a53ad8SAndrew Turner 
394*09a53ad8SAndrew Turner   double elapsed = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) * 1e-9;
395*09a53ad8SAndrew Turner   /* Estimate the bounce time.  Measured on a Panda. */
396*09a53ad8SAndrew Turner   double bounced = 0.448730 * loops / 50000000;
397*09a53ad8SAndrew Turner 
398*09a53ad8SAndrew Turner   /* Dump both machine and human readable versions */
399*09a53ad8SAndrew Turner   printf("%s:%s:%u:%u:%d:%d:%s:%.6f: took %.6f s for %u calls to %s of %u bytes.  ~%.3f MB/s corrected.\n",
400*09a53ad8SAndrew Turner          variant + 4, ptest->name,
401*09a53ad8SAndrew Turner 	 count, loops, src_alignment, dst_alignment, run_id,
402*09a53ad8SAndrew Turner 	 elapsed,
403*09a53ad8SAndrew Turner          elapsed, loops, ptest->name, count,
404*09a53ad8SAndrew Turner          (double)loops*count/(elapsed - bounced)/(1024*1024));
405*09a53ad8SAndrew Turner 
406*09a53ad8SAndrew Turner   return 0;
407*09a53ad8SAndrew Turner }
408