1/* 2 * Copyright (c) 2021-2022 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#include <algorithm> 16#include <cctype> 17#include <chrono> 18#include <cstring> 19#include <iostream> 20#include <random> 21#include <string> 22#include <thread> 23#include <vector> 24 25#include <sys/mman.h> 26#include <sys/syscall.h> 27#include <unistd.h> 28 29using namespace std::chrono; 30using namespace std::chrono_literals; 31 32namespace { 33#define USED_FUNCTION __attribute__((__used__)) __attribute__((optnone)) 34constexpr milliseconds eachStackFunRunTime = 100ms; 35constexpr milliseconds msDuartion = 1000ms; 36const ssize_t ERRINFOLEN = 512; 37 38extern USED_FUNCTION void LoopBranch0(std::default_random_engine &rnd, int level); 39extern USED_FUNCTION void LoopBranch1(std::default_random_engine &rnd, int level); 40 41struct Option { 42 int numThreads {5}; 43 int second {36000}; 44 int stack {5}; 45 bool noWait = false; 46 bool dynamicStack = false; 47 bool mmap = false; 48 bool iowait = false; 49 bool branch = false; 50 bool nonew = false; 51 bool nofunc = false; 52 int boundCpu {-1}; 53 int sleepms {0}; 54}; 55 56inline int GetTid() 57{ 58 int res = static_cast<int>(syscall(SYS_gettid)); 59 return res; 60} 61 62USED_FUNCTION void LoopDummy(milliseconds anything) 63{ 64 if (anything.count() > 0) { 65 printf(""); 66 } 67} 68 69USED_FUNCTION void LoopBranch0(std::default_random_engine &rnd, int level) 70{ 71 constexpr int two {2}; 72 if (level == 0) { 73 printf(""); 74 return; 75 } 76 if (rnd() % two == 0) { 77 LoopBranch0(rnd, --level); 78 } else { 79 LoopBranch1(rnd, --level); 80 } 81} 82 83USED_FUNCTION void LoopBranch1(std::default_random_engine &rnd, int level) 84{ 85 constexpr int two {2}; 86 if (level == 0) { 87 printf(""); 88 return; 89 } 90 if (rnd() % two == 0) { 91 LoopBranch0(rnd, --level); 92 } else { 93 LoopBranch1(rnd, --level); 94 } 95} 96 97USED_FUNCTION void LoopBranch() 98{ 99 constexpr int two {2}; 100 int branchLevel = 10; 101 std::default_random_engine rnd; 102 if (rnd() % two == 0) { 103 LoopBranch0(rnd, branchLevel); 104 } else { 105 LoopBranch1(rnd, branchLevel); 106 } 107} 108 109USED_FUNCTION void LoopIowait() 110{ 111 std::default_random_engine rnd; 112 FILE *fp = fopen("temp", "rw"); 113 if (fp == nullptr) { 114 return; 115 } 116 117 std::unique_ptr<FILE, decltype(&fclose)> fd {fp, &fclose}; 118 if (fd != nullptr) { 119 const std::string tempBuf = std::to_string(rnd()); 120 fwrite(tempBuf.c_str(), tempBuf.size(), 1, fd.get()); 121 } 122} 123 124USED_FUNCTION void LoopMmap() 125{ 126 int *arr = static_cast<int *>( 127 mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, 0, 0)); 128 129 int *ptr = arr; 130 int someVal1 {10}; 131 int someVal2 {20}; 132 int someVal3 {30}; 133 *ptr = someVal1; 134 ++ptr; 135 *ptr = someVal2; 136 ++ptr; 137 *ptr = someVal3; 138 munmap(arr, getpagesize()); 139 return; 140} 141 142USED_FUNCTION void LoopFunction(milliseconds timeOutMS, const Option &option) 143{ 144 auto now = std::chrono::steady_clock::now(); 145 auto sleepTime = now + seconds(1); 146 int count = 0; 147 while (std::chrono::steady_clock::now() < (now + timeOutMS)) { 148 if (option.sleepms > 0) { 149 if (std::chrono::steady_clock::now() >= sleepTime) { 150 sleepTime = std::chrono::steady_clock::now() + seconds(1); 151 std::this_thread::sleep_for(std::chrono::milliseconds(option.sleepms)); 152 } 153 } 154 if (option.mmap) { 155 LoopMmap(); 156 } 157 if (option.iowait) { 158 LoopIowait(); 159 } 160 if (option.branch) { 161 LoopBranch(); 162 } 163 164 std::default_random_engine rnd; 165 int a = rnd(); 166 int b = rnd(); 167 int c = rnd(); 168 a = (a++) * (b++) * (c++); 169 170 if (a == 0) { 171 continue; 172 } 173 174 if (!option.nonew) { 175 auto p = new unsigned int; 176 *p = count++; 177 delete p; 178 p = nullptr; 179 } 180 181 if (!option.nofunc) { 182 LoopDummy(timeOutMS); 183 } 184 } 185 return; 186} 187 188inline void Loop(milliseconds timeOutMS, const Option &option) 189{ 190 printf("loop at %s\n", __func__); 191 LoopFunction(timeOutMS, option); 192 return; 193} 194 195USED_FUNCTION void CallStack10(int currentStack, const Option &option) 196{ 197 if (option.stack > 0) { 198 Loop(option.second * msDuartion, option); 199 } 200} 201 202USED_FUNCTION void CallStack9(int currentStack, const Option &option) 203{ 204 if (option.stack > 0) { 205 if (option.dynamicStack) { 206 Loop(eachStackFunRunTime, option); // loop 100 ms 207 } 208 CallStack10(currentStack - 1, option); 209 } else { 210 Loop(option.second * msDuartion, option); 211 } 212} 213 214USED_FUNCTION void CallStack8(int currentStack, const Option &option) 215{ 216 if (option.stack > 0) { 217 if (option.dynamicStack) { 218 Loop(eachStackFunRunTime, option); // loop 100 ms 219 } 220 CallStack9(currentStack - 1, option); 221 } else { 222 Loop(option.second * msDuartion, option); 223 } 224} 225 226USED_FUNCTION void CallStack7(int currentStack, const Option &option) 227{ 228 if (option.stack > 0) { 229 if (option.dynamicStack) { 230 Loop(eachStackFunRunTime, option); // loop 100 ms 231 } 232 CallStack8(currentStack - 1, option); 233 } else { 234 Loop(option.second * msDuartion, option); 235 } 236} 237 238USED_FUNCTION void CallStack6(int currentStack, const Option &option) 239{ 240 if (option.stack > 0) { 241 if (option.dynamicStack) { 242 Loop(eachStackFunRunTime, option); // loop 100 ms 243 } 244 CallStack7(currentStack - 1, option); 245 } else { 246 Loop(option.second * msDuartion, option); 247 } 248} 249 250USED_FUNCTION void CallStack5(int currentStack, const Option &option) 251{ 252 if (option.stack > 0) { 253 if (option.dynamicStack) { 254 Loop(eachStackFunRunTime, option); // loop 100 ms 255 } 256 CallStack6(currentStack - 1, option); 257 } else { 258 Loop(option.second * msDuartion, option); 259 } 260} 261 262USED_FUNCTION void CallStack4(int currentStack, const Option &option) 263{ 264 if (option.stack > 0) { 265 if (option.dynamicStack) { 266 Loop(eachStackFunRunTime, option); // loop 100 ms 267 } 268 CallStack5(currentStack - 1, option); 269 } else { 270 Loop(option.second * msDuartion, option); 271 } 272} 273 274USED_FUNCTION void CallStack3(int currentStack, const Option &option) 275{ 276 if (option.stack > 0) { 277 if (option.dynamicStack) { 278 Loop(eachStackFunRunTime, option); // loop 100 ms 279 } 280 CallStack4(currentStack - 1, option); 281 } else { 282 Loop(option.second * msDuartion, option); 283 } 284} 285 286USED_FUNCTION void CallStack2(int currentStack, const Option &option) 287{ 288 if (option.stack > 0) { 289 if (option.dynamicStack) { 290 Loop(eachStackFunRunTime, option); // loop 100 ms 291 } 292 CallStack3(currentStack - 1, option); 293 } else { 294 Loop(option.second * msDuartion, option); 295 } 296} 297 298USED_FUNCTION void CallStack1(int currentStack, const Option &option) 299{ 300 if (option.stack > 0) { 301 if (option.dynamicStack) { 302 Loop(eachStackFunRunTime, option); // loop 100 ms 303 } 304 CallStack2(currentStack - 1, option); 305 } else { 306 Loop(option.second * msDuartion, option); 307 } 308} 309 310USED_FUNCTION void CallStack0(int currentStack, const Option &option) 311{ 312 if (option.stack > 0) { 313 if (option.dynamicStack) { 314 Loop(eachStackFunRunTime, option); // loop 100 ms 315 } 316 CallStack1(currentStack - 1, option); 317 } else { 318 Loop(option.second * msDuartion, option); 319 } 320} 321 322USED_FUNCTION void ExampleThread(const Option &option) 323{ 324 printf("thread %d ++ with %d %d \n", GetTid(), option.second, option.stack); 325 CallStack0(option.stack, option); 326 printf("thread %d --\n", GetTid()); 327 328 return; 329} 330 331USED_FUNCTION void RunSampleThread(const Option &option) 332{ 333 printf("run %d threads for %d second with %d stack level\n", option.numThreads, option.second, 334 option.stack); 335 printf("main thread %d\n", GetTid()); 336 337 std::thread threads[option.numThreads]; 338 for (int count = 0; count < option.numThreads; ++count) { 339 threads[count] = std::thread(ExampleThread, option); 340 } 341 for (int count = 0; count < option.numThreads; ++count) { 342 threads[count].join(); 343 } 344 printf("all thread exit\n"); 345} 346 347void WaitStart() 348{ 349 std::string startArg; 350 std::cout << "Please input 'start' to begin the subthread: \n"; 351 while (true) { 352 std::cin >> startArg; 353 if (startArg.compare("start") == 0) { 354 break; 355 } else { 356 continue; 357 } 358 } 359} 360 361void Help() 362{ 363 printf("this is a demo test command\n"); 364 printf(" Use the following commands to simulate different scenarios\n"); 365 printf(" --help\n"); 366 printf(" this page\n"); 367 printf(" --thread <number>\n"); 368 printf(" setup the thread number, default is 5 second\n"); 369 printf(" --time <time>\n"); 370 printf(" setup run sec, default is 36000 second\n"); 371 printf(" --stack <level>\n"); 372 printf(" setup stack level, default is 5\n"); 373 printf(" --nowait\n"); 374 printf(" setup skip the start, default wait the start\n"); 375 printf(" --dynamic\n"); 376 printf(" will run some code in each stack level\n"); 377 printf(" --mmap\n"); 378 printf(" will run mmap code in the loop\n"); 379 printf(" --iowait\n"); 380 printf(" will run iowait code in the loop\n"); 381 printf(" --branch\n"); 382 printf(" will run branch code in the loop\n"); 383 printf(" --nonew\n"); 384 printf(" will not new memory in the loop\n"); 385 printf(" --nofunc\n"); 386 printf(" will not call dummy func in the loop\n"); 387 printf(" --boundcpu <cpu>\n"); 388 printf(" the process will bound to <cpu>\n"); 389 printf(" --sleep <milliseconds>\n"); 390 printf(" threads will sleep <milliseconds> per second, default is 0.\n"); 391} 392 393bool GetIntFromArg(std::vector<std::string> &args, int &value) 394{ 395 if (!args.empty()) { 396 if (std::all_of(args.begin()->begin(), args.begin()->end(), ::isdigit)) { 397 value = std::stoi(args[0]); 398 args.erase(args.begin()); 399 } else { 400 printf("unknown format '%s'\n", args[0].c_str()); 401 return false; 402 } 403 } 404 return true; 405} 406 407bool MatchArgs(std::vector<std::string> &args, const std::string &option) 408{ 409 if (args[0] == option) { 410 args.erase(args.begin()); 411 return true; 412 } 413 return false; 414} 415bool GetBoolFromArg(std::vector<std::string> &args, const std::string &option, bool &value) 416{ 417 if (MatchArgs(args, option)) { 418 value = true; 419 return true; 420 } else { 421 return false; 422 } 423} 424} // namespace 425 426USED_FUNCTION int main(int argc, char *argv[]) 427{ 428 std::vector<std::string> args; 429 for (int i = 1; i < argc; i++) { 430 args.push_back(argv[i]); 431 } 432 Option option; 433 434 while (!args.empty()) { 435 if (MatchArgs(args, "--help")) { 436 Help(); 437 return 0; 438 } else if (MatchArgs(args, "--boundcpu")) { 439 if (!GetIntFromArg(args, option.boundCpu)) { 440 return -1; 441 } 442 } else if (MatchArgs(args, "--sleep")) { 443 if (!GetIntFromArg(args, option.sleepms)) { 444 return -1; 445 } 446 } else if (MatchArgs(args, "--thread")) { 447 if (!GetIntFromArg(args, option.numThreads)) { 448 return -1; 449 } 450 } else if (MatchArgs(args, "--time")) { 451 if (!GetIntFromArg(args, option.second)) { 452 return -1; 453 } 454 } else if (MatchArgs(args, "--stack")) { 455 if (!GetIntFromArg(args, option.stack)) { 456 return -1; 457 } 458 } else if (GetBoolFromArg(args, "--dynamic", option.dynamicStack)) { 459 continue; 460 } else if (GetBoolFromArg(args, "--nowait", option.noWait)) { 461 continue; 462 } else if (GetBoolFromArg(args, "--mmap", option.mmap)) { 463 continue; 464 } else if (GetBoolFromArg(args, "--iowait", option.iowait)) { 465 continue; 466 } else if (GetBoolFromArg(args, "--branch", option.branch)) { 467 continue; 468 } else if (GetBoolFromArg(args, "--nonew", option.nonew)) { 469 continue; 470 } else if (GetBoolFromArg(args, "--nofunc", option.nofunc)) { 471 continue; 472 } else { 473 printf("unknown format '%s'\n", args[0].c_str()); 474 return -1; 475 } 476 } 477 478 if (option.boundCpu > -1) { 479 cpu_set_t mask; 480 CPU_ZERO(&mask); 481 CPU_SET(option.boundCpu, &mask); 482 if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) { 483 char errInfo[ERRINFOLEN] = { 0 }; 484 strerror_r(errno, errInfo, ERRINFOLEN); 485 printf("Set CPU(%d) affinity failure, ERROR:%s\n", option.boundCpu, errInfo); 486 } 487 } 488 if (!option.noWait) { 489 WaitStart(); 490 } 491 492 RunSampleThread(option); 493 return 0; 494} 495