]> git.sesse.net Git - nageru/commitdiff
Expose metrics about used GPU memory (and also print to stdout), for GPUs that expose...
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 28 Apr 2018 14:19:16 +0000 (16:19 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 28 Apr 2018 14:19:16 +0000 (16:19 +0200)
basic_stats.cpp
basic_stats.h
kaeru.cpp
mixer.cpp

index 63d549309ca0f11a3cdd554cf86dc40ee0e22377..548f04bee0424f67a612ec6615ff7a0818bed8d9 100644 (file)
@@ -3,13 +3,31 @@
 
 #include <assert.h>
 #include <sys/resource.h>
+#include <epoxy/gl.h>
+
+// 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));
+               }
+       }
+}
index 800d6e60f59f52b9fdf9c63458a785eb34f4c119..bff788129fb6306a0a1ce7627c5048ff21531bab 100644 (file)
@@ -7,17 +7,21 @@
 
 #include <atomic>
 #include <chrono>
+#include <memory>
 
 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<GPUMemoryStats> gpu_memory_stats;
 
        // Metrics.
        std::atomic<int64_t> metric_frames_output_total{0};
@@ -27,4 +31,23 @@ private:
        std::atomic<double> 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<int64_t> metric_memory_gpu_total_bytes{0};
+       std::atomic<int64_t> metric_memory_gpu_dedicated_bytes{0};
+       std::atomic<int64_t> metric_memory_gpu_used_bytes{0};
+       std::atomic<int64_t> metric_memory_gpu_evicted_bytes{0};
+       std::atomic<int64_t> metric_memory_gpu_evictions{0};
+};
+
 #endif  // !defined(_BASIC_STATS_H)
index e763c3429383064c529d8d1e45c5f8450b75ec51..168cf1d6033b40801992186cb92fea47fca08729 100644 (file)
--- 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);
 
index e66a3881975d1ef1ffd2119c0c23ddf3e6e7a375..7a3f437d6ec745048c57be3283005cbf94597937 100644 (file)
--- 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) {