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