yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_performance_integration.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <sstream>
5#include <iomanip>
6#include <chrono>
7
10#include "util/log.h"
11#include "imgui/imgui.h"
12
13namespace yaze {
14namespace gui {
15namespace canvas {
16
17void CanvasPerformanceIntegration::Initialize(const std::string& canvas_id) {
18 canvas_id_ = canvas_id;
21
22 // Initialize performance profiler integration
24
25 LOG_DEBUG("CanvasPerformance",
26 "Initialized performance integration for canvas: %s",
27 canvas_id_.c_str());
28}
29
31 if (!monitoring_enabled_) return;
32
33 // Start frame timer
35 frame_timer_ = std::make_unique<gfx::ScopedTimer>("canvas_frame_" + canvas_id_);
36
37 LOG_DEBUG("CanvasPerformance", "Started performance monitoring for canvas: %s",
38 canvas_id_.c_str());
39}
40
42 // Release timers in reverse order of creation to ensure clean shutdown
44 modal_timer_.reset();
45 modal_timer_active_ = false;
46 }
48 interaction_timer_.reset();
50 }
52 draw_timer_.reset();
53 draw_timer_active_ = false;
54 }
56 frame_timer_.reset();
57 frame_timer_active_ = false;
58 }
59
60 LOG_DEBUG("CanvasPerformance", "Stopped performance monitoring for canvas: %s",
61 canvas_id_.c_str());
62}
63
65 if (!monitoring_enabled_) return;
66
67 // Update frame time
69
70 // Update draw time
72
73 // Update interaction time
75
76 // Update modal time
78
79 // Calculate cache hit ratio
81
82 // Save current metrics periodically
83 static auto last_save = std::chrono::steady_clock::now();
84 auto now = std::chrono::steady_clock::now();
85 if (std::chrono::duration_cast<std::chrono::seconds>(now - last_save).count() >= 5) {
87 last_save = now;
88 }
89}
90
91void CanvasPerformanceIntegration::RecordOperation(const std::string& operation_name,
92 double time_ms,
93 CanvasUsage usage_mode) {
94 if (!monitoring_enabled_) return;
95
96 // Update operation counts based on usage mode
97 switch (usage_mode) {
100 break;
103 break;
106 break;
109 break;
112 break;
113 default:
114 break;
115 }
116
117 // Record operation timing in internal metrics
118 // Note: PerformanceProfiler uses StartTimer/EndTimer pattern, not RecordOperation
119
120 // Update usage tracker if available
121 if (usage_tracker_) {
122 usage_tracker_->RecordOperation(operation_name, time_ms);
123 }
124}
125
127 size_t bitmap_memory,
128 size_t palette_memory) {
129 current_metrics_.texture_memory_mb = texture_memory / (1024 * 1024);
130 current_metrics_.bitmap_memory_mb = bitmap_memory / (1024 * 1024);
131 current_metrics_.palette_memory_mb = palette_memory / (1024 * 1024);
132}
133
139
140// These methods are already defined in the header as inline, removing duplicates
141
143 std::ostringstream summary;
144
145 summary << "Canvas Performance Summary (" << canvas_id_ << ")\n";
146 summary << "=====================================\n\n";
147
148 summary << "Timing Metrics:\n";
149 summary << " Frame Time: " << FormatTime(current_metrics_.frame_time_ms) << "\n";
150 summary << " Draw Time: " << FormatTime(current_metrics_.draw_time_ms) << "\n";
151 summary << " Interaction Time: " << FormatTime(current_metrics_.interaction_time_ms) << "\n";
152 summary << " Modal Time: " << FormatTime(current_metrics_.modal_time_ms) << "\n\n";
153
154 summary << "Operation Counts:\n";
155 summary << " Draw Calls: " << current_metrics_.draw_calls << "\n";
156 summary << " Texture Updates: " << current_metrics_.texture_updates << "\n";
157 summary << " Palette Lookups: " << current_metrics_.palette_lookups << "\n";
158 summary << " Bitmap Operations: " << current_metrics_.bitmap_operations << "\n\n";
159
160 summary << "Canvas Operations:\n";
161 summary << " Tile Paint: " << current_metrics_.tile_paint_operations << "\n";
162 summary << " Tile Select: " << current_metrics_.tile_select_operations << "\n";
163 summary << " Rectangle Select: " << current_metrics_.rectangle_select_operations << "\n";
164 summary << " Color Paint: " << current_metrics_.color_paint_operations << "\n";
165 summary << " BPP Conversion: " << current_metrics_.bpp_conversion_operations << "\n\n";
166
167 summary << "Memory Usage:\n";
168 summary << " Texture Memory: " << FormatMemory(current_metrics_.texture_memory_mb * 1024 * 1024) << "\n";
169 summary << " Bitmap Memory: " << FormatMemory(current_metrics_.bitmap_memory_mb * 1024 * 1024) << "\n";
170 summary << " Palette Memory: " << FormatMemory(current_metrics_.palette_memory_mb * 1024 * 1024) << "\n\n";
171
172 summary << "Cache Performance:\n";
173 summary << " Hit Ratio: " << std::fixed << std::setprecision(1)
174 << (current_metrics_.cache_hit_ratio * 100.0) << "%\n";
175 summary << " Hits: " << current_metrics_.cache_hits << "\n";
176 summary << " Misses: " << current_metrics_.cache_misses << "\n";
177
178 return summary.str();
179}
180
182 std::vector<std::string> recommendations;
183
184 // Frame time recommendations
185 if (current_metrics_.frame_time_ms > 16.67) { // 60 FPS threshold
186 recommendations.push_back("Frame time is high - consider reducing draw calls or optimizing rendering");
187 }
188
189 // Draw time recommendations
190 if (current_metrics_.draw_time_ms > 10.0) {
191 recommendations.push_back("Draw time is high - consider using texture atlases or reducing texture switches");
192 }
193
194 // Memory recommendations
195 size_t total_memory = current_metrics_.texture_memory_mb +
198 if (total_memory > 100) { // 100MB threshold
199 recommendations.push_back("Memory usage is high - consider implementing texture streaming or compression");
200 }
201
202 // Cache recommendations
204 recommendations.push_back("Cache hit ratio is low - consider increasing cache size or improving cache strategy");
205 }
206
207 // Operation count recommendations
208 if (current_metrics_.draw_calls > 1000) {
209 recommendations.push_back("High draw call count - consider batching operations or using instanced rendering");
210 }
211
213 recommendations.push_back("Frequent texture updates - consider using texture arrays or atlases");
214 }
215
216 return recommendations;
217}
218
220 std::ostringstream report;
221
222 report << "Canvas Performance Report\n";
223 report << "========================\n\n";
224
225 report << "Canvas ID: " << canvas_id_ << "\n";
226 report << "Monitoring Enabled: " << (monitoring_enabled_ ? "Yes" : "No") << "\n\n";
227
228 report << GetPerformanceSummary() << "\n";
229
230 // Performance history
231 if (!performance_history_.empty()) {
232 report << "Performance History:\n";
233 report << "===================\n\n";
234
235 for (size_t i = 0; i < performance_history_.size(); ++i) {
236 const auto& metrics = performance_history_[i];
237 report << "Sample " << (i + 1) << ":\n";
238 report << " Frame Time: " << FormatTime(metrics.frame_time_ms) << "\n";
239 report << " Draw Calls: " << metrics.draw_calls << "\n";
240 report << " Memory: " << FormatMemory((metrics.texture_memory_mb +
241 metrics.bitmap_memory_mb +
242 metrics.palette_memory_mb) * 1024 * 1024) << "\n\n";
243 }
244 }
245
246 // Recommendations
247 auto recommendations = GetPerformanceRecommendations();
248 if (!recommendations.empty()) {
249 report << "Recommendations:\n";
250 report << "===============\n\n";
251 for (const auto& rec : recommendations) {
252 report << "• " << rec << "\n";
253 }
254 }
255
256 return report.str();
257}
258
260 if (!monitoring_enabled_) return;
261
262 if (ImGui::Begin("Canvas Performance", &show_performance_ui_)) {
263 // Performance overview
265
267 ImGui::Separator();
269 }
270
272 ImGui::Separator();
274 }
275
276 // Control buttons
277 ImGui::Separator();
278 if (ImGui::Button("Toggle Detailed Metrics")) {
280 }
281 ImGui::SameLine();
282 if (ImGui::Button("Toggle Recommendations")) {
284 }
285 ImGui::SameLine();
286 if (ImGui::Button("Export Report")) {
287 std::string report = ExportPerformanceReport();
288 // Could save to file or show in modal
289 }
290 }
291 ImGui::End();
292}
293
294void CanvasPerformanceIntegration::SetUsageTracker(std::shared_ptr<CanvasUsageTracker> tracker) {
295 usage_tracker_ = tracker;
296}
297
299 if (frame_timer_) {
300 // Frame time would be calculated by the timer
301 current_metrics_.frame_time_ms = 16.67; // Placeholder
302 }
303}
304
306 if (draw_timer_) {
307 // Draw time would be calculated by the timer
308 current_metrics_.draw_time_ms = 5.0; // Placeholder
309 }
310}
311
313 if (interaction_timer_) {
314 // Interaction time would be calculated by the timer
315 current_metrics_.interaction_time_ms = 1.0; // Placeholder
316 }
317}
318
320 if (modal_timer_) {
321 // Modal time would be calculated by the timer
322 current_metrics_.modal_time_ms = 0.5; // Placeholder
323 }
324}
325
328 if (total_requests > 0) {
329 current_metrics_.cache_hit_ratio = static_cast<double>(current_metrics_.cache_hits) / total_requests;
330 } else {
332 }
333}
334
337
338 // Keep only last 100 samples
339 if (performance_history_.size() > 100) {
341 }
342}
343
345 // Analyze performance trends and patterns
346 if (performance_history_.size() < 2) return;
347
348 // Calculate trends
349 double frame_time_trend = 0.0;
350 double memory_trend = 0.0;
351
352 for (size_t i = 1; i < performance_history_.size(); ++i) {
353 const auto& prev = performance_history_[i - 1];
354 const auto& curr = performance_history_[i];
355
356 frame_time_trend += (curr.frame_time_ms - prev.frame_time_ms);
357 memory_trend += ((curr.texture_memory_mb + curr.bitmap_memory_mb + curr.palette_memory_mb) -
358 (prev.texture_memory_mb + prev.bitmap_memory_mb + prev.palette_memory_mb));
359 }
360
361 frame_time_trend /= (performance_history_.size() - 1);
362 memory_trend /= (performance_history_.size() - 1);
363
364 // Log trends
365 if (std::abs(frame_time_trend) > 1.0) {
366 LOG_DEBUG("CanvasPerformance", "Canvas %s: Frame time trend: %.2f ms/sample",
367 canvas_id_.c_str(), frame_time_trend);
368 }
369
370 if (std::abs(memory_trend) > 1.0) {
371 LOG_DEBUG("CanvasPerformance", "Canvas %s: Memory trend: %.2f MB/sample",
372 canvas_id_.c_str(), memory_trend);
373 }
374}
375
377 ImGui::Text("Performance Overview");
378 ImGui::Separator();
379
380 // Frame time
381 ImVec4 frame_color = GetPerformanceColor(current_metrics_.frame_time_ms, 16.67, 33.33);
382 ImGui::TextColored(frame_color, "Frame Time: %s", FormatTime(current_metrics_.frame_time_ms).c_str());
383
384 // Draw time
385 ImVec4 draw_color = GetPerformanceColor(current_metrics_.draw_time_ms, 10.0, 20.0);
386 ImGui::TextColored(draw_color, "Draw Time: %s", FormatTime(current_metrics_.draw_time_ms).c_str());
387
388 // Memory usage
389 size_t total_memory = current_metrics_.texture_memory_mb +
392 ImVec4 memory_color = GetPerformanceColor(total_memory, 50.0, 100.0);
393 ImGui::TextColored(memory_color, "Memory: %s", FormatMemory(total_memory * 1024 * 1024).c_str());
394
395 // Cache performance
396 ImVec4 cache_color = GetPerformanceColor(current_metrics_.cache_hit_ratio * 100.0, 80.0, 60.0);
397 ImGui::TextColored(cache_color, "Cache Hit Ratio: %.1f%%", current_metrics_.cache_hit_ratio * 100.0);
398}
399
401 ImGui::Text("Detailed Metrics");
402 ImGui::Separator();
403
404 // Operation counts
406
407 // Memory breakdown
409
410 // Cache performance
412}
413
415 if (ImGui::CollapsingHeader("Memory Usage")) {
416 ImGui::Text("Texture Memory: %s", FormatMemory(current_metrics_.texture_memory_mb * 1024 * 1024).c_str());
417 ImGui::Text("Bitmap Memory: %s", FormatMemory(current_metrics_.bitmap_memory_mb * 1024 * 1024).c_str());
418 ImGui::Text("Palette Memory: %s", FormatMemory(current_metrics_.palette_memory_mb * 1024 * 1024).c_str());
419
420 size_t total = current_metrics_.texture_memory_mb +
423 ImGui::Text("Total Memory: %s", FormatMemory(total * 1024 * 1024).c_str());
424 }
425}
426
428 if (ImGui::CollapsingHeader("Operation Counts")) {
429 ImGui::Text("Draw Calls: %d", current_metrics_.draw_calls);
430 ImGui::Text("Texture Updates: %d", current_metrics_.texture_updates);
431 ImGui::Text("Palette Lookups: %d", current_metrics_.palette_lookups);
432 ImGui::Text("Bitmap Operations: %d", current_metrics_.bitmap_operations);
433
434 ImGui::Separator();
435 ImGui::Text("Canvas Operations:");
436 ImGui::Text(" Tile Paint: %d", current_metrics_.tile_paint_operations);
437 ImGui::Text(" Tile Select: %d", current_metrics_.tile_select_operations);
438 ImGui::Text(" Rectangle Select: %d", current_metrics_.rectangle_select_operations);
439 ImGui::Text(" Color Paint: %d", current_metrics_.color_paint_operations);
440 ImGui::Text(" BPP Conversion: %d", current_metrics_.bpp_conversion_operations);
441 }
442}
443
445 if (ImGui::CollapsingHeader("Cache Performance")) {
446 ImGui::Text("Cache Hits: %d", current_metrics_.cache_hits);
447 ImGui::Text("Cache Misses: %d", current_metrics_.cache_misses);
448 ImGui::Text("Hit Ratio: %.1f%%", current_metrics_.cache_hit_ratio * 100.0);
449
450 // Cache hit ratio bar
451 ImGui::ProgressBar(current_metrics_.cache_hit_ratio, ImVec2(0, 0));
452 }
453}
454
456 ImGui::Text("Performance Recommendations");
457 ImGui::Separator();
458
459 auto recommendations = GetPerformanceRecommendations();
460 if (recommendations.empty()) {
461 ImGui::TextColored(ImVec4(0.2F, 1.0F, 0.2F, 1.0F), "✓ Performance looks good!");
462 } else {
463 for (const auto& rec : recommendations) {
464 ImGui::TextColored(ImVec4(1.0F, 0.8F, 0.2F, 1.0F), "⚠ %s", rec.c_str());
465 }
466 }
467}
468
470 if (ImGui::CollapsingHeader("Performance Graph")) {
471 // Simple performance graph using ImGui plot lines
472 static std::vector<float> frame_times;
473 static std::vector<float> draw_times;
474
475 // Add current values
476 frame_times.push_back(static_cast<float>(current_metrics_.frame_time_ms));
477 draw_times.push_back(static_cast<float>(current_metrics_.draw_time_ms));
478
479 // Keep only last 100 samples
480 if (frame_times.size() > 100) {
481 frame_times.erase(frame_times.begin());
482 draw_times.erase(draw_times.begin());
483 }
484
485 if (!frame_times.empty()) {
486 ImGui::PlotLines("Frame Time (ms)", frame_times.data(),
487 static_cast<int>(frame_times.size()), 0, nullptr, 0.0F, 50.0F,
488 ImVec2(0, 100));
489 ImGui::PlotLines("Draw Time (ms)", draw_times.data(),
490 static_cast<int>(draw_times.size()), 0, nullptr, 0.0F, 30.0F,
491 ImVec2(0, 100));
492 }
493 }
494}
495
496std::string CanvasPerformanceIntegration::FormatTime(double time_ms) const {
497 if (time_ms < 1.0) {
498 return std::to_string(static_cast<int>(time_ms * 1000)) + " μs";
499 } else if (time_ms < 1000.0) {
500 return std::to_string(static_cast<int>(time_ms * 10) / 10.0) + " ms";
501 } else {
502 return std::to_string(static_cast<int>(time_ms / 1000)) + " s";
503 }
504}
505
506std::string CanvasPerformanceIntegration::FormatMemory(size_t bytes) const {
507 if (bytes < 1024) {
508 return std::to_string(bytes) + " B";
509 } else if (bytes < 1024 * 1024) {
510 return std::to_string(bytes / 1024) + " KB";
511 } else {
512 return std::to_string(bytes / (1024 * 1024)) + " MB";
513 }
514}
515
517 double threshold_good,
518 double threshold_warning) const {
519 if (value <= threshold_good) {
520 return ImVec4(0.2F, 1.0F, 0.2F, 1.0F); // Green
521 } else if (value <= threshold_warning) {
522 return ImVec4(1.0F, 1.0F, 0.2F, 1.0F); // Yellow
523 } else {
524 return ImVec4(1.0F, 0.2F, 0.2F, 1.0F); // Red
525 }
526}
527
528// CanvasPerformanceManager implementation
529
531 static CanvasPerformanceManager instance;
532 return instance;
533}
534
536 const std::string& canvas_id,
537 std::shared_ptr<CanvasPerformanceIntegration> integration) {
538 integrations_[canvas_id] = integration;
539 LOG_DEBUG("CanvasPerformance",
540 "Registered performance integration for canvas: %s",
541 canvas_id.c_str());
542}
543
544std::shared_ptr<CanvasPerformanceIntegration>
545CanvasPerformanceManager::GetIntegration(const std::string& canvas_id) {
546 auto it = integrations_.find(canvas_id);
547 if (it != integrations_.end()) {
548 return it->second;
549 }
550 return nullptr;
551}
552
554 for (auto& [id, integration] : integrations_) {
555 integration->UpdateMetrics();
556 }
557}
558
560 std::ostringstream summary;
561
562 summary << "Global Canvas Performance Summary\n";
563 summary << "=================================\n\n";
564
565 summary << "Registered Canvases: " << integrations_.size() << "\n\n";
566
567 for (const auto& [id, integration] : integrations_) {
568 summary << "Canvas: " << id << "\n";
569 summary << "----------------------------------------\n";
570 summary << integration->GetPerformanceSummary() << "\n\n";
571 }
572
573 return summary.str();
574}
575
577 std::ostringstream report;
578
579 report << "Global Canvas Performance Report\n";
580 report << "================================\n\n";
581
582 report << GetGlobalPerformanceSummary();
583
584 // Global recommendations
585 report << "Global Recommendations:\n";
586 report << "=======================\n\n";
587
588 for (const auto& [id, integration] : integrations_) {
589 auto recommendations = integration->GetPerformanceRecommendations();
590 if (!recommendations.empty()) {
591 report << "Canvas " << id << ":\n";
592 for (const auto& rec : recommendations) {
593 report << " • " << rec << "\n";
594 }
595 report << "\n";
596 }
597 }
598
599 return report.str();
600}
601
603 for (auto& [id, integration] : integrations_) {
604 integration->StopMonitoring();
605 }
606 integrations_.clear();
607 LOG_DEBUG("CanvasPerformance", "Cleared all canvas performance integrations");
608}
609
610} // namespace canvas
611} // namespace gui
612} // namespace yaze
static PerformanceDashboard & Get()
std::string ExportPerformanceReport() const
Export performance report.
void RecordOperation(const std::string &operation_name, double time_ms, CanvasUsage usage_mode=CanvasUsage::kUnknown)
Record canvas operation.
std::vector< std::string > GetPerformanceRecommendations() const
Get performance recommendations.
void Initialize(const std::string &canvas_id)
Initialize performance integration.
void RecordCachePerformance(int hits, int misses)
Record cache performance.
void SetUsageTracker(std::shared_ptr< CanvasUsageTracker > tracker)
Set usage tracker integration.
std::vector< CanvasPerformanceMetrics > performance_history_
std::string GetPerformanceSummary() const
Get performance summary.
void RecordMemoryUsage(size_t texture_memory, size_t bitmap_memory, size_t palette_memory)
Record memory usage.
ImVec4 GetPerformanceColor(double value, double threshold_good, double threshold_warning) const
std::shared_ptr< CanvasPerformanceIntegration > GetIntegration(const std::string &canvas_id)
Get integration for canvas.
std::string ExportGlobalPerformanceReport() const
Export global performance report.
std::string GetGlobalPerformanceSummary() const
Get global performance summary.
std::unordered_map< std::string, std::shared_ptr< CanvasPerformanceIntegration > > integrations_
void RegisterIntegration(const std::string &canvas_id, std::shared_ptr< CanvasPerformanceIntegration > integration)
Register a canvas performance integration.
#define LOG_DEBUG(category, format,...)
Definition log.h:104
CanvasUsage
Canvas usage patterns and tracking.
Main namespace for the application.