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, atlas_stats.total_entries);
270 ImGui::Text("Atlas Memory: %s", FormatMemory(atlas_stats.total_memory).c_str());
271
272 if (atlas_stats.total_entries > 0) {
273 float atlas_usage = static_cast<float>(atlas_stats.used_entries) / atlas_stats.total_entries;
274 ImGui::ProgressBar(atlas_usage, ImVec2(-1, 0), "Atlas Utilization");
275 }
276}
277
279 ImGui::Text("Frame Rate Analysis");
280
281 if (!frame_time_history_.empty()) {
282 // Convert frame times to FPS
283 std::vector<float> fps_history;
284 fps_history.reserve(frame_time_history_.size());
285
286 for (double frame_time : frame_time_history_) {
287 if (frame_time > 0.0) {
288 fps_history.push_back(1000.0F / static_cast<float>(frame_time));
289 }
290 }
291
292 if (!fps_history.empty()) {
293 ImGui::PlotLines("FPS", fps_history.data(),
294 static_cast<int>(fps_history.size()));
295 }
296 }
297
298 // Frame time statistics
299 if (!frame_time_history_.empty()) {
300 double avg_frame_time = CalculateAverage(frame_time_history_);
301 double p95_frame_time = CalculatePercentile(frame_time_history_, 95.0);
302 double p99_frame_time = CalculatePercentile(frame_time_history_, 99.0);
303
304 ImGui::Text("Average Frame Time: %.2f ms", avg_frame_time);
305 ImGui::Text("95th Percentile: %.2f ms", p95_frame_time);
306 ImGui::Text("99th Percentile: %.2f ms", p99_frame_time);
307 }
308}
309
311 ImGui::Text("Performance Recommendations");
312
313 auto summary = GetSummary();
314
315 if (summary.recommendations.empty()) {
316 ImGui::TextColored(ImVec4(0, 1, 0, 1), "✓ All optimizations are active!");
317 } else {
318 ImGui::TextColored(ImVec4(1, 1, 0, 1),
319 "⚠ Performance improvements available:");
320 for (const auto& rec : summary.recommendations) {
321 ImGui::BulletText("%s", rec.c_str());
322 }
323 }
324
325 // Performance monitoring controls
326 static bool monitoring_enabled = PerformanceProfiler::IsEnabled();
327 if (ImGui::Checkbox("Enable Performance Monitoring", &monitoring_enabled)) {
328 PerformanceProfiler::SetEnabled(monitoring_enabled);
329 }
330
331 ImGui::SameLine();
332 if (ImGui::Button("Clear All Data")) {
334 }
335
336 ImGui::SameLine();
337 if (ImGui::Button("Generate Report")) {
338 std::string report = PerformanceProfiler::Get().GenerateReport(true);
339 }
340
341 // Export button
342 if (ImGui::Button("Export Performance Report")) {
343 std::string report = ExportReport();
344 // In a real implementation, you'd save this to a file
345 ImGui::SetClipboardText(report.c_str());
346 ImGui::Text("Report copied to clipboard");
347 }
348}
349
351 // Collect metrics from unified performance profiler
352 auto profiler = PerformanceProfiler::Get();
353
354 // Frame time (simplified - in real implementation, measure actual frame time)
355 if (!frame_time_history_.empty()) {
357 }
358
359 // Operation timings from various categories
360 auto palette_stats = profiler.GetStats("palette_lookup_optimized");
361 current_metrics_.palette_lookup_time_us = palette_stats.avg_time_us;
362
363 auto texture_stats = profiler.GetStats("texture_update_optimized");
364 current_metrics_.texture_update_time_us = texture_stats.avg_time_us;
365
366 auto batch_stats = profiler.GetStats("texture_batch_queue");
367 current_metrics_.batch_operation_time_us = batch_stats.avg_time_us;
368
369 // Memory usage from memory pool
370 auto [used_bytes, total_bytes] = MemoryPool::Get().GetMemoryStats();
371 current_metrics_.memory_usage_mb = used_bytes / (1024.0 * 1024.0);
372
373 // Calculate cache hit ratio based on actual performance data
374 double total_cache_operations = 0.0;
375 double total_cache_time = 0.0;
376
377 // Look for cache-related operations
378 for (const auto& op_name : profiler.GetOperationNames()) {
379 if (op_name.find("cache") != std::string::npos ||
380 op_name.find("tile_cache") != std::string::npos) {
381 auto stats = profiler.GetStats(op_name);
382 total_cache_operations += stats.sample_count;
383 total_cache_time += stats.total_time_ms;
384 }
385 }
386
387 // Estimate cache hit ratio based on operation speed
388 if (total_cache_operations > 0) {
389 double avg_cache_time = total_cache_time / total_cache_operations;
390 // Assume cache hits are < 10μs, misses are > 50μs
391 current_metrics_.cache_hit_ratio = std::max(0.0, std::min(1.0,
392 1.0 - (avg_cache_time - 10.0) / 40.0));
393 } else {
394 current_metrics_.cache_hit_ratio = 0.85; // Default estimate
395 }
396
397 // Count draw calls and texture updates from profiler data
398 int draw_calls = 0;
399 int texture_updates = 0;
400
401 for (const auto& op_name : profiler.GetOperationNames()) {
402 if (op_name.find("draw") != std::string::npos ||
403 op_name.find("render") != std::string::npos) {
404 draw_calls += profiler.GetOperationCount(op_name);
405 }
406 if (op_name.find("texture_update") != std::string::npos ||
407 op_name.find("texture") != std::string::npos) {
408 texture_updates += profiler.GetOperationCount(op_name);
409 }
410 }
411
414
415 // Update history
418
419 if (frame_time_history_.size() > kHistorySize) {
421 }
422 if (memory_usage_history_.size() > kHistorySize) {
424 }
425}
426
428 auto profiler = PerformanceProfiler::Get();
429 auto [used_bytes, total_bytes] = MemoryPool::Get().GetMemoryStats();
430
431 // Check optimization status based on actual performance data
436 optimization_status_.atlas_rendering_enabled = true; // AtlasRenderer is implemented
437 optimization_status_.memory_pool_active = (total_bytes > 0);
438
439 // Analyze palette lookup performance
440 auto palette_stats = profiler.GetStats("palette_lookup_optimized");
441 if (palette_stats.avg_time_us > 0 && palette_stats.avg_time_us < 5.0) {
443 }
444
445 // Analyze texture update performance
446 auto texture_stats = profiler.GetStats("texture_update_optimized");
447 if (texture_stats.avg_time_us > 0 && texture_stats.avg_time_us < 200.0) {
449 }
450
451 // Check for batch operations
452 auto batch_stats = profiler.GetStats("texture_batch_queue");
453 if (batch_stats.sample_count > 0) {
455 }
456}
457
459 // Compare with previous metrics to detect regressions
461 double frame_time_change =
463 if (frame_time_change > 2.0) { // 2ms increase
464 // Performance regression detected
465 }
466 }
467
469}
470
472 const std::vector<double>& values) {
473 if (values.empty())
474 return 0.0;
475
476 double sum = 0.0;
477 for (double value : values) {
478 sum += value;
479 }
480 return sum / values.size();
481}
482
484 const std::vector<double>& values, double percentile) {
485 if (values.empty())
486 return 0.0;
487
488 std::vector<double> sorted_values = values;
489 std::sort(sorted_values.begin(), sorted_values.end());
490
491 size_t index =
492 static_cast<size_t>((percentile / 100.0) * sorted_values.size());
493 if (index >= sorted_values.size()) {
494 index = sorted_values.size() - 1;
495 }
496
497 return sorted_values[index];
498}
499
500std::string PerformanceDashboard::FormatTime(double time_us) {
501 if (time_us < 1.0) {
502 return std::to_string(static_cast<int>(time_us * 1000.0)) + " ns";
503 }
504 if (time_us < 1000.0) {
505 return std::to_string(static_cast<int>(time_us)) + " μs";
506 }
507 return std::to_string(static_cast<int>(time_us / 1000.0)) + " ms";
508}
509
510std::string PerformanceDashboard::FormatMemory(size_t bytes) {
511 if (bytes < 1024) {
512 return std::to_string(bytes) + " B";
513 }
514 if (bytes < 1024 * 1024) {
515 return std::to_string(bytes / 1024) + " KB";
516 }
517 return std::to_string(bytes / (1024 * 1024)) + " MB";
518}
519
521 auto summary = GetSummary();
522
523 if (summary.optimization_score >= 90) {
524 return "Performance is excellent. All optimizations are active.";
525 }
526 if (summary.optimization_score >= 70) {
527 return "Performance is good. Consider enabling remaining optimizations.";
528 }
529 if (summary.optimization_score >= 50) {
530 return "Performance is fair. Several optimizations are available.";
531 }
532 return "Performance needs improvement. Enable graphics optimizations.";
533}
534
535} // namespace gfx
536} // 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.
Main namespace for the application.
Performance summary for external consumption.
std::vector< std::string > recommendations