1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <benchmark/benchmark.h> 17#include <err.h> 18#include <getopt.h> 19#include <cinttypes> 20#include <sys/resource.h> 21#include <sys/stat.h> 22#include <sstream> 23#include <string> 24#include <utility> 25#include <vector> 26 27#include "benchmark_fwk.h" 28using namespace std; 29using namespace init_benchmark_test; 30 31namespace { 32constexpr auto K = 1024; 33using args_vector = std::vector<std::vector<int64_t>>; 34 35static const std::vector<int> commonArgs { 36 8, 37 16, 38 32, 39 64, 40 512, 41 1 * K, 42 8 * K, 43 16 * K, 44 32 * K, 45 64 * K, 46 128 * K, 47}; 48 49static const std::vector<int> limitSizes { 50 1, 51 2, 52 3, 53 4, 54 5, 55 6, 56 7, 57}; 58} 59 60namespace init_benchmark_test { 61std::map<std::string, std::pair<benchmark_func, std::string>> g_allBenchmarks; 62std::mutex g_benchmarkLock; 63static struct option g_benchmarkLongOptions[] = { 64 {"init_cpu", required_argument, nullptr, 'c'}, 65 {"init_iterations", required_argument, nullptr, 'i'}, 66 {"help", no_argument, nullptr, 'h'}, 67 {nullptr, 0, nullptr, 0}, 68 }; 69} 70 71static void PrintUsageAndExit() 72{ 73 printf("Usage:\n"); 74 printf("init_benchmarks [--init_cpu=<cpu_to_isolate>]\n"); 75 printf(" [--init_iterations=<num_iter>]\n"); 76 printf(" [<original benchmark flags>]\n"); 77 printf("benchmark flags:\n"); 78 79 int argc = 2; 80 char argv0[] = "init_benchmark"; 81 char argv1[] = "--help"; 82 char *argv[3] = { argv0, argv1, nullptr }; 83 benchmark::Initialize(&argc, argv); 84 exit(1); 85} 86 87static void ShiftOptions(int argc, char **argv, std::vector<char *> *argvAfterShift) 88{ 89 (*argvAfterShift)[0] = argv[0]; 90 for (int i = 1; i < argc; ++i) { 91 char *optarg = argv[i]; 92 size_t index = 0; 93 // Find if musl defined this arg. 94 while (g_benchmarkLongOptions[index].name && strncmp(g_benchmarkLongOptions[index].name, optarg + 2, // 2 arg 95 strlen(g_benchmarkLongOptions[index].name))) { 96 ++index; 97 } 98 // Not defined. 99 if (!g_benchmarkLongOptions[index].name) { 100 argvAfterShift->push_back(optarg); 101 } else if ((g_benchmarkLongOptions[index].has_arg == required_argument) && !strchr(optarg, '=')) { 102 i++; 103 } 104 } 105 argvAfterShift->push_back(nullptr); 106} 107 108static bench_opts_t ParseOptions(int argc, char **argv) 109{ 110 bench_opts_t opts; 111 int opt; 112 char *errorCheck = nullptr; 113 opterr = 0; // Don't show unrecognized option error. 114 115 while ((opt = getopt_long(argc, argv, "c:i:a:h", g_benchmarkLongOptions, nullptr)) != -1) { 116 switch (opt) { 117 case 'c': 118 if (!(*optarg)) { 119 printf("ERROR: no argument specified for init_cpu.\n"); 120 PrintUsageAndExit(); 121 break; 122 } 123 opts.cpuNum = strtol(optarg, &errorCheck, 10); // 10 base 124 if (*errorCheck) { 125 errx(1, "ERROR: Args %s is not a valid integer.", optarg); 126 } 127 break; 128 case 'i': 129 if (!(*optarg)) { 130 printf("ERROR: no argument specified for init_iterations.\n"); 131 PrintUsageAndExit(); 132 break; 133 } 134 opts.iterNum = strtol(optarg, &errorCheck, 10); // 10 base 135 if (*errorCheck != '\0' || opts.iterNum < 0) { 136 errx(1, "ERROR: Args %s is not a valid number of iterations.", optarg); 137 } 138 break; 139 case 'h': 140 PrintUsageAndExit(); 141 break; 142 case '?': 143 break; 144 default: 145 exit(1); 146 } 147 } 148 return opts; 149} 150 151static void LockAndRun(benchmark::State &state, benchmark_func func, int cpuNum) 152{ 153 if (cpuNum >= 0) { 154 cpu_set_t cpuset; 155 CPU_ZERO(&cpuset); 156 CPU_SET(cpuNum, &cpuset); 157 158 if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) { 159 printf("lock CPU failed, ERROR:%s\n", strerror(errno)); 160 } 161 } 162 163 reinterpret_cast<void (*)(benchmark::State &)>(func)(state); 164} 165 166static args_vector *ResolveArgs(args_vector *argsVector, std::string args, 167 std::map<std::string, args_vector> &presetArgs) 168{ 169 // Get it from preset args. 170 if (presetArgs.count(args)) { 171 return &presetArgs[args]; 172 } 173 174 // Convert string to int. 175 argsVector->push_back(std::vector<int64_t>()); 176 std::stringstream sstream(args); 177 std::string arg; 178 while (sstream >> arg) { 179 char *errorCheck; 180 int converted = static_cast<int>(strtol(arg.c_str(), &errorCheck, 10)); // 10 base 181 if (*errorCheck) { 182 errx(1, "ERROR: Args str %s contains an invalid macro or int.", args.c_str()); 183 } 184 (*argsVector)[0].push_back(converted); 185 } 186 return argsVector; 187} 188 189static args_vector GetArgs(const std::vector<int> &sizes) 190{ 191 args_vector args; 192 for (int size : sizes) { 193 args.push_back({size}); 194 } 195 return args; 196} 197 198static args_vector GetArgs(const std::vector<int> &sizes, int value) 199{ 200 args_vector args; 201 for (int size : sizes) { 202 args.push_back({size, value}); 203 } 204 return args; 205} 206 207static args_vector GetArgs(const std::vector<int> &sizes, int value1, int value2) 208{ 209 args_vector args; 210 for (int size : sizes) { 211 args.push_back({size, value1, value2}); 212 } 213 return args; 214} 215 216static args_vector GetArgs(const std::vector<int> &sizes, const std::vector<int> &limits, int value) 217{ 218 args_vector args; 219 for (int size : sizes) { 220 for (int limit : limits) { 221 args.push_back({size, limit, value}); 222 } 223 } 224 return args; 225} 226 227static std::map<std::string, args_vector> GetPresetArgs() 228{ 229 std::map<std::string, args_vector> presetArgs { 230 {"COMMON_ARGS", GetArgs(commonArgs)}, 231 {"ALIGNED_ONEBUF", GetArgs(commonArgs, 0)}, 232 {"ALIGNED_TWOBUF", GetArgs(commonArgs, 0, 0)}, 233 {"STRING_LIMIT", GetArgs(commonArgs, limitSizes, 0)}, 234 {"MATH_COMMON", args_vector{{0}, {1}, {2}, {3}, {4}, {5}}}, 235 {"BENCHMARK_VARIABLE", args_vector{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}}}, 236 {"REALPATH_VARIABLE", args_vector{{0}, {1}, {2}, {3}, {4}}}, 237 {"MMAP_SIZE", args_vector{{8}, {16}, {32}, {64}, {128}, {512}}}, 238 }; 239 240 return presetArgs; 241} 242 243static void RegisterSingleBenchmark(bench_opts_t opts, const std::string &funcName, args_vector *runArgs) 244{ 245 if (g_allBenchmarks.find(funcName) == g_allBenchmarks.end()) { 246 errx(1, "ERROR: No benchmark for function %s", funcName.c_str()); 247 } 248 249 benchmark_func func = g_allBenchmarks.at(funcName).first; 250 for (const std::vector<int64_t> &args : (*runArgs)) { 251 // It will call LockAndRun(func, opts.cpuNum). 252 auto registration = benchmark::RegisterBenchmark(funcName.c_str(), LockAndRun, func, opts.cpuNum)->Args(args); 253 printf("opts.iterNum %ld \n", opts.iterNum); 254 if (opts.iterNum > 0) { 255 registration->Iterations(opts.iterNum); 256 } 257 } 258} 259 260static void RegisterAllBenchmarks(const bench_opts_t &opts, std::map<std::string, args_vector> &presetArgs) 261{ 262 for (auto &entry : g_allBenchmarks) { 263 auto &funcInfo = entry.second; 264 args_vector arg_vector; 265 args_vector *runArgs = ResolveArgs(&arg_vector, funcInfo.second, presetArgs); 266 RegisterSingleBenchmark(opts, entry.first, runArgs); 267 } 268} 269 270int main(int argc, char **argv) 271{ 272 std::map<std::string, args_vector> presetArgs = GetPresetArgs(); 273 bench_opts_t opts = ParseOptions(argc, argv); 274 std::vector<char *> argvAfterShift(argc); 275 ShiftOptions(argc, argv, &argvAfterShift); 276 RegisterAllBenchmarks(opts, presetArgs); 277 if (setpriority(PRIO_PROCESS, 0, -20)) { // 20 max 278 perror("Set priority of process failed.\n"); 279 } 280 CreateLocalParameterTest(512); // test max 512 281 int argcAfterShift = argvAfterShift.size(); 282 benchmark::Initialize(&argcAfterShift, argvAfterShift.data()); 283 benchmark::RunSpecifiedBenchmarks(); 284} 285