blob: e35f8fc84c8494336e65d8b6b39507d04886899e [file] [log] [blame]
Stephan Pleines682928d2024-05-31 20:43:48 -07001#include <inttypes.h>
2#include <string.h>
Austin Schuh5af45eb2019-09-16 20:54:18 -07003#include <sys/eventfd.h>
Stephan Pleines682928d2024-05-31 20:43:48 -07004#include <unistd.h>
Austin Schuh60e77942022-05-16 17:48:24 -07005
Stephan Pleines682928d2024-05-31 20:43:48 -07006#include <algorithm>
Austin Schuh5af45eb2019-09-16 20:54:18 -07007#include <chrono>
Stephan Pleines682928d2024-05-31 20:43:48 -07008#include <compare>
Austin Schuh5af45eb2019-09-16 20:54:18 -07009#include <random>
Stephan Pleines682928d2024-05-31 20:43:48 -070010#include <ratio>
Austin Schuh5af45eb2019-09-16 20:54:18 -070011#include <thread>
12
Austin Schuh99f7c6a2024-06-25 22:07:44 -070013#include "absl/flags/flag.h"
14#include "absl/log/check.h"
15#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070016
Austin Schuh5af45eb2019-09-16 20:54:18 -070017#include "aos/events/epoll.h"
Austin Schuh99f7c6a2024-06-25 22:07:44 -070018#include "aos/init.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070019#include "aos/ipc_lib/latency_lib.h"
20#include "aos/logging/implementations.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070021#include "aos/realtime.h"
22#include "aos/time/time.h"
23
24// This is a demo program which uses named pipes to communicate.
25// It measures both latency of a random timer thread, and latency of the
26// pipe.
27
Austin Schuh99f7c6a2024-06-25 22:07:44 -070028ABSL_FLAG(int32_t, seconds, 10, "Duration of the test to run");
29ABSL_FLAG(
30 int32_t, latency_threshold, 1000,
Austin Schuh5af45eb2019-09-16 20:54:18 -070031 "Disable tracing when anything takes more than this many microseoncds");
Austin Schuh99f7c6a2024-06-25 22:07:44 -070032ABSL_FLAG(int32_t, core, 7, "Core to pin to");
33ABSL_FLAG(int32_t, sender_priority, 53, "RT priority to send at");
34ABSL_FLAG(int32_t, receiver_priority, 52, "RT priority to receive at");
35ABSL_FLAG(int32_t, timer_priority, 51, "RT priority to spin the timer at");
Austin Schuh5af45eb2019-09-16 20:54:18 -070036
Austin Schuh99f7c6a2024-06-25 22:07:44 -070037ABSL_FLAG(bool, log_latency, false, "If true, log the latency");
Austin Schuh5af45eb2019-09-16 20:54:18 -070038
39namespace chrono = ::std::chrono;
40
41namespace aos {
42
43void SenderThread(int fd) {
44 const monotonic_clock::time_point end_time =
Austin Schuh99f7c6a2024-06-25 22:07:44 -070045 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds));
Austin Schuh5af45eb2019-09-16 20:54:18 -070046 // Standard mersenne_twister_engine seeded with 0
47 ::std::mt19937 generator(0);
48
49 // Sleep between 1 and 15 ms.
50 ::std::uniform_int_distribution<> distribution(1000, 15000);
51
Austin Schuh99f7c6a2024-06-25 22:07:44 -070052 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
53 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_sender_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -070054 while (true) {
55 const monotonic_clock::time_point wakeup_time =
56 monotonic_clock::now() + chrono::microseconds(distribution(generator));
57
58 ::std::this_thread::sleep_until(wakeup_time);
59 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
60 char sent_time_buffer[8];
61 memcpy(sent_time_buffer, &monotonic_now, sizeof(sent_time_buffer));
62 PCHECK(write(fd, sent_time_buffer, sizeof(sent_time_buffer)));
63
64 if (monotonic_now > end_time) {
65 break;
66 }
67 }
68
69 {
70 ::std::this_thread::sleep_for(chrono::milliseconds(100));
71 const monotonic_clock::time_point stop_time(chrono::nanoseconds(1));
72 char sent_time_buffer[8];
73 memcpy(sent_time_buffer, &stop_time, sizeof(sent_time_buffer));
74 PCHECK(write(fd, sent_time_buffer, sizeof(sent_time_buffer)));
75 }
76 UnsetCurrentThreadRealtimePriority();
77}
78
79void ReceiverThread(int fd) {
80 Tracing t;
81 t.Start();
82
83 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
84
85 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
86 int latency_count = 0;
87
88 internal::EPoll epoll;
89
90 epoll.OnReadable(fd, [&t, &epoll, &max_wakeup_latency, &sum_latency,
91 &latency_count, fd]() {
92 char sent_time_buffer[8];
93 const int ret = read(fd, static_cast<void *>(sent_time_buffer),
94 sizeof(sent_time_buffer));
95 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
96 CHECK_EQ(ret, 8);
97
98 monotonic_clock::time_point sent_time;
99 memcpy(&sent_time, sent_time_buffer, sizeof(sent_time_buffer));
100
101 if (sent_time == monotonic_clock::time_point(chrono::nanoseconds(1))) {
102 epoll.Quit();
103 return;
104 }
105
106 const chrono::nanoseconds wakeup_latency = monotonic_now - sent_time;
107
108 sum_latency += wakeup_latency;
109 ++latency_count;
110
111 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
112
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700113 if (wakeup_latency >
114 chrono::microseconds(absl::GetFlag(FLAGS_latency_threshold))) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700115 t.Stop();
116 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
117 static_cast<int64_t>(wakeup_latency.count()));
118 }
119
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700120 if (absl::GetFlag(FLAGS_log_latency)) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700121 AOS_LOG(INFO, "dt: %8d.%03d\n",
122 static_cast<int>(wakeup_latency.count() / 1000),
123 static_cast<int>(wakeup_latency.count() % 1000));
124 }
125 });
126
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700127 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
128 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_receiver_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700129 epoll.Run();
130 UnsetCurrentThreadRealtimePriority();
131 epoll.DeleteFd(fd);
132
133 const chrono::nanoseconds average_latency = sum_latency / latency_count;
134
135 AOS_LOG(INFO,
136 "Max eventfd wakeup latency: %d.%03d microseconds, average: %d.%03d "
137 "microseconds\n",
138 static_cast<int>(max_wakeup_latency.count() / 1000),
139 static_cast<int>(max_wakeup_latency.count() % 1000),
140 static_cast<int>(average_latency.count() / 1000),
141 static_cast<int>(average_latency.count() % 1000));
142}
143
144int Main(int /*argc*/, char ** /*argv*/) {
145 AOS_LOG(INFO, "Main!\n");
146 ::std::thread t([]() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700147 TimerThread(
148 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds)),
149 absl::GetFlag(FLAGS_timer_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700150 });
151
152 int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
153 PCHECK(fd);
154
155 ::std::thread st([&fd]() { SenderThread(fd); });
156
157 ReceiverThread(fd);
158 st.join();
159
160 PCHECK(close(fd));
161
162 t.join();
163 return 0;
164}
165
166} // namespace aos
167
168int main(int argc, char **argv) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700169 aos::InitGoogle(&argc, &argv);
Austin Schuh5af45eb2019-09-16 20:54:18 -0700170
Austin Schuh5af45eb2019-09-16 20:54:18 -0700171 return ::aos::Main(argc, argv);
172}