]> git.sesse.net Git - nageru/blob - nageru/basic_stats.cpp
IWYU-fix nageru/*.cpp.
[nageru] / nageru / basic_stats.cpp
1 #include "basic_stats.h"
2 #include "shared/metrics.h"
3
4 #include <assert.h>
5 #include <chrono>
6 #include <cstdint>
7 #include <cstdio>
8 #include <sys/resource.h>
9 #include <epoxy/gl.h>
10
11 // Epoxy seems to be missing these. Taken from the NVX_gpu_memory_info spec.
12 #ifndef GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX
13 #define GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX          0x9047
14 #endif
15 #ifndef GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX
16 #define GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX    0x9048
17 #endif
18 #ifndef GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX
19 #define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX  0x9049
20 #endif
21 #ifndef GPU_MEMORY_INFO_EVICTION_COUNT_NVX
22 #define GPU_MEMORY_INFO_EVICTION_COUNT_NVX            0x904A
23 #endif
24 #ifndef GPU_MEMORY_INFO_EVICTED_MEMORY_NVX
25 #define GPU_MEMORY_INFO_EVICTED_MEMORY_NVX            0x904B
26 #endif
27
28 using namespace std;
29 using namespace std::chrono;
30
31 bool uses_mlock = false;
32
33 BasicStats::BasicStats(bool verbose, bool use_opengl)
34         : verbose(verbose)
35 {
36         start = steady_clock::now();
37
38         metric_start_time_seconds = get_timestamp_for_metrics();
39         global_metrics.add("frames_output_total", &metric_frames_output_total);
40         global_metrics.add("frames_output_dropped", &metric_frames_output_dropped);
41         global_metrics.add("start_time_seconds", &metric_start_time_seconds, Metrics::TYPE_GAUGE);
42         global_metrics.add("memory_used_bytes", &metrics_memory_used_bytes);
43         global_metrics.add("memory_locked_limit_bytes", &metrics_memory_locked_limit_bytes);
44
45         // TODO: It would be nice to compile this out entirely for Kaeru,
46         // to avoid pulling in the symbols from libGL/Epoxy.
47         if (use_opengl) {
48                 gpu_memory_stats.reset(new GPUMemoryStats(verbose));
49         }
50 }
51
52 void BasicStats::update(int frame_num, int stats_dropped_frames)
53 {
54         steady_clock::time_point now = steady_clock::now();
55         double elapsed = duration<double>(now - start).count();
56
57         metric_frames_output_total = frame_num;
58         metric_frames_output_dropped = stats_dropped_frames;
59
60         if (frame_num % 100 != 0) {
61                 return;
62         }
63
64         if (verbose) {
65                 printf("%d frames (%d dropped) in %.3f seconds = %.1f fps (%.1f ms/frame)",
66                         frame_num, stats_dropped_frames, elapsed, frame_num / elapsed,
67                         1e3 * elapsed / frame_num);
68         }
69
70         // Check our memory usage, to see if we are close to our mlockall()
71         // limit (if at all set).
72         rusage used;
73         if (getrusage(RUSAGE_SELF, &used) == -1) {
74                 perror("getrusage(RUSAGE_SELF)");
75                 assert(false);
76         }
77         metrics_memory_used_bytes = used.ru_maxrss * 1024;
78
79         if (uses_mlock) {
80                 rlimit limit;
81                 if (getrlimit(RLIMIT_MEMLOCK, &limit) == -1) {
82                         perror("getrlimit(RLIMIT_MEMLOCK)");
83                         assert(false);
84                 }
85                 metrics_memory_locked_limit_bytes = limit.rlim_cur;
86
87                 if (verbose) {
88                         if (limit.rlim_cur == 0) {
89                                 printf(", using %ld MB memory (locked)",
90                                                 long(used.ru_maxrss / 1024));
91                         } else {
92                                 printf(", using %ld / %ld MB lockable memory (%.1f%%)",
93                                                 long(used.ru_maxrss / 1024),
94                                                 long(limit.rlim_cur / 1048576),
95                                                 float(100.0 * (used.ru_maxrss * 1024.0) / limit.rlim_cur));
96                         }
97                 }
98         } else {
99                 metrics_memory_locked_limit_bytes = 0.0 / 0.0;
100                 if (verbose) {
101                         printf(", using %ld MB memory (not locked)",
102                                         long(used.ru_maxrss / 1024));
103                 }
104         }
105
106         if (gpu_memory_stats != nullptr) {
107                 gpu_memory_stats->update();
108         }
109
110         if (verbose) {
111                 printf("\n");
112         }
113 }
114
115 GPUMemoryStats::GPUMemoryStats(bool verbose)
116         : verbose(verbose)
117 {
118         // GL_NV_query_memory is exposed but supposedly only works on
119         // Quadro/Titan cards, so we use GL_NVX_gpu_memory_info even though it's
120         // formally marked as experimental.
121         // Intel/Mesa doesn't seem to have anything comparable (at least nothing
122         // that gets the amount of _available_ memory).
123         supported = epoxy_has_gl_extension("GL_NVX_gpu_memory_info");
124         if (supported) {
125                 global_metrics.add("memory_gpu_total_bytes", &metric_memory_gpu_total_bytes, Metrics::TYPE_GAUGE);
126                 global_metrics.add("memory_gpu_dedicated_bytes", &metric_memory_gpu_dedicated_bytes, Metrics::TYPE_GAUGE);
127                 global_metrics.add("memory_gpu_used_bytes", &metric_memory_gpu_used_bytes, Metrics::TYPE_GAUGE);
128                 global_metrics.add("memory_gpu_evicted_bytes", &metric_memory_gpu_evicted_bytes, Metrics::TYPE_GAUGE);
129                 global_metrics.add("memory_gpu_evictions", &metric_memory_gpu_evictions);
130         }
131 }
132
133 void GPUMemoryStats::update()
134 {
135         if (!supported) {
136                 return;
137         }
138
139         GLint total, dedicated, available, evicted, evictions;
140         glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &total);
141         glGetIntegerv(GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated);
142         glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &available);
143         glGetIntegerv(GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &evicted);
144         glGetIntegerv(GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &evictions);
145
146         if (glGetError() == 0) {
147                 metric_memory_gpu_total_bytes = int64_t(total) * 1024;
148                 metric_memory_gpu_dedicated_bytes = int64_t(dedicated) * 1024;
149                 metric_memory_gpu_used_bytes = int64_t(total - available) * 1024;
150                 metric_memory_gpu_evicted_bytes = int64_t(evicted) * 1024;
151                 metric_memory_gpu_evictions = evictions;
152
153                 if (verbose) {
154                         printf(", using %d / %d MB GPU memory (%.1f%%)",
155                                 (total - available) / 1024, total / 1024,
156                                 float(100.0 * (total - available) / total));
157                 }
158         }
159 }