From: Steinar H. Gunderson Date: Sat, 28 Apr 2018 14:19:16 +0000 (+0200) Subject: Expose metrics about used GPU memory (and also print to stdout), for GPUs that expose... X-Git-Tag: 1.7.2~5 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=a5746714e6ca1e665bf9e74344e67712443f947a;p=nageru Expose metrics about used GPU memory (and also print to stdout), for GPUs that expose such information. --- diff --git a/basic_stats.cpp b/basic_stats.cpp index 63d5493..548f04b 100644 --- a/basic_stats.cpp +++ b/basic_stats.cpp @@ -3,13 +3,31 @@ #include #include +#include + +// Epoxy seems to be missing these. Taken from the NVX_gpu_memory_info spec. +#ifndef GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX +#define GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047 +#endif +#ifndef GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX +#define GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048 +#endif +#ifndef GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX +#define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049 +#endif +#ifndef GPU_MEMORY_INFO_EVICTION_COUNT_NVX +#define GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A +#endif +#ifndef GPU_MEMORY_INFO_EVICTED_MEMORY_NVX +#define GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B +#endif using namespace std; using namespace std::chrono; bool uses_mlock = false; -BasicStats::BasicStats(bool verbose) +BasicStats::BasicStats(bool verbose, bool use_opengl) : verbose(verbose) { start = steady_clock::now(); @@ -20,6 +38,12 @@ BasicStats::BasicStats(bool verbose) 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); + + // TODO: It would be nice to compile this out entirely for Kaeru, + // to avoid pulling in the symbols from libGL/Epoxy. + if (use_opengl) { + gpu_memory_stats.reset(new GPUMemoryStats(verbose)); + } } void BasicStats::update(int frame_num, int stats_dropped_frames) @@ -76,9 +100,57 @@ void BasicStats::update(int frame_num, int stats_dropped_frames) } } + if (gpu_memory_stats != nullptr) { + gpu_memory_stats->update(); + } + if (verbose) { printf("\n"); } } +GPUMemoryStats::GPUMemoryStats(bool verbose) + : verbose(verbose) +{ + // GL_NV_query_memory is exposed but supposedly only works on + // Quadro/Titan cards, so we use GL_NVX_gpu_memory_info even though it's + // formally marked as experimental. + // Intel/Mesa doesn't seem to have anything comparable (at least nothing + // that gets the amount of _available_ memory). + supported = epoxy_has_gl_extension("GL_NVX_gpu_memory_info"); + if (supported) { + global_metrics.add("metric_memory_gpu_total_bytes", &metric_memory_gpu_total_bytes, Metrics::TYPE_GAUGE); + global_metrics.add("metric_memory_gpu_dedicated_bytes", &metric_memory_gpu_dedicated_bytes, Metrics::TYPE_GAUGE); + global_metrics.add("metric_memory_gpu_used_bytes", &metric_memory_gpu_used_bytes, Metrics::TYPE_GAUGE); + global_metrics.add("metric_memory_gpu_evicted_bytes", &metric_memory_gpu_evicted_bytes, Metrics::TYPE_GAUGE); + global_metrics.add("metric_memory_gpu_evictions", &metric_memory_gpu_evictions); + } +} +void GPUMemoryStats::update() +{ + if (!supported) { + return; + } + + GLint total, dedicated, available, evicted, evictions; + glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total); + glGetIntegerv(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated); + glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &available); + glGetIntegerv(GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &evicted); + glGetIntegerv(GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &evictions); + + if (glGetError() == 0) { + metric_memory_gpu_total_bytes = int64_t(total) * 1024; + metric_memory_gpu_dedicated_bytes = int64_t(dedicated) * 1024; + metric_memory_gpu_used_bytes = int64_t(total - available) * 1024; + metric_memory_gpu_evicted_bytes = int64_t(evicted) * 1024; + metric_memory_gpu_evictions = evictions; + + if (verbose) { + printf(", using %d / %d MB GPU memory (%.1f%%)", + (total - available) / 1024, total / 1024, + float(100.0 * (total - available) / total)); + } + } +} diff --git a/basic_stats.h b/basic_stats.h index 800d6e6..bff7881 100644 --- a/basic_stats.h +++ b/basic_stats.h @@ -7,17 +7,21 @@ #include #include +#include extern bool uses_mlock; +class GPUMemoryStats; + class BasicStats { public: - BasicStats(bool verbose); + BasicStats(bool verbose, bool use_opengl); void update(int frame_num, int stats_dropped_frames); private: std::chrono::steady_clock::time_point start; bool verbose; + std::unique_ptr gpu_memory_stats; // Metrics. std::atomic metric_frames_output_total{0}; @@ -27,4 +31,23 @@ private: std::atomic metrics_memory_locked_limit_bytes{0.0 / 0.0}; }; +// Holds some metrics for GPU memory usage. Currently only exposed for NVIDIA cards +// (no-op on all other platforms). + +class GPUMemoryStats { +public: + GPUMemoryStats(bool verbose); + void update(); + +private: + bool verbose, supported; + + // Metrics. + std::atomic metric_memory_gpu_total_bytes{0}; + std::atomic metric_memory_gpu_dedicated_bytes{0}; + std::atomic metric_memory_gpu_used_bytes{0}; + std::atomic metric_memory_gpu_evicted_bytes{0}; + std::atomic metric_memory_gpu_evictions{0}; +}; + #endif // !defined(_BASIC_STATS_H) diff --git a/kaeru.cpp b/kaeru.cpp index e763c34..168cf1d 100644 --- a/kaeru.cpp +++ b/kaeru.cpp @@ -206,7 +206,7 @@ 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); + BasicStats basic_stats(/*verbose=*/false, /*use_opengl=*/false); global_basic_stats = &basic_stats; httpd.start(global_flags.http_port); diff --git a/mixer.cpp b/mixer.cpp index e66a388..7a3f437 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -993,7 +993,7 @@ void Mixer::thread_func() } } - BasicStats basic_stats(/*verbose=*/true); + BasicStats basic_stats(/*verbose=*/true, /*use_opengl=*/true); int stats_dropped_frames = 0; while (!should_quit) {