]> git.sesse.net Git - nageru/commitdiff
Export some metrics from x264 speed control.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 11 Jun 2017 13:36:39 +0000 (15:36 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 11 Jun 2017 13:55:10 +0000 (15:55 +0200)
metrics.cpp
metrics.h
x264_speed_control.cpp
x264_speed_control.h

index a60eb6c6a25d1dec85eb79b2f11aa0dfb1f8f84d..2874ad42a8a70260bfb038b7f9320d3aa1880cfb 100644 (file)
@@ -9,6 +9,26 @@ using namespace std;
 
 Metrics global_metrics;
 
+namespace {
+
+string serialize_name(const string &name, const vector<pair<string, string>> &labels)
+{
+       if (labels.empty()) {
+               return "nageru_" + name;
+       }
+
+       string label_str;
+       for (const pair<string, string> &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<pair<string, string>> &labels, atomic<int64_t> *location, Metrics::Type type)
 {
        Metric metric;
@@ -37,6 +57,18 @@ void Metrics::add(const string &name, const vector<pair<string, string>> &labels
        types[name] = type;
 }
 
+void Metrics::add_histogram(const string &name, const vector<pair<string, string>> &labels, atomic<int64_t> *location, size_t num_elements)
+{
+       Histogram histogram;
+       histogram.name = name;
+       histogram.labels = labels;
+       histogram.location_int64 = location;
+       histogram.num_elements = num_elements;
+
+       lock_guard<mutex> 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<string, string> &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<pair<string, string>> 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();
 }
index 519cb80f694c03756aaa34d5d809eaa1c569a722..2a19e259cc32bf4df11c1eb779d6339b16382fd9 100644 (file)
--- a/metrics.h
+++ b/metrics.h
@@ -32,6 +32,9 @@ public:
        void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<int64_t> *location, Type type = TYPE_COUNTER);
        void add(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<double> *location, Type type = TYPE_COUNTER);
 
+       // Only integer histogram, ie. keys are 0..(N-1).
+       void add_histogram(const std::string &name, const std::vector<std::pair<std::string, std::string>> &labels, std::atomic<int64_t> *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<std::pair<std::string, std::string>> labels;
+               std::atomic<int64_t> *location_int64;  // First bucket.
+               size_t num_elements;
+       };
+
        mutable std::mutex mu;
        std::map<std::string, Type> types;
        std::vector<Metric> metrics;
+       std::vector<Histogram> histograms;
 };
 
 extern Metrics global_metrics;
index 47086829dbf0a239a85a96bf4adeede319fab752..b6a60e97b877a566331bec7f7c99a578321af1c8 100644 (file)
@@ -11,6 +11,7 @@
 #include <type_traits>
 
 #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];
 }
index de88f66705a7f15a068c91cb84f6e3e815852c34..8a1f344db847cc2d8daaf5747378ede9cbee96d6 100644 (file)
@@ -44,6 +44,7 @@
 // some cleanup, but it's much, much better than just using a static preset.
 
 #include <stdint.h>
+#include <atomic>
 #include <chrono>
 #include <functional>
 
@@ -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<void(x264_param_t *)> override_func = nullptr;
+
+       // Metrics.
+       std::atomic<int64_t> metric_x264_speedcontrol_preset_used_frames[SC_PRESETS]{{0}};
+       std::atomic<double> metric_x264_speedcontrol_buffer_available_seconds{0.0};
+       std::atomic<double> metric_x264_speedcontrol_buffer_size_seconds{0.0};
+       std::atomic<int64_t> metric_x264_speedcontrol_idle_frames{0};
+       std::atomic<int64_t> metric_x264_speedcontrol_late_frames{0};
 };