blob: f6264aa8778d7061e0517103dcbbf5d6101be6d7 [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
Austin Schuh99f7c6a2024-06-25 22:07:44 -070011#include "absl/flags/flag.h"
12#include "absl/log/check.h"
13#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070014
Austin Schuh5af45eb2019-09-16 20:54:18 -070015#include "aos/condition.h"
Austin Schuh99f7c6a2024-06-25 22:07:44 -070016#include "aos/init.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070017#include "aos/ipc_lib/latency_lib.h"
18#include "aos/logging/implementations.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070019#include "aos/mutex/mutex.h"
20#include "aos/realtime.h"
21#include "aos/time/time.h"
22
Austin Schuh99f7c6a2024-06-25 22:07:44 -070023ABSL_FLAG(int32_t, seconds, 10, "Duration of the test to run");
24ABSL_FLAG(
25 int32_t, latency_threshold, 1000,
Austin Schuh5af45eb2019-09-16 20:54:18 -070026 "Disable tracing when anything takes more than this many microseoncds");
Austin Schuh99f7c6a2024-06-25 22:07:44 -070027ABSL_FLAG(int32_t, core, 7, "Core to pin to");
28ABSL_FLAG(int32_t, sender_priority, 53, "RT priority to send at");
29ABSL_FLAG(int32_t, receiver_priority, 52, "RT priority to receive at");
30ABSL_FLAG(int32_t, timer_priority, 51, "RT priority to spin the timer at");
Austin Schuh5af45eb2019-09-16 20:54:18 -070031
Austin Schuh99f7c6a2024-06-25 22:07:44 -070032ABSL_FLAG(bool, log_latency, false, "If true, log the latency");
Austin Schuh5af45eb2019-09-16 20:54:18 -070033
34const uint32_t kSignalNumber = SIGRTMIN + 1;
35const uint32_t kQuitSignalNumber = SIGRTMIN + 2;
36
37namespace chrono = ::std::chrono;
38
39namespace aos {
40
41struct WakeupData {
42 Mutex mutex;
43 Condition condition;
44
45 WakeupData() : condition(&mutex) {}
46
47 monotonic_clock::time_point wakeup_time = monotonic_clock::epoch();
48
49 bool done = false;
50};
51
52void SenderThread(WakeupData *data) {
53 const monotonic_clock::time_point end_time =
Austin Schuh99f7c6a2024-06-25 22:07:44 -070054 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds));
Austin Schuh5af45eb2019-09-16 20:54:18 -070055 // Standard mersenne_twister_engine seeded with 0
56 ::std::mt19937 generator(0);
57
58 // Sleep between 1 and 15 ms.
59 ::std::uniform_int_distribution<> distribution(1000, 15000);
60
Austin Schuh99f7c6a2024-06-25 22:07:44 -070061 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
62 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_sender_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -070063 while (true) {
64 const monotonic_clock::time_point wakeup_time =
65 monotonic_clock::now() + chrono::microseconds(distribution(generator));
66
67 ::std::this_thread::sleep_until(wakeup_time);
68 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
69
70 {
71 MutexLocker locker(&data->mutex);
72 data->wakeup_time = monotonic_now;
73 data->condition.Broadcast();
74
75 if (monotonic_now > end_time) {
76 break;
77 }
78 }
79 }
80
81 {
82 MutexLocker locker(&data->mutex);
83 data->done = true;
84 data->condition.Broadcast();
85 }
86
87 UnsetCurrentThreadRealtimePriority();
88}
89
90void ReceiverThread(WakeupData *data) {
91 Tracing t;
92 t.Start();
93
94 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
95 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
96 int latency_count = 0;
97
Austin Schuh99f7c6a2024-06-25 22:07:44 -070098 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
99 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_receiver_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700100 while (true) {
101 chrono::nanoseconds wakeup_latency;
102 {
103 MutexLocker locker(&data->mutex);
104 while (data->wakeup_time == monotonic_clock::epoch() && !data->done) {
105 CHECK(!data->condition.Wait());
106 }
107
108 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
109
110 if (data->done) {
111 break;
112 }
113
114 wakeup_latency = monotonic_now - data->wakeup_time;
115 data->wakeup_time = monotonic_clock::epoch();
116 }
117
118 sum_latency += wakeup_latency;
119 ++latency_count;
120
121 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
122
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700123 if (wakeup_latency >
124 chrono::microseconds(absl::GetFlag(FLAGS_latency_threshold))) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700125 t.Stop();
126 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
127 static_cast<int64_t>(wakeup_latency.count()));
128 }
129
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700130 if (absl::GetFlag(FLAGS_log_latency)) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700131 AOS_LOG(INFO, "dt: %8d.%03d\n",
132 static_cast<int>(wakeup_latency.count() / 1000),
133 static_cast<int>(wakeup_latency.count() % 1000));
134 }
135 }
136 UnsetCurrentThreadRealtimePriority();
137
138 const chrono::nanoseconds average_latency = sum_latency / latency_count;
139
140 AOS_LOG(INFO,
141 "Max futex wakeup latency: %d.%03d microseconds, average: %d.%03d "
142 "microseconds\n",
143 static_cast<int>(max_wakeup_latency.count() / 1000),
144 static_cast<int>(max_wakeup_latency.count() % 1000),
145 static_cast<int>(average_latency.count() / 1000),
146 static_cast<int>(average_latency.count() % 1000));
147}
148
149int Main(int /*argc*/, char ** /*argv*/) {
150 WakeupData data;
151
152 AOS_LOG(INFO, "Main!\n");
153 ::std::thread t([]() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700154 TimerThread(
155 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds)),
156 absl::GetFlag(FLAGS_timer_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700157 });
158
159 ::std::thread st([&data]() { SenderThread(&data); });
160
161 ReceiverThread(&data);
162
163 st.join();
164 t.join();
165 return 0;
166}
167
168} // namespace aos
169
170int main(int argc, char **argv) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700171 aos::InitGoogle(&argc, &argv);
Austin Schuh5af45eb2019-09-16 20:54:18 -0700172
Austin Schuh5af45eb2019-09-16 20:54:18 -0700173 return ::aos::Main(argc, argv);
174}