1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <getopt.h>
18 #include <stdint.h>
19 #include <unistd.h>
20 
21 #include <thread>
22 
23 #include "perfetto/base/logging.h"
24 #include "perfetto/base/time.h"
25 
26 // Spawns the requested number threads that alternate between busy-waiting and
27 // sleeping.
28 
29 namespace perfetto {
30 namespace {
31 
BusyWait(long busy_us,long sleep_us)32 __attribute__((noreturn)) void BusyWait(long busy_us, long sleep_us) {
33   while (1) {
34     base::TimeNanos start = base::GetWallTimeNs();
35     while ((base::GetWallTimeNs() - start).count() < busy_us * 1000) {
36       for (int i = 0; i < 10000; i++) {
37         asm volatile("" ::: "memory");
38       }
39     }
40     if (sleep_us > 0)
41       base::SleepMicroseconds(static_cast<unsigned>(sleep_us));
42     else
43       std::this_thread::yield();
44   }
45 }
46 
BusyThreadsMain(int argc,char ** argv)47 int BusyThreadsMain(int argc, char** argv) {
48   long num_threads = -1;
49   long period_us = -1;
50   long duty_cycle = -1;
51 
52   static struct option long_options[] = {
53       {"threads", required_argument, nullptr, 't'},
54       {"period_us", required_argument, nullptr, 'p'},
55       {"duty_cycle", required_argument, nullptr, 'd'},
56       {nullptr, 0, nullptr, 0}};
57   int option_index;
58   int c;
59   while ((c = getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
60     switch (c) {
61       case 't':
62         num_threads = atol(optarg);
63         break;
64       case 'p':
65         period_us = atol(optarg);
66         break;
67       case 'd':
68         duty_cycle = atol(optarg);
69         break;
70       default:
71         break;
72     }
73   }
74   if (num_threads < 1 || period_us < 0 || duty_cycle < 1 || duty_cycle > 100) {
75     PERFETTO_ELOG("Usage: %s --threads=N --period_us=N --duty_cycle=[1-100]",
76                   argv[0]);
77     return 1;
78   }
79 
80   long busy_us = period_us * duty_cycle / 100;
81   long sleep_us = period_us - busy_us;
82 
83   PERFETTO_LOG(
84       "Spawning %ld threads; wait duration: %ldus; sleep duration: %ldus.",
85       num_threads, busy_us, sleep_us);
86   for (int i = 0; i < num_threads; i++) {
87     std::thread th(BusyWait, busy_us, sleep_us);
88     th.detach();
89   }
90   PERFETTO_LOG("Threads spawned, Ctrl-C to stop.");
91   while (sleep(600))
92     ;
93 
94   return 0;
95 }
96 
97 }  // namespace
98 }  // namespace perfetto
99 
main(int argc,char ** argv)100 int main(int argc, char** argv) {
101   return perfetto::BusyThreadsMain(argc, argv);
102 }
103