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