blob: 032b72ea3cc9b493cc23a5bcda29906ffee19ee4 [file] [log] [blame]
Austin Schuh5af45eb2019-09-16 20:54:18 -07001#include <sys/stat.h>
2#include <sys/types.h>
Austin Schuh60e77942022-05-16 17:48:24 -07003
Austin Schuh5af45eb2019-09-16 20:54:18 -07004#include <chrono>
5#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 named pipes to communicate.
19// It measures both latency of a random timer thread, and latency of the
20// pipe.
21
22DEFINE_bool(sender, true, "If true, send signals to the other process.");
Austin Schuha0c41ba2020-09-10 22:59:14 -070023DEFINE_string(fifo, "/dev/shm/aos/named_pipe_latency",
24 "FIFO to use for the test.");
Austin Schuh5af45eb2019-09-16 20:54:18 -070025DEFINE_int32(seconds, 10, "Duration of the test to run");
26DEFINE_int32(
27 latency_threshold, 1000,
28 "Disable tracing when anything takes more than this many microseoncds");
29DEFINE_int32(core, 7, "Core to pin to");
30DEFINE_int32(sender_priority, 53, "RT priority to send at");
31DEFINE_int32(receiver_priority, 52, "RT priority to receive at");
32DEFINE_int32(timer_priority, 51, "RT priority to spin the timer at");
33
34DEFINE_bool(log_latency, false, "If true, log the latency");
35
36namespace chrono = ::std::chrono;
37
38namespace aos {
39
40void SenderThread() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070041 int pipefd =
42 open(FLAGS_fifo.c_str(), FD_CLOEXEC | O_NONBLOCK | O_WRONLY | O_NOATIME);
Austin Schuh5af45eb2019-09-16 20:54:18 -070043 const monotonic_clock::time_point end_time =
44 monotonic_clock::now() + chrono::seconds(FLAGS_seconds);
45 // Standard mersenne_twister_engine seeded with 0
46 ::std::mt19937 generator(0);
47
48 // Sleep between 1 and 15 ms.
49 ::std::uniform_int_distribution<> distribution(1000, 15000);
50
Austin Schuh9014e3b2020-11-21 14:26:07 -080051 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -070052 SetCurrentThreadRealtimePriority(FLAGS_sender_priority);
53 while (true) {
54 const monotonic_clock::time_point wakeup_time =
55 monotonic_clock::now() + chrono::microseconds(distribution(generator));
56
57 ::std::this_thread::sleep_until(wakeup_time);
58 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
59 char sent_time_buffer[8];
60 memcpy(sent_time_buffer, &monotonic_now, sizeof(sent_time_buffer));
61 PCHECK(write(pipefd, static_cast<void *>(sent_time_buffer),
62 sizeof(sent_time_buffer)));
63
64 if (monotonic_now > end_time) {
65 break;
66 }
67 }
68
69 {
70 char sent_time_buffer[8];
71 memset(sent_time_buffer, 0, sizeof(sent_time_buffer));
72 PCHECK(write(pipefd, static_cast<void *>(sent_time_buffer),
73 sizeof(sent_time_buffer)));
74 }
75 UnsetCurrentThreadRealtimePriority();
76
77 PCHECK(close(pipefd));
78}
79
80void ReceiverThread() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070081 int pipefd =
82 open(FLAGS_fifo.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY | O_NOATIME);
Austin Schuh5af45eb2019-09-16 20:54:18 -070083 Tracing t;
84 t.Start();
85
86 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
87
88 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
89 int latency_count = 0;
90
91 internal::EPoll epoll;
92
93 epoll.OnReadable(pipefd, [&t, &epoll, &max_wakeup_latency, &sum_latency,
94 &latency_count, pipefd]() {
95 char sent_time_buffer[8];
96 const int ret = read(pipefd, static_cast<void *>(sent_time_buffer),
97 sizeof(sent_time_buffer));
98 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
99 CHECK_EQ(ret, 8);
100
101 monotonic_clock::time_point sent_time;
102 memcpy(&sent_time, sent_time_buffer, sizeof(sent_time_buffer));
103
104 if (sent_time == monotonic_clock::epoch()) {
105 epoll.Quit();
106 return;
107 }
108
109 const chrono::nanoseconds wakeup_latency = monotonic_now - sent_time;
110
111 sum_latency += wakeup_latency;
112 ++latency_count;
113
114 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
115
116 if (wakeup_latency > chrono::microseconds(FLAGS_latency_threshold)) {
117 t.Stop();
118 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
119 static_cast<int64_t>(wakeup_latency.count()));
120 }
121
122 if (FLAGS_log_latency) {
123 AOS_LOG(INFO, "dt: %8d.%03d\n",
124 static_cast<int>(wakeup_latency.count() / 1000),
125 static_cast<int>(wakeup_latency.count() % 1000));
126 }
127 });
128
Austin Schuh9014e3b2020-11-21 14:26:07 -0800129 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700130 SetCurrentThreadRealtimePriority(FLAGS_receiver_priority);
131 epoll.Run();
132 UnsetCurrentThreadRealtimePriority();
133 epoll.DeleteFd(pipefd);
134
135 const chrono::nanoseconds average_latency = sum_latency / latency_count;
136
137 AOS_LOG(
138 INFO,
139 "Max named pip wakeup latency: %d.%03d microseconds, average: %d.%03d "
140 "microseconds\n",
141 static_cast<int>(max_wakeup_latency.count() / 1000),
142 static_cast<int>(max_wakeup_latency.count() % 1000),
143 static_cast<int>(average_latency.count() / 1000),
144 static_cast<int>(average_latency.count() % 1000));
145
146 PCHECK(close(pipefd));
147}
148
149int Main(int /*argc*/, char ** /*argv*/) {
150 mkfifo(FLAGS_fifo.c_str(), 0777);
151
152 AOS_LOG(INFO, "Main!\n");
153 ::std::thread t([]() {
154 TimerThread(monotonic_clock::now() + chrono::seconds(FLAGS_seconds),
155 FLAGS_timer_priority);
156 });
157
Austin Schuha0c41ba2020-09-10 22:59:14 -0700158 ::std::thread st([]() { SenderThread(); });
Austin Schuh5af45eb2019-09-16 20:54:18 -0700159
160 ReceiverThread();
161 st.join();
162
163 t.join();
164 return 0;
165}
166
167} // namespace aos
168
169int main(int argc, char **argv) {
170 ::gflags::ParseCommandLineFlags(&argc, &argv, true);
171
Austin Schuh5af45eb2019-09-16 20:54:18 -0700172 return ::aos::Main(argc, argv);
173}