// This function removes any bionic benchmarks command line arguments by checking them // against g_long_options. It fills new_argv with the filtered args. void SanitizeOpts(int argc, char** argv, std::vector<char*>* new_argv) { // TO THOSE ADDING OPTIONS: This currently doesn't support optional arguments.
(*new_argv)[0] = argv[0]; for (int i = 1; i < argc; ++i) { char* optarg = argv[i];
size_t opt_idx = 0;
// Iterate through g_long_options until either we hit the end or we have a match. for (opt_idx = 0; g_long_options[opt_idx].name &&
strncmp(g_long_options[opt_idx].name, optarg + 2,
strlen(g_long_options[opt_idx].name)); ++opt_idx) {
}
if (!g_long_options[opt_idx].name) {
new_argv->push_back(optarg);
} else { if (g_long_options[opt_idx].has_arg == required_argument) { // If the arg was passed in with an =, it spans one char *. // Otherwise, we skip a spot for the argument. if (!strchr(optarg, '=')) {
i++;
}
}
}
}
new_argv->push_back(nullptr);
}
bench_opts_t ParseOpts(int argc, char** argv) {
bench_opts_t opts; int opt; int option_index = 0;
// To make this parser handle the benchmark options silently: externint opterr;
opterr = 0;
while ((opt = getopt_long(argc, argv, "c:x:i:a:h", g_long_options, &option_index)) != -1) { if (opt == -1) { break;
} switch (opt) { case'c': if (*optarg) { char* check_null;
opts.cpu_to_lock = strtol(optarg, &check_null, 10); if (*check_null) {
errx(1, "ERROR: Args %s is not a valid integer.", optarg);
}
} else {
printf("ERROR: no argument specified for bionic_cpu\n");
Usage();
} break; case'x': if (*optarg) {
opts.xmlpath = optarg;
} else {
printf("ERROR: no argument specified for bionic_xml\n");
Usage();
} break; case'a': if (*optarg) {
opts.extra_benchmarks.push_back(optarg);
} else {
printf("ERROR: no argument specified for bionic_extra\n");
Usage();
} break; case'i': if (*optarg){ char* check_null;
opts.num_iterations = strtol(optarg, &check_null, 10); if (*check_null != '\0'or opts.num_iterations < 0) {
errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg);
}
} else {
printf("ERROR: no argument specified for bionic_iterations\n");
Usage();
} break; case'h':
Usage(); break; case'?': break; default: exit(1);
}
} return opts;
}
// This is a wrapper for every function call for per-benchmark cpu pinning. void LockAndRun(benchmark::State& state, benchmark_func_t func_to_bench, int cpu_to_lock) { if (cpu_to_lock >= 0) LockToCPU(cpu_to_lock);
// To avoid having to link against Google benchmarks in libutil, // benchmarks are kept without parameter information, necessitating this cast. reinterpret_cast<void(*) (benchmark::State&)>(func_to_bench)(state);
}
staticbool ParseOnebufManualStr(std::string& arg, args_vector_t* to_populate) { // The format of this is: // AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY // Where: // XX is the alignment // YY is the size // The YY size can be either a number or a string representing the pre-defined // sets of values: // SMALL (for values between 1 and 256) // MEDIUM (for values between 512 and 128KB) // LARGE (for values between 256KB and 2048KB)
int64_t align;
int64_t size; char sizes[32] = { 0 }; int ret;
ret = sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%" SCNd64 "_SIZE_%" SCNd64,
&align, &size); if (ret == 1) {
ret = sscanf(arg.c_str(), "AT_ONEBUF_MANUAL_ALIGN_%" SCNd64 "_SIZE_" "%" STRINGFY(sizeof(sizes)-1) "s", &align, sizes);
} if (ret != 2) { returnfalse;
}
// Verify the alignment is a power of 2. if (align != 0 && !powerof2(align)) { returnfalse;
}
auto sit = kSizes.find(sizes); if (sit == kSizes.cend()) {
to_populate->push_back({size, align});
} else { for (auto ssize : sit->second) {
to_populate->push_back({ssize, align});
}
} returntrue;
}
staticbool ParseTwobufManualStr(std::string& arg, args_vector_t* to_populate) { // The format of this is: // AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGN2_YY_SIZE_ZZ // Where: // XX is the alignment of the first argument // YY is the alignment of the second argument // ZZ is the size // The ZZ size can be either a number or a string representing the pre-defined // sets of values: // SMALL (for values between 1 and 256) // MEDIUM (for values between 512 and 128KB) // LARGE (for values between 256KB and 2048KB)
int64_t align1;
int64_t align2;
int64_t size; char sizes[32] = { 0 }; int ret;
ret = sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%" SCNd64 "_ALIGN2_%" SCNd64 "_SIZE_%" SCNd64,
&align1, &align2, &size); if (ret == 2) {
ret = sscanf(arg.c_str(), "AT_TWOBUF_MANUAL_ALIGN1_%" SCNd64 "_ALIGN2_%" SCNd64 "_SIZE_" "%" STRINGFY(sizeof(sizes)-1) "s",
&align1, &align2, sizes);
} if (ret != 3) { returnfalse;
}
// Verify the alignments are powers of 2. if ((align1 != 0 && !powerof2(align1)) || (align2 != 0 && !powerof2(align2))) { returnfalse;
}
auto sit = kSizes.find(sizes); if (sit == kSizes.cend()) {
to_populate->push_back({size, align1, align2});
} else { for (auto ssize : sit->second) {
to_populate->push_back({ssize, align1, align2});
}
} returntrue;
}
args_vector_t* ResolveArgs(args_vector_t* to_populate, std::string args,
std::map<std::string, args_vector_t>& args_shorthand) { // args is either a space-separated list of ints, a macro name, or // special free form macro. // To ease formatting in XML files, args is left and right trimmed. if (args_shorthand.count(args)) { return &args_shorthand[args];
} // Check for free form macro. if (android::base::StartsWith(args, kOnebufManualStr)) { if (!ParseOnebufManualStr(args, to_populate)) {
errx(1, "ERROR: Bad format of macro %s, should be AT_ONEBUF_MANUAL_ALIGN_XX_SIZE_YY",
args.c_str());
} return to_populate;
} elseif (android::base::StartsWith(args, kTwobufManualStr)) { if (!ParseTwobufManualStr(args, to_populate)) {
errx(1, "ERROR: Bad format of macro %s, should be AT_TWOBUF_MANUAL_ALIGN1_XX_ALIGNE2_YY_SIZE_ZZ",
args.c_str());
} return to_populate;
}
std::string trimmed_args = android::base::Trim(args); if (!trimmed_args.empty()) {
std::stringstream sstream(trimmed_args);
std::string argstr; while (sstream >> argstr) { char* check_null; int converted = static_cast<int>(strtol(argstr.c_str(), &check_null, 10)); if (*check_null == '\0') {
to_populate->emplace_back(std::vector<int64_t>{converted}); continue;
} elseif (*check_null == '/') { // The only supported format with a / is \d+(/\d+)\s*. Example 8/8/8 or 16/23.
std::vector<int64_t> test_args{converted}; while (true) {
converted = static_cast<int>(strtol(check_null + 1, &check_null, 10));
test_args.push_back(converted); if (*check_null == '\0') {
to_populate->emplace_back(std::move(test_args)); break;
} elseif (*check_null != '/') {
errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str());
}
}
} else {
errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str());
}
}
} else { // No arguments, only the base benchmark.
to_populate->emplace_back(std::vector<int64_t>{});
} return to_populate;
}
void RegisterGoogleBenchmarks(bench_opts_t primary_opts, bench_opts_t secondary_opts, const std::string& fn_name, args_vector_t* run_args) { if (!g_str_to_func.contains(fn_name)) {
errx(1, "ERROR: No benchmark for function %s", fn_name.c_str());
} long iterations_to_use = primary_opts.num_iterations ? primary_opts.num_iterations :
secondary_opts.num_iterations; int cpu_to_use = -1; if (primary_opts.cpu_to_lock >= 0) {
cpu_to_use = primary_opts.cpu_to_lock;
benchmark_func_t benchmark_function = g_str_to_func.at(fn_name).first; for (const std::vector<int64_t>& args : (*run_args)) { auto registration = benchmark::RegisterBenchmark(fn_name.c_str(), LockAndRun,
benchmark_function,
cpu_to_use)->Args(args); if (iterations_to_use > 0) {
registration->Iterations(iterations_to_use);
}
}
}
void RegisterCliBenchmarks(bench_opts_t cmdline_opts,
std::map<std::string, args_vector_t>& args_shorthand) { // Register any of the extra benchmarks that were specified in the options.
args_vector_t arg_vector;
args_vector_t* run_args = &arg_vector; for (std::string extra_fn : cmdline_opts.extra_benchmarks) {
extra_fn = android::base::Trim(extra_fn);
size_t first_space_pos = extra_fn.find(' ');
std::string fn_name = extra_fn.substr(0, first_space_pos);
std::string cmd_args; if (first_space_pos != std::string::npos) {
cmd_args = extra_fn.substr(extra_fn.find(' ') + 1);
} else {
cmd_args = "";
}
run_args = ResolveArgs(run_args, cmd_args, args_shorthand);
RegisterGoogleBenchmarks(bench_opts_t(), cmdline_opts, fn_name, run_args);
run_args = &arg_vector;
arg_vector.clear();
}
}
int RegisterXmlBenchmarks(bench_opts_t cmdline_opts,
std::map<std::string, args_vector_t>& args_shorthand) { // Structure of the XML file: // - Element "fn" Function to benchmark. // - - Element "iterations" Number of iterations to run. Leaving this blank uses // Google benchmarks' convergence heuristics. // - - Element "cpu" CPU to isolate to, if any. // - - Element "args" Whitespace-separated list of per-function integer arguments, or // one of the macros defined in util.h.
tinyxml2::XMLDocument doc; if (doc.LoadFile(cmdline_opts.xmlpath.c_str()) != tinyxml2::XML_SUCCESS) {
doc.PrintError(); return doc.ErrorID();
}
// Read and register the functions.
tinyxml2::XMLNode* fn = doc.FirstChildElement("fn"); while (fn) { if (fn == fn->ToComment()) { // Skip comments.
fn = fn->NextSibling(); continue;
}
auto fn_elem = fn->FirstChildElement("name"); if (!fn_elem) {
errx(1, "ERROR: Malformed XML entry: missing name element.");
}
std::string fn_name = fn_elem->GetText(); if (fn_name.empty()) {
errx(1, "ERROR: Malformed XML entry: error parsing name text.");
} auto* xml_args = fn->FirstChildElement("args");
args_vector_t arg_vector;
args_vector_t* run_args = ResolveArgs(&arg_vector,
xml_args ? android::base::Trim(xml_args->GetText()) : "",
args_shorthand);
// XML values for CPU and iterations take precedence over those passed in via CLI.
bench_opts_t xml_opts{}; auto* num_iterations_elem = fn->FirstChildElement("iterations"); if (num_iterations_elem) { int temp;
num_iterations_elem->QueryIntText(&temp);
xml_opts.num_iterations = temp;
} auto* cpu_to_lock_elem = fn->FirstChildElement("cpu"); if (cpu_to_lock_elem) { int temp;
cpu_to_lock_elem->QueryIntText(&temp);
xml_opts.cpu_to_lock = temp;
}
// Do not exceed 512. that is about the largest number of properties // that can be created with the current property area size.
{"NUM_PROPS", args_vector_t{{1}, {4}, {16}, {64}, {128}, {256}, {512}}},
if (opts.xmlpath.empty()) { // Don't add the default xml file if a user is specifying the tests to run. if (opts.extra_benchmarks.empty()) {
RegisterAllBenchmarks(opts, args_shorthand);
}
} elseif (!FileExists(opts.xmlpath)) { // See if this is a file in the suites directory.
std::string file(android::base::GetExecutableDirectory() + "/suites/" + opts.xmlpath); if (opts.xmlpath[0] == '/' || !FileExists(file)) {
printf("Cannot find xml file %s: does not exist or is not a file.\n", opts.xmlpath.c_str()); return1;
}
opts.xmlpath = file;
}
if (!opts.xmlpath.empty()) { if (int err = RegisterXmlBenchmarks(opts, args_shorthand)) { return err;
}
}
RegisterCliBenchmarks(opts, args_shorthand);
// Set the thread priority to the maximum. if (setpriority(PRIO_PROCESS, 0, -20)) {
perror("Failed to raise priority of process. Are you root?\n");
}
int new_argc = new_argv.size();
benchmark::Initialize(&new_argc, new_argv.data());
benchmark::RunSpecifiedBenchmarks();
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.3 Sekunden
(vorverarbeitet am 2026-06-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.