blob: 5f2393549f5639629086ece41b508daba321d747 [file] [log] [blame]
Austin Schuh99004602024-03-16 11:59:24 -07001#include <unistd.h>
2
Stephan Pleines6191f1d2024-05-30 20:44:45 -07003#include <iomanip>
4#include <iostream> // IWYU pragma: keep
Austin Schuh99004602024-03-16 11:59:24 -07005
6#include "gflags/gflags.h"
7
8#include "aos/aos_cli_utils.h"
9#include "aos/configuration.h"
10#include "aos/ftrace.h"
11#include "aos/init.h"
12#include "aos/json_to_flatbuffer.h"
13#include "aos/realtime.h"
14
15DEFINE_int32(priority, -1, "If set, the RT priority to run at.");
16DEFINE_double(max_jitter, 0.01,
17 "The max time in milliseconds between messages before marking it "
18 "as too late.");
19DEFINE_bool(print_jitter, true,
20 "If true, print jitter events. These will impact RT performance.");
21DECLARE_bool(enable_ftrace);
Filip Kujawa23f21652024-03-16 15:24:14 -070022DEFINE_bool(print_latency_stats, false,
23 "If true, print latency stats. These will impact RT performance.");
Austin Schuh99004602024-03-16 11:59:24 -070024
25namespace aos {
26
27class State {
28 public:
29 State(Ftrace *ftrace, aos::EventLoop *event_loop, const Channel *channel)
30 : ftrace_(ftrace),
31 channel_(channel),
32 channel_name_(aos::configuration::StrippedChannelToString(channel_)) {
33 LOG(INFO) << "Watching for jitter on " << channel_name_;
Filip Kujawa23f21652024-03-16 15:24:14 -070034
Austin Schuh99004602024-03-16 11:59:24 -070035 event_loop->MakeRawWatcher(
36 channel_, [this](const aos::Context &context, const void *message) {
37 HandleMessage(context, message);
38 });
Filip Kujawa23f21652024-03-16 15:24:14 -070039
40 if (FLAGS_print_latency_stats) {
41 timer_handle_ = event_loop->AddTimer([this]() { PrintLatencyStats(); });
42 timer_handle_->set_name("jitter");
43 event_loop->OnRun([this, event_loop]() {
44 timer_handle_->Schedule(event_loop->monotonic_now(),
Filip Kujawa2b56ff32024-03-16 16:52:17 -070045 std::chrono::milliseconds(1000));
Filip Kujawa23f21652024-03-16 15:24:14 -070046 });
47 }
Austin Schuh99004602024-03-16 11:59:24 -070048 }
49
50 void HandleMessage(const aos::Context &context, const void * /*message*/) {
51 if (last_time_ != aos::monotonic_clock::min_time) {
Filip Kujawa23f21652024-03-16 15:24:14 -070052 latency_.push_back(std::chrono::duration<double>(
53 context.monotonic_event_time - last_time_)
54 .count());
Austin Schuh99004602024-03-16 11:59:24 -070055 if (context.monotonic_event_time >
56 last_time_ + std::chrono::duration_cast<std::chrono::nanoseconds>(
57 std::chrono::duration<double>(FLAGS_max_jitter))) {
58 if (FLAGS_enable_ftrace) {
59 ftrace_->FormatMessage(
60 "Got high latency event on %s -> %.9f between messages",
61 channel_name_.c_str(),
62 std::chrono::duration<double>(context.monotonic_event_time -
63 last_time_)
64 .count());
65 ftrace_->TurnOffOrDie();
66 }
67
68 if (FLAGS_print_jitter) {
69 // Printing isn't realtime, but if someone wants to run as RT, they
70 // should know this. Bypass the warning.
71 ScopedNotRealtime nrt;
72
73 LOG(INFO) << "Got a high latency event on "
74 << aos::configuration::StrippedChannelToString(channel_)
75 << " -> " << std::fixed << std::setprecision(9)
76 << std::chrono::duration<double>(
77 context.monotonic_event_time - last_time_)
78 .count()
79 << " between messages.";
80 }
81 }
82 }
83
84 last_time_ = context.monotonic_event_time;
85 }
86
Filip Kujawa23f21652024-03-16 15:24:14 -070087 void PrintLatencyStats() {
88 std::sort(latency_.begin(), latency_.end());
89 if (latency_.size() >= 100) {
90 LOG(INFO) << "Percentiles 25th: " << latency_[latency_.size() * 0.25]
91 << " 50th: " << latency_[latency_.size() * 0.5]
92 << " 75th: " << latency_[latency_.size() * 0.75]
93 << " 90th: " << latency_[latency_.size() * 0.9]
94 << " 95th: " << latency_[latency_.size() * 0.95]
95 << " 99th: " << latency_[latency_.size() * 0.99];
96 LOG(INFO) << "Max: " << latency_.back() << " Min: " << latency_.front()
97 << " Mean: "
98 << std::accumulate(latency_.begin(), latency_.end(), 0.0) /
99 latency_.size();
100 }
101 }
102
Austin Schuh99004602024-03-16 11:59:24 -0700103 private:
104 Ftrace *ftrace_;
105 const Channel *channel_;
106
107 std::string channel_name_;
108
109 aos::monotonic_clock::time_point last_time_ = aos::monotonic_clock::min_time;
Filip Kujawa23f21652024-03-16 15:24:14 -0700110
111 std::vector<double> latency_;
112
113 aos::TimerHandler *timer_handle_;
Austin Schuh99004602024-03-16 11:59:24 -0700114};
115
116} // namespace aos
117
118int main(int argc, char **argv) {
119 aos::InitGoogle(&argc, &argv);
120
121 aos::CliUtilInfo cli_info;
122 if (cli_info.Initialize(
123 &argc, &argv,
124 [&cli_info](const aos::Channel *channel) {
125 return aos::configuration::ChannelIsReadableOnNode(
126 channel, cli_info.event_loop->node());
127 },
128 "channel is readeable on node", true)) {
129 return 0;
130 }
131
132 aos::Ftrace ftrace;
133
134 std::vector<std::unique_ptr<aos::State>> states;
135
136 for (const aos::Channel *channel : cli_info.found_channels) {
137 states.emplace_back(std::make_unique<aos::State>(
138 &ftrace, &(cli_info.event_loop.value()), channel));
139 }
140
141 if (FLAGS_priority > 0) {
142 cli_info.event_loop->SetRuntimeRealtimePriority(FLAGS_priority);
143 }
144
145 cli_info.event_loop->Run();
146
147 return 0;
148}