yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
performance_dashboard.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <iomanip>
5#include <sstream>
6
10#include "imgui/imgui.h"
11
12namespace yaze {
13namespace gfx {
14
16 static PerformanceDashboard instance;
17 return instance;
18}
19
21 visible_ = false;
22 last_update_time_ = std::chrono::high_resolution_clock::now();
25}
26
28 auto now = std::chrono::high_resolution_clock::now();
29 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
30 now - last_update_time_);
31
32 if (elapsed.count() >= kUpdateIntervalMs) {
37 }
38}
39
41 if (!visible_) {
42 return;
43 }
44
45 ImGui::Begin("Graphics Performance Dashboard", &visible_);
46
48 ImGui::Separator();
50 ImGui::Separator();
52 ImGui::Separator();
54 ImGui::Separator();
56
57 ImGui::End();
58}
59
61 PerformanceSummary summary;
62
66
67 // Calculate optimization score (0-100)
68 int score = 0;
70 score += 20;
72 score += 20;
74 score += 15;
76 score += 15;
78 score += 15;
80 score += 15;
81
82 summary.optimization_score = score;
83
84 // Generate status message
85 if (score >= 90) {
86 summary.status_message = "Excellent - All optimizations active";
87 } else if (score >= 70) {
88 summary.status_message = "Good - Most optimizations active";
89 } else if (score >= 50) {
90 summary.status_message = "Fair - Some optimizations active";
91 } else {
92 summary.status_message = "Poor - Few optimizations active";
93 }
94
95 // Generate recommendations
97 summary.recommendations.push_back("Enable palette lookup optimization");
98 }
100 summary.recommendations.push_back("Enable dirty region tracking");
101 }
103 summary.recommendations.push_back("Enable resource pooling");
104 }
106 summary.recommendations.push_back("Enable batch operations");
107 }
109 summary.recommendations.push_back("Enable atlas rendering");
110 }
112 summary.recommendations.push_back("Enable memory pool allocator");
113 }
114
115 return summary;
116}
117
119 std::ostringstream report;
120
121 report << "=== YAZE Graphics Performance Report ===\n";
122 report << "Generated: "
123 << std::chrono::system_clock::now().time_since_epoch().count()
124 << "\n\n";
125
126 // Current metrics
127 report << "Current Performance Metrics:\n";
128 report << " Frame Time: " << std::fixed << std::setprecision(2)
129 << current_metrics_.frame_time_ms << " ms\n";
130 report << " Palette Lookup: "
132 report << " Texture Updates: "
134 report << " Batch Operations: "
136 report << " Memory Usage: " << std::fixed << std::setprecision(2)
137 << current_metrics_.memory_usage_mb << " MB\n";
138 report << " Cache Hit Ratio: " << std::fixed << std::setprecision(1)
139 << current_metrics_.cache_hit_ratio * 100.0 << "%\n";
140 report << " Draw Calls/Frame: " << current_metrics_.draw_calls_per_frame
141 << "\n";
142 report << " Texture Updates/Frame: "
144
145 // Optimization status
146 report << "Optimization Status:\n";
147 report << " Palette Lookup: "
148 << (optimization_status_.palette_lookup_optimized ? "✓" : "✗") << "\n";
149 report << " Dirty Region Tracking: "
151 << "\n";
152 report << " Resource Pooling: "
153 << (optimization_status_.resource_pooling_active ? "✓" : "✗") << "\n";
154 report << " Batch Operations: "
155 << (optimization_status_.batch_operations_enabled ? "✓" : "✗") << "\n";
156 report << " Atlas Rendering: "
157 << (optimization_status_.atlas_rendering_enabled ? "✓" : "✗") << "\n";
158 report << " Memory Pool: "
159 << (optimization_status_.memory_pool_active ? "✓" : "✗") << "\n\n";
160
161 // Performance analysis
162 auto summary = GetSummary();
163 report << "Performance Summary:\n";
164 report << " Optimization Score: " << summary.optimization_score << "/100\n";
165 report << " Status: " << summary.status_message << "\n";
166
167 if (!summary.recommendations.empty()) {
168 report << "\nRecommendations:\n";
169 for (const auto& rec : summary.recommendations) {
170 report << " - " << rec << "\n";
171 }
172 }
173
174 return report.str();
175}
176
178 ImGui::Text("Performance Metrics");
179
180 ImGui::Columns(2, "MetricsColumns");
181
182 ImGui::Text("Frame Time: %.2f ms", current_metrics_.frame_time_ms);
183 ImGui::Text("Palette Lookup: %s",
185 ImGui::Text("Texture Updates: %s",
187 ImGui::Text("Batch Operations: %s",
189
190 ImGui::NextColumn();
191
192 ImGui::Text("Memory Usage: %.2f MB", current_metrics_.memory_usage_mb);
193 ImGui::Text("Cache Hit Ratio: %.1f%%",
195 ImGui::Text("Draw Calls/Frame: %d", current_metrics_.draw_calls_per_frame);
196 ImGui::Text("Texture Updates/Frame: %d",
198
199 ImGui::Columns(1);
200}
201
203 ImGui::Text("Optimization Status");
204
205 ImGui::Columns(2, "OptimizationColumns");
206
207 ImGui::Text("Palette Lookup: %s",
209 ? "✓ Optimized"
210 : "✗ Not Optimized");
211 ImGui::Text("Dirty Regions: %s",
213 ? "✓ Enabled"
214 : "✗ Disabled");
215 ImGui::Text(
216 "Resource Pooling: %s",
217 optimization_status_.resource_pooling_active ? "✓ Active" : "✗ Inactive");
218
219 ImGui::NextColumn();
220
221 ImGui::Text("Batch Operations: %s",
223 : "✗ Disabled");
224 ImGui::Text("Atlas Rendering: %s",
226 : "✗ Disabled");
227 ImGui::Text("Memory Pool: %s", optimization_status_.memory_pool_active
228 ? "✓ Active"
229 : "✗ Inactive");
230
231 ImGui::Columns(1);
232
233 // Optimization score
234 auto summary = GetSummary();
235 ImGui::Text("Optimization Score: %d/100", summary.optimization_score);
236
237 // Progress bar
238 float progress = summary.optimization_score / 100.0F;
239 ImGui::ProgressBar(progress, ImVec2(-1, 0), summary.status_message.c_str());
240}
241
243 ImGui::Text("Memory Usage");
244
245 // Memory usage graph
246 if (!memory_usage_history_.empty()) {
247 // Convert double vector to float vector for ImGui
248 std::vector<float> float_history;
249 float_history.reserve(memory_usage_history_.size());
250 for (double value : memory_usage_history_) {
251 float_history.push_back(static_cast<float>(value));
252 }
253
254 ImGui::PlotLines("Memory (MB)", float_history.data(),
255 static_cast<int>(float_history.size()));
256 }
257 // Memory pool stats
258 auto [used_bytes, total_bytes] = MemoryPool::Get().GetMemoryStats();
259 ImGui::Text("Memory Pool: %s / %s", FormatMemory(used_bytes).c_str(),
260 FormatMemory(total_bytes).c_str());
261
262 float pool_usage =
263 total_bytes > 0 ? static_cast<float>(used_bytes) / total_bytes : 0.0F;
264 ImGui::ProgressBar(pool_usage, ImVec2(-1, 0), "Memory Pool Usage");
265
266 // Atlas renderer stats
267 auto atlas_stats = AtlasRenderer::Get().GetStats();
268 ImGui::Text("Atlas Renderer: %d atlases, %d/%d entries used",
269 atlas_stats.total_atlases, atlas_stats.used_entries,
270 atlas_stats.total_entries);
271 ImGui::Text("Atlas Memory: %s",
272 FormatMemory(atlas_stats.total_memory).c_str());
273
274 if (atlas_stats.total_entries > 0) {
275 float atlas_usage = static_cast<float>(atlas_stats.used_entries) /
276 atlas_stats.total_entries;
277 ImGui::ProgressBar(atlas_usage, ImVec2(-1, 0), "Atlas Utilization");
278 }
279}
280
282 ImGui::Text("Frame Rate Analysis");
283
284 if (!frame_time_history_.empty()) {
285 // Convert frame times to FPS
286 std::vector<float> fps_history;
287 fps_history.reserve(frame_time_history_.size());
288
289 for (double frame_time : frame_time_history_) {
290 if (frame_time > 0.0) {
291 fps_history.push_back(1000.0F / static_cast<float>(frame_time));
292 }
293 }
294
295 if (!fps_history.empty()) {
296 ImGui::PlotLines("FPS", fps_history.data(),
297 static_cast<int>(fps_history.size()));
298 }
299 }
300
301 // Frame time statistics
302 if (!frame_time_history_.empty()) {
303 double avg_frame_time = CalculateAverage(frame_time_history_);
304 double p95_frame_time = CalculatePercentile(frame_time_history_, 95.0);
305 double p99_frame_time = CalculatePercentile(frame_time_history_, 99.0);
306
307 ImGui::Text("Average Frame Time: %.2f ms", avg_frame_time);
308 ImGui::Text("95th Percentile: %.2f ms", p95_frame_time);
309 ImGui::Text("99th Percentile: %.2f ms", p99_frame_time);
310 }
311}
312
314 ImGui::Text("Performance Recommendations");
315
316 auto summary = GetSummary();
317
318 if (summary.recommendations.empty()) {
319 ImGui::TextColored(ImVec4(0, 1, 0, 1), "✓ All optimizations are active!");
320 } else {
321 ImGui::TextColored(ImVec4(1, 1, 0, 1),
322 "⚠ Performance improvements available:");
323 for (const auto& rec : summary.recommendations) {
324 ImGui::BulletText("%s", rec.c_str());
325 }
326 }
327
328 // Performance monitoring controls
329 static bool monitoring_enabled = PerformanceProfiler::IsEnabled();
330 if (ImGui::Checkbox("Enable Performance Monitoring", &monitoring_enabled)) {
331 PerformanceProfiler::SetEnabled(monitoring_enabled);
332 }
333
334 ImGui::SameLine();
335 if (ImGui::Button("Clear All Data")) {
337 }
338
339 ImGui::SameLine();
340 if (ImGui::Button("Generate Report")) {
341 std::string report = PerformanceProfiler::Get().GenerateReport(true);
342 }
343
344 // Export button
345 if (ImGui::Button("Export Performance Report")) {
346 std::string report = ExportReport();
347 // In a real implementation, you'd save this to a file
348 ImGui::SetClipboardText(report.c_str());
349 ImGui::Text("Report copied to clipboard");
350 }
351}
352
354 // Collect metrics from unified performance profiler
355 auto profiler = PerformanceProfiler::Get();
356
357 // Frame time (simplified - in real implementation, measure actual frame time)
358 if (!frame_time_history_.empty()) {
360 }
361
362 // Operation timings from various categories
363 auto palette_stats = profiler.GetStats("palette_lookup_optimized");
364 current_metrics_.palette_lookup_time_us = palette_stats.avg_time_us;
365
366 auto texture_stats = profiler.GetStats("texture_update_optimized");
367 current_metrics_.texture_update_time_us = texture_stats.avg_time_us;
368
369 auto batch_stats = profiler.GetStats("texture_batch_queue");
370 current_metrics_.batch_operation_time_us = batch_stats.avg_time_us;
371
372 // Memory usage from memory pool
373 auto [used_bytes, total_bytes] = MemoryPool::Get().GetMemoryStats();
374 current_metrics_.memory_usage_mb = used_bytes / (1024.0 * 1024.0);
375
376 // Calculate cache hit ratio based on actual performance data
377 double total_cache_operations = 0.0;
378 double total_cache_time = 0.0;
379
380 // Look for cache-related operations
381 for (const auto& op_name : profiler.GetOperationNames()) {
382 if (op_name.find("cache") != std::string::npos ||
383 op_name.find("tile_cache") != std::string::npos) {
384 auto stats = profiler.GetStats(op_name);
385 total_cache_operations += stats.sample_count;
386 total_cache_time += stats.total_time_ms;
387 }
388 }
389
390 // Estimate cache hit ratio based on operation speed
391 if (total_cache_operations > 0) {
392 double avg_cache_time = total_cache_time / total_cache_operations;
393 // Assume cache hits are < 10μs, misses are > 50μs
395 std::max(0.0, std::min(1.0, 1.0 - (avg_cache_time - 10.0) / 40.0));
396 } else {
397 current_metrics_.cache_hit_ratio = 0.85; // Default estimate
398 }
399
400 // Count draw calls and texture updates from profiler data
401 int draw_calls = 0;
402 int texture_updates = 0;
403
404 for (const auto& op_name : profiler.GetOperationNames()) {
405 if (op_name.find("draw") != std::string::npos ||
406 op_name.find("render") != std::string::npos) {
407 draw_calls += profiler.GetOperationCount(op_name);
408 }
409 if (op_name.find("texture_update") != std::string::npos ||
410 op_name.find("texture") != std::string::npos) {
411 texture_updates += profiler.GetOperationCount(op_name);
412 }
413 }
414
417
418 // Update history
421
422 if (frame_time_history_.size() > kHistorySize) {
424 }
425 if (memory_usage_history_.size() > kHistorySize) {
427 }
428}
429
431 auto profiler = PerformanceProfiler::Get();
432 auto [used_bytes, total_bytes] = MemoryPool::Get().GetMemoryStats();
433
434 // Check optimization status based on actual performance data
440 true; // AtlasRenderer is implemented
441 optimization_status_.memory_pool_active = (total_bytes > 0);
442
443 // Analyze palette lookup performance
444 auto palette_stats = profiler.GetStats("palette_lookup_optimized");
445 if (palette_stats.avg_time_us > 0 && palette_stats.avg_time_us < 5.0) {
447 }
448
449 // Analyze texture update performance
450 auto texture_stats = profiler.GetStats("texture_update_optimized");
451 if (texture_stats.avg_time_us > 0 && texture_stats.avg_time_us < 200.0) {
453 }
454
455 // Check for batch operations
456 auto batch_stats = profiler.GetStats("texture_batch_queue");
457 if (batch_stats.sample_count > 0) {
459 }
460}
461
463 // Compare with previous metrics to detect regressions
465 double frame_time_change =
467 if (frame_time_change > 2.0) { // 2ms increase
468 // Performance regression detected
469 }
470 }
471
473}
474
476 const std::vector<double>& values) {
477 if (values.empty())
478 return 0.0;
479
480 double sum = 0.0;
481 for (double value : values) {
482 sum += value;
483 }
484 return sum / values.size();
485}
486
488 const std::vector<double>& values, double percentile) {
489 if (values.empty())
490 return 0.0;
491
492 std::vector<double> sorted_values = values;
493 std::sort(sorted_values.begin(), sorted_values.end());
494
495 size_t index =
496 static_cast<size_t>((percentile / 100.0) * sorted_values.size());
497 if (index >= sorted_values.size()) {
498 index = sorted_values.size() - 1;
499 }
500
501 return sorted_values[index];
502}
503
504std::string PerformanceDashboard::FormatTime(double time_us) {
505 if (time_us < 1.0) {
506 return std::to_string(static_cast<int>(time_us * 1000.0)) + " ns";
507 }
508 if (time_us < 1000.0) {
509 return std::to_string(static_cast<int>(time_us)) + " μs";
510 }
511 return std::to_string(static_cast<int>(time_us / 1000.0)) + " ms";
512}
513
514std::string PerformanceDashboard::FormatMemory(size_t bytes) {
515 if (bytes < 1024) {
516 return std::to_string(bytes) + " B";
517 }
518 if (bytes < 1024 * 1024) {
519 return std::to_string(bytes / 1024) + " KB";
520 }
521 return std::to_string(bytes / (1024 * 1024)) + " MB";
522}
523
525 auto summary = GetSummary();
526
527 if (summary.optimization_score >= 90) {
528 return "Performance is excellent. All optimizations are active.";
529 }
530 if (summary.optimization_score >= 70) {
531 return "Performance is good. Consider enabling remaining optimizations.";
532 }
533 if (summary.optimization_score >= 50) {
534 return "Performance is fair. Several optimizations are available.";
535 }
536 return "Performance needs improvement. Enable graphics optimizations.";
537}
538
539} // namespace gfx
540} // namespace yaze
AtlasStats GetStats() const
Get atlas statistics.
static AtlasRenderer & Get()
std::pair< size_t, size_t > GetMemoryStats() const
Get memory usage statistics.
static MemoryPool & Get()
Comprehensive performance monitoring dashboard for YAZE graphics system.
static PerformanceDashboard & Get()
static std::string FormatTime(double time_us)
static double CalculatePercentile(const std::vector< double > &values, double percentile)
std::vector< double > memory_usage_history_
PerformanceSummary GetSummary() const
Get current performance summary.
void Update()
Update dashboard with current performance data.
static std::string FormatMemory(size_t bytes)
static double CalculateAverage(const std::vector< double > &values)
std::chrono::high_resolution_clock::time_point last_update_time_
static constexpr double kUpdateIntervalMs
void Initialize()
Initialize the performance dashboard.
void Render()
Render the performance dashboard UI.
std::string ExportReport() const
Export performance report.
std::string GetOptimizationRecommendation() const
void Clear()
Clear all timing data.
static void SetEnabled(bool enabled)
Enable or disable performance monitoring.
static PerformanceProfiler & Get()
std::string GenerateReport(bool log_to_sdl=true) const
Generate a comprehensive performance report.
static bool IsEnabled()
Check if performance monitoring is enabled.
Performance summary for external consumption.
std::vector< std::string > recommendations