blob: 074c3c8fc514dc180c74ac99287bab70b39b8569 [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>
19#include <math.h>
20#include <sys/resource.h>
21
22#include <map>
23#include <mutex>
24#include <sstream>
25#include <string>
Christopher Ferris858e3362017-11-30 08:53:15 -080026#include <utility>
Anders Lewisa7b0f882017-07-24 20:01:13 -070027#include <vector>
28
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070029#include <android-base/file.h>
Christopher Ferrise2188d42017-11-08 23:28:57 -080030#include <android-base/stringprintf.h>
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070031#include <android-base/strings.h>
Anders Lewisa7b0f882017-07-24 20:01:13 -070032#include <benchmark/benchmark.h>
33#include <tinyxml2.h>
34#include "util.h"
35
Christopher Ferrise2188d42017-11-08 23:28:57 -080036static const std::vector<int> kCommonSizes{
37 8,
38 64,
39 512,
40 1 * KB,
41 8 * KB,
42 16 * KB,
43 32 * KB,
44 64 * KB,
45 128 * KB,
46};
47
48static const std::vector<int> kSmallSizes{
49 // Increment by 1
50 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
51 // Increment by 8
52 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144,
53 // Increment by 16
54 160, 176, 192, 208, 224, 240, 256,
55};
56
57static const std::vector<int> kMediumSizes{
58 512,
59 1 * KB,
60 8 * KB,
61 16 * KB,
62 32 * KB,
63 64 * KB,
64 128 * KB,
65};
66
67static const std::vector<int> kLargeSizes{
68 256 * KB,
69 512 * KB,
70 1024 * KB,
71 2048 * KB,
72};
73
Christopher Ferris858e3362017-11-30 08:53:15 -080074std::map<std::string, std::pair<benchmark_func_t, std::string>> g_str_to_func;
Anders Lewisa7b0f882017-07-24 20:01:13 -070075
76std::mutex g_map_lock;
77
78static struct option g_long_options[] =
79{
80 {"bionic_cpu", required_argument, 0, 'c'},
81 {"bionic_xml", required_argument, 0, 'x'},
82 {"bionic_iterations", required_argument, 0, 'i'},
83 {"bionic_extra", required_argument, 0, 'a'},
84 {"help", no_argument, 0, 'h'},
85 {0, 0, 0, 0},
86};
87
88typedef std::vector<std::vector<int>> args_vector_t;
89
90void Usage() {
91 printf("Usage:\n");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070092 printf("bionic_benchmarks [--bionic_cpu=<cpu_to_isolate>]\n");
93 printf(" [--bionic_xml=<path_to_xml>]\n");
Anders Lewisa7b0f882017-07-24 20:01:13 -070094 printf(" [--bionic_iterations=<num_iter>]\n");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070095 printf(" [--bionic_extra=\"<fn_name> <arg1> <arg 2> ...\"]\n");
Anders Lewisa7b0f882017-07-24 20:01:13 -070096 printf(" [<Google benchmark flags>]\n");
97 printf("Google benchmark flags:\n");
98
99 int fake_argc = 2;
100 char argv0[] = "bionic_benchmarks";
101 char argv1[] = "--help";
102 char* fake_argv[3] {argv0, argv1, NULL};
103 benchmark::Initialize(&fake_argc, fake_argv);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700104 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700105}
106
107// This function removes any bionic benchmarks command line arguments by checking them
108// against g_long_options. It fills new_argv with the filtered args.
109void SanitizeOpts(int argc, char** argv, std::vector<char*>* new_argv) {
110 // TO THOSE ADDING OPTIONS: This currently doesn't support optional arguments.
111 (*new_argv)[0] = argv[0];
112 for (int i = 1; i < argc; ++i) {
113 char* optarg = argv[i];
114 size_t opt_idx = 0;
115
116 // Iterate through g_long_options until either we hit the end or we have a match.
117 for (opt_idx = 0; g_long_options[opt_idx].name &&
118 strncmp(g_long_options[opt_idx].name, optarg + 2,
119 strlen(g_long_options[opt_idx].name)); ++opt_idx) {
120 }
121
122 if (!g_long_options[opt_idx].name) {
123 new_argv->push_back(optarg);
124 } else {
125 if (g_long_options[opt_idx].has_arg == required_argument) {
126 // If the arg was passed in with an =, it spans one char *.
127 // Otherwise, we skip a spot for the argument.
128 if (!strchr(optarg, '=')) {
129 i++;
130 }
131 }
132 }
133 }
134 new_argv->push_back(0);
135}
136
137bench_opts_t ParseOpts(int argc, char** argv) {
138 bench_opts_t opts;
139 int opt;
140 int option_index = 0;
141
Anders Lewisa7b0f882017-07-24 20:01:13 -0700142 // To make this parser handle the benchmark options silently:
143 extern int opterr;
144 opterr = 0;
145
146 while ((opt = getopt_long(argc, argv, "c:x:i:a:h", g_long_options, &option_index)) != -1) {
147 if (opt == -1) {
148 break;
149 }
150 switch (opt) {
151 case 'c':
152 if (*optarg) {
153 char* check_null;
154 opts.cpu_to_lock = strtol(optarg, &check_null, 10);
155 if (*check_null) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700156 errx(1, "ERROR: Args %s is not a valid integer.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700157 }
158 } else {
159 printf("ERROR: no argument specified for bionic_cpu\n");
160 Usage();
161 }
162 break;
163 case 'x':
164 if (*optarg) {
165 opts.xmlpath = optarg;
166 } else {
167 printf("ERROR: no argument specified for bionic_xml\n");
168 Usage();
169 }
170 break;
171 case 'a':
172 if (*optarg) {
173 opts.extra_benchmarks.push_back(optarg);
174 } else {
175 printf("ERROR: no argument specified for bionic_extra\n");
176 Usage();
177 }
178 break;
179 case 'i':
180 if (*optarg){
181 char* check_null;
182 opts.num_iterations = strtol(optarg, &check_null, 10);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700183 if (*check_null != '\0' or opts.num_iterations < 0) {
184 errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700185 }
186 } else {
187 printf("ERROR: no argument specified for bionic_iterations\n");
188 Usage();
189 }
190 break;
191 case 'h':
192 Usage();
193 break;
194 case '?':
195 break;
196 default:
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700197 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700198 }
199 }
200 return opts;
201}
202
203// This is a wrapper for every function call for per-benchmark cpu pinning.
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700204void LockAndRun(benchmark::State& state, benchmark_func_t func_to_bench, int cpu_to_lock) {
205 if (cpu_to_lock >= 0) LockToCPU(cpu_to_lock);
206
Anders Lewisa7b0f882017-07-24 20:01:13 -0700207 // To avoid having to link against Google benchmarks in libutil,
208 // benchmarks are kept without parameter information, necessitating this cast.
209 reinterpret_cast<void(*) (benchmark::State&)>(func_to_bench)(state);
210}
211
Christopher Ferrise2188d42017-11-08 23:28:57 -0800212static constexpr char kOnebufManualStr[] = "AT_ONEBUF_MANUAL_ALIGN_";
213static constexpr char kTwobufManualStr[] = "AT_TWOBUF_MANUAL_ALIGN1_";
214
215static bool ParseOnebufManualStr(std::string& arg, std::vector<int>* values) {
216 // The format of this is:
217 // AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY
218 // Where:
219 // XX is the alignment
220 // YY is the size
221 int align;
222 int size;
223 if (sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%d_SIZE_%d" , &align, &size) != 2) {
224 return false;
225 }
226
227 if (align != 0 && (align & (align - 1)) != 0) {
228 return false;
229 }
230
231 values->push_back(static_cast<int>(size));
232 values->push_back(static_cast<int>(align));
233 return true;
234}
235
236static bool ParseTwobufManualStr(std::string& arg, std::vector<int>* values) {
237 // The format of this is:
238 // AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGN2_YY_SIZE_ZZ
239 // Where:
240 // XX is the alignment of the first argument
241 // YY is the alignment of the second argument
242 // ZZ is the size
243 int align1;
244 int align2;
245 int size;
246 if (sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%d_ALIGN2_%d_SIZE_%d" ,
247 &align1, &align2, &size) != 3) {
248 return false;
249 }
250
251 // Verify the alignments are powers of 2.
252 if ((align1 != 0 && (align1 & (align1 - 1)) != 0)
253 || (align2 != 0 && (align2 & (align2 - 1)) != 0)) {
254 return false;
255 }
256
257 values->push_back(static_cast<int>(size));
258 values->push_back(static_cast<int>(align1));
259 values->push_back(static_cast<int>(align2));
260 return true;
261}
262
Anders Lewisa7b0f882017-07-24 20:01:13 -0700263args_vector_t* ResolveArgs(args_vector_t* to_populate, std::string args,
264 std::map<std::string, args_vector_t>& args_shorthand) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800265 // args is either a space-separated list of ints, a macro name, or
266 // special free form macro.
Anders Lewisa7b0f882017-07-24 20:01:13 -0700267 // To ease formatting in XML files, args is left and right trimmed.
268 if (args_shorthand.count(args)) {
269 return &args_shorthand[args];
270 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800271 // Check for free form macro.
272 if (android::base::StartsWith(args, kOnebufManualStr)) {
273 std::vector<int> values;
274 if (!ParseOnebufManualStr(args, &values)) {
275 errx(1, "ERROR: Bad format of macro %s, should be AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY",
276 args.c_str());
277 }
278 to_populate->push_back(std::move(values));
279 return to_populate;
280 } else if (android::base::StartsWith(args, kTwobufManualStr)) {
281 std::vector<int> values;
282 if (!ParseTwobufManualStr(args, &values)) {
283 errx(1,
284 "ERROR: Bad format of macro %s, should be AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGNE2_YY_SIZE_ZZ",
285 args.c_str());
286 }
287 to_populate->push_back(std::move(values));
288 return to_populate;
289 }
290
Anders Lewisa7b0f882017-07-24 20:01:13 -0700291 to_populate->push_back(std::vector<int>());
292 std::stringstream sstream(args);
293 std::string argstr;
294 while (sstream >> argstr) {
295 char* check_null;
296 int converted = static_cast<int>(strtol(argstr.c_str(), &check_null, 10));
297 if (*check_null) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700298 errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str());
Anders Lewisa7b0f882017-07-24 20:01:13 -0700299 }
300 (*to_populate)[0].push_back(converted);
301 }
302 return to_populate;
303}
304
305void RegisterGoogleBenchmarks(bench_opts_t primary_opts, bench_opts_t secondary_opts,
Elliott Hughes5cec3772018-01-19 15:45:23 -0800306 const std::string& fn_name, args_vector_t* run_args) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700307 if (g_str_to_func.find(fn_name) == g_str_to_func.end()) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700308 errx(1, "ERROR: No benchmark for function %s", fn_name.c_str());
Anders Lewisa7b0f882017-07-24 20:01:13 -0700309 }
310 long iterations_to_use = primary_opts.num_iterations ? primary_opts.num_iterations :
311 secondary_opts.num_iterations;
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700312 int cpu_to_use = -1;
313 if (primary_opts.cpu_to_lock >= 0) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700314 cpu_to_use = primary_opts.cpu_to_lock;
315
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700316 } else if (secondary_opts.cpu_to_lock >= 0) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700317 cpu_to_use = secondary_opts.cpu_to_lock;
318 }
319
Christopher Ferris858e3362017-11-30 08:53:15 -0800320 benchmark_func_t benchmark_function = g_str_to_func.at(fn_name).first;
Elliott Hughes5cec3772018-01-19 15:45:23 -0800321 for (const std::vector<int>& args : (*run_args)) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700322 auto registration = benchmark::RegisterBenchmark(fn_name.c_str(), LockAndRun,
Christopher Ferris858e3362017-11-30 08:53:15 -0800323 benchmark_function,
Anders Lewisa7b0f882017-07-24 20:01:13 -0700324 cpu_to_use)->Args(args);
325 if (iterations_to_use > 0) {
326 registration->Iterations(iterations_to_use);
327 }
328 }
329}
330
331void RegisterCliBenchmarks(bench_opts_t cmdline_opts,
332 std::map<std::string, args_vector_t>& args_shorthand) {
333 // Register any of the extra benchmarks that were specified in the options.
334 args_vector_t arg_vector;
335 args_vector_t* run_args = &arg_vector;
Elliott Hughes5cec3772018-01-19 15:45:23 -0800336 for (const std::string& extra_fn : cmdline_opts.extra_benchmarks) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700337 android::base::Trim(extra_fn);
Elliott Hughes5cec3772018-01-19 15:45:23 -0800338 size_t first_space_pos = extra_fn.find(' ');
Anders Lewisa7b0f882017-07-24 20:01:13 -0700339 std::string fn_name = extra_fn.substr(0, first_space_pos);
340 std::string cmd_args;
341 if (first_space_pos != std::string::npos) {
Elliott Hughes5cec3772018-01-19 15:45:23 -0800342 cmd_args = extra_fn.substr(extra_fn.find(' ') + 1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700343 } else {
344 cmd_args = "";
345 }
346 run_args = ResolveArgs(run_args, cmd_args, args_shorthand);
347 RegisterGoogleBenchmarks(bench_opts_t(), cmdline_opts, fn_name, run_args);
348
349 run_args = &arg_vector;
350 arg_vector.clear();
351 }
352}
353
354int RegisterXmlBenchmarks(bench_opts_t cmdline_opts,
355 std::map<std::string, args_vector_t>& args_shorthand) {
356 // Structure of the XML file:
357 // - Element "fn" Function to benchmark.
358 // - - Element "iterations" Number of iterations to run. Leaving this blank uses
359 // Google benchmarks' convergence heuristics.
360 // - - Element "cpu" CPU to isolate to, if any.
361 // - - Element "args" Whitespace-separated list of per-function integer arguments, or
362 // one of the macros defined in util.h.
363 tinyxml2::XMLDocument doc;
Elliott Hughesc2223f72017-08-08 11:23:27 -0700364 if (doc.LoadFile(cmdline_opts.xmlpath.c_str()) != tinyxml2::XML_SUCCESS) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700365 doc.PrintError();
366 return doc.ErrorID();
367 }
368
369 // Read and register the functions.
370 tinyxml2::XMLNode* fn = doc.FirstChildElement("fn");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700371 while (fn) {
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700372 if (fn == fn->ToComment()) {
373 // Skip comments.
374 fn = fn->NextSibling();
375 continue;
376 }
377
Anders Lewisa7b0f882017-07-24 20:01:13 -0700378 auto fn_elem = fn->FirstChildElement("name");
379 if (!fn_elem) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700380 errx(1, "ERROR: Malformed XML entry: missing name element.");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700381 }
382 std::string fn_name = fn_elem->GetText();
383 if (fn_name.empty()) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700384 errx(1, "ERROR: Malformed XML entry: error parsing name text.");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700385 }
386 auto* xml_args = fn->FirstChildElement("args");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700387 args_vector_t arg_vector;
388 args_vector_t* run_args = ResolveArgs(&arg_vector,
389 xml_args ? android::base::Trim(xml_args->GetText()) : "",
390 args_shorthand);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700391
392 // XML values for CPU and iterations take precedence over those passed in via CLI.
393 bench_opts_t xml_opts{};
394 auto* num_iterations_elem = fn->FirstChildElement("iterations");
395 if (num_iterations_elem) {
396 int temp;
397 num_iterations_elem->QueryIntText(&temp);
398 xml_opts.num_iterations = temp;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700399 }
400 auto* cpu_to_lock_elem = fn->FirstChildElement("cpu");
401 if (cpu_to_lock_elem) {
402 int temp;
403 cpu_to_lock_elem->QueryIntText(&temp);
404 xml_opts.cpu_to_lock = temp;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700405 }
406
407 RegisterGoogleBenchmarks(xml_opts, cmdline_opts, fn_name, run_args);
408
409 fn = fn->NextSibling();
Anders Lewisa7b0f882017-07-24 20:01:13 -0700410 }
411 return 0;
412}
413
Christopher Ferrise2188d42017-11-08 23:28:57 -0800414static void SetArgs(const std::vector<int>& sizes, args_vector_t* args) {
415 for (int size : sizes) {
416 args->push_back({size});
417 }
418}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700419
Christopher Ferrise2188d42017-11-08 23:28:57 -0800420static void SetArgs(const std::vector<int>& sizes, int align, args_vector_t* args) {
421 for (int size : sizes) {
422 args->push_back({size, align});
423 }
424}
425
426
427static void SetArgs(const std::vector<int>& sizes, int align1, int align2, args_vector_t* args) {
428 for (int size : sizes) {
429 args->push_back({size, align1, align2});
430 }
431}
432
433static args_vector_t GetArgs(const std::vector<int>& sizes) {
434 args_vector_t args;
435 SetArgs(sizes, &args);
436 return args;
437}
438
439static args_vector_t GetArgs(const std::vector<int>& sizes, int align) {
440 args_vector_t args;
441 SetArgs(sizes, align, &args);
442 return args;
443}
444
445static args_vector_t GetArgs(const std::vector<int>& sizes, int align1, int align2) {
446 args_vector_t args;
447 SetArgs(sizes, align1, align2, &args);
448 return args;
449}
450
451std::map<std::string, args_vector_t> GetShorthand() {
452 std::vector<int> all_sizes(kSmallSizes);
453 all_sizes.insert(all_sizes.end(), kMediumSizes.begin(), kMediumSizes.end());
454 all_sizes.insert(all_sizes.end(), kLargeSizes.begin(), kLargeSizes.end());
455
456 std::map<std::string, args_vector_t> args_shorthand {
457 {"AT_COMMON_SIZES", GetArgs(kCommonSizes)},
458 {"AT_SMALL_SIZES", GetArgs(kSmallSizes)},
459 {"AT_MEDIUM_SIZES", GetArgs(kMediumSizes)},
460 {"AT_LARGE_SIZES", GetArgs(kLargeSizes)},
461 {"AT_ALL_SIZES", GetArgs(all_sizes)},
462
463 {"AT_ALIGNED_ONEBUF", GetArgs(kCommonSizes, 0)},
464 {"AT_ALIGNED_ONEBUF_SMALL", GetArgs(kSmallSizes, 0)},
465 {"AT_ALIGNED_ONEBUF_MEDIUM", GetArgs(kMediumSizes, 0)},
466 {"AT_ALIGNED_ONEBUF_LARGE", GetArgs(kLargeSizes, 0)},
467 {"AT_ALIGNED_ONEBUF_ALL", GetArgs(all_sizes, 0)},
468
469 {"AT_ALIGNED_TWOBUF", GetArgs(kCommonSizes, 0, 0)},
470 {"AT_ALIGNED_TWOBUF_SMALL", GetArgs(kSmallSizes, 0, 0)},
471 {"AT_ALIGNED_TWOBUF_MEDIUM", GetArgs(kMediumSizes, 0, 0)},
472 {"AT_ALIGNED_TWOBUF_LARGE", GetArgs(kLargeSizes, 0, 0)},
473 {"AT_ALIGNED_TWOBUF_ALL", GetArgs(all_sizes, 0, 0)},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700474
475 // Do not exceed 512. that is about the largest number of properties
476 // that can be created with the current property area size.
477 {"NUM_PROPS", args_vector_t{ {1}, {4}, {16}, {64}, {128}, {256}, {512} }},
478
479 {"MATH_COMMON", args_vector_t{ {0}, {1}, {2}, {3} }}
480 };
Christopher Ferrise2188d42017-11-08 23:28:57 -0800481
482 args_vector_t args_onebuf;
483 args_vector_t args_twobuf;
484 for (int size : all_sizes) {
485 args_onebuf.push_back({size, 0});
486 args_twobuf.push_back({size, 0, 0});
487 // Skip alignments on zero sizes.
488 if (size == 0) {
489 continue;
490 }
491 for (int align1 = 1; align1 <= 32; align1 <<= 1) {
492 args_onebuf.push_back({size, align1});
493 for (int align2 = 1; align2 <= 32; align2 <<= 1) {
494 args_twobuf.push_back({size, align1, align2});
495 }
496 }
Anders Lewisa7b0f882017-07-24 20:01:13 -0700497 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800498 args_shorthand.emplace("AT_MANY_ALIGNED_ONEBUF", args_onebuf);
499 args_shorthand.emplace("AT_MANY_ALIGNED_TWOBUF", args_twobuf);
500
Anders Lewisa7b0f882017-07-24 20:01:13 -0700501 return args_shorthand;
502}
503
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700504static bool FileExists(const std::string& file) {
505 struct stat st;
506 return stat(file.c_str(), &st) != -1 && S_ISREG(st.st_mode);
507}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700508
Christopher Ferris858e3362017-11-30 08:53:15 -0800509void RegisterAllBenchmarks(const bench_opts_t& opts,
510 std::map<std::string, args_vector_t>& args_shorthand) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800511 for (auto& entry : g_str_to_func) {
Christopher Ferris4c5fde02018-01-08 16:13:14 -0800512 auto& function_info = entry.second;
Christopher Ferris858e3362017-11-30 08:53:15 -0800513 args_vector_t arg_vector;
514 args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
515 args_shorthand);
Christopher Ferris4c5fde02018-01-08 16:13:14 -0800516 RegisterGoogleBenchmarks(bench_opts_t(), opts, entry.first, run_args);
Christopher Ferris858e3362017-11-30 08:53:15 -0800517 }
518}
519
Anders Lewisa7b0f882017-07-24 20:01:13 -0700520int main(int argc, char** argv) {
521 std::map<std::string, args_vector_t> args_shorthand = GetShorthand();
522 bench_opts_t opts = ParseOpts(argc, argv);
523 std::vector<char*> new_argv(argc);
524 SanitizeOpts(argc, argv, &new_argv);
525
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700526 if (opts.xmlpath.empty()) {
527 // Don't add the default xml file if a user is specifying the tests to run.
528 if (opts.extra_benchmarks.empty()) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800529 RegisterAllBenchmarks(opts, args_shorthand);
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700530 }
531 } else if (!FileExists(opts.xmlpath)) {
532 // See if this is a file in the suites directory.
533 std::string file(android::base::GetExecutableDirectory() + "/suites/" + opts.xmlpath);
534 if (opts.xmlpath[0] == '/' || !FileExists(file)) {
535 printf("Cannot find xml file %s: does not exist or is not a file.\n", opts.xmlpath.c_str());
536 return 1;
537 }
538 opts.xmlpath = file;
539 }
540
Anders Lewisa7b0f882017-07-24 20:01:13 -0700541 if (!opts.xmlpath.empty()) {
542 if (int err = RegisterXmlBenchmarks(opts, args_shorthand)) {
543 return err;
544 }
545 }
546 RegisterCliBenchmarks(opts, args_shorthand);
547
548 // Set the thread priority to the maximum.
549 if (setpriority(PRIO_PROCESS, 0, -20)) {
550 perror("Failed to raise priority of process. Are you root?\n");
551 }
552
553 int new_argc = new_argv.size();
554 benchmark::Initialize(&new_argc, new_argv.data());
555 benchmark::RunSpecifiedBenchmarks();
556}