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 const ssize_t ERRINFOLEN = 512;
37
38 extern USED_FUNCTION void LoopBranch0(std::default_random_engine &rnd, int level);
39 extern USED_FUNCTION void LoopBranch1(std::default_random_engine &rnd, int level);
40
41 struct 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
GetTid()56 inline int GetTid()
57 {
58 int res = static_cast<int>(syscall(SYS_gettid));
59 return res;
60 }
61
LoopDummy(milliseconds anything)62 USED_FUNCTION void LoopDummy(milliseconds anything)
63 {
64 if (anything.count() > 0) {
65 printf("");
66 }
67 }
68
LoopBranch0(std::default_random_engine & rnd,int level)69 USED_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
LoopBranch1(std::default_random_engine & rnd,int level)83 USED_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
LoopBranch()97 USED_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
LoopIowait()109 USED_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
LoopMmap()124 USED_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
LoopFunction(milliseconds timeOutMS,const Option & option)142 USED_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
Loop(milliseconds timeOutMS,const Option & option)188 inline void Loop(milliseconds timeOutMS, const Option &option)
189 {
190 printf("loop at %s\n", __func__);
191 LoopFunction(timeOutMS, option);
192 return;
193 }
194
CallStack10(int currentStack,const Option & option)195 USED_FUNCTION void CallStack10(int currentStack, const Option &option)
196 {
197 if (option.stack > 0) {
198 Loop(option.second * msDuartion, option);
199 }
200 }
201
CallStack9(int currentStack,const Option & option)202 USED_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
CallStack8(int currentStack,const Option & option)214 USED_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
CallStack7(int currentStack,const Option & option)226 USED_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
CallStack6(int currentStack,const Option & option)238 USED_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
CallStack5(int currentStack,const Option & option)250 USED_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
CallStack4(int currentStack,const Option & option)262 USED_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
CallStack3(int currentStack,const Option & option)274 USED_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
CallStack2(int currentStack,const Option & option)286 USED_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
CallStack1(int currentStack,const Option & option)298 USED_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
CallStack0(int currentStack,const Option & option)310 USED_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
ExampleThread(const Option & option)322 USED_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
RunSampleThread(const Option & option)331 USED_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
WaitStart()347 void 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
Help()361 void 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
GetIntFromArg(std::vector<std::string> & args,int & value)393 bool 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
MatchArgs(std::vector<std::string> & args,const std::string & option)407 bool 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 }
GetBoolFromArg(std::vector<std::string> & args,const std::string & option,bool & value)415 bool 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
main(int argc,char * argv[])426 USED_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