Compare commits
2 Commits
f27b971565
...
1f760f2381
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f760f2381 | |||
| a4c267d864 |
@@ -84,9 +84,14 @@ This file tracks all major tracks for the project. Each track has its own detail
|
||||
19. [ ] **Track: Manual UX Validation & Review**
|
||||
*Link: [./tracks/manual_ux_validation_20260302/](./tracks/manual_ux_validation_20260302/)*
|
||||
|
||||
### Misc Side-tracks
|
||||
|
||||
20. [x] **Track: Enhanced Context Control & Cache Awareness**
|
||||
*Link: [./tracks/enhanced_context_control_20260307/](./tracks/enhanced_context_control_20260307/)*
|
||||
|
||||
22. [~] **Track: GUI Performance Profiling & Optimization**
|
||||
*Link: [./tracks/gui_performance_profiling_20260307/](./tracks/gui_performance_profiling_20260307/)*
|
||||
|
||||
---
|
||||
|
||||
## Completed / Archived
|
||||
|
||||
23
conductor/tracks/gui_performance_profiling_20260307/plan.md
Normal file
23
conductor/tracks/gui_performance_profiling_20260307/plan.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Implementation Plan: GUI Performance Profiling & Optimization (gui_performance_profiling_20260307)
|
||||
|
||||
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
|
||||
|
||||
## Phase 1: Instrumentation
|
||||
Focus: Add profiling hooks to gui_2.py
|
||||
|
||||
- [x] Task 1.1: Wrap `_render_log_management` with profiling calls. (f27b971)
|
||||
- [x] Task 1.2: Wrap `_render_discussion_panel` with profiling calls. (f27b971)
|
||||
- [x] Task 1.3: Wrap `_render_mma_dashboard` with profiling calls. (f27b971)
|
||||
- [x] Task 1.4: Wrap core `_gui_func` logic with profiling calls. (f27b971)
|
||||
|
||||
## Phase 2: Diagnostics UI
|
||||
Focus: Display timings in the GUI
|
||||
|
||||
- [x] Task 2.1: Add "Detailed Component Timings" table to Diagnostics panel in `src/gui_2.py`. (f27b971)
|
||||
- [x] Task 2.2: Implement 10ms threshold highlighting in the table. (f27b971)
|
||||
|
||||
## Phase 3: Verification & Optimization
|
||||
Focus: Analyze results and fix bottlenecks
|
||||
|
||||
- [ ] Task 3.1: Verify timings are accurate via manual walkthrough.
|
||||
- [ ] Task 3.2: Identify components consistently > 10ms and propose optimizations.
|
||||
21
conductor/tracks/gui_performance_profiling_20260307/spec.md
Normal file
21
conductor/tracks/gui_performance_profiling_20260307/spec.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Track Specification: GUI Performance Profiling & Optimization (gui_performance_profiling_20260307)
|
||||
|
||||
## Overview
|
||||
Implement fine-grained performance profiling within the main ImGui rendering loop (`gui_2.py`) to ensure adherence to data-oriented and immediate mode heuristics. This track will provide visual diagnostics for high-overhead UI components, allowing developers to monitor and optimize render frame times.
|
||||
|
||||
## Core Requirements
|
||||
1. **Instrumentation:** Inject `start_component()` and `end_component()` calls from the `PerformanceMonitor` API (`src/performance_monitor.py`) around identified high-overhead methods in `src/gui_2.py`.
|
||||
2. **Diagnostics UI:** Expand the Diagnostics panel in `gui_2.py` to include a new table titled "Detailed Component Timings".
|
||||
3. **Threshold Alerting:** Add visual threshold alerts (e.g., color highlighting) in the new Diagnostics table for any individual component whose execution time exceeds 10ms.
|
||||
4. **Target Methods:**
|
||||
- `_render_log_management`
|
||||
- `_render_discussion_panel`
|
||||
- `_render_mma_dashboard`
|
||||
- `_gui_func` (as a global wrapper)
|
||||
|
||||
## Acceptance Criteria
|
||||
- [ ] Profiling calls correctly wrap target methods.
|
||||
- [ ] "Detailed Component Timings" table displays in Diagnostics panel.
|
||||
- [ ] Timings update in real-time (every 0.5s or similar).
|
||||
- [ ] Components exceeding 10ms are highlighted (e.g., Red).
|
||||
- [ ] 1-space indentation maintained.
|
||||
93
src/gui_2.py
93
src/gui_2.py
@@ -114,6 +114,8 @@ class App:
|
||||
self._tool_log_dirty: bool = True
|
||||
self._last_ui_focus_agent: Optional[str] = None
|
||||
self._log_registry: Optional[log_registry.LogRegistry] = None
|
||||
self.perf_profiling_enabled = False
|
||||
self.perf_profiling_enabled = False
|
||||
|
||||
def _handle_approve_tool(self, user_data=None) -> None:
|
||||
"""UI-level wrapper for approving a pending tool execution ask."""
|
||||
@@ -241,6 +243,7 @@ class App:
|
||||
imgui.end_menu()
|
||||
|
||||
def _gui_func(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_gui_func")
|
||||
try:
|
||||
self.perf_monitor.start_frame()
|
||||
self._autofocus_response_tab = self.controller._autofocus_response_tab
|
||||
@@ -342,7 +345,9 @@ class App:
|
||||
exp, opened = imgui.begin("MMA Dashboard", self.show_windows["MMA Dashboard"])
|
||||
self.show_windows["MMA Dashboard"] = bool(opened)
|
||||
if exp:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_mma_dashboard")
|
||||
self._render_mma_dashboard()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_mma_dashboard")
|
||||
imgui.end()
|
||||
if self.show_windows.get("Tier 1: Strategy", False):
|
||||
exp, opened = imgui.begin("Tier 1: Strategy", self.show_windows["Tier 1: Strategy"])
|
||||
@@ -376,7 +381,9 @@ class App:
|
||||
if exp:
|
||||
# Top part for the history
|
||||
imgui.begin_child("HistoryChild", size=(0, -200))
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_discussion_panel")
|
||||
self._render_discussion_panel()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_discussion_panel")
|
||||
imgui.end_child()
|
||||
# Bottom part with tabs for message and response
|
||||
# Detach controls
|
||||
@@ -472,7 +479,9 @@ class App:
|
||||
imgui.end()
|
||||
|
||||
if self.show_windows.get("Log Management", False):
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_log_management")
|
||||
self._render_log_management()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_log_management")
|
||||
if self.show_windows["Diagnostics"]:
|
||||
exp, opened = imgui.begin("Diagnostics", self.show_windows["Diagnostics"])
|
||||
self.show_windows["Diagnostics"] = bool(opened)
|
||||
@@ -491,6 +500,8 @@ class App:
|
||||
self.perf_history["input_lag"].append(metrics.get("input_lag_ms", 0.0))
|
||||
metrics = self.perf_monitor.get_metrics()
|
||||
imgui.text("Performance Telemetry")
|
||||
imgui.same_line()
|
||||
_, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled)
|
||||
imgui.separator()
|
||||
if imgui.begin_table("perf_table", 2, imgui.TableFlags_.borders_inner_h):
|
||||
imgui.table_setup_column("Metric")
|
||||
@@ -517,6 +528,66 @@ class App:
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{metrics.get('input_lag_ms', 0.0):.1f}")
|
||||
imgui.end_table()
|
||||
|
||||
if self.perf_profiling_enabled:
|
||||
imgui.separator()
|
||||
imgui.text("Detailed Component Timings")
|
||||
if imgui.begin_table("comp_timings", 2, imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Component")
|
||||
imgui.table_setup_column("Time (ms)")
|
||||
imgui.table_headers_row()
|
||||
for key, val in metrics.items():
|
||||
if key.startswith("time_") and key.endswith("_ms"):
|
||||
comp_name = key[5:-3]
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(comp_name)
|
||||
imgui.table_next_column()
|
||||
if val > 10.0:
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{val:.2f}")
|
||||
else:
|
||||
imgui.text(f"{val:.2f}")
|
||||
imgui.end_table()
|
||||
|
||||
if self.perf_profiling_enabled:
|
||||
imgui.separator()
|
||||
imgui.text("Detailed Component Timings")
|
||||
if imgui.begin_table("comp_timings", 2, imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Component")
|
||||
imgui.table_setup_column("Time (ms)")
|
||||
imgui.table_headers_row()
|
||||
for key, val in metrics.items():
|
||||
if key.startswith("time_") and key.endswith("_ms"):
|
||||
comp_name = key[5:-3]
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(comp_name)
|
||||
imgui.table_next_column()
|
||||
if val > 10.0:
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{val:.2f}")
|
||||
else:
|
||||
imgui.text(f"{val:.2f}")
|
||||
imgui.end_table()
|
||||
|
||||
if self.perf_profiling_enabled:
|
||||
imgui.separator()
|
||||
imgui.text("Detailed Component Timings")
|
||||
if imgui.begin_table("comp_timings", 2, imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Component")
|
||||
imgui.table_setup_column("Time (ms)")
|
||||
imgui.table_headers_row()
|
||||
for key, val in metrics.items():
|
||||
if key.startswith("time_") and key.endswith("_ms"):
|
||||
comp_name = key[5:-3]
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(comp_name)
|
||||
imgui.table_next_column()
|
||||
if val > 10.0:
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{val:.2f}")
|
||||
else:
|
||||
imgui.text(f"{val:.2f}")
|
||||
imgui.end_table()
|
||||
imgui.separator()
|
||||
imgui.text("Frame Time (ms)")
|
||||
imgui.plot_lines("##ft_plot", np.array(self.perf_history["frame_time"], dtype=np.float32), overlay_text="frame_time", graph_size=imgui.ImVec2(-1, 60))
|
||||
@@ -1012,8 +1083,6 @@ class App:
|
||||
if imgui.button("Refresh Registry"):
|
||||
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
||||
imgui.same_line()
|
||||
if imgui.button("Force Prune Logs"):
|
||||
self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"})
|
||||
|
||||
registry = self._log_registry
|
||||
sessions = registry.data
|
||||
@@ -1068,6 +1137,8 @@ class App:
|
||||
)
|
||||
imgui.end_table()
|
||||
|
||||
if imgui.button("Force Prune Logs"):
|
||||
self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"})
|
||||
imgui.end()
|
||||
|
||||
def _render_files_panel(self) -> None:
|
||||
@@ -1084,11 +1155,11 @@ class App:
|
||||
r.destroy()
|
||||
if d: self.ui_files_base_dir = d
|
||||
imgui.separator()
|
||||
imgui.begin_child("f_paths", imgui.ImVec2(0, 200), True)
|
||||
if imgui.begin_table("files_table", 4, imgui.TableFlags_.resizable | imgui.TableFlags_.borders | imgui.TableFlags_.scroll_x):
|
||||
imgui.begin_child("f_paths", imgui.ImVec2(0, -40), True)
|
||||
if imgui.begin_table("files_table", 4, imgui.TableFlags_.resizable | imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Actions", imgui.TableColumnFlags_.width_fixed, 40)
|
||||
imgui.table_setup_column("File Path", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 110)
|
||||
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 150)
|
||||
imgui.table_setup_column("Cache", imgui.TableColumnFlags_.width_fixed, 40)
|
||||
imgui.table_headers_row()
|
||||
|
||||
@@ -1146,7 +1217,7 @@ class App:
|
||||
r.destroy()
|
||||
if d: self.ui_shots_base_dir = d
|
||||
imgui.separator()
|
||||
imgui.begin_child("s_paths", imgui.ImVec2(0, 200), True)
|
||||
imgui.begin_child("s_paths", imgui.ImVec2(0, -40), True)
|
||||
for i, s in enumerate(self.screenshots):
|
||||
if imgui.button(f"x##s{i}"):
|
||||
self.screenshots.pop(i)
|
||||
@@ -1619,21 +1690,21 @@ class App:
|
||||
with self._send_thread_lock:
|
||||
if self.send_thread and self.send_thread.is_alive():
|
||||
send_busy = True
|
||||
if imgui.button("Inject File"):
|
||||
self.show_inject_modal = True
|
||||
imgui.same_line()
|
||||
if (imgui.button("Gen + Send") or ctrl_enter) and not send_busy:
|
||||
self._handle_generate_send()
|
||||
imgui.same_line()
|
||||
if imgui.button("MD Only"):
|
||||
self._handle_md_only()
|
||||
imgui.same_line()
|
||||
if imgui.button("Inject File"):
|
||||
self.show_inject_modal = True
|
||||
if imgui.button("Reset"):
|
||||
self._handle_reset_session()
|
||||
imgui.same_line()
|
||||
if imgui.button("-> History"):
|
||||
if self.ui_ai_input:
|
||||
self.disc_entries.append({"role": "User", "content": self.ui_ai_input, "collapsed": False, "ts": project_manager.now_ts()})
|
||||
imgui.same_line()
|
||||
if imgui.button("Reset"):
|
||||
self._handle_reset_session()
|
||||
|
||||
def _render_response_panel(self) -> None:
|
||||
if self._trigger_blink:
|
||||
|
||||
Reference in New Issue
Block a user