blob: d5d13234ead7d1be68ef5952a454b5445f11833a [file] [log] [blame]
Stephan Pleines682928d2024-05-31 20:43:48 -07001#include <inttypes.h>
Austin Schuh5af45eb2019-09-16 20:54:18 -07002#include <sys/signalfd.h>
Stephan Pleines682928d2024-05-31 20:43:48 -07003#include <unistd.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004
Stephan Pleines682928d2024-05-31 20:43:48 -07005#include <algorithm>
Austin Schuh5af45eb2019-09-16 20:54:18 -07006#include <chrono>
Stephan Pleines682928d2024-05-31 20:43:48 -07007#include <compare>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07008#include <csignal>
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 Real-Time posix signals to communicate.
25// It measures both latency of a random timer thread, and latency of the
26// signals.
27//
28// To enable function graph:
29// echo "function_graph" > current_tracer
30
Austin Schuh99f7c6a2024-06-25 22:07:44 -070031ABSL_FLAG(bool, sender, true, "If true, send signals to the other process.");
32ABSL_FLAG(int32_t, other_pid, -1, "PID of other process to ping");
33ABSL_FLAG(int32_t, seconds, 10, "Duration of the test to run");
34ABSL_FLAG(
35 int32_t, latency_threshold, 1000,
Austin Schuh5af45eb2019-09-16 20:54:18 -070036 "Disable tracing when anything takes more than this many microseoncds");
Austin Schuh99f7c6a2024-06-25 22:07:44 -070037ABSL_FLAG(int32_t, core, 7, "Core to pin to");
38ABSL_FLAG(int32_t, sender_priority, 53, "RT priority to send at");
39ABSL_FLAG(int32_t, receiver_priority, 52, "RT priority to receive at");
40ABSL_FLAG(int32_t, timer_priority, 51, "RT priority to spin the timer at");
Austin Schuh5af45eb2019-09-16 20:54:18 -070041
Austin Schuh99f7c6a2024-06-25 22:07:44 -070042ABSL_FLAG(bool, log_latency, false, "If true, log the latency");
Austin Schuh5af45eb2019-09-16 20:54:18 -070043
44const uint32_t kSignalNumber = SIGRTMIN + 1;
45const uint32_t kQuitSignalNumber = SIGRTMIN + 2;
46
47namespace chrono = ::std::chrono;
48
49namespace aos {
50
51void SenderThread() {
52 const monotonic_clock::time_point end_time =
Austin Schuh99f7c6a2024-06-25 22:07:44 -070053 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds));
Austin Schuh5af45eb2019-09-16 20:54:18 -070054 // Standard mersenne_twister_engine seeded with 0
55 ::std::mt19937 generator(0);
56
57 // Sleep between 1 and 15 ms.
58 ::std::uniform_int_distribution<> distribution(1000, 15000);
59
60 int pid = getpid();
Austin Schuh99f7c6a2024-06-25 22:07:44 -070061 if (absl::GetFlag(FLAGS_other_pid) != -1) {
62 pid = absl::GetFlag(FLAGS_other_pid);
Austin Schuh5af45eb2019-09-16 20:54:18 -070063 }
64 AOS_LOG(INFO, "Current PID: %d\n", pid);
65
Austin Schuh99f7c6a2024-06-25 22:07:44 -070066 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
67 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_sender_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -070068 while (true) {
69 const monotonic_clock::time_point wakeup_time =
70 monotonic_clock::now() + chrono::microseconds(distribution(generator));
71
72 ::std::this_thread::sleep_until(wakeup_time);
73 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
74 sigval s;
75 s.sival_int = static_cast<uint32_t>(
76 static_cast<uint64_t>(monotonic_now.time_since_epoch().count()) &
77 0xfffffffful);
78
79 PCHECK(sigqueue(pid, kSignalNumber, s));
80
81 if (monotonic_now > end_time) {
82 break;
83 }
84 }
85
86 {
87 sigval s;
88 s.sival_int = 0;
89 PCHECK(sigqueue(pid, kQuitSignalNumber, s));
90 }
91 UnsetCurrentThreadRealtimePriority();
92}
93
94void ReceiverThread() {
95 int signalfd_fd;
96 Tracing t;
97 t.Start();
98
99 sigset_t x;
100 sigemptyset(&x);
101 sigaddset(&x, kSignalNumber);
102 sigaddset(&x, kQuitSignalNumber);
103
104 PCHECK(signalfd_fd = signalfd(-1, &x, SFD_NONBLOCK | SFD_CLOEXEC));
105 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
106
107 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
108 int latency_count = 0;
109
110 internal::EPoll epoll;
111
112 epoll.OnReadable(signalfd_fd, [&t, &epoll, &max_wakeup_latency, &sum_latency,
113 &latency_count, signalfd_fd]() {
114 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
115 signalfd_siginfo si;
116 const int ret =
117 read(signalfd_fd, static_cast<void *>(&si), sizeof(signalfd_siginfo));
118 CHECK_EQ(ret, static_cast<int>(sizeof(signalfd_siginfo)));
119
120 if (si.ssi_signo == kQuitSignalNumber) {
121 epoll.Quit();
122 return;
123 }
124
125 int64_t wakeup_latency_int64 =
126 static_cast<int64_t>(monotonic_now.time_since_epoch().count()) &
127 0xfffffffful;
128
129 wakeup_latency_int64 -= static_cast<int64_t>(si.ssi_int);
130
131 if (wakeup_latency_int64 > 0x80000000l) {
132 wakeup_latency_int64 -= 0x100000000l;
133 }
134
135 const chrono::nanoseconds wakeup_latency(wakeup_latency_int64);
136
137 sum_latency += wakeup_latency;
138 ++latency_count;
139
140 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
141
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700142 if (wakeup_latency >
143 chrono::microseconds(absl::GetFlag(FLAGS_latency_threshold))) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700144 t.Stop();
145 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
146 static_cast<int64_t>(wakeup_latency.count()));
147 }
148
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700149 if (absl::GetFlag(FLAGS_log_latency)) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700150 AOS_LOG(INFO, "signo: %d, sending pid: %d, dt: %8d.%03d\n", si.ssi_signo,
151 si.ssi_pid, static_cast<int>(wakeup_latency_int64 / 1000),
152 static_cast<int>(wakeup_latency_int64 % 1000));
153 }
154 });
155
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700156 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
157 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_receiver_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700158 epoll.Run();
159 UnsetCurrentThreadRealtimePriority();
160 epoll.DeleteFd(signalfd_fd);
161
162 const chrono::nanoseconds average_latency = sum_latency / latency_count;
163
164 AOS_LOG(INFO,
165 "Max signal wakeup latency: %d.%03d microseconds, average: %d.%03d "
166 "microseconds\n",
167 static_cast<int>(max_wakeup_latency.count() / 1000),
168 static_cast<int>(max_wakeup_latency.count() % 1000),
169 static_cast<int>(average_latency.count() / 1000),
170 static_cast<int>(average_latency.count() % 1000));
171
172 PCHECK(close(signalfd_fd));
173}
174
175int Main(int /*argc*/, char ** /*argv*/) {
176 sigset_t x;
177 sigemptyset(&x);
178 sigaddset(&x, kSignalNumber);
179 sigaddset(&x, kQuitSignalNumber);
180 pthread_sigmask(SIG_BLOCK, &x, NULL);
181
182 AOS_LOG(INFO, "Main!\n");
183 ::std::thread t([]() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700184 TimerThread(
185 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds)),
186 absl::GetFlag(FLAGS_timer_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700187 });
188
189 ::std::thread st([]() { SenderThread(); });
190
191 ReceiverThread();
192 st.join();
193
194 t.join();
195 return 0;
196}
197
198} // namespace aos
199
200int main(int argc, char **argv) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700201 aos::InitGoogle(&argc, &argv);
Austin Schuh5af45eb2019-09-16 20:54:18 -0700202
Austin Schuh5af45eb2019-09-16 20:54:18 -0700203 return ::aos::Main(argc, argv);
204}