blob: 240bf78f254869fc043986e202e4a77985f2e5ef [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
Austin Schuh99f7c6a2024-06-25 22:07:44 -070014#include "absl/flags/flag.h"
15#include "absl/log/check.h"
16#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070017
Austin Schuh5af45eb2019-09-16 20:54:18 -070018#include "aos/events/epoll.h"
Austin Schuh99f7c6a2024-06-25 22:07:44 -070019#include "aos/init.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070020#include "aos/ipc_lib/latency_lib.h"
21#include "aos/logging/implementations.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070022#include "aos/realtime.h"
23#include "aos/time/time.h"
24
25// This is a demo program which uses named pipes to communicate.
26// It measures both latency of a random timer thread, and latency of the
27// pipe.
28
Austin Schuh99f7c6a2024-06-25 22:07:44 -070029ABSL_FLAG(bool, sender, true, "If true, send signals to the other process.");
30ABSL_FLAG(std::string, fifo, "/dev/shm/aos/named_pipe_latency",
31 "FIFO to use for the test.");
32ABSL_FLAG(int32_t, seconds, 10, "Duration of the test to run");
33ABSL_FLAG(
34 int32_t, latency_threshold, 1000,
Austin Schuh5af45eb2019-09-16 20:54:18 -070035 "Disable tracing when anything takes more than this many microseoncds");
Austin Schuh99f7c6a2024-06-25 22:07:44 -070036ABSL_FLAG(int32_t, core, 7, "Core to pin to");
37ABSL_FLAG(int32_t, sender_priority, 53, "RT priority to send at");
38ABSL_FLAG(int32_t, receiver_priority, 52, "RT priority to receive at");
39ABSL_FLAG(int32_t, timer_priority, 51, "RT priority to spin the timer at");
Austin Schuh5af45eb2019-09-16 20:54:18 -070040
Austin Schuh99f7c6a2024-06-25 22:07:44 -070041ABSL_FLAG(bool, log_latency, false, "If true, log the latency");
Austin Schuh5af45eb2019-09-16 20:54:18 -070042
43namespace chrono = ::std::chrono;
44
45namespace aos {
46
47void SenderThread() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -070048 int pipefd = open(absl::GetFlag(FLAGS_fifo).c_str(),
49 FD_CLOEXEC | O_NONBLOCK | O_WRONLY | O_NOATIME);
Austin Schuh5af45eb2019-09-16 20:54:18 -070050 const monotonic_clock::time_point end_time =
Austin Schuh99f7c6a2024-06-25 22:07:44 -070051 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds));
Austin Schuh5af45eb2019-09-16 20:54:18 -070052 // Standard mersenne_twister_engine seeded with 0
53 ::std::mt19937 generator(0);
54
55 // Sleep between 1 and 15 ms.
56 ::std::uniform_int_distribution<> distribution(1000, 15000);
57
Austin Schuh99f7c6a2024-06-25 22:07:44 -070058 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
59 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_sender_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -070060 while (true) {
61 const monotonic_clock::time_point wakeup_time =
62 monotonic_clock::now() + chrono::microseconds(distribution(generator));
63
64 ::std::this_thread::sleep_until(wakeup_time);
65 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
66 char sent_time_buffer[8];
67 memcpy(sent_time_buffer, &monotonic_now, sizeof(sent_time_buffer));
68 PCHECK(write(pipefd, static_cast<void *>(sent_time_buffer),
69 sizeof(sent_time_buffer)));
70
71 if (monotonic_now > end_time) {
72 break;
73 }
74 }
75
76 {
77 char sent_time_buffer[8];
78 memset(sent_time_buffer, 0, sizeof(sent_time_buffer));
79 PCHECK(write(pipefd, static_cast<void *>(sent_time_buffer),
80 sizeof(sent_time_buffer)));
81 }
82 UnsetCurrentThreadRealtimePriority();
83
84 PCHECK(close(pipefd));
85}
86
87void ReceiverThread() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -070088 int pipefd = open(absl::GetFlag(FLAGS_fifo).c_str(),
89 O_CLOEXEC | O_NONBLOCK | O_RDONLY | O_NOATIME);
Austin Schuh5af45eb2019-09-16 20:54:18 -070090 Tracing t;
91 t.Start();
92
93 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
94
95 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
96 int latency_count = 0;
97
98 internal::EPoll epoll;
99
100 epoll.OnReadable(pipefd, [&t, &epoll, &max_wakeup_latency, &sum_latency,
101 &latency_count, pipefd]() {
102 char sent_time_buffer[8];
103 const int ret = read(pipefd, static_cast<void *>(sent_time_buffer),
104 sizeof(sent_time_buffer));
105 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
106 CHECK_EQ(ret, 8);
107
108 monotonic_clock::time_point sent_time;
109 memcpy(&sent_time, sent_time_buffer, sizeof(sent_time_buffer));
110
111 if (sent_time == monotonic_clock::epoch()) {
112 epoll.Quit();
113 return;
114 }
115
116 const chrono::nanoseconds wakeup_latency = monotonic_now - sent_time;
117
118 sum_latency += wakeup_latency;
119 ++latency_count;
120
121 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
122
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700123 if (wakeup_latency >
124 chrono::microseconds(absl::GetFlag(FLAGS_latency_threshold))) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700125 t.Stop();
126 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
127 static_cast<int64_t>(wakeup_latency.count()));
128 }
129
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700130 if (absl::GetFlag(FLAGS_log_latency)) {
Austin Schuh5af45eb2019-09-16 20:54:18 -0700131 AOS_LOG(INFO, "dt: %8d.%03d\n",
132 static_cast<int>(wakeup_latency.count() / 1000),
133 static_cast<int>(wakeup_latency.count() % 1000));
134 }
135 });
136
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700137 SetCurrentThreadAffinity(MakeCpusetFromCpus({absl::GetFlag(FLAGS_core)}));
138 SetCurrentThreadRealtimePriority(absl::GetFlag(FLAGS_receiver_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700139 epoll.Run();
140 UnsetCurrentThreadRealtimePriority();
141 epoll.DeleteFd(pipefd);
142
143 const chrono::nanoseconds average_latency = sum_latency / latency_count;
144
145 AOS_LOG(
146 INFO,
147 "Max named pip wakeup latency: %d.%03d microseconds, average: %d.%03d "
148 "microseconds\n",
149 static_cast<int>(max_wakeup_latency.count() / 1000),
150 static_cast<int>(max_wakeup_latency.count() % 1000),
151 static_cast<int>(average_latency.count() / 1000),
152 static_cast<int>(average_latency.count() % 1000));
153
154 PCHECK(close(pipefd));
155}
156
157int Main(int /*argc*/, char ** /*argv*/) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700158 mkfifo(absl::GetFlag(FLAGS_fifo).c_str(), 0777);
Austin Schuh5af45eb2019-09-16 20:54:18 -0700159
160 AOS_LOG(INFO, "Main!\n");
161 ::std::thread t([]() {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700162 TimerThread(
163 monotonic_clock::now() + chrono::seconds(absl::GetFlag(FLAGS_seconds)),
164 absl::GetFlag(FLAGS_timer_priority));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700165 });
166
Austin Schuha0c41ba2020-09-10 22:59:14 -0700167 ::std::thread st([]() { SenderThread(); });
Austin Schuh5af45eb2019-09-16 20:54:18 -0700168
169 ReceiverThread();
170 st.join();
171
172 t.join();
173 return 0;
174}
175
176} // namespace aos
177
178int main(int argc, char **argv) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -0700179 aos::InitGoogle(&argc, &argv);
Austin Schuh5af45eb2019-09-16 20:54:18 -0700180
Austin Schuh5af45eb2019-09-16 20:54:18 -0700181 return ::aos::Main(argc, argv);
182}