blob: 3c8c741f3fe9e54492f2c3877984d85941d22a6f [file] [log] [blame]
#ifndef AOS_EVENTS_TIMING_STATISTICS_H_
#define AOS_EVENTS_TIMING_STATISTICS_H_
#include <cmath>
#include "aos/events/event_loop_generated.h"
#include "aos/util/error_counter.h"
namespace aos {
namespace internal {
// Class to compute statistics for the timing report.
class TimingStatistic {
public:
TimingStatistic() {}
// Sets the flatbuffer to mutate.
void set_statistic(timing::Statistic *statistic) { statistic_ = statistic; }
// Adds a sample to the statistic.
void Add(float sample) {
if (!statistic_) {
return;
}
++count_;
if (count_ == 1) {
statistic_->mutate_average(sample);
statistic_->mutate_min(sample);
statistic_->mutate_max(sample);
statistic_->mutate_standard_deviation(0.0);
} else {
// https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
const float prior_average = statistic_->average();
const float average = prior_average + (sample - prior_average) / count_;
statistic_->mutate_average(average);
statistic_->mutate_max(std::max(statistic_->max(), sample));
statistic_->mutate_min(std::min(statistic_->min(), sample));
Q_ = Q_ + (sample - prior_average) * (sample - average);
statistic_->mutate_standard_deviation(std::sqrt(Q_ / (count_ - 1)));
}
}
// Clears any accumulated statistics.
void Reset() {
if (!statistic_) {
return;
}
statistic_->mutate_average(std::numeric_limits<float>::quiet_NaN());
statistic_->mutate_min(std::numeric_limits<float>::quiet_NaN());
statistic_->mutate_max(std::numeric_limits<float>::quiet_NaN());
statistic_->mutate_standard_deviation(
std::numeric_limits<float>::quiet_NaN());
Q_ = 0;
count_ = 0;
}
private:
timing::Statistic *statistic_ = nullptr;
// Number of samples accumulated.
size_t count_ = 0;
// State Q from wikipedia.
float Q_ = 0.0;
};
// Class to hold timing information for a raw fetcher.
struct RawFetcherTiming {
RawFetcherTiming(int new_channel_index) : channel_index(new_channel_index) {}
void set_timing_report(timing::Fetcher *fetcher);
void ResetTimingReport();
const int channel_index;
timing::Fetcher *fetcher = nullptr;
internal::TimingStatistic latency;
};
// Class to hold timing information for a raw sender.
struct RawSenderTiming {
typedef util::ErrorCounter<timing::SendError, timing::SendErrorCount>
ErrorCounter;
static constexpr size_t kNumErrors = ErrorCounter::kNumErrors;
RawSenderTiming(int new_channel_index) : channel_index(new_channel_index) {}
void set_timing_report(timing::Sender *sender);
void ResetTimingReport();
void IncrementError(timing::SendError error);
// Sanity check that the enum values are such that we can just use the enum
// values themselves as array indices without anything weird happening.
static_assert(
sizeof(std::invoke_result<decltype(timing::EnumValuesSendError)>::type) /
sizeof(timing::SendError) ==
kNumErrors,
"Expected continguous enum values.");
const int channel_index;
timing::Sender *sender = nullptr;
internal::TimingStatistic size;
ErrorCounter error_counter;
};
// Class to hold timing information for timers.
struct TimerTiming {
void set_timing_report(timing::Timer *timer);
void ResetTimingReport();
internal::TimingStatistic wakeup_latency;
internal::TimingStatistic handler_time;
timing::Timer *timer = nullptr;
};
} // namespace internal
} // namespace aos
#endif // AOS_EVENTS_TIMING_STATISTICS_H_