~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
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
}