blob: 0e6553797bd786875daa84b193022a2e86df9089 [file] [log] [blame]
Christopher Ferris82ac1af2013-02-15 12:27:58 -08001/*
2** Copyright 2010 The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8** http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17/*
Christopher Ferris25ada902013-04-02 13:28:16 -070018 * Micro-benchmarking of sleep/cpu speed/memcpy/memset/memory reads/strcmp.
Christopher Ferris82ac1af2013-02-15 12:27:58 -080019 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include <math.h>
25#include <sched.h>
26#include <sys/resource.h>
27#include <time.h>
28#include <unistd.h>
29
30// The default size of data that will be manipulated in each iteration of
31// a memory benchmark. Can be modified with the --data_size option.
32#define DEFAULT_DATA_SIZE 1000000000
33
34// Number of nanoseconds in a second.
35#define NS_PER_SEC 1000000000
36
37// The maximum number of arguments that a benchmark will accept.
38#define MAX_ARGS 2
39
40// Use macros to compute values to try and avoid disturbing memory as much
41// as possible after each iteration.
42#define COMPUTE_AVERAGE_KB(avg_kb, bytes, time_ns) \
43 avg_kb = ((bytes) / 1024.0) / ((double)(time_ns) / NS_PER_SEC);
44
45#define COMPUTE_RUNNING(avg, running_avg, square_avg, cur_idx) \
46 running_avg = ((running_avg) / ((cur_idx) + 1)) * (cur_idx) + (avg) / ((cur_idx) + 1); \
47 square_avg = ((square_avg) / ((cur_idx) + 1)) * (cur_idx) + ((avg) / ((cur_idx) + 1)) * (avg);
Christopher Ferris25ada902013-04-02 13:28:16 -070048#define COMPUTE_MIN_MAX(avg, min, max) \
49 if (avg < min || min == 0.0) { \
50 min = avg; \
51 } \
52 if (avg > max) { \
53 max = avg; \
54 }
Christopher Ferris82ac1af2013-02-15 12:27:58 -080055
56#define GET_STD_DEV(running_avg, square_avg) \
57 sqrt((square_avg) - (running_avg) * (running_avg))
58
59// Contains information about benchmark options.
60typedef struct {
61 bool print_average;
62 bool print_each_iter;
63
64 int dst_align;
Christopher Ferris25ada902013-04-02 13:28:16 -070065 int dst_or_mask;
Christopher Ferris82ac1af2013-02-15 12:27:58 -080066 int src_align;
Christopher Ferris25ada902013-04-02 13:28:16 -070067 int src_or_mask;
Christopher Ferris82ac1af2013-02-15 12:27:58 -080068
69 int cpu_to_lock;
70
71 int data_size;
72
73 int args[MAX_ARGS];
74 int num_args;
75} command_data_t;
76
77// Struct that contains a mapping of benchmark name to benchmark function.
78typedef struct {
79 const char *name;
80 int (*ptr)(const command_data_t &cmd_data);
81} function_t;
82
83// Get the current time in nanoseconds.
84uint64_t nanoTime() {
85 struct timespec t;
86
87 t.tv_sec = t.tv_nsec = 0;
88 clock_gettime(CLOCK_MONOTONIC, &t);
89 return static_cast<uint64_t>(t.tv_sec) * NS_PER_SEC + t.tv_nsec;
90}
91
92// Allocate memory with a specific alignment and return that pointer.
93// This function assumes an alignment value that is a power of 2.
94// If the alignment is 0, then use the pointer returned by malloc.
Christopher Ferris25ada902013-04-02 13:28:16 -070095uint8_t *getAlignedMemory(uint8_t *orig_ptr, int alignment, int or_mask) {
96 uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
Christopher Ferris82ac1af2013-02-15 12:27:58 -080097 if (alignment > 0) {
98 // When setting the alignment, set it to exactly the alignment chosen.
99 // The pointer returned will be guaranteed not to be aligned to anything
100 // more than that.
101 ptr += alignment - (ptr & (alignment - 1));
Christopher Ferris25ada902013-04-02 13:28:16 -0700102 ptr |= alignment | or_mask;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800103 }
104
105 return reinterpret_cast<uint8_t*>(ptr);
106}
107
Christopher Ferris25ada902013-04-02 13:28:16 -0700108// Allocate memory with a specific alignment and return that pointer.
109// This function assumes an alignment value that is a power of 2.
110// If the alignment is 0, then use the pointer returned by malloc.
111uint8_t *allocateAlignedMemory(size_t size, int alignment, int or_mask) {
112 uint64_t ptr = reinterpret_cast<uint64_t>(malloc(size + 3 * alignment));
113 if (!ptr)
114 return NULL;
115 return getAlignedMemory((uint8_t*)ptr, alignment, or_mask);
116}
117
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800118int benchmarkSleep(const command_data_t &cmd_data) {
119 uint64_t time_ns;
120
121 int delay = cmd_data.args[0];
122 int iters = cmd_data.args[1];
123 bool print_each_iter = cmd_data.print_each_iter;
124 bool print_average = cmd_data.print_average;
125 double avg, running_avg = 0.0, square_avg = 0.0;
Christopher Ferris25ada902013-04-02 13:28:16 -0700126 double max = 0.0, min = 0.0;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800127 for (int i = 0; iters == -1 || i < iters; i++) {
128 time_ns = nanoTime();
129 sleep(delay);
130 time_ns = nanoTime() - time_ns;
131
132 avg = (double)time_ns / NS_PER_SEC;
133
134 if (print_average) {
135 COMPUTE_RUNNING(avg, running_avg, square_avg, i);
Christopher Ferris25ada902013-04-02 13:28:16 -0700136 COMPUTE_MIN_MAX(avg, min, max);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800137 }
138
139 if (print_each_iter) {
140 printf("sleep(%d) took %.06f seconds\n", delay, avg);
141 }
142 }
143
144 if (print_average) {
Christopher Ferris25ada902013-04-02 13:28:16 -0700145 printf(" sleep(%d) average %.06f seconds std dev %f min %.06f seconds max %0.6f seconds\n", delay,
146 running_avg, GET_STD_DEV(running_avg, square_avg),
147 min, max);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800148 }
149
150 return 0;
151}
152
153int benchmarkCpu(const command_data_t &cmd_data) {
154 // Use volatile so that the loop is not optimized away by the compiler.
155 volatile int cpu_foo;
156
157 uint64_t time_ns;
158 int iters = cmd_data.args[1];
159 bool print_each_iter = cmd_data.print_each_iter;
160 bool print_average = cmd_data.print_average;
161 double avg, running_avg = 0.0, square_avg = 0.0;
Christopher Ferris25ada902013-04-02 13:28:16 -0700162 double max = 0.0, min = 0.0;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800163 for (int i = 0; iters == -1 || i < iters; i++) {
164 time_ns = nanoTime();
165 for (cpu_foo = 0; cpu_foo < 100000000; cpu_foo++);
166 time_ns = nanoTime() - time_ns;
167
168 avg = (double)time_ns / NS_PER_SEC;
169
170 if (print_average) {
171 COMPUTE_RUNNING(avg, running_avg, square_avg, i);
Christopher Ferris25ada902013-04-02 13:28:16 -0700172 COMPUTE_MIN_MAX(avg, min, max);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800173 }
174
175 if (print_each_iter) {
176 printf("cpu took %.06f seconds\n", avg);
177 }
178 }
179
180 if (print_average) {
Christopher Ferris25ada902013-04-02 13:28:16 -0700181 printf(" cpu average %.06f seconds std dev %f min %0.6f seconds max %0.6f seconds\n",
182 running_avg, GET_STD_DEV(running_avg, square_avg),
183 min, max);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800184 }
185
186 return 0;
187}
188
189int benchmarkMemset(const command_data_t &cmd_data) {
190 int size = cmd_data.args[0];
191 int iters = cmd_data.args[1];
192
Christopher Ferris25ada902013-04-02 13:28:16 -0700193 uint8_t *dst = allocateAlignedMemory(size, cmd_data.dst_align, cmd_data.dst_or_mask);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800194 if (!dst)
195 return -1;
196
197 double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
Christopher Ferris25ada902013-04-02 13:28:16 -0700198 double max_kb = 0.0, min_kb = 0.0;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800199 uint64_t time_ns;
200 int j;
201 bool print_average = cmd_data.print_average;
202 bool print_each_iter = cmd_data.print_each_iter;
203 int copies = cmd_data.data_size/size;
204 for (int i = 0; iters == -1 || i < iters; i++) {
205 time_ns = nanoTime();
206 for (j = 0; j < copies; j++)
207 memset(dst, 0, size);
208 time_ns = nanoTime() - time_ns;
209
210 // Compute in kb to avoid any overflows.
211 COMPUTE_AVERAGE_KB(avg_kb, copies * size, time_ns);
212
213 if (print_average) {
214 COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
Christopher Ferris25ada902013-04-02 13:28:16 -0700215 COMPUTE_MIN_MAX(avg_kb, min_kb, max_kb);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800216 }
217
218 if (print_each_iter) {
219 printf("memset %dx%d bytes took %.06f seconds (%f MB/s)\n",
220 copies, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
221 }
222 }
223
224 if (print_average) {
Christopher Ferris25ada902013-04-02 13:28:16 -0700225 printf(" memset %dx%d bytes average %.2f MB/s std dev %.4f min %.2f MB/s max %.2f MB/s\n",
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800226 copies, size, running_avg_kb / 1024.0,
Christopher Ferris25ada902013-04-02 13:28:16 -0700227 GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0,
228 min_kb / 1024.0, max_kb / 1024.0);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800229 }
230 return 0;
231}
232
233int benchmarkMemcpy(const command_data_t &cmd_data) {
234 int size = cmd_data.args[0];
235 int iters = cmd_data.args[1];
236
Christopher Ferris25ada902013-04-02 13:28:16 -0700237 uint8_t *src = allocateAlignedMemory(size, cmd_data.src_align, cmd_data.src_or_mask);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800238 if (!src)
239 return -1;
Christopher Ferris25ada902013-04-02 13:28:16 -0700240 uint8_t *dst = allocateAlignedMemory(size, cmd_data.dst_align, cmd_data.dst_or_mask);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800241 if (!dst)
242 return -1;
243
Christopher Ferris25ada902013-04-02 13:28:16 -0700244 // Initialize the source and destination to known values.
245 // If not initialized, the benchmark results are skewed.
246 memset(src, 0xffff, size);
247 memset(dst, 0, size);
248
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800249 uint64_t time_ns;
250 double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
Christopher Ferris25ada902013-04-02 13:28:16 -0700251 double max_kb = 0.0, min_kb = 0.0;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800252 int j;
253 bool print_average = cmd_data.print_average;
254 bool print_each_iter = cmd_data.print_each_iter;
255 int copies = cmd_data.data_size / size;
256 for (int i = 0; iters == -1 || i < iters; i++) {
257 time_ns = nanoTime();
258 for (j = 0; j < copies; j++)
259 memcpy(dst, src, size);
260 time_ns = nanoTime() - time_ns;
261
262 // Compute in kb to avoid any overflows.
263 COMPUTE_AVERAGE_KB(avg_kb, copies * size, time_ns);
264
265 if (print_average) {
266 COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
Christopher Ferris25ada902013-04-02 13:28:16 -0700267 COMPUTE_MIN_MAX(avg_kb, min_kb, max_kb);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800268 }
269
270 if (print_each_iter) {
271 printf("memcpy %dx%d bytes took %.06f seconds (%f MB/s)\n",
272 copies, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
273 }
274 }
275 if (print_average) {
Christopher Ferris25ada902013-04-02 13:28:16 -0700276 printf(" memcpy %dx%d bytes average %.2f MB/s std dev %.4f min %.2f MB/s max %.2f MB/s\n",
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800277 copies, size, running_avg_kb/1024.0,
Christopher Ferris25ada902013-04-02 13:28:16 -0700278 GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0,
279 min_kb / 1024.0, max_kb / 1024.0);
280 }
281 return 0;
282}
283
284int benchmarkStrcmp(const command_data_t &cmd_data) {
285 int size = cmd_data.args[0];
286 int iters = cmd_data.args[1];
287
288 // Allocate a large chunk of memory to hold both strings.
289 uint8_t *memory = (uint8_t*)malloc(2*size + 2048);
290 if (!memory)
291 return -1;
292
293 char *string1 = reinterpret_cast<char*>(getAlignedMemory(memory, cmd_data.src_align, cmd_data.src_or_mask));
294 char *string2 = reinterpret_cast<char*>(getAlignedMemory((uint8_t*)string1+size, cmd_data.dst_align, cmd_data.dst_or_mask));
295
296 for (int i = 0; i < size - 1; i++) {
297 string1[i] = (char)(32 + (i % 96));
298 string2[i] = string1[i];
299 }
300 string1[size-1] = '\0';
301 string2[size-1] = '\0';
302
303 uint64_t time_ns;
304 double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
305 double max_kb = 0.0, min_kb = 0.0;
306 int j;
307 bool print_average = cmd_data.print_average;
308 bool print_each_iter = cmd_data.print_each_iter;
309 int copies = cmd_data.data_size / size;
310
311 int retval = 0;
312 for (int i = 0; iters == -1 || i < iters; i++) {
313 time_ns = nanoTime();
314 for (j = 0; j < copies; j++) {
315 retval = strcmp(string1, string2);
316 if (retval != 0) {
317 printf("strcmp failed, return value %d\n", retval);
318 }
319 }
320 time_ns = nanoTime() - time_ns;
321
322 // Compute in kb to avoid any overflows.
323 COMPUTE_AVERAGE_KB(avg_kb, copies * size, time_ns);
324
325 if (print_average) {
326 COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
327 COMPUTE_MIN_MAX(avg_kb, min_kb, max_kb);
328 }
329
330 if (print_each_iter) {
331 printf("strcmp %dx%d bytes took %.06f seconds (%f MB/s)\n",
332 copies, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
333 }
334 }
335 if (print_average) {
336 printf(" strcmp %dx%d bytes average %.2f MB/s std dev %.4f min %.2f MB/s max %.2f MB/s\n",
337 copies, size, running_avg_kb/1024.0,
338 GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0,
339 min_kb / 1024.0, max_kb / 1024.0);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800340 }
341 return 0;
342}
343
344int benchmarkMemread(const command_data_t &cmd_data) {
345 int size = cmd_data.args[0];
346 int iters = cmd_data.args[1];
347
348 int *src = reinterpret_cast<int*>(malloc(size));
349 if (!src)
350 return -1;
351
352 // Use volatile so the compiler does not optimize away the reads.
353 volatile int foo;
354 uint64_t time_ns;
355 int j, k;
356 double avg_kb, running_avg_kb = 0.0, square_avg_kb = 0.0;
Christopher Ferris25ada902013-04-02 13:28:16 -0700357 double max_kb = 0.0, min_kb = 0.0;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800358 bool print_average = cmd_data.print_average;
359 bool print_each_iter = cmd_data.print_each_iter;
360 int c = cmd_data.data_size / size;
361 for (int i = 0; iters == -1 || i < iters; i++) {
362 time_ns = nanoTime();
363 for (j = 0; j < c; j++)
364 for (k = 0; k < size/4; k++)
365 foo = src[k];
366 time_ns = nanoTime() - time_ns;
367
368 // Compute in kb to avoid any overflows.
369 COMPUTE_AVERAGE_KB(avg_kb, c * size, time_ns);
370
371 if (print_average) {
372 COMPUTE_RUNNING(avg_kb, running_avg_kb, square_avg_kb, i);
Christopher Ferris25ada902013-04-02 13:28:16 -0700373 COMPUTE_MIN_MAX(avg_kb, min_kb, max_kb);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800374 }
375
376 if (print_each_iter) {
377 printf("read %dx%d bytes took %.06f seconds (%f MB/s)\n",
378 c, size, (double)time_ns / NS_PER_SEC, avg_kb / 1024.0);
379 }
380 }
381
382 if (print_average) {
Christopher Ferris25ada902013-04-02 13:28:16 -0700383 printf(" read %dx%d bytes average %.2f MB/s std dev %.4f min %.2f MB/s max %.2f MB/s\n",
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800384 c, size, running_avg_kb/1024.0,
Christopher Ferris25ada902013-04-02 13:28:16 -0700385 GET_STD_DEV(running_avg_kb, square_avg_kb) / 1024.0,
386 min_kb / 1024.0, max_kb / 1024.0);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800387 }
388
389 return 0;
390}
391
392// Create the mapping structure.
393function_t function_table[] = {
394 { "sleep", benchmarkSleep },
395 { "cpu", benchmarkCpu },
396 { "memset", benchmarkMemset },
397 { "memcpy", benchmarkMemcpy },
398 { "memread", benchmarkMemread },
Christopher Ferris25ada902013-04-02 13:28:16 -0700399 { "strcmp", benchmarkStrcmp },
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800400 { NULL, NULL }
401};
402
403void usage() {
404 printf("Usage:\n");
405 printf(" micro_bench [--data_size DATA_BYTES] [--print_average]\n");
406 printf(" [--no_print_each_iter] [--lock_to_cpu CORE]\n");
407 printf(" --data_size DATA_BYTES\n");
408 printf(" For the data benchmarks (memcpy/memset/memread) the approximate\n");
409 printf(" size of data, in bytes, that will be manipulated in each iteration.\n");
410 printf(" --print_average\n");
411 printf(" Print the average and standard deviation of all iterations.\n");
412 printf(" --no_print_each_iter\n");
413 printf(" Do not print any values in each iteration.\n");
414 printf(" --lock_to_cpu CORE\n");
415 printf(" Lock to the specified CORE. The default is to use the last core found.\n");
416 printf(" ITERS\n");
417 printf(" The number of iterations to execute each benchmark. If not\n");
418 printf(" passed in then run forever.\n");
419 printf(" micro_bench sleep TIME_TO_SLEEP [ITERS]\n");
420 printf(" TIME_TO_SLEEP\n");
421 printf(" The time in seconds to sleep.\n");
422 printf(" micro_bench cpu UNUSED [ITERS]\n");
423 printf(" micro_bench [--dst_align ALIGN] memset NUM_BYTES [ITERS]\n");
424 printf(" --dst_align ALIGN\n");
425 printf(" Align the memset destination pointer to ALIGN. The default is to use the\n");
426 printf(" value returned by malloc.\n");
427 printf(" micro_bench [--src_align ALIGN] [--dst_align ALIGN] memcpy NUM_BYTES [ITERS]\n");
428 printf(" --src_align ALIGN\n");
429 printf(" Align the memcpy source pointer to ALIGN. The default is to use the\n");
430 printf(" value returned by malloc.\n");
431 printf(" --dst_align ALIGN\n");
432 printf(" Align the memcpy destination pointer to ALIGN. The default is to use the\n");
433 printf(" value returned by malloc.\n");
434 printf(" micro_bench memread NUM_BYTES [ITERS]\n");
435}
436
437function_t *processOptions(int argc, char **argv, command_data_t *cmd_data) {
438 function_t *command = NULL;
439
440 // Initialize the command_flags.
441 cmd_data->print_average = false;
442 cmd_data->print_each_iter = true;
443 cmd_data->dst_align = 0;
444 cmd_data->src_align = 0;
Christopher Ferris25ada902013-04-02 13:28:16 -0700445 cmd_data->src_or_mask = 0;
446 cmd_data->dst_or_mask = 0;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800447 cmd_data->num_args = 0;
448 cmd_data->cpu_to_lock = -1;
449 cmd_data->data_size = DEFAULT_DATA_SIZE;
450 for (int i = 0; i < MAX_ARGS; i++) {
451 cmd_data->args[i] = -1;
452 }
453
454 for (int i = 1; i < argc; i++) {
455 if (argv[i][0] == '-') {
456 int *save_value = NULL;
457 if (strcmp(argv[i], "--print_average") == 0) {
458 cmd_data->print_average = true;
459 } else if (strcmp(argv[i], "--no_print_each_iter") == 0) {
460 cmd_data->print_each_iter = false;
461 } else if (strcmp(argv[i], "--dst_align") == 0) {
462 save_value = &cmd_data->dst_align;
463 } else if (strcmp(argv[i], "--src_align") == 0) {
464 save_value = &cmd_data->src_align;
Christopher Ferris25ada902013-04-02 13:28:16 -0700465 } else if (strcmp(argv[i], "--dst_or_mask") == 0) {
466 save_value = &cmd_data->dst_or_mask;
467 } else if (strcmp(argv[i], "--src_or_mask") == 0) {
468 save_value = &cmd_data->src_or_mask;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800469 } else if (strcmp(argv[i], "--lock_to_cpu") == 0) {
470 save_value = &cmd_data->cpu_to_lock;
471 } else if (strcmp(argv[i], "--data_size") == 0) {
472 save_value = &cmd_data->data_size;
473 } else {
474 printf("Unknown option %s\n", argv[i]);
475 return NULL;
476 }
477 if (save_value) {
478 // Checking both characters without a strlen() call should be
479 // safe since as long as the argument exists, one character will
480 // be present (\0). And if the first character is '-', then
481 // there will always be a second character (\0 again).
482 if (i == argc - 1 || (argv[i + 1][0] == '-' && !isdigit(argv[i + 1][1]))) {
483 printf("The option %s requires one argument.\n",
484 argv[i]);
485 return NULL;
486 }
Christopher Ferris25ada902013-04-02 13:28:16 -0700487 *save_value = (int)strtol(argv[++i], NULL, 0);
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800488 }
489 } else if (!command) {
490 for (function_t *function = function_table; function->name != NULL; function++) {
491 if (strcmp(argv[i], function->name) == 0) {
492 command = function;
493 break;
494 }
495 }
496 if (!command) {
497 printf("Uknown command %s\n", argv[i]);
498 return NULL;
499 }
500 } else if (cmd_data->num_args > MAX_ARGS) {
501 printf("More than %d number arguments passed in.\n", MAX_ARGS);
502 return NULL;
503 } else {
504 cmd_data->args[cmd_data->num_args++] = atoi(argv[i]);
505 }
506 }
507
508 // Check the arguments passed in make sense.
509 if (cmd_data->num_args != 1 && cmd_data->num_args != 2) {
510 printf("Not enough arguments passed in.\n");
511 return NULL;
512 } else if (cmd_data->dst_align < 0) {
513 printf("The --dst_align option must be greater than or equal to 0.\n");
514 return NULL;
515 } else if (cmd_data->src_align < 0) {
516 printf("The --src_align option must be greater than or equal to 0.\n");
517 return NULL;
518 } else if (cmd_data->data_size <= 0) {
519 printf("The --data_size option must be a positive number.\n");
520 return NULL;
521 } else if ((cmd_data->dst_align & (cmd_data->dst_align - 1))) {
522 printf("The --dst_align option must be a power of 2.\n");
523 return NULL;
524 } else if ((cmd_data->src_align & (cmd_data->src_align - 1))) {
525 printf("The --src_align option must be a power of 2.\n");
526 return NULL;
Christopher Ferris25ada902013-04-02 13:28:16 -0700527 } else if (!cmd_data->src_align && cmd_data->src_or_mask) {
528 printf("The --src_or_mask option requires that --src_align be set.\n");
529 return NULL;
530 } else if (!cmd_data->dst_align && cmd_data->dst_or_mask) {
531 printf("The --dst_or_mask option requires that --dst_align be set.\n");
532 return NULL;
533 } else if (cmd_data->src_or_mask > cmd_data->src_align) {
534 printf("The value of --src_or_mask cannot be larger that --src_align.\n");
535 return NULL;
536 } else if (cmd_data->dst_or_mask > cmd_data->dst_align) {
537 printf("The value of --src_or_mask cannot be larger that --src_align.\n");
538 return NULL;
Christopher Ferris82ac1af2013-02-15 12:27:58 -0800539 }
540
541 return command;
542}
543
544bool raisePriorityAndLock(int cpu_to_lock) {
545 cpu_set_t cpuset;
546
547 if (setpriority(PRIO_PROCESS, 0, -20)) {
548 perror("Unable to raise priority of process.\n");
549 return false;
550 }
551
552 CPU_ZERO(&cpuset);
553 if (sched_getaffinity(0, sizeof(cpuset), &cpuset) != 0) {
554 perror("sched_getaffinity failed");
555 return false;
556 }
557
558 if (cpu_to_lock < 0) {
559 // Lock to the last active core we find.
560 for (int i = 0; i < CPU_SETSIZE; i++) {
561 if (CPU_ISSET(i, &cpuset)) {
562 cpu_to_lock = i;
563 }
564 }
565 } else if (!CPU_ISSET(cpu_to_lock, &cpuset)) {
566 printf("Cpu %d does not exist.\n", cpu_to_lock);
567 return false;
568 }
569
570 if (cpu_to_lock < 0) {
571 printf("Cannot find any valid cpu to lock.\n");
572 return false;
573 }
574
575 CPU_ZERO(&cpuset);
576 CPU_SET(cpu_to_lock, &cpuset);
577 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) {
578 perror("sched_setaffinity failed");
579 return false;
580 }
581
582 return true;
583}
584
585int main(int argc, char **argv) {
586 command_data_t cmd_data;
587
588 function_t *command = processOptions(argc, argv, &cmd_data);
589 if (!command) {
590 usage();
591 return -1;
592 }
593
594 if (!raisePriorityAndLock(cmd_data.cpu_to_lock)) {
595 return -1;
596 }
597
598 printf("%s\n", command->name);
599 return (*command->ptr)(cmd_data);
600}