diff options
| -rw-r--r-- | EFFECT_DEPTH_ANALYSIS.md | 115 | ||||
| -rw-r--r-- | timeline_analysis.html | 425 | ||||
| -rw-r--r-- | tools/seq_compiler.cc | 182 |
3 files changed, 721 insertions, 1 deletions
diff --git a/EFFECT_DEPTH_ANALYSIS.md b/EFFECT_DEPTH_ANALYSIS.md new file mode 100644 index 0000000..7a33baf --- /dev/null +++ b/EFFECT_DEPTH_ANALYSIS.md @@ -0,0 +1,115 @@ +# Effect Depth Analysis Results + +## Overview +The `seq_compiler` tool now includes a `--analyze` flag to identify performance bottlenecks by analyzing how many effects are stacked (running simultaneously) at each moment in the demo. + +## Usage + +```bash +# Analyze effect stacking depth +./build/seq_compiler assets/demo.seq --analyze + +# Generate analysis with visual Gantt chart +./build/seq_compiler assets/demo.seq --analyze --gantt-html=timeline_analysis.html +``` + +## Current Demo Analysis (demo.seq) + +### Summary +- **Timeline duration**: 36s (65 beats @ 120 BPM) +- **Total effects**: 57 +- **Max concurrent effects**: 11 at t=8.8s ⚠️ +- **Bottleneck periods**: 28 time periods with >5 effects + +### Effect Depth Distribution + +| Depth | Time % | Severity | +|-------|--------|----------| +| 1-2 | 28.3% | Light | +| 3-4 | 26.1% | Moderate | +| 5-6 | 15.9% | Heavy | +| 7-11 | 29.6% | Critical ⚠️ | + +**Key Finding**: Nearly 30% of the demo has 7+ effects running simultaneously, which may cause frame rate drops on lower-end hardware. + +### Identified Bottlenecks + +**Most Critical Sections** (10+ concurrent effects): + +1. **t=4.3s** (10 effects): FlashCubeEffect, FadeEffect, ParticleSprayEffect, ParticlesEffect, GaussianBlurEffect, HeptagonEffect, ThemeModulationEffect, ChromaAberrationEffect, SolarizeEffect, FlashEffect +2. **t=8.6s** (10 effects): FlashCubeEffect, ThemeModulationEffect, ParticleSprayEffect, ParticlesEffect, Hybrid3DEffect, GaussianBlurEffect, ChromaAberrationEffect, HeptagonEffect, FlashEffect (×2) +3. **t=8.8s** (11 effects) - **Peak bottleneck** + +**Heavy Sections** (7-9 concurrent effects): +- t=4.9s: 9 effects +- t=6.7s: 9 effects +- t=7.3s: 7 effects +- t=7.9s: 8 effects +- t=9.1s: 9 effects +- ... and 18 more peaks + +### Recommendations + +**Immediate Actions**: +1. **Reduce overlap at t=8.8s**: The 11-effect peak is excessive. Consider: + - Staggering effect start/end times by 0.1-0.2s + - Removing redundant effects (e.g., duplicate FlashEffect instances) + - Combining similar effects (e.g., multiple GaussianBlur passes) + +2. **Optimize sequence at 8b-12b** (4-6 seconds): + - This section has sustained high effect counts (6-10 effects) + - Consider moving some post-processing effects to later sequences + - Test frame rate on target hardware during this section + +3. **Profile specific effects**: + - GaussianBlurEffect appears frequently (28 instances) + - Hybrid3DEffect runs for long durations (20s total) + - ChromaAberrationEffect appears in most bottleneck periods + +**Optimization Strategies**: +- Use priority layering to ensure critical effects render at higher priority +- Consider effect LOD (Level of Detail) system for lower-end hardware +- Combine multiple post-process passes into single shaders where possible +- Profile GPU time per effect to identify true bottlenecks (not just count) + +### Effect Frequency Analysis + +**Most Used Effects** (estimated from analysis output): +1. GaussianBlurEffect: ~10 instances +2. HeptagonEffect: ~9 instances +3. ThemeModulationEffect: ~7 instances +4. ChromaAberrationEffect: ~6 instances +5. FlashCubeEffect: ~6 instances +6. ParticleSprayEffect: ~5 instances +7. ParticlesEffect: ~5 instances +8. SolarizeEffect: ~4 instances +9. Hybrid3DEffect: ~3 instances +10. FadeEffect: ~2 instances + +**Insight**: GaussianBlur and Heptagon effects are the most heavily used - optimizing these will have the biggest impact on overall performance. + +## Technical Details + +### Analysis Method +- Samples timeline at 10 Hz (every 0.1s) +- Counts overlapping effect time ranges at each sample +- Generates histogram of effect depth distribution +- Identifies peaks (>5 effects) with at least 0.5s separation + +### Limitations +- Does not measure actual GPU/CPU time per effect (only counts) +- Assumes all effects have equal performance cost (not true in practice) +- Does not account for effect complexity (e.g., particle count, shader passes) + +### Future Improvements +- Add GPU profiling integration (Tracy, RenderDoc) +- Weight effects by estimated performance cost +- Suggest specific optimizations per bottleneck +- Generate timeline heatmap visualization +- Compare multiple .seq files (before/after optimization) + +--- + +**Generated**: February 8, 2026 +**Analysis Tool**: seq_compiler v1.1 (--analyze flag) +**Target**: assets/demo.seq diff --git a/timeline_analysis.html b/timeline_analysis.html new file mode 100644 index 0000000..92e4a3f --- /dev/null +++ b/timeline_analysis.html @@ -0,0 +1,425 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="UTF-8"> +<title>Demo Timeline - BPM 120</title> +<style> +body { font-family: 'Courier New', monospace; margin: 20px; background: #1e1e1e; color: #d4d4d4; } +h1 { color: #569cd6; } +.info { background: #252526; padding: 10px; border-radius: 4px; margin: 10px 0; } +svg { background: #252526; border-radius: 4px; } +.sequence-bar { fill: #3a3a3a; stroke: #569cd6; stroke-width: 2; } +.effect-bar { fill: #4ec9b0; opacity: 0.8; stroke: #2a7a6a; stroke-width: 1; } +.effect-bar.invalid { fill: #f48771; stroke: #d16969; } +.label { fill: #d4d4d4; font-size: 12px; } +.label.effect { fill: #cccccc; font-size: 11px; } +.axis-line { stroke: #6a6a6a; stroke-width: 1; } +.axis-label { fill: #858585; font-size: 10px; } +.time-marker { stroke: #444444; stroke-width: 1; stroke-dasharray: 2,2; } +rect:hover { opacity: 1; } +title { font-size: 11px; } +</style> +</head> +<body> +<h1>Demo Timeline Gantt Chart</h1> +<div class="info"> +<strong>BPM:</strong> 120 | <strong>Duration:</strong> 36s (explicit end) | <strong>Sequences:</strong> 14 +</div> + +<svg width="1400" height="2230" xmlns="http://www.w3.org/2000/svg"> + <!-- Time axis --> + <line x1="250" y1="50" x2="1350" y2="50" class="axis-line"/> + <line x1="250" y1="45" x2="250" y2="55" class="axis-line"/> + <text x="250" y="40" class="axis-label" text-anchor="middle">0s</text> + <line x1="250" y1="60" x2="250" y2="2210" class="time-marker"/> + <line x1="311" y1="45" x2="311" y2="55" class="axis-line"/> + <text x="311" y="40" class="axis-label" text-anchor="middle">2s</text> + <line x1="311" y1="60" x2="311" y2="2210" class="time-marker"/> + <line x1="372" y1="45" x2="372" y2="55" class="axis-line"/> + <text x="372" y="40" class="axis-label" text-anchor="middle">4s</text> + <line x1="372" y1="60" x2="372" y2="2210" class="time-marker"/> + <line x1="433" y1="45" x2="433" y2="55" class="axis-line"/> + <text x="433" y="40" class="axis-label" text-anchor="middle">6s</text> + <line x1="433" y1="60" x2="433" y2="2210" class="time-marker"/> + <line x1="494" y1="45" x2="494" y2="55" class="axis-line"/> + <text x="494" y="40" class="axis-label" text-anchor="middle">8s</text> + <line x1="494" y1="60" x2="494" y2="2210" class="time-marker"/> + <line x1="555" y1="45" x2="555" y2="55" class="axis-line"/> + <text x="555" y="40" class="axis-label" text-anchor="middle">10s</text> + <line x1="555" y1="60" x2="555" y2="2210" class="time-marker"/> + <line x1="616" y1="45" x2="616" y2="55" class="axis-line"/> + <text x="616" y="40" class="axis-label" text-anchor="middle">12s</text> + <line x1="616" y1="60" x2="616" y2="2210" class="time-marker"/> + <line x1="677" y1="45" x2="677" y2="55" class="axis-line"/> + <text x="677" y="40" class="axis-label" text-anchor="middle">14s</text> + <line x1="677" y1="60" x2="677" y2="2210" class="time-marker"/> + <line x1="738" y1="45" x2="738" y2="55" class="axis-line"/> + <text x="738" y="40" class="axis-label" text-anchor="middle">16s</text> + <line x1="738" y1="60" x2="738" y2="2210" class="time-marker"/> + <line x1="800" y1="45" x2="800" y2="55" class="axis-line"/> + <text x="800" y="40" class="axis-label" text-anchor="middle">18s</text> + <line x1="800" y1="60" x2="800" y2="2210" class="time-marker"/> + <line x1="861" y1="45" x2="861" y2="55" class="axis-line"/> + <text x="861" y="40" class="axis-label" text-anchor="middle">20s</text> + <line x1="861" y1="60" x2="861" y2="2210" class="time-marker"/> + <line x1="922" y1="45" x2="922" y2="55" class="axis-line"/> + <text x="922" y="40" class="axis-label" text-anchor="middle">22s</text> + <line x1="922" y1="60" x2="922" y2="2210" class="time-marker"/> + <line x1="983" y1="45" x2="983" y2="55" class="axis-line"/> + <text x="983" y="40" class="axis-label" text-anchor="middle">24s</text> + <line x1="983" y1="60" x2="983" y2="2210" class="time-marker"/> + <line x1="1044" y1="45" x2="1044" y2="55" class="axis-line"/> + <text x="1044" y="40" class="axis-label" text-anchor="middle">26s</text> + <line x1="1044" y1="60" x2="1044" y2="2210" class="time-marker"/> + <line x1="1105" y1="45" x2="1105" y2="55" class="axis-line"/> + <text x="1105" y="40" class="axis-label" text-anchor="middle">28s</text> + <line x1="1105" y1="60" x2="1105" y2="2210" class="time-marker"/> + <line x1="1166" y1="45" x2="1166" y2="55" class="axis-line"/> + <text x="1166" y="40" class="axis-label" text-anchor="middle">30s</text> + <line x1="1166" y1="60" x2="1166" y2="2210" class="time-marker"/> + <line x1="1227" y1="45" x2="1227" y2="55" class="axis-line"/> + <text x="1227" y="40" class="axis-label" text-anchor="middle">32s</text> + <line x1="1227" y1="60" x2="1227" y2="2210" class="time-marker"/> + <line x1="1288" y1="45" x2="1288" y2="55" class="axis-line"/> + <text x="1288" y="40" class="axis-label" text-anchor="middle">34s</text> + <line x1="1288" y1="60" x2="1288" y2="2210" class="time-marker"/> + <line x1="1350" y1="45" x2="1350" y2="55" class="axis-line"/> + <text x="1350" y="40" class="axis-label" text-anchor="middle">36s</text> + <line x1="1350" y1="60" x2="1350" y2="2210" class="time-marker"/> + <!-- Sequence --> + <rect x="250" y="60" width="61" height="30" class="sequence-bar"> + <title>SEQ@0s [pri=0] (0-2s)</title> + </rect> + <text x="10" y="79" class="label">SEQ@0s [pri=0]</text> + <rect x="256" y="95" width="39" height="20" class="effect-bar"> + <title>FlashCubeEffect [pri=-1] (0.2-1.5s)</title> + </rect> + <text x="20" y="110" class="label effect">FlashCubeEffect [pri=-1]</text> + <rect x="250" y="125" width="30" height="20" class="effect-bar"> + <title>FlashEffect [pri=0] (0-1s)</title> + </rect> + <text x="20" y="140" class="label effect">FlashEffect [pri=0]</text> + <rect x="253" y="155" width="27" height="20" class="effect-bar"> + <title>FadeEffect [pri=1] (0.1-1s)</title> + </rect> + <text x="20" y="170" class="label effect">FadeEffect [pri=1]</text> + <rect x="250" y="185" width="61" height="20" class="effect-bar"> + <title>SolarizeEffect [pri=2] (0-2s)</title> + </rect> + <text x="20" y="200" class="label effect">SolarizeEffect [pri=2]</text> + <!-- Separator --> + <line x1="250" y1="215" x2="1350" y2="215" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="311" y="220" width="91" height="30" class="sequence-bar"> + <title>SEQ@2s [pri=0] (2-5s)</title> + </rect> + <text x="10" y="239" class="label">SEQ@2s [pri=0]</text> + <rect x="314" y="255" width="88" height="20" class="effect-bar"> + <title>FlashCubeEffect [pri=-1] (2.1-5s)</title> + </rect> + <text x="20" y="270" class="label effect">FlashCubeEffect [pri=-1]</text> + <rect x="311" y="285" width="6" height="20" class="effect-bar"> + <title>FlashEffect [pri=0] (2-2.2s)</title> + </rect> + <text x="20" y="300" class="label effect">FlashEffect [pri=0]</text> + <!-- Separator --> + <line x1="250" y1="315" x2="1350" y2="315" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="341" y="320" width="122" height="30" class="sequence-bar"> + <title>SEQ@3s [pri=1] (3-7s)</title> + </rect> + <text x="10" y="339" class="label">SEQ@3s [pri=1]</text> + <rect x="341" y="355" width="61" height="20" class="effect-bar"> + <title>ParticleSprayEffect [pri=0] (3-5s)</title> + </rect> + <text x="20" y="370" class="label effect">ParticleSprayEffect [pri=0]</text> + <rect x="341" y="385" width="61" height="20" class="effect-bar"> + <title>ParticlesEffect [pri=1] (3-5s)</title> + </rect> + <text x="20" y="400" class="label effect">ParticlesEffect [pri=1]</text> + <rect x="341" y="415" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=1] (3-7s)</title> + </rect> + <text x="20" y="430" class="label effect">GaussianBlurEffect [pri=1]</text> + <!-- Separator --> + <line x1="250" y1="445" x2="1350" y2="445" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="356" y="450" width="31" height="30" class="sequence-bar"> + <title>SEQ@3.5s [pri=0] (3.5-4.5s)</title> + </rect> + <text x="10" y="469" class="label">SEQ@3.5s [pri=0]</text> + <rect x="356" y="485" width="7" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=0] (3.5-3.7s)</title> + </rect> + <text x="20" y="500" class="label effect">HeptagonEffect [pri=0]</text> + <rect x="360" y="515" width="27" height="20" class="effect-bar"> + <title>FadeEffect [pri=1] (3.6-4.5s)</title> + </rect> + <text x="20" y="530" class="label effect">FadeEffect [pri=1]</text> + <!-- Separator --> + <line x1="250" y1="545" x2="1350" y2="545" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="372" y="550" width="153" height="30" class="sequence-bar"> + <title>SEQ@4s [pri=3] (4-9s)</title> + </rect> + <text x="10" y="569" class="label">SEQ@4s [pri=3]</text> + <rect x="372" y="585" width="61" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (4-6s)</title> + </rect> + <text x="20" y="600" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="372" y="615" width="122" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=0] (4-8s)</title> + </rect> + <text x="20" y="630" class="label effect">HeptagonEffect [pri=0]</text> + <rect x="372" y="645" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=1] (4-8s)</title> + </rect> + <text x="20" y="660" class="label effect">GaussianBlurEffect [pri=1]</text> + <rect x="372" y="675" width="91" height="20" class="effect-bar"> + <title>ChromaAberrationEffect [pri=2] (4-7s)</title> + </rect> + <text x="20" y="690" class="label effect">ChromaAberrationEffect [pri=2]</text> + <rect x="372" y="705" width="153" height="20" class="effect-bar"> + <title>SolarizeEffect [pri=3] (4-9s)</title> + </rect> + <text x="20" y="720" class="label effect">SolarizeEffect [pri=3]</text> + <!-- Separator --> + <line x1="250" y1="735" x2="1350" y2="735" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="433" y="740" width="61" height="30" class="sequence-bar"> + <title>SEQ@6s [pri=2] (6-8s)</title> + </rect> + <text x="10" y="759" class="label">SEQ@6s [pri=2]</text> + <rect x="439" y="775" width="40" height="20" class="effect-bar"> + <title>FlashCubeEffect [pri=-1] (6.2-7.5s)</title> + </rect> + <text x="20" y="790" class="label effect">FlashCubeEffect [pri=-1]</text> + <rect x="433" y="805" width="61" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=0] (6-8s)</title> + </rect> + <text x="20" y="820" class="label effect">HeptagonEffect [pri=0]</text> + <rect x="433" y="835" width="61" height="20" class="effect-bar"> + <title>ParticleSprayEffect [pri=1] (6-8s)</title> + </rect> + <text x="20" y="850" class="label effect">ParticleSprayEffect [pri=1]</text> + <rect x="433" y="865" width="61" height="20" class="effect-bar"> + <title>ParticlesEffect [pri=2] (6-8s)</title> + </rect> + <text x="20" y="880" class="label effect">ParticlesEffect [pri=2]</text> + <!-- Separator --> + <line x1="250" y1="895" x2="1350" y2="895" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="479" y="900" width="46" height="30" class="sequence-bar"> + <title>SEQ@7.5s [pri=2] (7.5-9s)</title> + </rect> + <text x="10" y="919" class="label">SEQ@7.5s [pri=2]</text> + <rect x="485" y="935" width="40" height="20" class="effect-bar"> + <title>FlashCubeEffect [pri=-1] (7.7-9s)</title> + </rect> + <text x="20" y="950" class="label effect">FlashCubeEffect [pri=-1]</text> + <rect x="479" y="965" width="15" height="20" class="effect-bar"> + <title>FlashEffect [pri=0] (7.5-8s)</title> + </rect> + <text x="20" y="980" class="label effect">FlashEffect [pri=0]</text> + <!-- Separator --> + <line x1="250" y1="995" x2="1350" y2="995" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="494" y="1000" width="122" height="30" class="sequence-bar"> + <title>SEQ@8s [pri=10] (8-12s)</title> + </rect> + <text x="10" y="1019" class="label">SEQ@8s [pri=10]</text> + <rect x="500" y="1035" width="40" height="20" class="effect-bar"> + <title>FlashCubeEffect [pri=-1] (8.2-9.5s)</title> + </rect> + <text x="20" y="1050" class="label effect">FlashCubeEffect [pri=-1]</text> + <rect x="494" y="1065" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=0] (8-12s)</title> + </rect> + <text x="20" y="1080" class="label effect">GaussianBlurEffect [pri=0]</text> + <rect x="494" y="1095" width="6" height="20" class="effect-bar"> + <title>FlashEffect [pri=1] (8-8.2s)</title> + </rect> + <text x="20" y="1110" class="label effect">FlashEffect [pri=1]</text> + <rect x="509" y="1125" width="2" height="20" class="effect-bar invalid"> + <title>FlashEffect [pri=1] (8.5-8.2s) *** INVALID TIME RANGE ***</title> + </rect> + <text x="20" y="1140" class="label effect">FlashEffect [pri=1] ⚠</text> + <!-- Separator --> + <line x1="250" y1="1155" x2="1350" y2="1155" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="509" y="1160" width="122" height="30" class="sequence-bar"> + <title>SEQ@8.5s [pri=2] (8.5-12.5s)</title> + </rect> + <text x="10" y="1179" class="label">SEQ@8.5s [pri=2]</text> + <rect x="509" y="1195" width="61" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (8.5-10.5s)</title> + </rect> + <text x="20" y="1210" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="515" y="1225" width="55" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=1] (8.7-10.5s)</title> + </rect> + <text x="20" y="1240" class="label effect">HeptagonEffect [pri=1]</text> + <rect x="509" y="1255" width="61" height="20" class="effect-bar"> + <title>ParticleSprayEffect [pri=2] (8.5-10.5s)</title> + </rect> + <text x="20" y="1270" class="label effect">ParticleSprayEffect [pri=2]</text> + <rect x="509" y="1285" width="61" height="20" class="effect-bar"> + <title>ParticlesEffect [pri=2] (8.5-10.5s)</title> + </rect> + <text x="20" y="1300" class="label effect">ParticlesEffect [pri=2]</text> + <rect x="509" y="1315" width="61" height="20" class="effect-bar"> + <title>Hybrid3DEffect [pri=3] (8.5-10.5s)</title> + </rect> + <text x="20" y="1330" class="label effect">Hybrid3DEffect [pri=3]</text> + <rect x="509" y="1345" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=4] (8.5-12.5s)</title> + </rect> + <text x="20" y="1360" class="label effect">GaussianBlurEffect [pri=4]</text> + <rect x="509" y="1375" width="92" height="20" class="effect-bar"> + <title>ChromaAberrationEffect [pri=5] (8.5-11.5s)</title> + </rect> + <text x="20" y="1390" class="label effect">ChromaAberrationEffect [pri=5]</text> + <!-- Separator --> + <line x1="250" y1="1405" x2="1350" y2="1405" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="616" y="1410" width="306" height="30" class="sequence-bar"> + <title>SEQ@12s [pri=1] (12-22s)</title> + </rect> + <text x="10" y="1429" class="label">SEQ@12s [pri=1]</text> + <rect x="616" y="1445" width="122" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (12-16s)</title> + </rect> + <text x="20" y="1460" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="622" y="1475" width="55" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=1] (12.2-14s)</title> + </rect> + <text x="20" y="1490" class="label effect">HeptagonEffect [pri=1]</text> + <rect x="616" y="1505" width="122" height="20" class="effect-bar"> + <title>ParticleSprayEffect [pri=2] (12-16s)</title> + </rect> + <text x="20" y="1520" class="label effect">ParticleSprayEffect [pri=2]</text> + <rect x="616" y="1535" width="306" height="20" class="effect-bar"> + <title>Hybrid3DEffect [pri=3] (12-22s)</title> + </rect> + <text x="20" y="1550" class="label effect">Hybrid3DEffect [pri=3]</text> + <rect x="616" y="1565" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=4] (12-16s)</title> + </rect> + <text x="20" y="1580" class="label effect">GaussianBlurEffect [pri=4]</text> + <rect x="616" y="1595" width="153" height="20" class="effect-bar"> + <title>ChromaAberrationEffect [pri=5] (12-17s)</title> + </rect> + <text x="20" y="1610" class="label effect">ChromaAberrationEffect [pri=5]</text> + <rect x="616" y="1625" width="153" height="20" class="effect-bar"> + <title>SolarizeEffect [pri=6] (12-17s)</title> + </rect> + <text x="20" y="1640" class="label effect">SolarizeEffect [pri=6]</text> + <!-- Separator --> + <line x1="250" y1="1655" x2="1350" y2="1655" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="738" y="1660" width="245" height="30" class="sequence-bar"> + <title>SEQ@16s [pri=0] (16-24s)</title> + </rect> + <text x="10" y="1679" class="label">SEQ@16s [pri=0]</text> + <rect x="738" y="1695" width="62" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (16-18s)</title> + </rect> + <text x="20" y="1710" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="738" y="1725" width="245" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=1] (16-24s)</title> + </rect> + <text x="20" y="1740" class="label effect">HeptagonEffect [pri=1]</text> + <rect x="738" y="1755" width="245" height="20" class="effect-bar"> + <title>ChromaAberrationEffect [pri=2] (16-24s)</title> + </rect> + <text x="20" y="1770" class="label effect">ChromaAberrationEffect [pri=2]</text> + <rect x="738" y="1785" width="123" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=3] (16-20s)</title> + </rect> + <text x="20" y="1800" class="label effect">GaussianBlurEffect [pri=3]</text> + <!-- Separator --> + <line x1="250" y1="1815" x2="1350" y2="1815" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="983" y="1820" width="122" height="30" class="sequence-bar"> + <title>SEQ@24s [pri=0] (24-28s)</title> + </rect> + <text x="10" y="1839" class="label">SEQ@24s [pri=0]</text> + <rect x="983" y="1855" width="61" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (24-26s)</title> + </rect> + <text x="20" y="1870" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="989" y="1885" width="55" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=1] (24.2-26s)</title> + </rect> + <text x="20" y="1900" class="label effect">HeptagonEffect [pri=1]</text> + <rect x="983" y="1915" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=2] (24-28s)</title> + </rect> + <text x="20" y="1930" class="label effect">GaussianBlurEffect [pri=2]</text> + <rect x="983" y="1945" width="30" height="20" class="effect-bar"> + <title>SolarizeEffect [pri=3] (24-25s)</title> + </rect> + <text x="20" y="1960" class="label effect">SolarizeEffect [pri=3]</text> + <!-- Separator --> + <line x1="250" y1="1975" x2="1350" y2="1975" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="1105" y="1980" width="245" height="30" class="sequence-bar"> + <title>SEQ@28s [pri=0] (28-36s)</title> + </rect> + <text x="10" y="1999" class="label">SEQ@28s [pri=0]</text> + <rect x="1105" y="2015" width="122" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (28-32s)</title> + </rect> + <text x="20" y="2030" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="1111" y="2045" width="55" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=0] (28.2-30s)</title> + </rect> + <text x="20" y="2060" class="label effect">HeptagonEffect [pri=0]</text> + <rect x="1105" y="2075" width="61" height="20" class="effect-bar"> + <title>Hybrid3DEffect [pri=1] (28-30s)</title> + </rect> + <text x="20" y="2090" class="label effect">Hybrid3DEffect [pri=1]</text> + <rect x="1105" y="2105" width="122" height="20" class="effect-bar"> + <title>ParticleSprayEffect [pri=2] (28-32s)</title> + </rect> + <text x="20" y="2120" class="label effect">ParticleSprayEffect [pri=2]</text> + <rect x="1105" y="2135" width="245" height="20" class="effect-bar"> + <title>HeptagonEffect [pri=3] (28-36s)</title> + </rect> + <text x="20" y="2150" class="label effect">HeptagonEffect [pri=3]</text> + <rect x="1105" y="2165" width="245" height="20" class="effect-bar"> + <title>ChromaAberrationEffect [pri=4] (28-36s)</title> + </rect> + <text x="20" y="2180" class="label effect">ChromaAberrationEffect [pri=4]</text> + <rect x="1105" y="2195" width="122" height="20" class="effect-bar"> + <title>GaussianBlurEffect [pri=5] (28-32s)</title> + </rect> + <text x="20" y="2210" class="label effect">GaussianBlurEffect [pri=5]</text> + <!-- Separator --> + <line x1="250" y1="2225" x2="1350" y2="2225" style="stroke:#444444; stroke-width:1; stroke-dasharray:4,2;"/> + <!-- Sequence --> + <rect x="1197" y="2230" width="46" height="30" class="sequence-bar"> + <title>SEQ@31s [pri=0] (31-32.5s)</title> + </rect> + <text x="10" y="2249" class="label">SEQ@31s [pri=0]</text> + <rect x="1197" y="2265" width="46" height="20" class="effect-bar"> + <title>ThemeModulationEffect [pri=0] (31-32.5s)</title> + </rect> + <text x="20" y="2280" class="label effect">ThemeModulationEffect [pri=0]</text> + <rect x="1197" y="2295" width="46" height="20" class="effect-bar"> + <title>SolarizeEffect [pri=1] (31-32.5s)</title> + </rect> + <text x="20" y="2310" class="label effect">SolarizeEffect [pri=1]</text> + <!-- Legend --> + <rect x="10" y="2215" width="20" height="10" class="sequence-bar"/> + <text x="35" y="2223" class="axis-label">Sequence</text> + <rect x="120" y="2215" width="20" height="10" class="effect-bar"/> + <text x="145" y="2223" class="axis-label">Effect</text> + <rect x="220" y="2215" width="20" height="10" class="effect-bar invalid"/> + <text x="245" y="2223" class="axis-label">Invalid Time Range</text> +</svg> +<div class="info"> +<strong>Tip:</strong> Hover over bars to see details. Higher priority numbers render later (on top). +</div> +</body> +</html> diff --git a/tools/seq_compiler.cc b/tools/seq_compiler.cc index f9409de..87d6222 100644 --- a/tools/seq_compiler.cc +++ b/tools/seq_compiler.cc @@ -3,8 +3,11 @@ // Converts a text-based timeline description into C++ code. #include <algorithm> +#include <cmath> #include <fstream> +#include <iomanip> #include <iostream> +#include <numeric> #include <sstream> #include <string> #include <vector> @@ -46,6 +49,171 @@ int calculate_tick_interval(float max_time) { return 20; } +// Analyze effect stacking depth across the timeline +void analyze_effect_depth(const std::vector<SequenceEntry>& sequences, + const std::string& demo_end_time, + float sample_rate = 10.0f) { + // Find max time for analysis + float max_time = demo_end_time.empty() ? 0.0f : std::stof(demo_end_time); + for (const auto& seq : sequences) { + float seq_start = std::stof(seq.start_time); + for (const auto& eff : seq.effects) { + float eff_end = seq_start + std::stof(eff.end); + max_time = std::max(max_time, eff_end); + } + } + + if (max_time <= 0.0f) { + std::cout << "\n=== Effect Depth Analysis ===\n"; + std::cout << "No effects found in timeline.\n"; + return; + } + + // Build list of all effects with absolute times + struct ActiveEffect { + std::string name; + float start_time; + float end_time; + int priority; + }; + std::vector<ActiveEffect> all_effects; + + for (const auto& seq : sequences) { + float seq_start = std::stof(seq.start_time); + float seq_end = seq_start; + if (seq.end_time != "-1.0") { + seq_end = seq_start + std::stof(seq.end_time); + } + + for (const auto& eff : seq.effects) { + float eff_start = seq_start + std::stof(eff.start); + float eff_end = seq_start + std::stof(eff.end); + + // Clamp effect end to sequence end if specified + if (seq.end_time != "-1.0") { + eff_end = std::min(eff_end, seq_end); + } + + all_effects.push_back( + {eff.class_name, eff_start, eff_end, std::stoi(eff.priority)}); + } + } + + // Sample timeline at regular intervals + const float dt = 1.0f / sample_rate; + int max_depth = 0; + float max_depth_time = 0.0f; + std::vector<int> depth_histogram(21, 0); // Track depths 0-20+ + + struct PeakInfo { + float time; + int depth; + std::vector<std::string> effects; + }; + std::vector<PeakInfo> peaks; + + for (float t = 0.0f; t <= max_time; t += dt) { + int depth = 0; + std::vector<std::string> active_effects; + + for (const auto& eff : all_effects) { + if (t >= eff.start_time && t < eff.end_time) { + depth++; + active_effects.push_back(eff.name); + } + } + + // Update max depth + if (depth > max_depth) { + max_depth = depth; + max_depth_time = t; + } + + // Record histogram + int hist_idx = std::min(depth, 20); + depth_histogram[hist_idx]++; + + // Record peaks (>5 effects) + if (depth > 5 && (peaks.empty() || t - peaks.back().time > 0.5f)) { + peaks.push_back({t, depth, active_effects}); + } + } + + // Print analysis report + std::cout << "\n=== Effect Depth Analysis ===\n"; + std::cout << "Timeline duration: " << max_time << "s\n"; + std::cout << "Total effects: " << all_effects.size() << "\n"; + std::cout << "Sample rate: " << sample_rate << " Hz (every " << dt << "s)\n"; + std::cout << "\n"; + + std::cout << "Max concurrent effects: " << max_depth << " at t=" << max_depth_time + << "s\n"; + std::cout << "\n"; + + // Print histogram + std::cout << "Effect Depth Distribution:\n"; + std::cout << "Depth | Count | Percentage | Bar\n"; + std::cout << "------|---------|------------|" + "-------------------------------------\n"; + + int total_samples = + std::accumulate(depth_histogram.begin(), depth_histogram.end(), 0); + + for (size_t i = 0; i < depth_histogram.size(); ++i) { + if (depth_histogram[i] == 0 && i > max_depth) + continue; + + float percentage = 100.0f * depth_histogram[i] / total_samples; + int bar_length = (int)(percentage / 2.0f); // Scale to ~50 chars max + + std::cout << std::setw(5) << (i < 20 ? std::to_string(i) : "20+") << " | " + << std::setw(7) << depth_histogram[i] << " | " << std::setw(9) + << std::fixed << std::setprecision(1) << percentage << "% | "; + + for (int j = 0; j < bar_length; ++j) { + std::cout << "█"; + } + std::cout << "\n"; + } + + // Print bottleneck warnings + if (max_depth > 5) { + std::cout << "\n⚠ WARNING: Performance bottlenecks detected!\n"; + std::cout << "Found " << peaks.size() << " time periods with >5 effects:\n\n"; + + int peak_count = 0; + for (const auto& peak : peaks) { + if (peak_count >= 10) + break; // Limit output + + std::cout << " t=" << std::fixed << std::setprecision(2) << peak.time + << "s: " << peak.depth << " effects [ "; + + // Show first 5 effects + for (size_t i = 0; i < std::min(size_t(5), peak.effects.size()); ++i) { + std::cout << peak.effects[i]; + if (i < peak.effects.size() - 1) + std::cout << ", "; + } + if (peak.effects.size() > 5) { + std::cout << " +" << (peak.effects.size() - 5) << " more"; + } + std::cout << " ]\n"; + + peak_count++; + } + + if (peaks.size() > 10) { + std::cout << " ... and " << (peaks.size() - 10) << " more peaks\n"; + } + } else { + std::cout << "\n✓ No significant bottlenecks detected (max depth: " + << max_depth << " <= 5)\n"; + } + + std::cout << "\n"; +} + // Generate ASCII Gantt chart for timeline visualization void generate_gantt_chart(const std::string& output_file, const std::vector<SequenceEntry>& sequences, @@ -452,16 +620,20 @@ int main(int argc, char* argv[]) { if (argc < 2) { std::cerr << "Usage: " << argv[0] << " <input.seq> [output.cc] [--gantt=<file.txt>] " - "[--gantt-html=<file.html>]\n"; + "[--gantt-html=<file.html>] [--analyze]\n"; std::cerr << "Examples:\n"; std::cerr << " " << argv[0] << " assets/demo.seq src/generated/timeline.cc\n"; std::cerr << " " << argv[0] << " assets/demo.seq --gantt=timeline.txt\n"; std::cerr << " " << argv[0] << " assets/demo.seq --gantt-html=timeline.html\n"; + std::cerr << " " << argv[0] << " assets/demo.seq --analyze\n"; std::cerr << " " << argv[0] << " assets/demo.seq timeline.cc --gantt=timeline.txt " "--gantt-html=timeline.html\n"; + std::cerr << "\nOptions:\n"; + std::cerr << " --analyze Analyze effect stacking depth and " + "identify bottlenecks\n"; std::cerr << "\nIf output.cc is omitted, only validation and Gantt " "generation are performed.\n"; return 1; @@ -470,6 +642,7 @@ int main(int argc, char* argv[]) { std::string output_cc = ""; std::string gantt_output = ""; std::string gantt_html_output = ""; + bool analyze_depth = false; // Parse command line arguments for (int i = 2; i < argc; ++i) { @@ -478,6 +651,8 @@ int main(int argc, char* argv[]) { gantt_output = arg.substr(8); } else if (arg.rfind("--gantt-html=", 0) == 0) { gantt_html_output = arg.substr(13); + } else if (arg == "--analyze") { + analyze_depth = true; } else if (output_cc.empty() && arg[0] != '-') { output_cc = arg; } @@ -738,5 +913,10 @@ int main(int argc, char* argv[]) { generate_gantt_html(gantt_html_output, sequences, bpm, demo_end_time); } + // Analyze effect stacking depth if requested + if (analyze_depth) { + analyze_effect_depth(sequences, demo_end_time); + } + return 0; } |
