• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }