mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
perf: visibility-gate dashboard render loop
Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
e07b7f2c06
commit
19af4dcba5
13 files changed
+140
-70
No files matched your search
@@ -0,0 +1,23 @@
|
|||||||
|
# Daily Perf Report: 2026-02-16
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Found and fixed a background CPU usage issue in the Agent Dashboard. No content documentation to audit.
|
||||||
|
|
||||||
|
## P0/P1/P2 Findings
|
||||||
|
|
||||||
|
### P1: Dashboard Background Rendering
|
||||||
|
- **File**: `dashboard/index.html`
|
||||||
|
- **Impact**: Unnecessary DOM updates/reflows every 30s when tab is hidden.
|
||||||
|
- **Fix**: Added `document.hidden` check to `setInterval` and added `visibilitychange` listener.
|
||||||
|
- **PR**: `perf: visibility-gate dashboard render loop`
|
||||||
|
|
||||||
|
## Metrics
|
||||||
|
- **Login Time**: N/A (Static Analysis)
|
||||||
|
- **Decrypt Queue**: N/A
|
||||||
|
- **Hits Found**: 3 (1 actionable)
|
||||||
|
|
||||||
|
## Blockers
|
||||||
|
- None.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
- See `src/decisions/DECISIONS_2026-02-16.md`
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
|
|
||||||
> [email protected] dashboard:serve
|
|
||||||
> node bin/torch-lock.mjs dashboard
|
|
||||||
|
|
||||||
Dashboard running at http://localhost:4173/dashboard/
|
|
||||||
Serving files from /app
|
|
||||||
Using configuration from /app
|
|
||||||
Terminated
|
|
||||||
@@ -814,11 +814,17 @@
|
|||||||
// Periodic TTL refresh
|
// Periodic TTL refresh
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
refreshIntervalId = setInterval(() => {
|
refreshIntervalId = setInterval(() => {
|
||||||
if (isAlive()) {
|
if (isAlive() && !document.hidden) {
|
||||||
renderLocks();
|
renderLocks();
|
||||||
}
|
}
|
||||||
}, 30_000);
|
}, 30_000);
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (!document.hidden && isAlive()) {
|
||||||
|
renderLocks();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// Event handlers
|
// Event handlers
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"file": "dashboard/index.html",
|
||||||
|
"line": 816,
|
||||||
|
"pattern": "setInterval",
|
||||||
|
"snippet": " refreshIntervalId = setInterval(() => {",
|
||||||
|
"risk": "Unbounded background DOM updates",
|
||||||
|
"trigger": "Page load",
|
||||||
|
"impact": "CPU usage when tab is hidden",
|
||||||
|
"priority": "P1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "dashboard/index.html",
|
||||||
|
"line": 799,
|
||||||
|
"pattern": "setTimeout",
|
||||||
|
"snippet": " setTimeout(() => {",
|
||||||
|
"risk": "Delayed retry",
|
||||||
|
"trigger": "WebSocket close",
|
||||||
|
"impact": "Low",
|
||||||
|
"priority": "P3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "src/services/memory/scheduler.js",
|
||||||
|
"line": 33,
|
||||||
|
"pattern": "setInterval",
|
||||||
|
"snippet": " const handle = setInterval(() => {",
|
||||||
|
"risk": "Background job loop",
|
||||||
|
"trigger": "Server start",
|
||||||
|
"impact": "Necessary backend process",
|
||||||
|
"priority": "P3"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Context: perf-agent (2026-02-16)
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
Improve app responsiveness by finding and fixing background CPU/network work.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
- Focus on "Visibility gating" for `dashboard/index.html`.
|
||||||
|
- Run grep searches for performance patterns.
|
||||||
|
- Ensure `INITIAL_BASELINE.md` exists.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
- Minimal changes.
|
||||||
|
- Safe changes only.
|
||||||
|
- No network access to external sites.
|
||||||
|
- Running as a simulated agent (Jules).
|
||||||
|
|
||||||
|
## Assumptions
|
||||||
|
- `dashboard/index.html` is the primary entry point for the dashboard.
|
||||||
|
- `setInterval` in `dashboard/index.html` runs even when tab is hidden, wasting CPU.
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# DECISIONS: perf-agent (2026-02-16)
|
||||||
|
|
||||||
|
## Decision: Visibility Gating for Dashboard Refresh Loop
|
||||||
|
|
||||||
|
- **Decision**: Modify the `setInterval` in `dashboard/index.html` to skip rendering if `document.hidden` is true.
|
||||||
|
- **Rationale**: The dashboard currently re-renders the DOM every 30 seconds to update TTL bars, even when the tab is in the background. This wastes CPU cycles.
|
||||||
|
- **Consequences**:
|
||||||
|
- Reduced CPU usage when tab is hidden.
|
||||||
|
- UI might be slightly stale when tab becomes visible, so we add a `visibilitychange` listener to force an immediate update.
|
||||||
|
|
||||||
|
## Alternatives Considered
|
||||||
|
- Remove the interval entirely: Would stop updates.
|
||||||
|
- Use `requestAnimationFrame`: Still runs (sometimes throttled) and more complex to manage with 30s intervals.
|
||||||
|
|
||||||
|
## Follow-ups
|
||||||
|
- Monitor if users complain about stale data (should be mitigated by `visibilitychange`).
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# TEST LOG: perf-agent (2026-02-16)
|
||||||
|
|
||||||
|
## Verification Steps
|
||||||
|
|
||||||
|
1. **Static Analysis**: Verify `dashboard/index.html` contains `document.hidden` check inside `setInterval`.
|
||||||
|
2. **Static Analysis**: Verify `dashboard/index.html` contains `document.addEventListener('visibilitychange', ...)` handler.
|
||||||
|
3. **Linting**: Run `npm run lint` to ensure no syntax errors or style violations.
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
- [x] Static Analysis (Hidden Check): Passed (Verified in `dashboard/index.html`)
|
||||||
|
- [x] Static Analysis (Visibility Listener): Passed (Verified in `dashboard/index.html`)
|
||||||
|
- [ ] Linting: Scheduled for Scheduler Completion step.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# TODO: perf-agent (2026-02-16)
|
||||||
|
|
||||||
|
- [ ] Create context file.
|
||||||
|
- [ ] Run grep searches.
|
||||||
|
- [ ] Create hits file.
|
||||||
|
- [ ] Implement visibility gating in `dashboard/index.html`.
|
||||||
|
- [ ] Document decisions.
|
||||||
|
- [ ] Create test logs.
|
||||||
|
- [ ] Create daily report.
|
||||||
|
- [ ] Commit and push.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
agent: perf-agent
|
||||||
|
status: completed
|
||||||
|
date: 2026-02-16
|
||||||
|
---
|
||||||
|
|
||||||
|
# perf-agent completed
|
||||||
|
|
||||||
|
- **PR**: `perf: visibility-gate dashboard render loop`
|
||||||
|
- **Artifacts**:
|
||||||
|
- `src/context/CONTEXT_2026-02-16.md`
|
||||||
|
- `src/todo/TODO_2026-02-16.md`
|
||||||
|
- `src/decisions/DECISIONS_2026-02-16.md`
|
||||||
|
- `src/test_logs/TEST_LOG_2026-02-16.md`
|
||||||
|
- `daily-perf-report-2026-02-16.md`
|
||||||
|
- `perf/hits-2026-02-16.json`
|
||||||
|
- **Summary**:
|
||||||
|
- Found and fixed a P1 issue in `dashboard/index.html` where the render loop ran unnecessarily when the tab was hidden.
|
||||||
|
- Added visibility gating and a `visibilitychange` listener.
|
||||||
|
- Verified changes with static analysis.
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 140 KiB |
@@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
from playwright.sync_api import sync_playwright
|
|
||||||
|
|
||||||
def verify_dashboard():
|
|
||||||
with sync_playwright() as p:
|
|
||||||
browser = p.chromium.launch(headless=True)
|
|
||||||
page = browser.new_page()
|
|
||||||
try:
|
|
||||||
page.goto("http://localhost:4173/dashboard/")
|
|
||||||
# Wait for title
|
|
||||||
page.wait_for_selector("h1:has-text('TORCH Agent Dashboard')")
|
|
||||||
# Wait a bit for JS to run and potentially render the summary bar
|
|
||||||
page.wait_for_timeout(3000)
|
|
||||||
|
|
||||||
# Take screenshot
|
|
||||||
page.screenshot(path="verification/dashboard.png")
|
|
||||||
print("Screenshot saved to verification/dashboard.png")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error: {e}")
|
|
||||||
finally:
|
|
||||||
browser.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
verify_dashboard()
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
from playwright.sync_api import sync_playwright
|
|
||||||
|
|
||||||
def run():
|
|
||||||
with sync_playwright() as p:
|
|
||||||
browser = p.chromium.launch(headless=True)
|
|
||||||
page = browser.new_page()
|
|
||||||
|
|
||||||
# Navigate to dashboard
|
|
||||||
print("Navigating to dashboard...")
|
|
||||||
page.goto("http://localhost:8081/dashboard/index.html")
|
|
||||||
|
|
||||||
# Click the TORCH link
|
|
||||||
print("Clicking TORCH link...")
|
|
||||||
page.click("#openDocs")
|
|
||||||
|
|
||||||
# Wait for modal to be visible and content to load
|
|
||||||
print("Waiting for modal...")
|
|
||||||
page.wait_for_selector("#docsModal.show")
|
|
||||||
|
|
||||||
# Wait for markdown content to be rendered (look for h1)
|
|
||||||
page.wait_for_selector("#markdown-content h1")
|
|
||||||
|
|
||||||
# Take screenshot
|
|
||||||
print("Taking screenshot...")
|
|
||||||
page.screenshot(path="verification/dashboard_modal.png")
|
|
||||||
|
|
||||||
# Verify content
|
|
||||||
content = page.inner_text("#markdown-content")
|
|
||||||
if "Task Orchestration via Relay-Coordinated Handoff" in content:
|
|
||||||
print("SUCCESS: Modal content verified.")
|
|
||||||
else:
|
|
||||||
print("FAILURE: Modal content not found.")
|
|
||||||
|
|
||||||
browser.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
run()
|
|
||||||
Reference in new issue
Block a user