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