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