From: Steinar H. Gunderson Date: Sun, 11 Jun 2017 13:36:39 +0000 (+0200) Subject: Export some metrics from x264 speed control. X-Git-Tag: 1.6.1~63 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=4194f21b1a5e4ccfe79d40024075ab9795814029 Export some metrics from x264 speed control. --- diff --git a/metrics.cpp b/metrics.cpp index a60eb6c..2874ad4 100644 --- a/metrics.cpp +++ b/metrics.cpp @@ -9,6 +9,26 @@ using namespace std; Metrics global_metrics; +namespace { + +string serialize_name(const string &name, const vector> &labels) +{ + if (labels.empty()) { + return "nageru_" + name; + } + + string label_str; + for (const pair &label : labels) { + if (!label_str.empty()) { + label_str += ","; + } + label_str += label.first + "=\"" + label.second + "\""; + } + return "nageru_" + name + "{" + label_str + "}"; +} + +} // namespace + void Metrics::add(const string &name, const vector> &labels, atomic *location, Metrics::Type type) { Metric metric; @@ -37,6 +57,18 @@ void Metrics::add(const string &name, const vector> &labels types[name] = type; } +void Metrics::add_histogram(const string &name, const vector> &labels, atomic *location, size_t num_elements) +{ + Histogram histogram; + histogram.name = name; + histogram.labels = labels; + histogram.location_int64 = location; + histogram.num_elements = num_elements; + + lock_guard lock(mu); + histograms.push_back(histogram); +} + string Metrics::serialize() const { stringstream ss; @@ -50,21 +82,7 @@ string Metrics::serialize() const } } for (const Metric &metric : metrics) { - string name; - if (metric.labels.empty()) { - name = "nageru_" + metric.name; - } else { - name = "nageru_" + metric.name + "{"; - bool first = true; - for (const pair &label : metric.labels) { - if (!first) { - name += ","; - } - first = false; - name += label.first + "=\"" + label.second + "\""; - } - name += "}"; - } + string name = serialize_name(metric.name, metric.labels); if (metric.data_type == DATA_TYPE_INT64) { ss << name << " " << metric.location_int64->load() << "\n"; @@ -72,6 +90,25 @@ string Metrics::serialize() const ss << name << " " << metric.location_double->load() << "\n"; } } + for (const Histogram &histogram : histograms) { + ss << "# TYPE nageru_" << histogram.name << " histogram\n"; + + int64_t sum = 0, count = 0; + for (size_t i = 0; i < histogram.num_elements; ++i) { + char buf[16]; + snprintf(buf, sizeof(buf), "%lu", i); + vector> labels = histogram.labels; + labels.emplace_back("le", buf); + + int64_t val = histogram.location_int64[i].load(); + sum += i * val; + count += val; + ss << serialize_name(histogram.name + "_bucket", labels) << " " << count << "\n"; + } + + ss << serialize_name(histogram.name + "_sum", histogram.labels) << " " << sum << "\n"; + ss << serialize_name(histogram.name + "_count", histogram.labels) << " " << count << "\n"; + } return ss.str(); } diff --git a/metrics.h b/metrics.h index 519cb80..2a19e25 100644 --- a/metrics.h +++ b/metrics.h @@ -32,6 +32,9 @@ public: void add(const std::string &name, const std::vector> &labels, std::atomic *location, Type type = TYPE_COUNTER); void add(const std::string &name, const std::vector> &labels, std::atomic *location, Type type = TYPE_COUNTER); + // Only integer histogram, ie. keys are 0..(N-1). + void add_histogram(const std::string &name, const std::vector> &labels, std::atomic *location, size_t num_elements); + std::string serialize() const; private: @@ -50,9 +53,18 @@ private: }; }; + // TODO: This needs to be more general. + struct Histogram { + std::string name; + std::vector> labels; + std::atomic *location_int64; // First bucket. + size_t num_elements; + }; + mutable std::mutex mu; std::map types; std::vector metrics; + std::vector histograms; }; extern Metrics global_metrics; diff --git a/x264_speed_control.cpp b/x264_speed_control.cpp index 4708682..b6a60e9 100644 --- a/x264_speed_control.cpp +++ b/x264_speed_control.cpp @@ -11,6 +11,7 @@ #include #include "flags.h" +#include "metrics.h" using namespace std; using namespace std::chrono; @@ -36,6 +37,14 @@ X264SpeedControl::X264SpeedControl(x264_t *x264, float f_speed, int i_buffer_siz stat.max_buffer = 0; stat.avg_preset = 0.0; stat.den = 0; + + metric_x264_speedcontrol_buffer_available_seconds = buffer_fill * 1e-6; + metric_x264_speedcontrol_buffer_size_seconds = buffer_size * 1e-6; + global_metrics.add_histogram("x264_speedcontrol_preset_used_frames", {}, metric_x264_speedcontrol_preset_used_frames, SC_PRESETS); + global_metrics.add("x264_speedcontrol_buffer_available_seconds", &metric_x264_speedcontrol_buffer_available_seconds, Metrics::TYPE_GAUGE); + global_metrics.add("x264_speedcontrol_buffer_size_seconds", &metric_x264_speedcontrol_buffer_size_seconds, Metrics::TYPE_GAUGE); + global_metrics.add("x264_speedcontrol_idle_frames", &metric_x264_speedcontrol_idle_frames); + global_metrics.add("x264_speedcontrol_late_frames", &metric_x264_speedcontrol_late_frames); } X264SpeedControl::~X264SpeedControl() @@ -74,7 +83,6 @@ typedef struct // Note that the two first and the two last are also used for extrapolation // should the desired time be outside the range. Thus, it is disadvantageous if // they are chosen so that the timings are too close to each other. -#define SC_PRESETS 26 static const sc_preset_t presets[SC_PRESETS] = { #define I4 X264_ANALYSE_I4x4 #define I8 X264_ANALYSE_I8x8 @@ -174,6 +182,7 @@ void X264SpeedControl::before_frame(float new_buffer_fill, int new_buffer_size, set_buffer_size(new_buffer_size); } buffer_fill = buffer_size * new_buffer_fill; + metric_x264_speedcontrol_buffer_available_seconds = buffer_fill * 1e-6; steady_clock::time_point t; @@ -216,8 +225,11 @@ void X264SpeedControl::before_frame(float new_buffer_fill, int new_buffer_size, first = false; } buffer_fill = buffer_size; + metric_x264_speedcontrol_buffer_available_seconds = buffer_fill * 1e-6; + ++metric_x264_speedcontrol_idle_frames; } else if (buffer_fill <= 0) { // oops, we're late // fprintf(stderr, "speedcontrol underflow (%.6f sec)\n", buffer_fill/1e6); + ++metric_x264_speedcontrol_late_frames; } { @@ -324,4 +336,6 @@ void X264SpeedControl::apply_preset(int new_preset) } dyn.x264_encoder_reconfig(x264, &p); preset = new_preset; + + ++metric_x264_speedcontrol_preset_used_frames[new_preset]; } diff --git a/x264_speed_control.h b/x264_speed_control.h index de88f66..8a1f344 100644 --- a/x264_speed_control.h +++ b/x264_speed_control.h @@ -44,6 +44,7 @@ // some cleanup, but it's much, much better than just using a static preset. #include +#include #include #include @@ -53,6 +54,8 @@ extern "C" { #include "x264_dynamic.h" +#define SC_PRESETS 26 + class X264SpeedControl { public: // x264: Encoding object we are using; must be opened. Assumed to be @@ -127,4 +130,11 @@ private: } stat; std::function override_func = nullptr; + + // Metrics. + std::atomic metric_x264_speedcontrol_preset_used_frames[SC_PRESETS]{{0}}; + std::atomic metric_x264_speedcontrol_buffer_available_seconds{0.0}; + std::atomic metric_x264_speedcontrol_buffer_size_seconds{0.0}; + std::atomic metric_x264_speedcontrol_idle_frames{0}; + std::atomic metric_x264_speedcontrol_late_frames{0}; };