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