blob: a03a73cc47dda3a1e2f795a46543c70f61588632 [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>
Elliott Hughese86a03f2025-06-05 09:23:19 -070021#include <sys/param.h>
Anders Lewisa7b0f882017-07-24 20:01:13 -070022#include <sys/resource.h>
23
24#include <map>
25#include <mutex>
26#include <sstream>
27#include <string>
Christopher Ferris858e3362017-11-30 08:53:15 -080028#include <utility>
Anders Lewisa7b0f882017-07-24 20:01:13 -070029#include <vector>
30
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070031#include <android-base/file.h>
Christopher Ferrise2188d42017-11-08 23:28:57 -080032#include <android-base/stringprintf.h>
Christopher Ferrisd9d39be2017-08-23 18:03:51 -070033#include <android-base/strings.h>
Anders Lewisa7b0f882017-07-24 20:01:13 -070034#include <benchmark/benchmark.h>
35#include <tinyxml2.h>
36#include "util.h"
37
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -030038#define _STR(x) #x
39#define STRINGFY(x) _STR(x)
40
Christopher Ferrise2188d42017-11-08 23:28:57 -080041static const std::vector<int> kCommonSizes{
42 8,
Jake Weinstein4b111922020-02-19 17:12:48 +010043 16,
44 32,
Christopher Ferrise2188d42017-11-08 23:28:57 -080045 64,
46 512,
47 1 * KB,
48 8 * KB,
49 16 * KB,
50 32 * KB,
51 64 * KB,
52 128 * KB,
53};
54
55static const std::vector<int> kSmallSizes{
56 // Increment by 1
57 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
58 // Increment by 8
59 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144,
60 // Increment by 16
61 160, 176, 192, 208, 224, 240, 256,
62};
63
64static const std::vector<int> kMediumSizes{
65 512,
66 1 * KB,
67 8 * KB,
68 16 * KB,
69 32 * KB,
70 64 * KB,
71 128 * KB,
72};
73
74static const std::vector<int> kLargeSizes{
75 256 * KB,
76 512 * KB,
77 1024 * KB,
78 2048 * KB,
79};
80
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -030081static std::map<std::string, const std::vector<int> &> kSizes{
82 { "SMALL", kSmallSizes },
83 { "MEDIUM", kMediumSizes },
84 { "LARGE", kLargeSizes },
85};
86
Christopher Ferris858e3362017-11-30 08:53:15 -080087std::map<std::string, std::pair<benchmark_func_t, std::string>> g_str_to_func;
Anders Lewisa7b0f882017-07-24 20:01:13 -070088
89std::mutex g_map_lock;
90
91static struct option g_long_options[] =
92{
Yi Kong32bc0fc2018-08-02 17:31:13 -070093 {"bionic_cpu", required_argument, nullptr, 'c'},
94 {"bionic_xml", required_argument, nullptr, 'x'},
95 {"bionic_iterations", required_argument, nullptr, 'i'},
96 {"bionic_extra", required_argument, nullptr, 'a'},
97 {"help", no_argument, nullptr, 'h'},
98 {nullptr, 0, nullptr, 0},
Anders Lewisa7b0f882017-07-24 20:01:13 -070099};
100
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700101typedef std::vector<std::vector<int64_t>> args_vector_t;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700102
103void Usage() {
104 printf("Usage:\n");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700105 printf("bionic_benchmarks [--bionic_cpu=<cpu_to_isolate>]\n");
106 printf(" [--bionic_xml=<path_to_xml>]\n");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700107 printf(" [--bionic_iterations=<num_iter>]\n");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700108 printf(" [--bionic_extra=\"<fn_name> <arg1> <arg 2> ...\"]\n");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700109 printf(" [<Google benchmark flags>]\n");
110 printf("Google benchmark flags:\n");
111
112 int fake_argc = 2;
113 char argv0[] = "bionic_benchmarks";
114 char argv1[] = "--help";
Yi Kong32bc0fc2018-08-02 17:31:13 -0700115 char* fake_argv[3] {argv0, argv1, nullptr};
Anders Lewisa7b0f882017-07-24 20:01:13 -0700116 benchmark::Initialize(&fake_argc, fake_argv);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700117 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700118}
119
120// This function removes any bionic benchmarks command line arguments by checking them
121// against g_long_options. It fills new_argv with the filtered args.
122void SanitizeOpts(int argc, char** argv, std::vector<char*>* new_argv) {
123 // TO THOSE ADDING OPTIONS: This currently doesn't support optional arguments.
124 (*new_argv)[0] = argv[0];
125 for (int i = 1; i < argc; ++i) {
126 char* optarg = argv[i];
127 size_t opt_idx = 0;
128
129 // Iterate through g_long_options until either we hit the end or we have a match.
130 for (opt_idx = 0; g_long_options[opt_idx].name &&
131 strncmp(g_long_options[opt_idx].name, optarg + 2,
132 strlen(g_long_options[opt_idx].name)); ++opt_idx) {
133 }
134
135 if (!g_long_options[opt_idx].name) {
136 new_argv->push_back(optarg);
137 } else {
138 if (g_long_options[opt_idx].has_arg == required_argument) {
139 // If the arg was passed in with an =, it spans one char *.
140 // Otherwise, we skip a spot for the argument.
141 if (!strchr(optarg, '=')) {
142 i++;
143 }
144 }
145 }
146 }
Yi Kong32bc0fc2018-08-02 17:31:13 -0700147 new_argv->push_back(nullptr);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700148}
149
150bench_opts_t ParseOpts(int argc, char** argv) {
151 bench_opts_t opts;
152 int opt;
153 int option_index = 0;
154
Anders Lewisa7b0f882017-07-24 20:01:13 -0700155 // To make this parser handle the benchmark options silently:
156 extern int opterr;
157 opterr = 0;
158
159 while ((opt = getopt_long(argc, argv, "c:x:i:a:h", g_long_options, &option_index)) != -1) {
160 if (opt == -1) {
161 break;
162 }
163 switch (opt) {
164 case 'c':
165 if (*optarg) {
166 char* check_null;
167 opts.cpu_to_lock = strtol(optarg, &check_null, 10);
168 if (*check_null) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700169 errx(1, "ERROR: Args %s is not a valid integer.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700170 }
171 } else {
172 printf("ERROR: no argument specified for bionic_cpu\n");
173 Usage();
174 }
175 break;
176 case 'x':
177 if (*optarg) {
178 opts.xmlpath = optarg;
179 } else {
180 printf("ERROR: no argument specified for bionic_xml\n");
181 Usage();
182 }
183 break;
184 case 'a':
185 if (*optarg) {
186 opts.extra_benchmarks.push_back(optarg);
187 } else {
188 printf("ERROR: no argument specified for bionic_extra\n");
189 Usage();
190 }
191 break;
192 case 'i':
193 if (*optarg){
194 char* check_null;
195 opts.num_iterations = strtol(optarg, &check_null, 10);
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700196 if (*check_null != '\0' or opts.num_iterations < 0) {
197 errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700198 }
199 } else {
200 printf("ERROR: no argument specified for bionic_iterations\n");
201 Usage();
202 }
203 break;
204 case 'h':
205 Usage();
206 break;
207 case '?':
208 break;
209 default:
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700210 exit(1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700211 }
212 }
213 return opts;
214}
215
216// This is a wrapper for every function call for per-benchmark cpu pinning.
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700217void LockAndRun(benchmark::State& state, benchmark_func_t func_to_bench, int cpu_to_lock) {
218 if (cpu_to_lock >= 0) LockToCPU(cpu_to_lock);
219
Anders Lewisa7b0f882017-07-24 20:01:13 -0700220 // To avoid having to link against Google benchmarks in libutil,
221 // benchmarks are kept without parameter information, necessitating this cast.
222 reinterpret_cast<void(*) (benchmark::State&)>(func_to_bench)(state);
223}
224
Christopher Ferrise2188d42017-11-08 23:28:57 -0800225static constexpr char kOnebufManualStr[] = "AT_ONEBUF_MANUAL_ALIGN_";
226static constexpr char kTwobufManualStr[] = "AT_TWOBUF_MANUAL_ALIGN1_";
227
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300228static bool ParseOnebufManualStr(std::string& arg, args_vector_t* to_populate) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800229 // The format of this is:
230 // AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY
231 // Where:
232 // XX is the alignment
233 // YY is the size
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300234 // The YY size can be either a number or a string representing the pre-defined
235 // sets of values:
236 // SMALL (for values between 1 and 256)
237 // MEDIUM (for values between 512 and 128KB)
238 // LARGE (for values between 256KB and 2048KB)
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700239 int64_t align;
240 int64_t size;
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300241 char sizes[32] = { 0 };
242 int ret;
243
244 ret = sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%" SCNd64 "_SIZE_%" SCNd64,
245 &align, &size);
246 if (ret == 1) {
247 ret = sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%" SCNd64 "_SIZE_"
248 "%" STRINGFY(sizeof(sizes)-1) "s", &align, sizes);
249 }
250 if (ret != 2) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800251 return false;
252 }
253
Elliott Hughese86a03f2025-06-05 09:23:19 -0700254 // Verify the alignment is a power of 2.
255 if (align != 0 && !powerof2(align)) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800256 return false;
257 }
258
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300259 auto sit = kSizes.find(sizes);
260 if (sit == kSizes.cend()) {
261 to_populate->push_back({size, align});
262 } else {
263 for (auto ssize : sit->second) {
264 to_populate->push_back({ssize, align});
265 }
266 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800267 return true;
268}
269
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300270static bool ParseTwobufManualStr(std::string& arg, args_vector_t* to_populate) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800271 // The format of this is:
272 // AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGN2_YY_SIZE_ZZ
273 // Where:
274 // XX is the alignment of the first argument
275 // YY is the alignment of the second argument
276 // ZZ is the size
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300277 // The ZZ size can be either a number or a string representing the pre-defined
278 // sets of values:
279 // SMALL (for values between 1 and 256)
280 // MEDIUM (for values between 512 and 128KB)
281 // LARGE (for values between 256KB and 2048KB)
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700282 int64_t align1;
283 int64_t align2;
284 int64_t size;
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300285 char sizes[32] = { 0 };
286 int ret;
287
288 ret = sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%" SCNd64 "_ALIGN2_%" SCNd64 "_SIZE_%" SCNd64,
289 &align1, &align2, &size);
290 if (ret == 2) {
291 ret = sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%" SCNd64 "_ALIGN2_%" SCNd64 "_SIZE_"
292 "%" STRINGFY(sizeof(sizes)-1) "s",
293 &align1, &align2, sizes);
294 }
295 if (ret != 3) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800296 return false;
297 }
298
299 // Verify the alignments are powers of 2.
Elliott Hughese86a03f2025-06-05 09:23:19 -0700300 if ((align1 != 0 && !powerof2(align1)) || (align2 != 0 && !powerof2(align2))) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800301 return false;
302 }
303
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300304 auto sit = kSizes.find(sizes);
305 if (sit == kSizes.cend()) {
306 to_populate->push_back({size, align1, align2});
307 } else {
308 for (auto ssize : sit->second) {
309 to_populate->push_back({ssize, align1, align2});
310 }
311 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800312 return true;
313}
314
Anders Lewisa7b0f882017-07-24 20:01:13 -0700315args_vector_t* ResolveArgs(args_vector_t* to_populate, std::string args,
316 std::map<std::string, args_vector_t>& args_shorthand) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800317 // args is either a space-separated list of ints, a macro name, or
318 // special free form macro.
Anders Lewisa7b0f882017-07-24 20:01:13 -0700319 // To ease formatting in XML files, args is left and right trimmed.
320 if (args_shorthand.count(args)) {
321 return &args_shorthand[args];
322 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800323 // Check for free form macro.
324 if (android::base::StartsWith(args, kOnebufManualStr)) {
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300325 if (!ParseOnebufManualStr(args, to_populate)) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800326 errx(1, "ERROR: Bad format of macro %s, should be AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY",
327 args.c_str());
328 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800329 return to_populate;
330 } else if (android::base::StartsWith(args, kTwobufManualStr)) {
Adhemerval Zanellaeda94aa2018-06-26 10:27:10 -0300331 if (!ParseTwobufManualStr(args, to_populate)) {
Christopher Ferrise2188d42017-11-08 23:28:57 -0800332 errx(1,
333 "ERROR: Bad format of macro %s, should be AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGNE2_YY_SIZE_ZZ",
334 args.c_str());
335 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800336 return to_populate;
337 }
338
Christopher Ferrisf2d93d62023-05-26 13:47:53 -0700339 std::string trimmed_args = android::base::Trim(args);
340 if (!trimmed_args.empty()) {
341 std::stringstream sstream(trimmed_args);
342 std::string argstr;
343 while (sstream >> argstr) {
344 char* check_null;
345 int converted = static_cast<int>(strtol(argstr.c_str(), &check_null, 10));
346 if (*check_null == '\0') {
347 to_populate->emplace_back(std::vector<int64_t>{converted});
348 continue;
349 } else if (*check_null == '/') {
350 // The only supported format with a / is \d+(/\d+)\s*. Example 8/8/8 or 16/23.
351 std::vector<int64_t> test_args{converted};
352 while (true) {
353 converted = static_cast<int>(strtol(check_null + 1, &check_null, 10));
354 test_args.push_back(converted);
355 if (*check_null == '\0') {
356 to_populate->emplace_back(std::move(test_args));
357 break;
358 } else if (*check_null != '/') {
359 errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str());
360 }
361 }
362 } else {
363 errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str());
364 }
Anders Lewisa7b0f882017-07-24 20:01:13 -0700365 }
Christopher Ferrisf2d93d62023-05-26 13:47:53 -0700366 } else {
367 // No arguments, only the base benchmark.
368 to_populate->emplace_back(std::vector<int64_t>{});
Anders Lewisa7b0f882017-07-24 20:01:13 -0700369 }
370 return to_populate;
371}
372
373void RegisterGoogleBenchmarks(bench_opts_t primary_opts, bench_opts_t secondary_opts,
Elliott Hughes5cec3772018-01-19 15:45:23 -0800374 const std::string& fn_name, args_vector_t* run_args) {
Elliott Hughese0f02b72024-06-25 11:22:59 +0000375 if (!g_str_to_func.contains(fn_name)) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700376 errx(1, "ERROR: No benchmark for function %s", fn_name.c_str());
Anders Lewisa7b0f882017-07-24 20:01:13 -0700377 }
378 long iterations_to_use = primary_opts.num_iterations ? primary_opts.num_iterations :
379 secondary_opts.num_iterations;
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700380 int cpu_to_use = -1;
381 if (primary_opts.cpu_to_lock >= 0) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700382 cpu_to_use = primary_opts.cpu_to_lock;
383
Christopher Ferrisbfb7c762018-05-04 13:27:47 -0700384 } else if (secondary_opts.cpu_to_lock >= 0) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700385 cpu_to_use = secondary_opts.cpu_to_lock;
386 }
387
Christopher Ferris858e3362017-11-30 08:53:15 -0800388 benchmark_func_t benchmark_function = g_str_to_func.at(fn_name).first;
Haibo Huangd5ee4c52018-07-06 15:55:25 -0700389 for (const std::vector<int64_t>& args : (*run_args)) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700390 auto registration = benchmark::RegisterBenchmark(fn_name.c_str(), LockAndRun,
Christopher Ferris858e3362017-11-30 08:53:15 -0800391 benchmark_function,
Anders Lewisa7b0f882017-07-24 20:01:13 -0700392 cpu_to_use)->Args(args);
393 if (iterations_to_use > 0) {
394 registration->Iterations(iterations_to_use);
395 }
396 }
397}
398
399void RegisterCliBenchmarks(bench_opts_t cmdline_opts,
400 std::map<std::string, args_vector_t>& args_shorthand) {
401 // Register any of the extra benchmarks that were specified in the options.
402 args_vector_t arg_vector;
403 args_vector_t* run_args = &arg_vector;
Elliott Hughes98c30272025-05-27 06:07:10 -0700404 for (std::string extra_fn : cmdline_opts.extra_benchmarks) {
405 extra_fn = android::base::Trim(extra_fn);
Elliott Hughes5cec3772018-01-19 15:45:23 -0800406 size_t first_space_pos = extra_fn.find(' ');
Anders Lewisa7b0f882017-07-24 20:01:13 -0700407 std::string fn_name = extra_fn.substr(0, first_space_pos);
408 std::string cmd_args;
409 if (first_space_pos != std::string::npos) {
Elliott Hughes5cec3772018-01-19 15:45:23 -0800410 cmd_args = extra_fn.substr(extra_fn.find(' ') + 1);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700411 } else {
412 cmd_args = "";
413 }
414 run_args = ResolveArgs(run_args, cmd_args, args_shorthand);
415 RegisterGoogleBenchmarks(bench_opts_t(), cmdline_opts, fn_name, run_args);
416
417 run_args = &arg_vector;
418 arg_vector.clear();
419 }
420}
421
422int RegisterXmlBenchmarks(bench_opts_t cmdline_opts,
423 std::map<std::string, args_vector_t>& args_shorthand) {
424 // Structure of the XML file:
425 // - Element "fn" Function to benchmark.
426 // - - Element "iterations" Number of iterations to run. Leaving this blank uses
427 // Google benchmarks' convergence heuristics.
428 // - - Element "cpu" CPU to isolate to, if any.
429 // - - Element "args" Whitespace-separated list of per-function integer arguments, or
430 // one of the macros defined in util.h.
431 tinyxml2::XMLDocument doc;
Elliott Hughesc2223f72017-08-08 11:23:27 -0700432 if (doc.LoadFile(cmdline_opts.xmlpath.c_str()) != tinyxml2::XML_SUCCESS) {
Anders Lewisa7b0f882017-07-24 20:01:13 -0700433 doc.PrintError();
434 return doc.ErrorID();
435 }
436
437 // Read and register the functions.
438 tinyxml2::XMLNode* fn = doc.FirstChildElement("fn");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700439 while (fn) {
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700440 if (fn == fn->ToComment()) {
441 // Skip comments.
442 fn = fn->NextSibling();
443 continue;
444 }
445
Anders Lewisa7b0f882017-07-24 20:01:13 -0700446 auto fn_elem = fn->FirstChildElement("name");
447 if (!fn_elem) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700448 errx(1, "ERROR: Malformed XML entry: missing name element.");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700449 }
450 std::string fn_name = fn_elem->GetText();
451 if (fn_name.empty()) {
Anders Lewisa98a5fb2017-08-09 16:52:19 -0700452 errx(1, "ERROR: Malformed XML entry: error parsing name text.");
Anders Lewisa7b0f882017-07-24 20:01:13 -0700453 }
454 auto* xml_args = fn->FirstChildElement("args");
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700455 args_vector_t arg_vector;
456 args_vector_t* run_args = ResolveArgs(&arg_vector,
457 xml_args ? android::base::Trim(xml_args->GetText()) : "",
458 args_shorthand);
Anders Lewisa7b0f882017-07-24 20:01:13 -0700459
460 // XML values for CPU and iterations take precedence over those passed in via CLI.
461 bench_opts_t xml_opts{};
462 auto* num_iterations_elem = fn->FirstChildElement("iterations");
463 if (num_iterations_elem) {
464 int temp;
465 num_iterations_elem->QueryIntText(&temp);
466 xml_opts.num_iterations = temp;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700467 }
468 auto* cpu_to_lock_elem = fn->FirstChildElement("cpu");
469 if (cpu_to_lock_elem) {
470 int temp;
471 cpu_to_lock_elem->QueryIntText(&temp);
472 xml_opts.cpu_to_lock = temp;
Anders Lewisa7b0f882017-07-24 20:01:13 -0700473 }
474
475 RegisterGoogleBenchmarks(xml_opts, cmdline_opts, fn_name, run_args);
476
477 fn = fn->NextSibling();
Anders Lewisa7b0f882017-07-24 20:01:13 -0700478 }
479 return 0;
480}
481
Christopher Ferrise2188d42017-11-08 23:28:57 -0800482static void SetArgs(const std::vector<int>& sizes, args_vector_t* args) {
483 for (int size : sizes) {
484 args->push_back({size});
485 }
486}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700487
Christopher Ferrise2188d42017-11-08 23:28:57 -0800488static void SetArgs(const std::vector<int>& sizes, int align, args_vector_t* args) {
489 for (int size : sizes) {
490 args->push_back({size, align});
491 }
492}
493
494
495static void SetArgs(const std::vector<int>& sizes, int align1, int align2, args_vector_t* args) {
496 for (int size : sizes) {
497 args->push_back({size, align1, align2});
498 }
499}
500
501static args_vector_t GetArgs(const std::vector<int>& sizes) {
502 args_vector_t args;
503 SetArgs(sizes, &args);
504 return args;
505}
506
507static args_vector_t GetArgs(const std::vector<int>& sizes, int align) {
508 args_vector_t args;
509 SetArgs(sizes, align, &args);
510 return args;
511}
512
513static args_vector_t GetArgs(const std::vector<int>& sizes, int align1, int align2) {
514 args_vector_t args;
515 SetArgs(sizes, align1, align2, &args);
516 return args;
517}
518
519std::map<std::string, args_vector_t> GetShorthand() {
520 std::vector<int> all_sizes(kSmallSizes);
521 all_sizes.insert(all_sizes.end(), kMediumSizes.begin(), kMediumSizes.end());
522 all_sizes.insert(all_sizes.end(), kLargeSizes.begin(), kLargeSizes.end());
523
Suren Baghdasaryan9a0a3602023-08-17 21:52:50 +0000524 int page_sz = getpagesize();
525 std::vector<int> sub_page_sizes = {page_sz / 2, page_sz / 4, page_sz / 8};
Christopher Ferrisb2bb21d2024-03-11 16:08:26 -0700526 std::vector<int> multi_page_sizes = {page_sz, page_sz * 2, page_sz * 3, page_sz * 10,
527 page_sz * 25, page_sz * 50, page_sz * 75, page_sz * 100};
Suren Baghdasaryan9a0a3602023-08-17 21:52:50 +0000528 std::vector<int> all_page_sizes(sub_page_sizes);
529 all_page_sizes.insert(all_page_sizes.end(), multi_page_sizes.begin(), multi_page_sizes.end());
530
Christopher Ferrisb2bb21d2024-03-11 16:08:26 -0700531 std::map<std::string, args_vector_t> args_shorthand{
532 {"AT_COMMON_SIZES", GetArgs(kCommonSizes)},
533 {"AT_SMALL_SIZES", GetArgs(kSmallSizes)},
534 {"AT_MEDIUM_SIZES", GetArgs(kMediumSizes)},
535 {"AT_LARGE_SIZES", GetArgs(kLargeSizes)},
536 {"AT_ALL_SIZES", GetArgs(all_sizes)},
537 {"AT_SUB_PAGE_SIZES", GetArgs(sub_page_sizes)},
538 {"AT_MULTI_PAGE_SIZES", GetArgs(multi_page_sizes)},
539 {"AT_ALL_PAGE_SIZES", GetArgs(all_page_sizes)},
Christopher Ferrise2188d42017-11-08 23:28:57 -0800540
Christopher Ferrisb2bb21d2024-03-11 16:08:26 -0700541 {"AT_ALIGNED_ONEBUF", GetArgs(kCommonSizes, 0)},
542 {"AT_ALIGNED_ONEBUF_SMALL", GetArgs(kSmallSizes, 0)},
543 {"AT_ALIGNED_ONEBUF_MEDIUM", GetArgs(kMediumSizes, 0)},
544 {"AT_ALIGNED_ONEBUF_LARGE", GetArgs(kLargeSizes, 0)},
545 {"AT_ALIGNED_ONEBUF_ALL", GetArgs(all_sizes, 0)},
Christopher Ferrise2188d42017-11-08 23:28:57 -0800546
Christopher Ferrisb2bb21d2024-03-11 16:08:26 -0700547 {"AT_ALIGNED_TWOBUF", GetArgs(kCommonSizes, 0, 0)},
548 {"AT_ALIGNED_TWOBUF_SMALL", GetArgs(kSmallSizes, 0, 0)},
549 {"AT_ALIGNED_TWOBUF_MEDIUM", GetArgs(kMediumSizes, 0, 0)},
550 {"AT_ALIGNED_TWOBUF_LARGE", GetArgs(kLargeSizes, 0, 0)},
551 {"AT_ALIGNED_TWOBUF_ALL", GetArgs(all_sizes, 0, 0)},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700552
Christopher Ferrisb2bb21d2024-03-11 16:08:26 -0700553 // Do not exceed 512. that is about the largest number of properties
554 // that can be created with the current property area size.
555 {"NUM_PROPS", args_vector_t{{1}, {4}, {16}, {64}, {128}, {256}, {512}}},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700556
Christopher Ferrisb2bb21d2024-03-11 16:08:26 -0700557 {"MATH_COMMON", args_vector_t{{0}, {1}, {2}, {3}}},
558 {"MATH_SINCOS_COMMON", args_vector_t{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}}},
Anders Lewisa7b0f882017-07-24 20:01:13 -0700559 };
Christopher Ferrise2188d42017-11-08 23:28:57 -0800560
561 args_vector_t args_onebuf;
562 args_vector_t args_twobuf;
563 for (int size : all_sizes) {
564 args_onebuf.push_back({size, 0});
565 args_twobuf.push_back({size, 0, 0});
566 // Skip alignments on zero sizes.
567 if (size == 0) {
568 continue;
569 }
570 for (int align1 = 1; align1 <= 32; align1 <<= 1) {
571 args_onebuf.push_back({size, align1});
572 for (int align2 = 1; align2 <= 32; align2 <<= 1) {
573 args_twobuf.push_back({size, align1, align2});
574 }
575 }
Anders Lewisa7b0f882017-07-24 20:01:13 -0700576 }
Christopher Ferrise2188d42017-11-08 23:28:57 -0800577 args_shorthand.emplace("AT_MANY_ALIGNED_ONEBUF", args_onebuf);
578 args_shorthand.emplace("AT_MANY_ALIGNED_TWOBUF", args_twobuf);
579
Anders Lewisa7b0f882017-07-24 20:01:13 -0700580 return args_shorthand;
581}
582
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700583static bool FileExists(const std::string& file) {
584 struct stat st;
585 return stat(file.c_str(), &st) != -1 && S_ISREG(st.st_mode);
586}
Anders Lewisa7b0f882017-07-24 20:01:13 -0700587
Christopher Ferris858e3362017-11-30 08:53:15 -0800588void RegisterAllBenchmarks(const bench_opts_t& opts,
589 std::map<std::string, args_vector_t>& args_shorthand) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800590 for (auto& entry : g_str_to_func) {
Christopher Ferris4c5fde02018-01-08 16:13:14 -0800591 auto& function_info = entry.second;
Christopher Ferris858e3362017-11-30 08:53:15 -0800592 args_vector_t arg_vector;
593 args_vector_t* run_args = ResolveArgs(&arg_vector, function_info.second,
594 args_shorthand);
Christopher Ferris4c5fde02018-01-08 16:13:14 -0800595 RegisterGoogleBenchmarks(bench_opts_t(), opts, entry.first, run_args);
Christopher Ferris858e3362017-11-30 08:53:15 -0800596 }
597}
598
Anders Lewisa7b0f882017-07-24 20:01:13 -0700599int main(int argc, char** argv) {
600 std::map<std::string, args_vector_t> args_shorthand = GetShorthand();
601 bench_opts_t opts = ParseOpts(argc, argv);
602 std::vector<char*> new_argv(argc);
603 SanitizeOpts(argc, argv, &new_argv);
604
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700605 if (opts.xmlpath.empty()) {
606 // Don't add the default xml file if a user is specifying the tests to run.
607 if (opts.extra_benchmarks.empty()) {
Christopher Ferris858e3362017-11-30 08:53:15 -0800608 RegisterAllBenchmarks(opts, args_shorthand);
Christopher Ferrisd9d39be2017-08-23 18:03:51 -0700609 }
610 } else if (!FileExists(opts.xmlpath)) {
611 // See if this is a file in the suites directory.
612 std::string file(android::base::GetExecutableDirectory() + "/suites/" + opts.xmlpath);
613 if (opts.xmlpath[0] == '/' || !FileExists(file)) {
614 printf("Cannot find xml file %s: does not exist or is not a file.\n", opts.xmlpath.c_str());
615 return 1;
616 }
617 opts.xmlpath = file;
618 }
619
Anders Lewisa7b0f882017-07-24 20:01:13 -0700620 if (!opts.xmlpath.empty()) {
621 if (int err = RegisterXmlBenchmarks(opts, args_shorthand)) {
622 return err;
623 }
624 }
625 RegisterCliBenchmarks(opts, args_shorthand);
626
627 // Set the thread priority to the maximum.
628 if (setpriority(PRIO_PROCESS, 0, -20)) {
629 perror("Failed to raise priority of process. Are you root?\n");
630 }
631
632 int new_argc = new_argv.size();
633 benchmark::Initialize(&new_argc, new_argv.data());
634 benchmark::RunSpecifiedBenchmarks();
635}