From 868450678563ed2c9fd5240dca704d87371d1478 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 10 Jul 2017 12:36:39 +0200 Subject: [PATCH] Factor the basic metrics (memory, uptime, etc.) into a separate class, so that Kaeru can also use it. --- Makefile | 4 +-- basic_stats.cpp | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ basic_stats.h | 30 ++++++++++++++++++ kaeru.cpp | 6 ++++ main.cpp | 1 + mixer.cpp | 64 +++---------------------------------- mixer.h | 8 ----- 7 files changed, 127 insertions(+), 70 deletions(-) create mode 100644 basic_stats.cpp create mode 100644 basic_stats.h diff --git a/Makefile b/Makefile index ae66a39..2c20001 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ OBJS += midi_mapper.o midi_mapping.pb.o # Mixer objects AUDIO_MIXER_OBJS = audio_mixer.o alsa_input.o alsa_pool.o ebu_r128_proc.o stereocompressor.o resampling_queue.o flags.o correlation_measurer.o filter.o input_mapping.o state.pb.o -OBJS += chroma_subsampler.o v210_converter.o mixer.o metrics.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o httpd.o flags.o image_input.o alsa_output.o disk_space_estimator.o print_latency.o timecode_renderer.o tweaked_inputs.o $(AUDIO_MIXER_OBJS) +OBJS += chroma_subsampler.o v210_converter.o mixer.o basic_stats.o metrics.o pbo_frame_allocator.o context.o ref_counted_frame.o theme.o httpd.o flags.o image_input.o alsa_output.o disk_space_estimator.o print_latency.o timecode_renderer.o tweaked_inputs.o $(AUDIO_MIXER_OBJS) # Streaming and encoding objects OBJS += quicksync_encoder.o x264_encoder.o x264_dynamic.o x264_speed_control.o video_encoder.o metacube2.o mux.o audio_encoder.o ffmpeg_raii.o ffmpeg_util.o @@ -30,7 +30,7 @@ OBJS += quicksync_encoder.o x264_encoder.o x264_dynamic.o x264_speed_control.o v # DeckLink OBJS += decklink_capture.o decklink_util.o decklink_output.o decklink/DeckLinkAPIDispatch.o -KAERU_OBJS = kaeru.o x264_encoder.o mux.o metrics.o flags.o audio_encoder.o x264_speed_control.o print_latency.o x264_dynamic.o ffmpeg_raii.o ffmpeg_capture.o ffmpeg_util.o httpd.o metacube2.o +KAERU_OBJS = kaeru.o x264_encoder.o mux.o basic_stats.o metrics.o flags.o audio_encoder.o x264_speed_control.o print_latency.o x264_dynamic.o ffmpeg_raii.o ffmpeg_capture.o ffmpeg_util.o httpd.o metacube2.o # bmusb ifeq ($(EMBEDDED_BMUSB),yes) diff --git a/basic_stats.cpp b/basic_stats.cpp new file mode 100644 index 0000000..63d5493 --- /dev/null +++ b/basic_stats.cpp @@ -0,0 +1,84 @@ +#include "basic_stats.h" +#include "metrics.h" + +#include +#include + +using namespace std; +using namespace std::chrono; + +bool uses_mlock = false; + +BasicStats::BasicStats(bool verbose) + : verbose(verbose) +{ + start = steady_clock::now(); + + metric_start_time_seconds = get_timestamp_for_metrics(); + global_metrics.add("frames_output_total", &metric_frames_output_total); + global_metrics.add("frames_output_dropped", &metric_frames_output_dropped); + global_metrics.add("start_time_seconds", &metric_start_time_seconds, Metrics::TYPE_GAUGE); + global_metrics.add("memory_used_bytes", &metrics_memory_used_bytes); + global_metrics.add("memory_locked_limit_bytes", &metrics_memory_locked_limit_bytes); +} + +void BasicStats::update(int frame_num, int stats_dropped_frames) +{ + steady_clock::time_point now = steady_clock::now(); + double elapsed = duration(now - start).count(); + + metric_frames_output_total = frame_num; + metric_frames_output_dropped = stats_dropped_frames; + + if (frame_num % 100 != 0) { + return; + } + + if (verbose) { + printf("%d frames (%d dropped) in %.3f seconds = %.1f fps (%.1f ms/frame)", + frame_num, stats_dropped_frames, elapsed, frame_num / elapsed, + 1e3 * elapsed / frame_num); + } + + // Check our memory usage, to see if we are close to our mlockall() + // limit (if at all set). + rusage used; + if (getrusage(RUSAGE_SELF, &used) == -1) { + perror("getrusage(RUSAGE_SELF)"); + assert(false); + } + metrics_memory_used_bytes = used.ru_maxrss * 1024; + + if (uses_mlock) { + rlimit limit; + if (getrlimit(RLIMIT_MEMLOCK, &limit) == -1) { + perror("getrlimit(RLIMIT_MEMLOCK)"); + assert(false); + } + metrics_memory_locked_limit_bytes = limit.rlim_cur; + + if (verbose) { + if (limit.rlim_cur == 0) { + printf(", using %ld MB memory (locked)", + long(used.ru_maxrss / 1024)); + } else { + printf(", using %ld / %ld MB lockable memory (%.1f%%)", + long(used.ru_maxrss / 1024), + long(limit.rlim_cur / 1048576), + float(100.0 * (used.ru_maxrss * 1024.0) / limit.rlim_cur)); + } + } + } else { + metrics_memory_locked_limit_bytes = 0.0 / 0.0; + if (verbose) { + printf(", using %ld MB memory (not locked)", + long(used.ru_maxrss / 1024)); + } + } + + if (verbose) { + printf("\n"); + } +} + + diff --git a/basic_stats.h b/basic_stats.h new file mode 100644 index 0000000..800d6e6 --- /dev/null +++ b/basic_stats.h @@ -0,0 +1,30 @@ +#ifndef _BASIC_STATS_H +#define _BASIC_STATS_H + +// Holds some metrics for basic statistics about uptime, memory usage and such. + +#include + +#include +#include + +extern bool uses_mlock; + +class BasicStats { +public: + BasicStats(bool verbose); + void update(int frame_num, int stats_dropped_frames); + +private: + std::chrono::steady_clock::time_point start; + bool verbose; + + // Metrics. + std::atomic metric_frames_output_total{0}; + std::atomic metric_frames_output_dropped{0}; + std::atomic metric_start_time_seconds{0.0 / 0.0}; + std::atomic metrics_memory_used_bytes{0}; + std::atomic metrics_memory_locked_limit_bytes{0.0 / 0.0}; +}; + +#endif // !defined(_BASIC_STATS_H) diff --git a/kaeru.cpp b/kaeru.cpp index 7bf0ae9..efbb4f1 100644 --- a/kaeru.cpp +++ b/kaeru.cpp @@ -2,6 +2,7 @@ // This is experimental code, not yet supported. #include "audio_encoder.h" +#include "basic_stats.h" #include "defs.h" #include "flags.h" #include "ffmpeg_capture.h" @@ -25,6 +26,8 @@ using namespace std::placeholders; Mixer *global_mixer = nullptr; X264Encoder *global_x264_encoder = nullptr; +int frame_num = 0; +BasicStats *global_basic_stats = nullptr; MuxMetrics stream_mux_metrics; int write_packet(void *opaque, uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time) @@ -84,6 +87,7 @@ void video_frame_callback(FFmpegCapture *video, X264Encoder *x264_encoder, Audio video_pts = av_rescale_q(video_pts, video_timebase, AVRational{ 1, TIMEBASE }); int64_t frame_duration = TIMEBASE * video_format.frame_rate_den / video_format.frame_rate_nom; x264_encoder->add_frame(video_pts, frame_duration, video->get_current_frame_ycbcr_format().luma_coefficients, video_frame.data + video_offset, ts); + global_basic_stats->update(frame_num++, /*dropped_frames=*/0); } if (audio_frame.len > 0) { // FFmpegCapture takes care of this for us. @@ -196,6 +200,8 @@ int main(int argc, char *argv[]) video.start_bm_capture(); video.change_rate(2.0); // Be sure never to really fall behind, but also don't dump huge amounts of stuff onto x264. + BasicStats basic_stats(/*verbose=*/false); + global_basic_stats = &basic_stats; httpd.start(9095); signal(SIGUSR1, adjust_bitrate); diff --git a/main.cpp b/main.cpp index fb67e0e..d0427d1 100644 --- a/main.cpp +++ b/main.cpp @@ -13,6 +13,7 @@ extern "C" { #include #include +#include "basic_stats.h" #include "context.h" #include "flags.h" #include "image_input.h" diff --git a/mixer.cpp b/mixer.cpp index 7bfa009..f1d116f 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -31,6 +30,7 @@ #include "DeckLinkAPI.h" #include "LinuxCOM.h" #include "alsa_output.h" +#include "basic_stats.h" #include "bmusb/bmusb.h" #include "bmusb/fake_capture.h" #include "chroma_subsampler.h" @@ -61,7 +61,6 @@ using namespace std::placeholders; using namespace bmusb; Mixer *global_mixer = nullptr; -bool uses_mlock = false; namespace { @@ -460,14 +459,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) set_output_card_internal(global_flags.output_card); } - metric_start_time_seconds = get_timestamp_for_metrics(); - output_jitter_history.register_metrics({{ "card", "output" }}); - global_metrics.add("frames_output_total", &metric_frames_output_total); - global_metrics.add("frames_output_dropped", &metric_frames_output_dropped); - global_metrics.add("start_time_seconds", &metric_start_time_seconds, Metrics::TYPE_GAUGE); - global_metrics.add("memory_used_bytes", &metrics_memory_used_bytes); - global_metrics.add("memory_locked_limit_bytes", &metrics_memory_locked_limit_bytes); } Mixer::~Mixer() @@ -947,9 +939,7 @@ void Mixer::thread_func() } } - steady_clock::time_point start, now; - start = steady_clock::now(); - + BasicStats basic_stats(/*verbose=*/true); int stats_dropped_frames = 0; while (!should_quit) { @@ -1026,54 +1016,8 @@ void Mixer::thread_func() ++frame_num; pts_int += frame_duration; - now = steady_clock::now(); - double elapsed = duration(now - start).count(); - - metric_frames_output_total = frame_num; - metric_frames_output_dropped = stats_dropped_frames; - - if (frame_num % 100 == 0) { - printf("%d frames (%d dropped) in %.3f seconds = %.1f fps (%.1f ms/frame)", - frame_num, stats_dropped_frames, elapsed, frame_num / elapsed, - 1e3 * elapsed / frame_num); - // chain->print_phase_timing(); - - // Check our memory usage, to see if we are close to our mlockall() - // limit (if at all set). - rusage used; - if (getrusage(RUSAGE_SELF, &used) == -1) { - perror("getrusage(RUSAGE_SELF)"); - assert(false); - } - - if (uses_mlock) { - rlimit limit; - if (getrlimit(RLIMIT_MEMLOCK, &limit) == -1) { - perror("getrlimit(RLIMIT_MEMLOCK)"); - assert(false); - } - - if (limit.rlim_cur == 0) { - printf(", using %ld MB memory (locked)", - long(used.ru_maxrss / 1024)); - } else { - printf(", using %ld / %ld MB lockable memory (%.1f%%)", - long(used.ru_maxrss / 1024), - long(limit.rlim_cur / 1048576), - float(100.0 * (used.ru_maxrss * 1024.0) / limit.rlim_cur)); - } - metrics_memory_locked_limit_bytes = limit.rlim_cur; - } else { - printf(", using %ld MB memory (not locked)", - long(used.ru_maxrss / 1024)); - metrics_memory_locked_limit_bytes = 0.0 / 0.0; - } - - printf("\n"); - - metrics_memory_used_bytes = used.ru_maxrss * 1024; - } - + basic_stats.update(frame_num, stats_dropped_frames); + // if (frame_num % 100 == 0) chain->print_phase_timing(); if (should_cut.exchange(false)) { // Test and clear. video_encoder->do_cut(frame_num); diff --git a/mixer.h b/mixer.h index 572b26f..ff501b1 100644 --- a/mixer.h +++ b/mixer.h @@ -592,16 +592,8 @@ private: std::vector mode_scanlist[MAX_VIDEO_CARDS]; unsigned mode_scanlist_index[MAX_VIDEO_CARDS]{ 0 }; std::chrono::steady_clock::time_point last_mode_scan_change[MAX_VIDEO_CARDS]; - - // Metrics. - std::atomic metric_frames_output_total{0}; - std::atomic metric_frames_output_dropped{0}; - std::atomic metric_start_time_seconds{0.0 / 0.0}; - std::atomic metrics_memory_used_bytes{0}; - std::atomic metrics_memory_locked_limit_bytes{0.0 / 0.0}; }; extern Mixer *global_mixer; -extern bool uses_mlock; #endif // !defined(_MIXER_H) -- 2.39.2