~linaro-toolchain-dev/cortex-strings/trunk

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
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
207
#define MIN_BUFFER_SIZE 1024*1024
208
9 by Michael Hope
Added comments. General tidy up.
209
/** Setup and run a test */
5 by Michael Hope
Pulled the raw throughput harness out
210
int main(int argc, char **argv)
211
{
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
212
  /* Size of src and dest buffers */
213
  size_t buffer_size = MIN_BUFFER_SIZE;
6 by Michael Hope
Fleshed out the test harness
214
9 by Michael Hope
Added comments. General tidy up.
215
  /* Number of bytes per call */
6 by Michael Hope
Fleshed out the test harness
216
  int count = 31;
9 by Michael Hope
Added comments. General tidy up.
217
  /* Number of times to run */
6 by Michael Hope
Fleshed out the test harness
218
  int loops = 10000000;
9 by Michael Hope
Added comments. General tidy up.
219
  /* True to flush the cache each time */
6 by Michael Hope
Fleshed out the test harness
220
  int flush = 0;
9 by Michael Hope
Added comments. General tidy up.
221
  /* Name of the test */
6 by Michael Hope
Fleshed out the test harness
222
  const char *name = NULL;
31 by Michael Hope
Added support for benchmarking with different alignments.
223
  /* Alignment of both buffers */
106 by Will Newton
Default alignment to 8 bytes rather than relying on malloc.
224
  int alignment = 8;
9 by Michael Hope
Added comments. General tidy up.
225
6 by Michael Hope
Fleshed out the test harness
226
  int opt;
227
31 by Michael Hope
Added support for benchmarking with different alignments.
228
  while ((opt = getopt(argc, argv, "c:l:ft:hva:")) > 0)
6 by Michael Hope
Fleshed out the test harness
229
    {
230
      switch (opt)
231
	{
232
	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.
233
          count = atoi(optarg);
234
          break;
6 by Michael Hope
Fleshed out the test harness
235
	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.
236
          loops = atoi(optarg);
237
          break;
31 by Michael Hope
Added support for benchmarking with different alignments.
238
	case 'a':
239
          alignment = atoi(optarg);
240
          break;
6 by Michael Hope
Fleshed out the test harness
241
	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.
242
          flush = 1;
243
          break;
6 by Michael Hope
Fleshed out the test harness
244
	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.
245
          name = strdup(optarg);
246
          break;
6 by Michael Hope
Fleshed out the test harness
247
	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.
248
          usage(argv[0]);
249
          break;
6 by Michael Hope
Fleshed out the test harness
250
	default:
13 by Michael Hope
Made sure that pure routines such as strlen() are called when benchmarking. Fixed a bug with the version number.
251
          usage(argv[0]);
252
          break;
6 by Michael Hope
Fleshed out the test harness
253
	}
254
    }
255
9 by Michael Hope
Added comments. General tidy up.
256
  /* Find the test by name */
257
  const struct test *ptest = find_test(name);
6 by Michael Hope
Fleshed out the test harness
258
259
  if (ptest == NULL)
260
    {
261
      usage(argv[0]);
262
    }
263
109 by Will Newton
Disallow 0 byte alignment as it is not meaningful. Also make sure we
264
  if (alignment > 256 || alignment < 1)
107 by Will Newton
Check alignment argument is valid.
265
    {
109 by Will Newton
Disallow 0 byte alignment as it is not meaningful. Also make sure we
266
      printf("Alignment should be in the range [1, 256].\n");
107 by Will Newton
Check alignment argument is valid.
267
      usage(argv[0]);
268
    }
269
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
270
  if (alignment == 256)
271
    alignment = 0;
272
109 by Will Newton
Disallow 0 byte alignment as it is not meaningful. Also make sure we
273
  if (count + alignment + 256 > MIN_BUFFER_SIZE)
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
274
    {
109 by Will Newton
Disallow 0 byte alignment as it is not meaningful. Also make sure we
275
      buffer_size = count + alignment + 256;
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
276
    }
277
278
  /* Buffers to read and write from */
279
  char *src = malloc(buffer_size);
280
  char *dest = malloc(buffer_size);
281
282
  assert(src != NULL && dest != NULL);
283
31 by Michael Hope
Added support for benchmarking with different alignments.
284
  src = realign(src, alignment);
285
  dest = realign(dest, alignment);
286
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
287
  /* Fill the buffer with non-zero, reproducable random data */
31 by Michael Hope
Added support for benchmarking with different alignments.
288
  srandom(1539);
289
108 by Will Newton
Support buffers larger than 1MB and fill the whole buffer with random
290
  for (int i = 0; i < buffer_size; i++)
31 by Michael Hope
Added support for benchmarking with different alignments.
291
    {
292
      src[i] = (char)random() | 1;
293
      dest[i] = src[i];
294
    }
295
9 by Michael Hope
Added comments. General tidy up.
296
  /* Make sure the buffers are null terminated for any string tests */
5 by Michael Hope
Pulled the raw throughput harness out
297
  src[count] = 0;
6 by Michael Hope
Fleshed out the test harness
298
  dest[count] = 0;
5 by Michael Hope
Pulled the raw throughput harness out
299
9 by Michael Hope
Added comments. General tidy up.
300
  struct timespec start, end;
25 by Michael Hope
Added memchr and strchr to the harness. Change to process time for the timers.
301
  int err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
9 by Michael Hope
Added comments. General tidy up.
302
  assert(err == 0);
303
304
  /* Preload */
305
  stub_t stub = ptest->stub;
5 by Michael Hope
Pulled the raw throughput harness out
306
31 by Michael Hope
Added support for benchmarking with different alignments.
307
  /* Run two variants to reduce the cost of testing for the flush */
308
  if (flush == 0)
309
    {
310
      for (int i = 0; i < loops; i++)
311
	{
312
	  (*stub)(dest, src, count);
313
	}
314
    }
315
  else
316
    {
317
      for (int i = 0; i < loops; i++)
318
	{
319
	  (*stub)(dest, src, count);
320
	  empty(dest);
5 by Michael Hope
Pulled the raw throughput harness out
321
	}
322
    }
323
25 by Michael Hope
Added memchr and strchr to the harness. Change to process time for the timers.
324
  err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
9 by Michael Hope
Added comments. General tidy up.
325
  assert(err == 0);
326
42 by Michael Hope
Added support for tests named try-foo-bar instead of just try-foo
327
  /* Drop any leading path and pull the variant name out of the executable */
328
  char *variant = strrchr(argv[0], '/');
9 by Michael Hope
Added comments. General tidy up.
329
330
  if (variant == NULL)
331
    {
332
      variant = argv[0];
333
    }
334
42 by Michael Hope
Added support for tests named try-foo-bar instead of just try-foo
335
  variant = strstr(variant, "try-");
336
  assert(variant != NULL);
337
9 by Michael Hope
Added comments. General tidy up.
338
  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.
339
  /* Estimate the bounce time.  Measured on a Panda. */
340
  double bounced = 0.448730 * loops / 50000000;
9 by Michael Hope
Added comments. General tidy up.
341
342
  /* Dump both machine and human readable versions */
31 by Michael Hope
Added support for benchmarking with different alignments.
343
  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
344
         variant + 4, ptest->name,
31 by Michael Hope
Added support for benchmarking with different alignments.
345
	 count, loops, alignment,
346
	 elapsed,
9 by Michael Hope
Added comments. General tidy up.
347
         elapsed, loops, ptest->name, count,
31 by Michael Hope
Added support for benchmarking with different alignments.
348
         (double)loops*count/(elapsed - bounced)/(1024*1024));
5 by Michael Hope
Pulled the raw throughput harness out
349
350
  return 0;
351
}