blob: 80ba711f10fdcc7dea8d3b9e49feaa3ef8386b45 [file] [log] [blame]
Austin Schuh5af45eb2019-09-16 20:54:18 -07001#include <fcntl.h>
2#include <sys/stat.h>
3#include <sys/types.h>
Austin Schuh60e77942022-05-16 17:48:24 -07004
Austin Schuh5af45eb2019-09-16 20:54:18 -07005#include <chrono>
6#include <random>
7#include <thread>
8
Philipp Schrader790cb542023-07-05 21:06:52 -07009#include "gflags/gflags.h"
10
Austin Schuh5af45eb2019-09-16 20:54:18 -070011#include "aos/condition.h"
12#include "aos/init.h"
13#include "aos/ipc_lib/latency_lib.h"
14#include "aos/logging/implementations.h"
15#include "aos/logging/logging.h"
16#include "aos/mutex/mutex.h"
17#include "aos/realtime.h"
18#include "aos/time/time.h"
19
20DEFINE_int32(seconds, 10, "Duration of the test to run");
21DEFINE_int32(
22 latency_threshold, 1000,
23 "Disable tracing when anything takes more than this many microseoncds");
24DEFINE_int32(core, 7, "Core to pin to");
25DEFINE_int32(sender_priority, 53, "RT priority to send at");
26DEFINE_int32(receiver_priority, 52, "RT priority to receive at");
27DEFINE_int32(timer_priority, 51, "RT priority to spin the timer at");
28
29DEFINE_bool(log_latency, false, "If true, log the latency");
30
31const uint32_t kSignalNumber = SIGRTMIN + 1;
32const uint32_t kQuitSignalNumber = SIGRTMIN + 2;
33
34namespace chrono = ::std::chrono;
35
36namespace aos {
37
38struct WakeupData {
39 Mutex mutex;
40 Condition condition;
41
42 WakeupData() : condition(&mutex) {}
43
44 monotonic_clock::time_point wakeup_time = monotonic_clock::epoch();
45
46 bool done = false;
47};
48
49void SenderThread(WakeupData *data) {
50 const monotonic_clock::time_point end_time =
51 monotonic_clock::now() + chrono::seconds(FLAGS_seconds);
52 // Standard mersenne_twister_engine seeded with 0
53 ::std::mt19937 generator(0);
54
55 // Sleep between 1 and 15 ms.
56 ::std::uniform_int_distribution<> distribution(1000, 15000);
57
Austin Schuh9014e3b2020-11-21 14:26:07 -080058 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -070059 SetCurrentThreadRealtimePriority(FLAGS_sender_priority);
60 while (true) {
61 const monotonic_clock::time_point wakeup_time =
62 monotonic_clock::now() + chrono::microseconds(distribution(generator));
63
64 ::std::this_thread::sleep_until(wakeup_time);
65 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
66
67 {
68 MutexLocker locker(&data->mutex);
69 data->wakeup_time = monotonic_now;
70 data->condition.Broadcast();
71
72 if (monotonic_now > end_time) {
73 break;
74 }
75 }
76 }
77
78 {
79 MutexLocker locker(&data->mutex);
80 data->done = true;
81 data->condition.Broadcast();
82 }
83
84 UnsetCurrentThreadRealtimePriority();
85}
86
87void ReceiverThread(WakeupData *data) {
88 Tracing t;
89 t.Start();
90
91 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
92 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
93 int latency_count = 0;
94
Austin Schuh9014e3b2020-11-21 14:26:07 -080095 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -070096 SetCurrentThreadRealtimePriority(FLAGS_receiver_priority);
97 while (true) {
98 chrono::nanoseconds wakeup_latency;
99 {
100 MutexLocker locker(&data->mutex);
101 while (data->wakeup_time == monotonic_clock::epoch() && !data->done) {
102 CHECK(!data->condition.Wait());
103 }
104
105 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
106
107 if (data->done) {
108 break;
109 }
110
111 wakeup_latency = monotonic_now - data->wakeup_time;
112 data->wakeup_time = monotonic_clock::epoch();
113 }
114
115 sum_latency += wakeup_latency;
116 ++latency_count;
117
118 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
119
120 if (wakeup_latency > chrono::microseconds(FLAGS_latency_threshold)) {
121 t.Stop();
122 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
123 static_cast<int64_t>(wakeup_latency.count()));
124 }
125
126 if (FLAGS_log_latency) {
127 AOS_LOG(INFO, "dt: %8d.%03d\n",
128 static_cast<int>(wakeup_latency.count() / 1000),
129 static_cast<int>(wakeup_latency.count() % 1000));
130 }
131 }
132 UnsetCurrentThreadRealtimePriority();
133
134 const chrono::nanoseconds average_latency = sum_latency / latency_count;
135
136 AOS_LOG(INFO,
137 "Max futex wakeup latency: %d.%03d microseconds, average: %d.%03d "
138 "microseconds\n",
139 static_cast<int>(max_wakeup_latency.count() / 1000),
140 static_cast<int>(max_wakeup_latency.count() % 1000),
141 static_cast<int>(average_latency.count() / 1000),
142 static_cast<int>(average_latency.count() % 1000));
143}
144
145int Main(int /*argc*/, char ** /*argv*/) {
146 WakeupData data;
147
148 AOS_LOG(INFO, "Main!\n");
149 ::std::thread t([]() {
150 TimerThread(monotonic_clock::now() + chrono::seconds(FLAGS_seconds),
151 FLAGS_timer_priority);
152 });
153
154 ::std::thread st([&data]() { SenderThread(&data); });
155
156 ReceiverThread(&data);
157
158 st.join();
159 t.join();
160 return 0;
161}
162
163} // namespace aos
164
165int main(int argc, char **argv) {
166 ::gflags::ParseCommandLineFlags(&argc, &argv, true);
167
Austin Schuh5af45eb2019-09-16 20:54:18 -0700168 return ::aos::Main(argc, argv);
169}