blob: 023853deed4845c676ffcdec57ae3b9d94377a46 [file] [log] [blame]
Stephan Pleines682928d2024-05-31 20:43:48 -07001#include <fcntl.h>
2#include <inttypes.h>
3#include <string.h>
Austin Schuh5af45eb2019-09-16 20:54:18 -07004#include <sys/stat.h>
Stephan Pleines682928d2024-05-31 20:43:48 -07005#include <unistd.h>
Austin Schuh60e77942022-05-16 17:48:24 -07006
Stephan Pleines682928d2024-05-31 20:43:48 -07007#include <algorithm>
Austin Schuh5af45eb2019-09-16 20:54:18 -07008#include <chrono>
Stephan Pleines682928d2024-05-31 20:43:48 -07009#include <compare>
Austin Schuh5af45eb2019-09-16 20:54:18 -070010#include <random>
Stephan Pleines682928d2024-05-31 20:43:48 -070011#include <ratio>
Austin Schuh5af45eb2019-09-16 20:54:18 -070012#include <thread>
13
Philipp Schrader790cb542023-07-05 21:06:52 -070014#include "gflags/gflags.h"
Stephan Pleines682928d2024-05-31 20:43:48 -070015#include "glog/logging.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070016
Austin Schuh5af45eb2019-09-16 20:54:18 -070017#include "aos/events/epoll.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070018#include "aos/ipc_lib/latency_lib.h"
19#include "aos/logging/implementations.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070020#include "aos/realtime.h"
21#include "aos/time/time.h"
22
23// This is a demo program which uses named pipes to communicate.
24// It measures both latency of a random timer thread, and latency of the
25// pipe.
26
27DEFINE_bool(sender, true, "If true, send signals to the other process.");
Austin Schuha0c41ba2020-09-10 22:59:14 -070028DEFINE_string(fifo, "/dev/shm/aos/named_pipe_latency",
29 "FIFO to use for the test.");
Austin Schuh5af45eb2019-09-16 20:54:18 -070030DEFINE_int32(seconds, 10, "Duration of the test to run");
31DEFINE_int32(
32 latency_threshold, 1000,
33 "Disable tracing when anything takes more than this many microseoncds");
34DEFINE_int32(core, 7, "Core to pin to");
35DEFINE_int32(sender_priority, 53, "RT priority to send at");
36DEFINE_int32(receiver_priority, 52, "RT priority to receive at");
37DEFINE_int32(timer_priority, 51, "RT priority to spin the timer at");
38
39DEFINE_bool(log_latency, false, "If true, log the latency");
40
41namespace chrono = ::std::chrono;
42
43namespace aos {
44
45void SenderThread() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070046 int pipefd =
47 open(FLAGS_fifo.c_str(), FD_CLOEXEC | O_NONBLOCK | O_WRONLY | O_NOATIME);
Austin Schuh5af45eb2019-09-16 20:54:18 -070048 const monotonic_clock::time_point end_time =
49 monotonic_clock::now() + chrono::seconds(FLAGS_seconds);
50 // Standard mersenne_twister_engine seeded with 0
51 ::std::mt19937 generator(0);
52
53 // Sleep between 1 and 15 ms.
54 ::std::uniform_int_distribution<> distribution(1000, 15000);
55
Austin Schuh9014e3b2020-11-21 14:26:07 -080056 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -070057 SetCurrentThreadRealtimePriority(FLAGS_sender_priority);
58 while (true) {
59 const monotonic_clock::time_point wakeup_time =
60 monotonic_clock::now() + chrono::microseconds(distribution(generator));
61
62 ::std::this_thread::sleep_until(wakeup_time);
63 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
64 char sent_time_buffer[8];
65 memcpy(sent_time_buffer, &monotonic_now, sizeof(sent_time_buffer));
66 PCHECK(write(pipefd, static_cast<void *>(sent_time_buffer),
67 sizeof(sent_time_buffer)));
68
69 if (monotonic_now > end_time) {
70 break;
71 }
72 }
73
74 {
75 char sent_time_buffer[8];
76 memset(sent_time_buffer, 0, sizeof(sent_time_buffer));
77 PCHECK(write(pipefd, static_cast<void *>(sent_time_buffer),
78 sizeof(sent_time_buffer)));
79 }
80 UnsetCurrentThreadRealtimePriority();
81
82 PCHECK(close(pipefd));
83}
84
85void ReceiverThread() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070086 int pipefd =
87 open(FLAGS_fifo.c_str(), O_CLOEXEC | O_NONBLOCK | O_RDONLY | O_NOATIME);
Austin Schuh5af45eb2019-09-16 20:54:18 -070088 Tracing t;
89 t.Start();
90
91 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
92
93 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
94 int latency_count = 0;
95
96 internal::EPoll epoll;
97
98 epoll.OnReadable(pipefd, [&t, &epoll, &max_wakeup_latency, &sum_latency,
99 &latency_count, pipefd]() {
100 char sent_time_buffer[8];
101 const int ret = read(pipefd, static_cast<void *>(sent_time_buffer),
102 sizeof(sent_time_buffer));
103 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
104 CHECK_EQ(ret, 8);
105
106 monotonic_clock::time_point sent_time;
107 memcpy(&sent_time, sent_time_buffer, sizeof(sent_time_buffer));
108
109 if (sent_time == monotonic_clock::epoch()) {
110 epoll.Quit();
111 return;
112 }
113
114 const chrono::nanoseconds wakeup_latency = monotonic_now - sent_time;
115
116 sum_latency += wakeup_latency;
117 ++latency_count;
118
119 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
120
121 if (wakeup_latency > chrono::microseconds(FLAGS_latency_threshold)) {
122 t.Stop();
123 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
124 static_cast<int64_t>(wakeup_latency.count()));
125 }
126
127 if (FLAGS_log_latency) {
128 AOS_LOG(INFO, "dt: %8d.%03d\n",
129 static_cast<int>(wakeup_latency.count() / 1000),
130 static_cast<int>(wakeup_latency.count() % 1000));
131 }
132 });
133
Austin Schuh9014e3b2020-11-21 14:26:07 -0800134 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700135 SetCurrentThreadRealtimePriority(FLAGS_receiver_priority);
136 epoll.Run();
137 UnsetCurrentThreadRealtimePriority();
138 epoll.DeleteFd(pipefd);
139
140 const chrono::nanoseconds average_latency = sum_latency / latency_count;
141
142 AOS_LOG(
143 INFO,
144 "Max named pip wakeup latency: %d.%03d microseconds, average: %d.%03d "
145 "microseconds\n",
146 static_cast<int>(max_wakeup_latency.count() / 1000),
147 static_cast<int>(max_wakeup_latency.count() % 1000),
148 static_cast<int>(average_latency.count() / 1000),
149 static_cast<int>(average_latency.count() % 1000));
150
151 PCHECK(close(pipefd));
152}
153
154int Main(int /*argc*/, char ** /*argv*/) {
155 mkfifo(FLAGS_fifo.c_str(), 0777);
156
157 AOS_LOG(INFO, "Main!\n");
158 ::std::thread t([]() {
159 TimerThread(monotonic_clock::now() + chrono::seconds(FLAGS_seconds),
160 FLAGS_timer_priority);
161 });
162
Austin Schuha0c41ba2020-09-10 22:59:14 -0700163 ::std::thread st([]() { SenderThread(); });
Austin Schuh5af45eb2019-09-16 20:54:18 -0700164
165 ReceiverThread();
166 st.join();
167
168 t.join();
169 return 0;
170}
171
172} // namespace aos
173
174int main(int argc, char **argv) {
175 ::gflags::ParseCommandLineFlags(&argc, &argv, true);
176
Austin Schuh5af45eb2019-09-16 20:54:18 -0700177 return ::aos::Main(argc, argv);
178}