blob: d82c739a3a6e1249fe6b41749407df2ebe9234dd [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
142 opts.cpu_to_lock = LONG_MAX;
143 opts.num_iterations = 0;
144
145 // To make this parser handle the benchmark options silently:
146 extern int opterr;
147 opterr = 0;
148
149 while ((opt = getopt_long(argc, argv, "c:x:i:a:h", g_long_options, &option_index)) != -1) {
150 if (opt == -1) {
151 break;
152 }
153 switch (opt) {
154 case 'c':
155 if (*optarg) {
156 char* check_null;
157 opts.cpu_to_lock = strtol(optarg, &check_null, 10);
158 if (*check_null) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700159 errx(1, "ERROR: Args %s is not a valid integer.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700160 }
161 } else {
162 printf("ERROR: no argument specified for bionic_cpu\n");
163 Usage();
164 }
165 break;
166 case 'x':
167 if (*optarg) {
168 opts.xmlpath = optarg;
169 } else {
170 printf("ERROR: no argument specified for bionic_xml\n");
171 Usage();
172 }
173 break;
174 case 'a':
175 if (*optarg) {
176 opts.extra_benchmarks.push_back(optarg);
177 } else {
178 printf("ERROR: no argument specified for bionic_extra\n");
179 Usage();
180 }
181 break;
182 case 'i':
183 if (*optarg){
184 char* check_null;
185 opts.num_iterations = strtol(optarg, &check_null, 10);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700186 if (*check_null != '\0' or opts.num_iterations < 0) {
187 errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700188 }
189 } else {
190 printf("ERROR: no argument specified for bionic_iterations\n");
191 Usage();
192 }
193 break;
194 case 'h':
195 Usage();
196 break;
197 case '?':
198 break;
199 default:
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700200 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700201 }
202 }
203 return opts;
204}
205
206// This is a wrapper for every function call for per-benchmark cpu pinning.
207void LockAndRun(benchmark::State& state, benchmark_func_t func_to_bench, long cpu_to_lock) {
208 if (cpu_to_lock != LONG_MAX) LockToCPU(cpu_to_lock);
209 // To avoid having to link against Google benchmarks in libutil,
210 // benchmarks are kept without parameter information, necessitating this cast.
211 reinterpret_cast<void(*) (benchmark::State&)>(func_to_bench)(state);
212}
213
Christopher Ferrise2188d42017-11-08 23:28:57 -0800214static constexpr char kOnebufManualStr[] = "AT_ONEBUF_MANUAL_ALIGN_";
215static constexpr char kTwobufManualStr[] = "AT_TWOBUF_MANUAL_ALIGN1_";
216
217static bool ParseOnebufManualStr(std::string& arg, std::vector<int>* values) {
218 // The format of this is:
219 // AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY
220 // Where:
221 // XX is the alignment
222 // YY is the size
223 int align;
224 int size;
225 if (sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%d_SIZE_%d" , &align, &size) != 2) {
226 return false;
227 }
228
229 if (align != 0 && (align & (align - 1)) != 0) {
230 return false;
231 }
232
233 values->push_back(static_cast<int>(size));
234 values->push_back(static_cast<int>(align));
235 return true;
236}
237
238static bool ParseTwobufManualStr(std::string& arg, std::vector<int>* values) {
239 // 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
245 int align1;
246 int align2;
247 int size;
248 if (sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%d_ALIGN2_%d_SIZE_%d" ,
249 &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
259 values->push_back(static_cast<int>(size));
260 values->push_back(static_cast<int>(align1));
261 values->push_back(static_cast<int>(align2));
262 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)) {
275 std::vector<int> values;
276 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)) {
283 std::vector<int> values;
284 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
Anders Lewisa7b0f882017-07-24 20:01:13 -0700293 to_populate->push_back(std::vector<int>());
294 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,
308 std::string fn_name, args_vector_t* run_args) {
309 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;
314 int cpu_to_use = INT_MAX;
315 if (primary_opts.cpu_to_lock != INT_MAX) {
316 cpu_to_use = primary_opts.cpu_to_lock;
317
318 } else if (secondary_opts.cpu_to_lock != INT_MAX) {
319 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;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700323 for (std::vector<int> args : (*run_args)) {
324 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;
338 for (std::string extra_fn : cmdline_opts.extra_benchmarks) {
339 android::base::Trim(extra_fn);
340 size_t first_space_pos = extra_fn.find(" ");
341 std::string fn_name = extra_fn.substr(0, first_space_pos);
342 std::string cmd_args;
343 if (first_space_pos != std::string::npos) {
344 cmd_args = extra_fn.substr(extra_fn.find(" ") + 1);
345 } 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;
401 } else {
402 xml_opts.num_iterations = 0;
403 }
404 auto* cpu_to_lock_elem = fn->FirstChildElement("cpu");
405 if (cpu_to_lock_elem) {
406 int temp;
407 cpu_to_lock_elem->QueryIntText(&temp);
408 xml_opts.cpu_to_lock = temp;
409 } else {
410 xml_opts.cpu_to_lock = INT_MAX;
411 }
412
413 RegisterGoogleBenchmarks(xml_opts, cmdline_opts, fn_name, run_args);
414
415 fn = fn->NextSibling();
Anders Lewisa7b0f882017-07-24 20:01:13 -0700416 }
417 return 0;
418}
419
Christopher Ferrise2188d42017-11-08 23:28:57 -0800420static void SetArgs(const std::vector<int>& sizes, args_vector_t* args) {
421 for (int size : sizes) {
422 args->push_back({size});
423 }
424}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700425
Christopher Ferrise2188d42017-11-08 23:28:57 -0800426static void SetArgs(const std::vector<int>& sizes, int align, args_vector_t* args) {
427 for (int size : sizes) {
428 args->push_back({size, align});
429 }
430}
431
432
433static void SetArgs(const std::vector<int>& sizes, int align1, int align2, args_vector_t* args) {
434 for (int size : sizes) {
435 args->push_back({size, align1, align2});
436 }
437}
438
439static args_vector_t GetArgs(const std::vector<int>& sizes) {
440 args_vector_t args;
441 SetArgs(sizes, &args);
442 return args;
443}
444
445static args_vector_t GetArgs(const std::vector<int>& sizes, int align) {
446 args_vector_t args;
447 SetArgs(sizes, align, &args);
448 return args;
449}
450
451static args_vector_t GetArgs(const std::vector<int>& sizes, int align1, int align2) {
452 args_vector_t args;
453 SetArgs(sizes, align1, align2, &args);
454 return args;
455}
456
457std::map<std::string, args_vector_t> GetShorthand() {
458 std::vector<int> all_sizes(kSmallSizes);
459 all_sizes.insert(all_sizes.end(), kMediumSizes.begin(), kMediumSizes.end());
460 all_sizes.insert(all_sizes.end(), kLargeSizes.begin(), kLargeSizes.end());
461
462 std::map<std::string, args_vector_t> args_shorthand {
463 {"AT_COMMON_SIZES", GetArgs(kCommonSizes)},
464 {"AT_SMALL_SIZES", GetArgs(kSmallSizes)},
465 {"AT_MEDIUM_SIZES", GetArgs(kMediumSizes)},
466 {"AT_LARGE_SIZES", GetArgs(kLargeSizes)},
467 {"AT_ALL_SIZES", GetArgs(all_sizes)},
468
469 {"AT_ALIGNED_ONEBUF", GetArgs(kCommonSizes, 0)},
470 {"AT_ALIGNED_ONEBUF_SMALL", GetArgs(kSmallSizes, 0)},
471 {"AT_ALIGNED_ONEBUF_MEDIUM", GetArgs(kMediumSizes, 0)},
472 {"AT_ALIGNED_ONEBUF_LARGE", GetArgs(kLargeSizes, 0)},
473 {"AT_ALIGNED_ONEBUF_ALL", GetArgs(all_sizes, 0)},
474
475 {"AT_ALIGNED_TWOBUF", GetArgs(kCommonSizes, 0, 0)},
476 {"AT_ALIGNED_TWOBUF_SMALL", GetArgs(kSmallSizes, 0, 0)},
477 {"AT_ALIGNED_TWOBUF_MEDIUM", GetArgs(kMediumSizes, 0, 0)},
478 {"AT_ALIGNED_TWOBUF_LARGE", GetArgs(kLargeSizes, 0, 0)},
479 {"AT_ALIGNED_TWOBUF_ALL", GetArgs(all_sizes, 0, 0)},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700480
481 // Do not exceed 512. that is about the largest number of properties
482 // that can be created with the current property area size.
483 {"NUM_PROPS", args_vector_t{ {1}, {4}, {16}, {64}, {128}, {256}, {512} }},
484
485 {"MATH_COMMON", args_vector_t{ {0}, {1}, {2}, {3} }}
486 };
Christopher Ferrise2188d42017-11-08 23:28:57 -0800487
488 args_vector_t args_onebuf;
489 args_vector_t args_twobuf;
490 for (int size : all_sizes) {
491 args_onebuf.push_back({size, 0});
492 args_twobuf.push_back({size, 0, 0});
493 // Skip alignments on zero sizes.
494 if (size == 0) {
495 continue;
496 }
497 for (int align1 = 1; align1 <= 32; align1 <<= 1) {
498 args_onebuf.push_back({size, align1});
499 for (int align2 = 1; align2 <= 32; align2 <<= 1) {
500 args_twobuf.push_back({size, align1, align2});
501 }
502 }
Anders Lewisa7b0f882017-07-24 20:01:13 -0700503 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800504 args_shorthand.emplace("AT_MANY_ALIGNED_ONEBUF", args_onebuf);
505 args_shorthand.emplace("AT_MANY_ALIGNED_TWOBUF", args_twobuf);
506
Anders Lewisa7b0f882017-07-24 20:01:13 -0700507 return args_shorthand;
508}
509
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700510static bool FileExists(const std::string& file) {
511 struct stat st;
512 return stat(file.c_str(), &st) != -1 && S_ISREG(st.st_mode);
513}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700514
Christopher Ferris858e3362017-11-30 08:53:15 -0800515void RegisterAllBenchmarks(const bench_opts_t& opts,
516 std::map<std::string, args_vector_t>& args_shorthand) {
517 // Add the property tests at the end since they might cause segfaults in
518 // tests running afterwards (b/62197783).
519 std::vector<std::string> prop_tests;
520
521 for (auto& entry : g_str_to_func) {
522 if (android::base::StartsWith(entry.first, "BM_property_")) {
523 prop_tests.push_back(entry.first);
524 } else {
525 auto& function_info = entry.second;
526 args_vector_t arg_vector;
527 args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
528 args_shorthand);
529 RegisterGoogleBenchmarks(bench_opts_t(), opts, entry.first, run_args);
530 }
531 }
532
533 for (auto& prop_name : prop_tests) {
534 auto& function_info = g_str_to_func.at(prop_name);
535 args_vector_t arg_vector;
536 args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
537 args_shorthand);
538 RegisterGoogleBenchmarks(bench_opts_t(), opts, prop_name, run_args);
539 }
540}
541
Anders Lewisa7b0f882017-07-24 20:01:13 -0700542int main(int argc, char** argv) {
543 std::map<std::string, args_vector_t> args_shorthand = GetShorthand();
544 bench_opts_t opts = ParseOpts(argc, argv);
545 std::vector<char*> new_argv(argc);
546 SanitizeOpts(argc, argv, &new_argv);
547
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700548 if (opts.xmlpath.empty()) {
549 // Don't add the default xml file if a user is specifying the tests to run.
550 if (opts.extra_benchmarks.empty()) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800551 RegisterAllBenchmarks(opts, args_shorthand);
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700552 }
553 } else if (!FileExists(opts.xmlpath)) {
554 // See if this is a file in the suites directory.
555 std::string file(android::base::GetExecutableDirectory() + "/suites/" + opts.xmlpath);
556 if (opts.xmlpath[0] == '/' || !FileExists(file)) {
557 printf("Cannot find xml file %s: does not exist or is not a file.\n", opts.xmlpath.c_str());
558 return 1;
559 }
560 opts.xmlpath = file;
561 }
562
Anders Lewisa7b0f882017-07-24 20:01:13 -0700563 if (!opts.xmlpath.empty()) {
564 if (int err = RegisterXmlBenchmarks(opts, args_shorthand)) {
565 return err;
566 }
567 }
568 RegisterCliBenchmarks(opts, args_shorthand);
569
570 // Set the thread priority to the maximum.
571 if (setpriority(PRIO_PROCESS, 0, -20)) {
572 perror("Failed to raise priority of process. Are you root?\n");
573 }
574
575 int new_argc = new_argv.size();
576 benchmark::Initialize(&new_argc, new_argv.data());
577 benchmark::RunSpecifiedBenchmarks();
578}