blob: e4c32fa1f62c6964d0e1f7d1f1806bb39da77a1b [file] [log] [blame]
Anders Lewisa7b0f882017-07-24 20:01:13 -07001/*
2 * Copyright (C) 2017 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
Anders Lewisa98a5fb2017-08-09 16:52:19 -070017#include <err.h>
Anders Lewisa7b0f882017-07-24 20:01:13 -070018#include <getopt.h>
Haibo Huangd5ee4c52018-07-06 15:55:25 -070019#include <inttypes.h>
Anders Lewisa7b0f882017-07-24 20:01:13 -070020#include <math.h>
21#include <sys/resource.h>
22
23#include <map>
24#include <mutex>
25#include <sstream>
26#include <string>
Christopher Ferris858e3362017-11-30 08:53:15 -080027#include <utility>
Anders Lewisa7b0f882017-07-24 20:01:13 -070028#include <vector>
29
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070030#include <android-base/file.h>
Christopher Ferrise2188d42017-11-08 23:28:57 -080031#include <android-base/stringprintf.h>
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070032#include <android-base/strings.h>
Anders Lewisa7b0f882017-07-24 20:01:13 -070033#include <benchmark/benchmark.h>
34#include <tinyxml2.h>
35#include "util.h"
36
Christopher Ferrise2188d42017-11-08 23:28:57 -080037static const std::vector<int> kCommonSizes{
38 8,
39 64,
40 512,
41 1 * KB,
42 8 * KB,
43 16 * KB,
44 32 * KB,
45 64 * KB,
46 128 * KB,
47};
48
49static const std::vector<int> kSmallSizes{
50 // Increment by 1
51 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
52 // Increment by 8
53 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144,
54 // Increment by 16
55 160, 176, 192, 208, 224, 240, 256,
56};
57
58static const std::vector<int> kMediumSizes{
59 512,
60 1 * KB,
61 8 * KB,
62 16 * KB,
63 32 * KB,
64 64 * KB,
65 128 * KB,
66};
67
68static const std::vector<int> kLargeSizes{
69 256 * KB,
70 512 * KB,
71 1024 * KB,
72 2048 * KB,
73};
74
Christopher Ferris858e3362017-11-30 08:53:15 -080075std::map<std::string, std::pair<benchmark_func_t, std::string>> g_str_to_func;
Anders Lewisa7b0f882017-07-24 20:01:13 -070076
77std::mutex g_map_lock;
78
79static struct option g_long_options[] =
80{
81 {"bionic_cpu", required_argument, 0, 'c'},
82 {"bionic_xml", required_argument, 0, 'x'},
83 {"bionic_iterations", required_argument, 0, 'i'},
84 {"bionic_extra", required_argument, 0, 'a'},
85 {"help", no_argument, 0, 'h'},
86 {0, 0, 0, 0},
87};
88
Haibo Huangd5ee4c52018-07-06 15:55:25 -070089typedef std::vector<std::vector<int64_t>> args_vector_t;
Anders Lewisa7b0f882017-07-24 20:01:13 -070090
91void Usage() {
92 printf("Usage:\n");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070093 printf("bionic_benchmarks [--bionic_cpu=<cpu_to_isolate>]\n");
94 printf(" [--bionic_xml=<path_to_xml>]\n");
Anders Lewisa7b0f882017-07-24 20:01:13 -070095 printf(" [--bionic_iterations=<num_iter>]\n");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070096 printf(" [--bionic_extra=\"<fn_name> <arg1> <arg 2> ...\"]\n");
Anders Lewisa7b0f882017-07-24 20:01:13 -070097 printf(" [<Google benchmark flags>]\n");
98 printf("Google benchmark flags:\n");
99
100 int fake_argc = 2;
101 char argv0[] = "bionic_benchmarks";
102 char argv1[] = "--help";
103 char* fake_argv[3] {argv0, argv1, NULL};
104 benchmark::Initialize(&fake_argc, fake_argv);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700105 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700106}
107
108// This function removes any bionic benchmarks command line arguments by checking them
109// against g_long_options. It fills new_argv with the filtered args.
110void SanitizeOpts(int argc, char** argv, std::vector<char*>* new_argv) {
111 // TO THOSE ADDING OPTIONS: This currently doesn't support optional arguments.
112 (*new_argv)[0] = argv[0];
113 for (int i = 1; i < argc; ++i) {
114 char* optarg = argv[i];
115 size_t opt_idx = 0;
116
117 // Iterate through g_long_options until either we hit the end or we have a match.
118 for (opt_idx = 0; g_long_options[opt_idx].name &&
119 strncmp(g_long_options[opt_idx].name, optarg + 2,
120 strlen(g_long_options[opt_idx].name)); ++opt_idx) {
121 }
122
123 if (!g_long_options[opt_idx].name) {
124 new_argv->push_back(optarg);
125 } else {
126 if (g_long_options[opt_idx].has_arg == required_argument) {
127 // If the arg was passed in with an =, it spans one char *.
128 // Otherwise, we skip a spot for the argument.
129 if (!strchr(optarg, '=')) {
130 i++;
131 }
132 }
133 }
134 }
135 new_argv->push_back(0);
136}
137
138bench_opts_t ParseOpts(int argc, char** argv) {
139 bench_opts_t opts;
140 int opt;
141 int option_index = 0;
142
Anders Lewisa7b0f882017-07-24 20:01:13 -0700143 // To make this parser handle the benchmark options silently:
144 extern int opterr;
145 opterr = 0;
146
147 while ((opt = getopt_long(argc, argv, "c:x:i:a:h", g_long_options, &option_index)) != -1) {
148 if (opt == -1) {
149 break;
150 }
151 switch (opt) {
152 case 'c':
153 if (*optarg) {
154 char* check_null;
155 opts.cpu_to_lock = strtol(optarg, &check_null, 10);
156 if (*check_null) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700157 errx(1, "ERROR: Args %s is not a valid integer.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700158 }
159 } else {
160 printf("ERROR: no argument specified for bionic_cpu\n");
161 Usage();
162 }
163 break;
164 case 'x':
165 if (*optarg) {
166 opts.xmlpath = optarg;
167 } else {
168 printf("ERROR: no argument specified for bionic_xml\n");
169 Usage();
170 }
171 break;
172 case 'a':
173 if (*optarg) {
174 opts.extra_benchmarks.push_back(optarg);
175 } else {
176 printf("ERROR: no argument specified for bionic_extra\n");
177 Usage();
178 }
179 break;
180 case 'i':
181 if (*optarg){
182 char* check_null;
183 opts.num_iterations = strtol(optarg, &check_null, 10);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700184 if (*check_null != '\0' or opts.num_iterations < 0) {
185 errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700186 }
187 } else {
188 printf("ERROR: no argument specified for bionic_iterations\n");
189 Usage();
190 }
191 break;
192 case 'h':
193 Usage();
194 break;
195 case '?':
196 break;
197 default:
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700198 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700199 }
200 }
201 return opts;
202}
203
204// This is a wrapper for every function call for per-benchmark cpu pinning.
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700205void LockAndRun(benchmark::State& state, benchmark_func_t func_to_bench, int cpu_to_lock) {
206 if (cpu_to_lock >= 0) LockToCPU(cpu_to_lock);
207
Anders Lewisa7b0f882017-07-24 20:01:13 -0700208 // To avoid having to link against Google benchmarks in libutil,
209 // benchmarks are kept without parameter information, necessitating this cast.
210 reinterpret_cast<void(*) (benchmark::State&)>(func_to_bench)(state);
211}
212
Christopher Ferrise2188d42017-11-08 23:28:57 -0800213static constexpr char kOnebufManualStr[] = "AT_ONEBUF_MANUAL_ALIGN_";
214static constexpr char kTwobufManualStr[] = "AT_TWOBUF_MANUAL_ALIGN1_";
215
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700216static bool ParseOnebufManualStr(std::string& arg, std::vector<int64_t>* values) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800217 // The format of this is:
218 // AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY
219 // Where:
220 // XX is the alignment
221 // YY is the size
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700222 int64_t align;
223 int64_t size;
224 if (sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%" SCNd64 "_SIZE_%" SCNd64,
225 &align, &size) != 2) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800226 return false;
227 }
228
229 if (align != 0 && (align & (align - 1)) != 0) {
230 return false;
231 }
232
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700233 values->push_back(static_cast<int64_t>(size));
234 values->push_back(static_cast<int64_t>(align));
Christopher Ferrise2188d42017-11-08 23:28:57 -0800235 return true;
236}
237
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700238static bool ParseTwobufManualStr(std::string& arg, std::vector<int64_t>* values) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800239 // The format of this is:
240 // AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGN2_YY_SIZE_ZZ
241 // Where:
242 // XX is the alignment of the first argument
243 // YY is the alignment of the second argument
244 // ZZ is the size
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700245 int64_t align1;
246 int64_t align2;
247 int64_t size;
248 if (sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%" SCNd64 "_ALIGN2_%" SCNd64 "_SIZE_%" SCNd64,
Christopher Ferrise2188d42017-11-08 23:28:57 -0800249 &align1, &align2, &size) != 3) {
250 return false;
251 }
252
253 // Verify the alignments are powers of 2.
254 if ((align1 != 0 && (align1 & (align1 - 1)) != 0)
255 || (align2 != 0 && (align2 & (align2 - 1)) != 0)) {
256 return false;
257 }
258
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700259 values->push_back(static_cast<int64_t>(size));
260 values->push_back(static_cast<int64_t>(align1));
261 values->push_back(static_cast<int64_t>(align2));
Christopher Ferrise2188d42017-11-08 23:28:57 -0800262 return true;
263}
264
Anders Lewisa7b0f882017-07-24 20:01:13 -0700265args_vector_t* ResolveArgs(args_vector_t* to_populate, std::string args,
266 std::map<std::string, args_vector_t>& args_shorthand) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800267 // args is either a space-separated list of ints, a macro name, or
268 // special free form macro.
Anders Lewisa7b0f882017-07-24 20:01:13 -0700269 // To ease formatting in XML files, args is left and right trimmed.
270 if (args_shorthand.count(args)) {
271 return &args_shorthand[args];
272 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800273 // Check for free form macro.
274 if (android::base::StartsWith(args, kOnebufManualStr)) {
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700275 std::vector<int64_t> values;
Christopher Ferrise2188d42017-11-08 23:28:57 -0800276 if (!ParseOnebufManualStr(args, &values)) {
277 errx(1, "ERROR: Bad format of macro %s, should be AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY",
278 args.c_str());
279 }
280 to_populate->push_back(std::move(values));
281 return to_populate;
282 } else if (android::base::StartsWith(args, kTwobufManualStr)) {
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700283 std::vector<int64_t> values;
Christopher Ferrise2188d42017-11-08 23:28:57 -0800284 if (!ParseTwobufManualStr(args, &values)) {
285 errx(1,
286 "ERROR: Bad format of macro %s, should be AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGNE2_YY_SIZE_ZZ",
287 args.c_str());
288 }
289 to_populate->push_back(std::move(values));
290 return to_populate;
291 }
292
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700293 to_populate->push_back(std::vector<int64_t>());
Anders Lewisa7b0f882017-07-24 20:01:13 -0700294 std::stringstream sstream(args);
295 std::string argstr;
296 while (sstream >> argstr) {
297 char* check_null;
298 int converted = static_cast<int>(strtol(argstr.c_str(), &check_null, 10));
299 if (*check_null) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700300 errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str());
Anders Lewisa7b0f882017-07-24 20:01:13 -0700301 }
302 (*to_populate)[0].push_back(converted);
303 }
304 return to_populate;
305}
306
307void RegisterGoogleBenchmarks(bench_opts_t primary_opts, bench_opts_t secondary_opts,
Elliott Hughes5cec3772018-01-19 15:45:23 -0800308 const std::string& fn_name, args_vector_t* run_args) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700309 if (g_str_to_func.find(fn_name) == g_str_to_func.end()) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700310 errx(1, "ERROR: No benchmark for function %s", fn_name.c_str());
Anders Lewisa7b0f882017-07-24 20:01:13 -0700311 }
312 long iterations_to_use = primary_opts.num_iterations ? primary_opts.num_iterations :
313 secondary_opts.num_iterations;
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700314 int cpu_to_use = -1;
315 if (primary_opts.cpu_to_lock >= 0) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700316 cpu_to_use = primary_opts.cpu_to_lock;
317
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700318 } else if (secondary_opts.cpu_to_lock >= 0) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700319 cpu_to_use = secondary_opts.cpu_to_lock;
320 }
321
Christopher Ferris858e3362017-11-30 08:53:15 -0800322 benchmark_func_t benchmark_function = g_str_to_func.at(fn_name).first;
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700323 for (const std::vector<int64_t>& args : (*run_args)) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700324 auto registration = benchmark::RegisterBenchmark(fn_name.c_str(), LockAndRun,
Christopher Ferris858e3362017-11-30 08:53:15 -0800325 benchmark_function,
Anders Lewisa7b0f882017-07-24 20:01:13 -0700326 cpu_to_use)->Args(args);
327 if (iterations_to_use > 0) {
328 registration->Iterations(iterations_to_use);
329 }
330 }
331}
332
333void RegisterCliBenchmarks(bench_opts_t cmdline_opts,
334 std::map<std::string, args_vector_t>& args_shorthand) {
335 // Register any of the extra benchmarks that were specified in the options.
336 args_vector_t arg_vector;
337 args_vector_t* run_args = &arg_vector;
Elliott Hughes5cec3772018-01-19 15:45:23 -0800338 for (const std::string& extra_fn : cmdline_opts.extra_benchmarks) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700339 android::base::Trim(extra_fn);
Elliott Hughes5cec3772018-01-19 15:45:23 -0800340 size_t first_space_pos = extra_fn.find(' ');
Anders Lewisa7b0f882017-07-24 20:01:13 -0700341 std::string fn_name = extra_fn.substr(0, first_space_pos);
342 std::string cmd_args;
343 if (first_space_pos != std::string::npos) {
Elliott Hughes5cec3772018-01-19 15:45:23 -0800344 cmd_args = extra_fn.substr(extra_fn.find(' ') + 1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700345 } else {
346 cmd_args = "";
347 }
348 run_args = ResolveArgs(run_args, cmd_args, args_shorthand);
349 RegisterGoogleBenchmarks(bench_opts_t(), cmdline_opts, fn_name, run_args);
350
351 run_args = &arg_vector;
352 arg_vector.clear();
353 }
354}
355
356int RegisterXmlBenchmarks(bench_opts_t cmdline_opts,
357 std::map<std::string, args_vector_t>& args_shorthand) {
358 // Structure of the XML file:
359 // - Element "fn" Function to benchmark.
360 // - - Element "iterations" Number of iterations to run. Leaving this blank uses
361 // Google benchmarks' convergence heuristics.
362 // - - Element "cpu" CPU to isolate to, if any.
363 // - - Element "args" Whitespace-separated list of per-function integer arguments, or
364 // one of the macros defined in util.h.
365 tinyxml2::XMLDocument doc;
Elliott Hughesc2223f72017-08-08 11:23:27 -0700366 if (doc.LoadFile(cmdline_opts.xmlpath.c_str()) != tinyxml2::XML_SUCCESS) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700367 doc.PrintError();
368 return doc.ErrorID();
369 }
370
371 // Read and register the functions.
372 tinyxml2::XMLNode* fn = doc.FirstChildElement("fn");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700373 while (fn) {
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700374 if (fn == fn->ToComment()) {
375 // Skip comments.
376 fn = fn->NextSibling();
377 continue;
378 }
379
Anders Lewisa7b0f882017-07-24 20:01:13 -0700380 auto fn_elem = fn->FirstChildElement("name");
381 if (!fn_elem) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700382 errx(1, "ERROR: Malformed XML entry: missing name element.");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700383 }
384 std::string fn_name = fn_elem->GetText();
385 if (fn_name.empty()) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700386 errx(1, "ERROR: Malformed XML entry: error parsing name text.");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700387 }
388 auto* xml_args = fn->FirstChildElement("args");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700389 args_vector_t arg_vector;
390 args_vector_t* run_args = ResolveArgs(&arg_vector,
391 xml_args ? android::base::Trim(xml_args->GetText()) : "",
392 args_shorthand);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700393
394 // XML values for CPU and iterations take precedence over those passed in via CLI.
395 bench_opts_t xml_opts{};
396 auto* num_iterations_elem = fn->FirstChildElement("iterations");
397 if (num_iterations_elem) {
398 int temp;
399 num_iterations_elem->QueryIntText(&temp);
400 xml_opts.num_iterations = temp;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700401 }
402 auto* cpu_to_lock_elem = fn->FirstChildElement("cpu");
403 if (cpu_to_lock_elem) {
404 int temp;
405 cpu_to_lock_elem->QueryIntText(&temp);
406 xml_opts.cpu_to_lock = temp;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700407 }
408
409 RegisterGoogleBenchmarks(xml_opts, cmdline_opts, fn_name, run_args);
410
411 fn = fn->NextSibling();
Anders Lewisa7b0f882017-07-24 20:01:13 -0700412 }
413 return 0;
414}
415
Christopher Ferrise2188d42017-11-08 23:28:57 -0800416static void SetArgs(const std::vector<int>& sizes, args_vector_t* args) {
417 for (int size : sizes) {
418 args->push_back({size});
419 }
420}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700421
Christopher Ferrise2188d42017-11-08 23:28:57 -0800422static void SetArgs(const std::vector<int>& sizes, int align, args_vector_t* args) {
423 for (int size : sizes) {
424 args->push_back({size, align});
425 }
426}
427
428
429static void SetArgs(const std::vector<int>& sizes, int align1, int align2, args_vector_t* args) {
430 for (int size : sizes) {
431 args->push_back({size, align1, align2});
432 }
433}
434
435static args_vector_t GetArgs(const std::vector<int>& sizes) {
436 args_vector_t args;
437 SetArgs(sizes, &args);
438 return args;
439}
440
441static args_vector_t GetArgs(const std::vector<int>& sizes, int align) {
442 args_vector_t args;
443 SetArgs(sizes, align, &args);
444 return args;
445}
446
447static args_vector_t GetArgs(const std::vector<int>& sizes, int align1, int align2) {
448 args_vector_t args;
449 SetArgs(sizes, align1, align2, &args);
450 return args;
451}
452
453std::map<std::string, args_vector_t> GetShorthand() {
454 std::vector<int> all_sizes(kSmallSizes);
455 all_sizes.insert(all_sizes.end(), kMediumSizes.begin(), kMediumSizes.end());
456 all_sizes.insert(all_sizes.end(), kLargeSizes.begin(), kLargeSizes.end());
457
458 std::map<std::string, args_vector_t> args_shorthand {
459 {"AT_COMMON_SIZES", GetArgs(kCommonSizes)},
460 {"AT_SMALL_SIZES", GetArgs(kSmallSizes)},
461 {"AT_MEDIUM_SIZES", GetArgs(kMediumSizes)},
462 {"AT_LARGE_SIZES", GetArgs(kLargeSizes)},
463 {"AT_ALL_SIZES", GetArgs(all_sizes)},
464
465 {"AT_ALIGNED_ONEBUF", GetArgs(kCommonSizes, 0)},
466 {"AT_ALIGNED_ONEBUF_SMALL", GetArgs(kSmallSizes, 0)},
467 {"AT_ALIGNED_ONEBUF_MEDIUM", GetArgs(kMediumSizes, 0)},
468 {"AT_ALIGNED_ONEBUF_LARGE", GetArgs(kLargeSizes, 0)},
469 {"AT_ALIGNED_ONEBUF_ALL", GetArgs(all_sizes, 0)},
470
471 {"AT_ALIGNED_TWOBUF", GetArgs(kCommonSizes, 0, 0)},
472 {"AT_ALIGNED_TWOBUF_SMALL", GetArgs(kSmallSizes, 0, 0)},
473 {"AT_ALIGNED_TWOBUF_MEDIUM", GetArgs(kMediumSizes, 0, 0)},
474 {"AT_ALIGNED_TWOBUF_LARGE", GetArgs(kLargeSizes, 0, 0)},
475 {"AT_ALIGNED_TWOBUF_ALL", GetArgs(all_sizes, 0, 0)},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700476
477 // Do not exceed 512. that is about the largest number of properties
478 // that can be created with the current property area size.
479 {"NUM_PROPS", args_vector_t{ {1}, {4}, {16}, {64}, {128}, {256}, {512} }},
480
Adhemerval Zanella7871ca12018-06-08 11:18:32 -0300481 {"MATH_COMMON", args_vector_t{ {0}, {1}, {2}, {3} }},
482 {"MATH_SINCOS_COMMON", args_vector_t{ {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7} }},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700483 };
Christopher Ferrise2188d42017-11-08 23:28:57 -0800484
485 args_vector_t args_onebuf;
486 args_vector_t args_twobuf;
487 for (int size : all_sizes) {
488 args_onebuf.push_back({size, 0});
489 args_twobuf.push_back({size, 0, 0});
490 // Skip alignments on zero sizes.
491 if (size == 0) {
492 continue;
493 }
494 for (int align1 = 1; align1 <= 32; align1 <<= 1) {
495 args_onebuf.push_back({size, align1});
496 for (int align2 = 1; align2 <= 32; align2 <<= 1) {
497 args_twobuf.push_back({size, align1, align2});
498 }
499 }
Anders Lewisa7b0f882017-07-24 20:01:13 -0700500 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800501 args_shorthand.emplace("AT_MANY_ALIGNED_ONEBUF", args_onebuf);
502 args_shorthand.emplace("AT_MANY_ALIGNED_TWOBUF", args_twobuf);
503
Anders Lewisa7b0f882017-07-24 20:01:13 -0700504 return args_shorthand;
505}
506
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700507static bool FileExists(const std::string& file) {
508 struct stat st;
509 return stat(file.c_str(), &st) != -1 && S_ISREG(st.st_mode);
510}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700511
Christopher Ferris858e3362017-11-30 08:53:15 -0800512void RegisterAllBenchmarks(const bench_opts_t& opts,
513 std::map<std::string, args_vector_t>& args_shorthand) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800514 for (auto& entry : g_str_to_func) {
Christopher Ferris4c5fde02018-01-08 16:13:14 -0800515 auto& function_info = entry.second;
Christopher Ferris858e3362017-11-30 08:53:15 -0800516 args_vector_t arg_vector;
517 args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
518 args_shorthand);
Christopher Ferris4c5fde02018-01-08 16:13:14 -0800519 RegisterGoogleBenchmarks(bench_opts_t(), opts, entry.first, run_args);
Christopher Ferris858e3362017-11-30 08:53:15 -0800520 }
521}
522
Anders Lewisa7b0f882017-07-24 20:01:13 -0700523int main(int argc, char** argv) {
524 std::map<std::string, args_vector_t> args_shorthand = GetShorthand();
525 bench_opts_t opts = ParseOpts(argc, argv);
526 std::vector<char*> new_argv(argc);
527 SanitizeOpts(argc, argv, &new_argv);
528
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700529 if (opts.xmlpath.empty()) {
530 // Don't add the default xml file if a user is specifying the tests to run.
531 if (opts.extra_benchmarks.empty()) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800532 RegisterAllBenchmarks(opts, args_shorthand);
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700533 }
534 } else if (!FileExists(opts.xmlpath)) {
535 // See if this is a file in the suites directory.
536 std::string file(android::base::GetExecutableDirectory() + "/suites/" + opts.xmlpath);
537 if (opts.xmlpath[0] == '/' || !FileExists(file)) {
538 printf("Cannot find xml file %s: does not exist or is not a file.\n", opts.xmlpath.c_str());
539 return 1;
540 }
541 opts.xmlpath = file;
542 }
543
Anders Lewisa7b0f882017-07-24 20:01:13 -0700544 if (!opts.xmlpath.empty()) {
545 if (int err = RegisterXmlBenchmarks(opts, args_shorthand)) {
546 return err;
547 }
548 }
549 RegisterCliBenchmarks(opts, args_shorthand);
550
551 // Set the thread priority to the maximum.
552 if (setpriority(PRIO_PROCESS, 0, -20)) {
553 perror("Failed to raise priority of process. Are you root?\n");
554 }
555
556 int new_argc = new_argv.size();
557 benchmark::Initialize(&new_argc, new_argv.data());
558 benchmark::RunSpecifiedBenchmarks();
559}