blob: 4a5616f7709b21b8adb2b10914ffc6644a89b0d9 [file] [log] [blame]
Stephan Pleines682928d2024-05-31 20:43:48 -07001#include <inttypes.h>
2#include <string.h>
Austin Schuh5af45eb2019-09-16 20:54:18 -07003#include <sys/eventfd.h>
Stephan Pleines682928d2024-05-31 20:43:48 -07004#include <unistd.h>
Austin Schuh60e77942022-05-16 17:48:24 -07005
Stephan Pleines682928d2024-05-31 20:43:48 -07006#include <algorithm>
Austin Schuh5af45eb2019-09-16 20:54:18 -07007#include <chrono>
Stephan Pleines682928d2024-05-31 20:43:48 -07008#include <compare>
Austin Schuh5af45eb2019-09-16 20:54:18 -07009#include <random>
Stephan Pleines682928d2024-05-31 20:43:48 -070010#include <ratio>
Austin Schuh5af45eb2019-09-16 20:54:18 -070011#include <thread>
12
Philipp Schrader790cb542023-07-05 21:06:52 -070013#include "gflags/gflags.h"
Stephan Pleines682928d2024-05-31 20:43:48 -070014#include "glog/logging.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070015
Austin Schuh5af45eb2019-09-16 20:54:18 -070016#include "aos/events/epoll.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070017#include "aos/ipc_lib/latency_lib.h"
18#include "aos/logging/implementations.h"
Austin Schuh5af45eb2019-09-16 20:54:18 -070019#include "aos/realtime.h"
20#include "aos/time/time.h"
21
22// This is a demo program which uses named pipes to communicate.
23// It measures both latency of a random timer thread, and latency of the
24// pipe.
25
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
37namespace chrono = ::std::chrono;
38
39namespace aos {
40
41void SenderThread(int fd) {
42 const monotonic_clock::time_point end_time =
43 monotonic_clock::now() + chrono::seconds(FLAGS_seconds);
44 // Standard mersenne_twister_engine seeded with 0
45 ::std::mt19937 generator(0);
46
47 // Sleep between 1 and 15 ms.
48 ::std::uniform_int_distribution<> distribution(1000, 15000);
49
Austin Schuh9014e3b2020-11-21 14:26:07 -080050 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -070051 SetCurrentThreadRealtimePriority(FLAGS_sender_priority);
52 while (true) {
53 const monotonic_clock::time_point wakeup_time =
54 monotonic_clock::now() + chrono::microseconds(distribution(generator));
55
56 ::std::this_thread::sleep_until(wakeup_time);
57 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
58 char sent_time_buffer[8];
59 memcpy(sent_time_buffer, &monotonic_now, sizeof(sent_time_buffer));
60 PCHECK(write(fd, sent_time_buffer, sizeof(sent_time_buffer)));
61
62 if (monotonic_now > end_time) {
63 break;
64 }
65 }
66
67 {
68 ::std::this_thread::sleep_for(chrono::milliseconds(100));
69 const monotonic_clock::time_point stop_time(chrono::nanoseconds(1));
70 char sent_time_buffer[8];
71 memcpy(sent_time_buffer, &stop_time, sizeof(sent_time_buffer));
72 PCHECK(write(fd, sent_time_buffer, sizeof(sent_time_buffer)));
73 }
74 UnsetCurrentThreadRealtimePriority();
75}
76
77void ReceiverThread(int fd) {
78 Tracing t;
79 t.Start();
80
81 chrono::nanoseconds max_wakeup_latency = chrono::nanoseconds(0);
82
83 chrono::nanoseconds sum_latency = chrono::nanoseconds(0);
84 int latency_count = 0;
85
86 internal::EPoll epoll;
87
88 epoll.OnReadable(fd, [&t, &epoll, &max_wakeup_latency, &sum_latency,
89 &latency_count, fd]() {
90 char sent_time_buffer[8];
91 const int ret = read(fd, static_cast<void *>(sent_time_buffer),
92 sizeof(sent_time_buffer));
93 const monotonic_clock::time_point monotonic_now = monotonic_clock::now();
94 CHECK_EQ(ret, 8);
95
96 monotonic_clock::time_point sent_time;
97 memcpy(&sent_time, sent_time_buffer, sizeof(sent_time_buffer));
98
99 if (sent_time == monotonic_clock::time_point(chrono::nanoseconds(1))) {
100 epoll.Quit();
101 return;
102 }
103
104 const chrono::nanoseconds wakeup_latency = monotonic_now - sent_time;
105
106 sum_latency += wakeup_latency;
107 ++latency_count;
108
109 max_wakeup_latency = ::std::max(wakeup_latency, max_wakeup_latency);
110
111 if (wakeup_latency > chrono::microseconds(FLAGS_latency_threshold)) {
112 t.Stop();
113 AOS_LOG(INFO, "Stopped tracing, latency %" PRId64 "\n",
114 static_cast<int64_t>(wakeup_latency.count()));
115 }
116
117 if (FLAGS_log_latency) {
118 AOS_LOG(INFO, "dt: %8d.%03d\n",
119 static_cast<int>(wakeup_latency.count() / 1000),
120 static_cast<int>(wakeup_latency.count() % 1000));
121 }
122 });
123
Austin Schuh9014e3b2020-11-21 14:26:07 -0800124 SetCurrentThreadAffinity(MakeCpusetFromCpus({FLAGS_core}));
Austin Schuh5af45eb2019-09-16 20:54:18 -0700125 SetCurrentThreadRealtimePriority(FLAGS_receiver_priority);
126 epoll.Run();
127 UnsetCurrentThreadRealtimePriority();
128 epoll.DeleteFd(fd);
129
130 const chrono::nanoseconds average_latency = sum_latency / latency_count;
131
132 AOS_LOG(INFO,
133 "Max eventfd wakeup latency: %d.%03d microseconds, average: %d.%03d "
134 "microseconds\n",
135 static_cast<int>(max_wakeup_latency.count() / 1000),
136 static_cast<int>(max_wakeup_latency.count() % 1000),
137 static_cast<int>(average_latency.count() / 1000),
138 static_cast<int>(average_latency.count() % 1000));
139}
140
141int Main(int /*argc*/, char ** /*argv*/) {
142 AOS_LOG(INFO, "Main!\n");
143 ::std::thread t([]() {
144 TimerThread(monotonic_clock::now() + chrono::seconds(FLAGS_seconds),
145 FLAGS_timer_priority);
146 });
147
148 int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
149 PCHECK(fd);
150
151 ::std::thread st([&fd]() { SenderThread(fd); });
152
153 ReceiverThread(fd);
154 st.join();
155
156 PCHECK(close(fd));
157
158 t.join();
159 return 0;
160}
161
162} // namespace aos
163
164int main(int argc, char **argv) {
165 ::gflags::ParseCommandLineFlags(&argc, &argv, true);
166
Austin Schuh5af45eb2019-09-16 20:54:18 -0700167 return ::aos::Main(argc, argv);
168}