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