/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include "benchmark_fwk.h" using namespace std; using namespace init_benchmark_test; namespace { constexpr auto K = 1024; using args_vector = std::vector>; static const std::vector commonArgs { 8, 16, 32, 64, 512, 1 * K, 8 * K, 16 * K, 32 * K, 64 * K, 128 * K, }; static const std::vector limitSizes { 1, 2, 3, 4, 5, 6, 7, }; } namespace init_benchmark_test { std::map> g_allBenchmarks; std::mutex g_benchmarkLock; static struct option g_benchmarkLongOptions[] = { {"init_cpu", required_argument, nullptr, 'c'}, {"init_iterations", required_argument, nullptr, 'i'}, {"help", no_argument, nullptr, 'h'}, {nullptr, 0, nullptr, 0}, }; } static void PrintUsageAndExit() { printf("Usage:\n"); printf("init_benchmarks [--init_cpu=]\n"); printf(" [--init_iterations=]\n"); printf(" []\n"); printf("benchmark flags:\n"); int argc = 2; char argv0[] = "init_benchmark"; char argv1[] = "--help"; char *argv[3] = { argv0, argv1, nullptr }; benchmark::Initialize(&argc, argv); exit(1); } static void ShiftOptions(int argc, char **argv, std::vector *argvAfterShift) { (*argvAfterShift)[0] = argv[0]; for (int i = 1; i < argc; ++i) { char *optarg = argv[i]; size_t index = 0; // Find if musl defined this arg. while (g_benchmarkLongOptions[index].name && strncmp(g_benchmarkLongOptions[index].name, optarg + 2, // 2 arg strlen(g_benchmarkLongOptions[index].name))) { ++index; } // Not defined. if (!g_benchmarkLongOptions[index].name) { argvAfterShift->push_back(optarg); } else if ((g_benchmarkLongOptions[index].has_arg == required_argument) && !strchr(optarg, '=')) { i++; } } argvAfterShift->push_back(nullptr); } static bench_opts_t ParseOptions(int argc, char **argv) { bench_opts_t opts; int opt; char *errorCheck = nullptr; opterr = 0; // Don't show unrecognized option error. while ((opt = getopt_long(argc, argv, "c:i:a:h", g_benchmarkLongOptions, nullptr)) != -1) { switch (opt) { case 'c': if (!(*optarg)) { printf("ERROR: no argument specified for init_cpu.\n"); PrintUsageAndExit(); break; } opts.cpuNum = strtol(optarg, &errorCheck, 10); // 10 base if (*errorCheck) { errx(1, "ERROR: Args %s is not a valid integer.", optarg); } break; case 'i': if (!(*optarg)) { printf("ERROR: no argument specified for init_iterations.\n"); PrintUsageAndExit(); break; } opts.iterNum = strtol(optarg, &errorCheck, 10); // 10 base if (*errorCheck != '\0' || opts.iterNum < 0) { errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg); } break; case 'h': PrintUsageAndExit(); break; case '?': break; default: exit(1); } } return opts; } static void LockAndRun(benchmark::State &state, benchmark_func func, int cpuNum) { if (cpuNum >= 0) { cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(cpuNum, &cpuset); if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) { printf("lock CPU failed, ERROR:%s\n", strerror(errno)); } } reinterpret_cast(func)(state); } static args_vector *ResolveArgs(args_vector *argsVector, std::string args, std::map &presetArgs) { // Get it from preset args. if (presetArgs.count(args)) { return &presetArgs[args]; } // Convert string to int. argsVector->push_back(std::vector()); std::stringstream sstream(args); std::string arg; while (sstream >> arg) { char *errorCheck; int converted = static_cast(strtol(arg.c_str(), &errorCheck, 10)); // 10 base if (*errorCheck) { errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str()); } (*argsVector)[0].push_back(converted); } return argsVector; } static args_vector GetArgs(const std::vector &sizes) { args_vector args; for (int size : sizes) { args.push_back({size}); } return args; } static args_vector GetArgs(const std::vector &sizes, int value) { args_vector args; for (int size : sizes) { args.push_back({size, value}); } return args; } static args_vector GetArgs(const std::vector &sizes, int value1, int value2) { args_vector args; for (int size : sizes) { args.push_back({size, value1, value2}); } return args; } static args_vector GetArgs(const std::vector &sizes, const std::vector &limits, int value) { args_vector args; for (int size : sizes) { for (int limit : limits) { args.push_back({size, limit, value}); } } return args; } static std::map GetPresetArgs() { std::map presetArgs { {"COMMON_ARGS", GetArgs(commonArgs)}, {"ALIGNED_ONEBUF", GetArgs(commonArgs, 0)}, {"ALIGNED_TWOBUF", GetArgs(commonArgs, 0, 0)}, {"STRING_LIMIT", GetArgs(commonArgs, limitSizes, 0)}, {"MATH_COMMON", args_vector{{0}, {1}, {2}, {3}, {4}, {5}}}, {"BENCHMARK_VARIABLE", args_vector{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}}}, {"REALPATH_VARIABLE", args_vector{{0}, {1}, {2}, {3}, {4}}}, {"MMAP_SIZE", args_vector{{8}, {16}, {32}, {64}, {128}, {512}}}, }; return presetArgs; } static void RegisterSingleBenchmark(bench_opts_t opts, const std::string &funcName, args_vector *runArgs) { if (g_allBenchmarks.find(funcName) == g_allBenchmarks.end()) { errx(1, "ERROR: No benchmark for function %s", funcName.c_str()); } benchmark_func func = g_allBenchmarks.at(funcName).first; for (const std::vector &args : (*runArgs)) { // It will call LockAndRun(func, opts.cpuNum). auto registration = benchmark::RegisterBenchmark(funcName.c_str(), LockAndRun, func, opts.cpuNum)->Args(args); printf("opts.iterNum %ld \n", opts.iterNum); if (opts.iterNum > 0) { registration->Iterations(opts.iterNum); } } } static void RegisterAllBenchmarks(const bench_opts_t &opts, std::map &presetArgs) { for (auto &entry : g_allBenchmarks) { auto &funcInfo = entry.second; args_vector arg_vector; args_vector *runArgs = ResolveArgs(&arg_vector, funcInfo.second, presetArgs); RegisterSingleBenchmark(opts, entry.first, runArgs); } } int main(int argc, char **argv) { std::map presetArgs = GetPresetArgs(); bench_opts_t opts = ParseOptions(argc, argv); std::vector argvAfterShift(argc); ShiftOptions(argc, argv, &argvAfterShift); RegisterAllBenchmarks(opts, presetArgs); if (setpriority(PRIO_PROCESS, 0, -20)) { // 20 max perror("Set priority of process failed.\n"); } CreateLocalParameterTest(512); // test max 512 int argcAfterShift = argvAfterShift.size(); benchmark::Initialize(&argcAfterShift, argvAfterShift.data()); benchmark::RunSpecifiedBenchmarks(); }