• 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 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