1 #include "basic_stats.h"
2 #include "shared/metrics.h"
5 #include <sys/resource.h>
8 // Epoxy seems to be missing these. Taken from the NVX_gpu_memory_info spec.
9 #ifndef GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX
10 #define GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047
12 #ifndef GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
13 #define GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048
15 #ifndef GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX
16 #define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049
18 #ifndef GPU_MEMORY_INFO_EVICTION_COUNT_NVX
19 #define GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A
21 #ifndef GPU_MEMORY_INFO_EVICTED_MEMORY_NVX
22 #define GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B
26 using namespace std::chrono;
28 bool uses_mlock = false;
30 BasicStats::BasicStats(bool verbose, bool use_opengl)
33 start = steady_clock::now();
35 metric_start_time_seconds = get_timestamp_for_metrics();
36 global_metrics.add("frames_output_total", &metric_frames_output_total);
37 global_metrics.add("frames_output_dropped", &metric_frames_output_dropped);
38 global_metrics.add("start_time_seconds", &metric_start_time_seconds, Metrics::TYPE_GAUGE);
39 global_metrics.add("memory_used_bytes", &metrics_memory_used_bytes);
40 global_metrics.add("memory_locked_limit_bytes", &metrics_memory_locked_limit_bytes);
42 // TODO: It would be nice to compile this out entirely for Kaeru,
43 // to avoid pulling in the symbols from libGL/Epoxy.
45 gpu_memory_stats.reset(new GPUMemoryStats(verbose));
49 void BasicStats::update(int frame_num, int stats_dropped_frames)
51 steady_clock::time_point now = steady_clock::now();
52 double elapsed = duration<double>(now - start).count();
54 metric_frames_output_total = frame_num;
55 metric_frames_output_dropped = stats_dropped_frames;
57 if (frame_num % 100 != 0) {
62 printf("%d frames (%d dropped) in %.3f seconds = %.1f fps (%.1f ms/frame)",
63 frame_num, stats_dropped_frames, elapsed, frame_num / elapsed,
64 1e3 * elapsed / frame_num);
67 // Check our memory usage, to see if we are close to our mlockall()
68 // limit (if at all set).
70 if (getrusage(RUSAGE_SELF, &used) == -1) {
71 perror("getrusage(RUSAGE_SELF)");
74 metrics_memory_used_bytes = used.ru_maxrss * 1024;
78 if (getrlimit(RLIMIT_MEMLOCK, &limit) == -1) {
79 perror("getrlimit(RLIMIT_MEMLOCK)");
82 metrics_memory_locked_limit_bytes = limit.rlim_cur;
85 if (limit.rlim_cur == 0) {
86 printf(", using %ld MB memory (locked)",
87 long(used.ru_maxrss / 1024));
89 printf(", using %ld / %ld MB lockable memory (%.1f%%)",
90 long(used.ru_maxrss / 1024),
91 long(limit.rlim_cur / 1048576),
92 float(100.0 * (used.ru_maxrss * 1024.0) / limit.rlim_cur));
96 metrics_memory_locked_limit_bytes = 0.0 / 0.0;
98 printf(", using %ld MB memory (not locked)",
99 long(used.ru_maxrss / 1024));
103 if (gpu_memory_stats != nullptr) {
104 gpu_memory_stats->update();
112 GPUMemoryStats::GPUMemoryStats(bool verbose)
115 // GL_NV_query_memory is exposed but supposedly only works on
116 // Quadro/Titan cards, so we use GL_NVX_gpu_memory_info even though it's
117 // formally marked as experimental.
118 // Intel/Mesa doesn't seem to have anything comparable (at least nothing
119 // that gets the amount of _available_ memory).
120 supported = epoxy_has_gl_extension("GL_NVX_gpu_memory_info");
122 global_metrics.add("memory_gpu_total_bytes", &metric_memory_gpu_total_bytes, Metrics::TYPE_GAUGE);
123 global_metrics.add("memory_gpu_dedicated_bytes", &metric_memory_gpu_dedicated_bytes, Metrics::TYPE_GAUGE);
124 global_metrics.add("memory_gpu_used_bytes", &metric_memory_gpu_used_bytes, Metrics::TYPE_GAUGE);
125 global_metrics.add("memory_gpu_evicted_bytes", &metric_memory_gpu_evicted_bytes, Metrics::TYPE_GAUGE);
126 global_metrics.add("memory_gpu_evictions", &metric_memory_gpu_evictions);
130 void GPUMemoryStats::update()
136 GLint total, dedicated, available, evicted, evictions;
137 glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total);
138 glGetIntegerv(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated);
139 glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &available);
140 glGetIntegerv(GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &evicted);
141 glGetIntegerv(GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &evictions);
143 if (glGetError() == 0) {
144 metric_memory_gpu_total_bytes = int64_t(total) * 1024;
145 metric_memory_gpu_dedicated_bytes = int64_t(dedicated) * 1024;
146 metric_memory_gpu_used_bytes = int64_t(total - available) * 1024;
147 metric_memory_gpu_evicted_bytes = int64_t(evicted) * 1024;
148 metric_memory_gpu_evictions = evictions;
151 printf(", using %d / %d MB GPU memory (%.1f%%)",
152 (total - available) / 1024, total / 1024,
153 float(100.0 * (total - available) / total));