bobframes 0.2.6__tar.gz → 0.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bobframes-0.2.6 → bobframes-0.2.7}/CHANGELOG.md +41 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/PKG-INFO +1 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/_default_config.toml +5 -1
- bobframes-0.2.7/bobframes/_version.py +1 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/aggregates.py +66 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/config.py +10 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/package.py +27 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/components.js +13 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/dashboard.py +28 -20
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/discovery.py +9 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/draws_by_class.py +16 -7
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/instancing_opportunities.py +4 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/orchestrator.py +11 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/overdraw.py +3 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/pass_gpu.py +16 -6
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/preview.py +4 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/shader_hotlist.py +1 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/summary.py +13 -8
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/trend_table.py +84 -32
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/draws_by_class.html +9 -2
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/index.html +10 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/instancing_opportunities.html +9 -2
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/overdraw.html +8 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/pass_gpu.html +11 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/draws_by_class.html +11 -5
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/index.html +10 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/instancing_opportunities.html +9 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/overdraw.html +10 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/pass_gpu.html +9 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/shader_hotlist.html +9 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/run/2026-05-27_r110565/summary.html +10 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/shader_hotlist.html +8 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/summary.html +10 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/trend_table.html +24 -17
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/draws_by_class.html +9 -2
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/index.html +10 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/instancing_opportunities.html +9 -2
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/overdraw.html +8 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/pass_gpu.html +11 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/draws_by_class.html +11 -5
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/index.html +10 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/instancing_opportunities.html +9 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/overdraw.html +10 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/pass_gpu.html +9 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/shader_hotlist.html +9 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/run/2026-05-27_r110565/summary.html +10 -4
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/shader_hotlist.html +8 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/summary.html +10 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/trend_table.html +24 -17
- {bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted → bobframes-0.2.7/bobframes/tests/data/golden_package/shared}/_assets/report.js +8 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/draws_by_class.html +1 -1
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared/_reports/index.html +44 -0
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared/_reports/instancing_opportunities.html +46 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/pass_gpu.html +3 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/draws_by_class.html +3 -4
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/index.html +45 -0
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/instancing_opportunities.html +43 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/overdraw.html +2 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/pass_gpu.html +1 -2
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/shader_hotlist.html +43 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/summary.html +2 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/summary.html +2 -2
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared/_reports/trend_table.html +57 -0
- {bobframes-0.2.6/bobframes/tests/data/golden_package/shared → bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted}/_assets/report.js +8 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/draws_by_class.html +1 -1
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted/_reports/index.html +44 -0
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted/_reports/instancing_opportunities.html +46 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/pass_gpu.html +3 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/draws_by_class.html +3 -4
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/index.html +45 -0
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/instancing_opportunities.html +43 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/overdraw.html +2 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/pass_gpu.html +1 -2
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/shader_hotlist.html +43 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/summary.html +2 -3
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/summary.html +2 -2
- bobframes-0.2.7/bobframes/tests/data/golden_package/shared_redacted/_reports/trend_table.html +57 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_preview/_chrome_preview.html +9 -2
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_aggregates.py +69 -2
- bobframes-0.2.7/bobframes/tests/test_browser_shots.py +90 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_config.py +6 -1
- bobframes-0.2.7/bobframes/tests/test_draws_by_class_kpis.py +34 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_package.py +31 -5
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_report_polish.py +3 -2
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_report_structure.py +41 -10
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_run_model.py +32 -1
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_summary.py +6 -6
- bobframes-0.2.7/bobframes/tests/test_trend_regression_basis.py +103 -0
- bobframes-0.2.6/bobframes/_version.py +0 -1
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared/_reports/index.html +0 -44
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared/_reports/instancing_opportunities.html +0 -46
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/index.html +0 -45
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/instancing_opportunities.html +0 -44
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared/_reports/run/2026-05-27_r110565/shader_hotlist.html +0 -44
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared/_reports/trend_table.html +0 -57
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted/_reports/index.html +0 -44
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted/_reports/instancing_opportunities.html +0 -46
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/index.html +0 -45
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/instancing_opportunities.html +0 -44
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted/_reports/run/2026-05-27_r110565/shader_hotlist.html +0 -44
- bobframes-0.2.6/bobframes/tests/data/golden_package/shared_redacted/_reports/trend_table.html +0 -57
- bobframes-0.2.6/bobframes/tests/test_browser_shots.py +0 -49
- {bobframes-0.2.6 → bobframes-0.2.7}/.gitignore +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/LICENSE +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/README.md +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/catalog.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/cli.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derive_post_merge.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/classifier.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/draw_classifier.toml +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/pass_class_breakdown.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/presets/custom-template.toml +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/presets/godot.toml +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/presets/unity.toml +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/derives/texture_usage.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/discovery.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/errors.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/global_entities.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/health.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/html/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/html/template.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/lint.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/lint_banlist.toml +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/manifest.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/parquetize.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/parsers/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/parsers/derive_program_transitions.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/parsers/parse_init_state.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/paths.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/probes/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/probes/whatif.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/qrd_harness.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/query_examples.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/rdcmd.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/replay/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/replay/replay_main.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/_tokens.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/ab.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/Inter-OFL.txt +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/README.md +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/chrome.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/components.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/container.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/design_tokens.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/icon_sprite.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/inter-subset.woff2 +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/link_kind.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/per_drop.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/print.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/rdc_table.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/rdc_table.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/assets/sticky.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/base.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/cache.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/charts.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/chrome.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/cli.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/delta.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/design_tokens.toml +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/reports/formatters.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/resource_labels.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/run.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/schemas.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/stable_keys.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/__init__.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/_render_util.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_pagedata/catalog.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/buffers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/clears.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/counters_per_event.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/descriptor_access.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/dispatches.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draw_bindings.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draws.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/fbos.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/frame_totals.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/ibo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/passes.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/pixel_history.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/post_vs_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/program_transitions.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/programs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/render_targets.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/resource_creation.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/rt_event_timeline.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/samplers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/shaders.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/state_change_events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/texture_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/textures.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vbo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vertex_inputs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/_reports/drill/District 01/2026-05-28_r110600/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/README.txt +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_pagedata/catalog.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/buffers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/clears.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/counters_per_event.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/descriptor_access.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/dispatches.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draw_bindings.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draws.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/fbos.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/frame_totals.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/ibo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/passes.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/pixel_history.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/post_vs_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/program_transitions.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/programs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/render_targets.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/resource_creation.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/rt_event_timeline.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/samplers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/shaders.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/state_change_events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/texture_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/textures.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vbo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vertex_inputs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/_reports/drill/District 01/2026-05-28_r110600/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/redacted/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/README.txt +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_assets/catalog.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_assets/catalog.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_assets/report.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_pagedata/catalog.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/buffers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/clears.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/counters_per_event.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/descriptor_access.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/dispatches.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draw_bindings.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draws.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/fbos.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/frame_totals.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/ibo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/passes.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/pixel_history.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/post_vs_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/program_transitions.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/programs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/render_targets.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/resource_creation.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/rt_event_timeline.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/samplers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/shaders.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/state_change_events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/texture_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/textures.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vbo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vertex_inputs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/drill/District 01/2026-05-28_r110600/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/overdraw.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/_reports/shader_hotlist.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/README.txt +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_assets/catalog.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_assets/catalog.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_assets/report.css +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_pagedata/catalog.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/buffers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/clears.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/counters_per_event.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/descriptor_access.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/dispatches.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draw_bindings.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/draws.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/fbos.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/frame_totals.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/ibo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/passes.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/pixel_history.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/post_vs_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/program_transitions.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/programs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/render_targets.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/resource_creation.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/rt_event_timeline.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/samplers.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/shaders.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/state_change_events.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/texture_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/textures.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vbo_samples.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/_pagedata/vertex_inputs.js +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/drill/District 01/2026-05-28_r110600/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/overdraw.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/_reports/shader_hotlist.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_package/shared_redacted/index.html +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/golden_parquet/digests.json +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/_manifest.json +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/buffers.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/clears.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/counters_per_event.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/descriptor_access.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/dispatches.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/draw_bindings.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/draws.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/events.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/fbos.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/frame_totals.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/ibo_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/indirect_args.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/passes.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/pixel_history.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/post_vs_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/program_transitions.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/programs.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/render_targets.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/resource_creation.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/rt_event_timeline.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/samplers.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/shaders.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/state_change_events.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/texture_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/textures.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/vbo_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-27_r110565/vertex_inputs.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/_manifest.json +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/buffers.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/clears.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/counters_per_event.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/descriptor_access.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/dispatches.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/draw_bindings.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/draws.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/events.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/fbos.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/frame_totals.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/ibo_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/indirect_args.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/passes.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/pixel_history.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/post_vs_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/program_transitions.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/programs.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/render_targets.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/resource_creation.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/rt_event_timeline.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/samplers.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/shaders.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/state_change_events.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/texture_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/textures.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/vbo_samples.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/data/synthetic/_data/District 01/2026-05-28_r110600/vertex_inputs.parquet +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/make_golden.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/make_package_golden.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/make_parquet_golden.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/make_preview_golden.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/make_synthetic.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/smoke.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_assets.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_cache.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_catalog_backup_dedup.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_charts.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_classifier.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_components.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_contrast.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_delta.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_design_tokens.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_determinism.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_discovery.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_element_builder.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_fonts.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_hardening.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_head_assets.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_health.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_js_coupled_classes.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_manifest_guard.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_multicapture_normalize.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_parity.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_parquet_parity.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_parquetize.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_perf.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_replay_drift.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_schemas.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_schemas_unit.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_stable_keys.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_table_component.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_theme.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/bobframes/tests/test_token_guard.py +0 -0
- {bobframes-0.2.6 → bobframes-0.2.7}/pyproject.toml +0 -0
|
@@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.7] - 2026-06-24
|
|
11
|
+
|
|
12
|
+
An aggregation-consistency pass plus four report/sharing correctness fixes. Every KPI now names its
|
|
13
|
+
estimator and rate KPIs read on one per-frame basis, so the same metric agrees across the summary,
|
|
14
|
+
dashboard, and trend. No schema change (still schema 3); parquet digests stay byte-identical on the
|
|
15
|
+
same captures. `_version` 0.2.6 -> 0.2.7.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- One canonical aggregation policy (ADR-46): every rendered KPI label names its estimator precisely --
|
|
19
|
+
`Pooled mean`, `Mean (per area)`, `Median`, `Total` -- and never a bare "avg". Rate KPIs (GPU, draws)
|
|
20
|
+
read per-frame on a single basis, so the same area's GPU now reads identically across the summary,
|
|
21
|
+
dashboard, and trend (previously e.g. `0.0356`/frame on the summary vs a raw `0.178` total on the
|
|
22
|
+
dashboard with no bridge). A naming gate (`test_no_vague_estimator_labels`) fails the build on any
|
|
23
|
+
vague estimator word. (D-13..D-16, Q-10..Q-13)
|
|
24
|
+
- Regression detection unified on the per-frame basis with config-driven thresholds: `trend_table`
|
|
25
|
+
reads every KPI per frame, so a regression flag is capture-count-independent and agrees with the
|
|
26
|
+
build-health verdict (a 7-vs-5-capture run no longer reports a false +40%); the per-KPI thresholds
|
|
27
|
+
(`draws`/`vbo`/`ibo`/`program_switches`) move from code literals to the `[report]` config, with
|
|
28
|
+
defaults that reproduce the prior values. (H-41)
|
|
29
|
+
- `draws_by_class` ratios use `statistics.median` (was the upper-middle `sorted[n//2]`, an off-by-one
|
|
30
|
+
on even N).
|
|
31
|
+
- `aggregates.frame_counts` is the single owner of every per-(drop, area) frame count; when the
|
|
32
|
+
GPU/draws denominator and the entity-rate denominator legitimately differ (a capture that replayed
|
|
33
|
+
but exported partial entity rows), the divergence is logged as a WARNING rather than silently
|
|
34
|
+
normalized away.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- Run-selector dropdown did nothing on every report: the component JS runs in `<head>`, so the custom
|
|
38
|
+
element upgraded before its child `<select>` had parsed; initialization now defers to
|
|
39
|
+
`DOMContentLoaded`. (R-20)
|
|
40
|
+
- Exported standalone one-pager carried dead tree-relative navigation -- a run dropdown pointing at
|
|
41
|
+
siblings not in the bundle, a breadcrumb, the dashboard link, and a "viewing an older run" banner.
|
|
42
|
+
The detached summary now strips them; the in-tree summary keeps its working navigation. (R-21)
|
|
43
|
+
- Older-run report pages showed cross-drop graphs and tables spanning all runs, including ones newer
|
|
44
|
+
than the page's own run. Cross-drop renderers now scope to run history (up to and including the
|
|
45
|
+
current run) while the run picker keeps the full list. (R-22)
|
|
46
|
+
|
|
10
47
|
## [0.2.6] - 2026-06-06
|
|
11
48
|
|
|
12
49
|
A build-health one-pager, a shareable `package` bundle, a server-side component system, and a full visual
|
|
@@ -123,5 +160,8 @@ First standalone release. v1 is Windows-only (the replay stage drives `qrenderdo
|
|
|
123
160
|
`python -m _analysis.*` entry points no longer work; switch to the `bobframes` commands (see the
|
|
124
161
|
migration table in the README). This is a hard rename with no compatibility shim.
|
|
125
162
|
|
|
126
|
-
[Unreleased]: https://github.com/altpsyche/bobframes/compare/v0.
|
|
163
|
+
[Unreleased]: https://github.com/altpsyche/bobframes/compare/v0.2.7...HEAD
|
|
164
|
+
[0.2.7]: https://github.com/altpsyche/bobframes/compare/v0.2.6...v0.2.7
|
|
165
|
+
[0.2.6]: https://github.com/altpsyche/bobframes/compare/v0.2.0...v0.2.6
|
|
166
|
+
[0.2.0]: https://github.com/altpsyche/bobframes/compare/v0.1.0...v0.2.0
|
|
127
167
|
[0.1.0]: https://github.com/altpsyche/bobframes/releases/tag/v0.1.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bobframes
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: RenderDoc capture pipeline: ingest, analyze, render.
|
|
5
5
|
Project-URL: Homepage, https://github.com/altpsyche/bobframes
|
|
6
6
|
Project-URL: Issues, https://github.com/altpsyche/bobframes/issues
|
|
@@ -57,5 +57,9 @@ shader_complexity_high = 60.0 # fragment shaders at/above this complexity a
|
|
|
57
57
|
overdraw_reject_warn_pct = 40.0 # RT sample-rejection % -> warn callout
|
|
58
58
|
overdraw_reject_alarm_pct = 70.0 # RT sample-rejection % -> alarm callout
|
|
59
59
|
instancing_repeat_min = 4 # min mesh repeat PER FRAME to flag an instancing candidate (c16v: repeat + shader cost are per-frame rates, normalized by the drop's captured-frame count)
|
|
60
|
-
gpu_regression_pct = 10.0 # latest-vs-previous GPU increase % -> regression
|
|
60
|
+
gpu_regression_pct = 10.0 # latest-vs-previous GPU/frame increase % -> regression (per frame, capture-count-independent)
|
|
61
|
+
draws_regression_pct = 10.0 # H-41 — per-KPI trend regression thresholds (were baked in trend_table.KPIS literals)
|
|
62
|
+
vbo_regression_pct = 15.0 # " vertex-buffer bytes / frame
|
|
63
|
+
ibo_regression_pct = 15.0 # " index-buffer bytes / frame
|
|
64
|
+
program_switches_regression_pct = 20.0 # " program switches / frame
|
|
61
65
|
max_prerendered_runs = 10 # c16f — cap on pre-rendered older-run pages (run selector)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.7"
|
|
@@ -163,3 +163,69 @@ def shader_aggregates(root: str, drops: list, *, stage: str | None = None) -> Sh
|
|
|
163
163
|
sa.cplx[k] = max(sa.cplx.get(k, 0.0), c_val)
|
|
164
164
|
sa.stype[k] = stype
|
|
165
165
|
return sa
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# --- frame counts (D-15: the single owner of every per-(drop, area) frame count) ----------------
|
|
169
|
+
|
|
170
|
+
def _frame_total_captures(root: str, drops: list) -> dict:
|
|
171
|
+
"""``{(drop_key, area): {captures}}`` from ``frame_totals.parquet`` -- the authoritative
|
|
172
|
+
captured-frame set (the distinct ``capture`` values present in the per-frame GPU/draws table that
|
|
173
|
+
``dashboard._run_totals`` / ``_top_areas_gpu`` divide by). Read live per drop_dir (frame_totals has
|
|
174
|
+
no per-drop cache, mirroring the dashboard readers). If a frame_totals has no ``capture`` column,
|
|
175
|
+
each row is treated as one distinct frame (num_rows) so the count never under-reports."""
|
|
176
|
+
out: dict = defaultdict(set)
|
|
177
|
+
for d in drops:
|
|
178
|
+
for r in d.rows:
|
|
179
|
+
p = os.path.join(r.drop_dir, 'frame_totals.parquet')
|
|
180
|
+
if not os.path.exists(p):
|
|
181
|
+
continue
|
|
182
|
+
try:
|
|
183
|
+
names = set(papq.read_schema(p).names)
|
|
184
|
+
if 'capture' in names:
|
|
185
|
+
caps = papq.read_table(p, columns=['capture']).column('capture').to_pylist()
|
|
186
|
+
else:
|
|
187
|
+
caps = [f'__row_{i}' for i in range(papq.read_metadata(p).num_rows)]
|
|
188
|
+
except Exception:
|
|
189
|
+
continue
|
|
190
|
+
out[(drop_key(r.drop_date, r.drop_label), r.area)].update(caps)
|
|
191
|
+
return out
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def frame_counts(root: str, drops: list) -> dict:
|
|
195
|
+
"""The ONE owner of every per-(drop, area) frame count (D-15 / D-A4). Returns
|
|
196
|
+
``{(drop_key, area): {'frames', 'draw_frames', 'shader_frames'}}`` where ``frames`` = distinct
|
|
197
|
+
captures in frame_totals (the GPU/draws-per-frame denominator) and ``draw_frames``/``shader_frames``
|
|
198
|
+
= distinct captures in the draws/shaders entity data (the c16v entity-rate denominators).
|
|
199
|
+
|
|
200
|
+
The three legitimately DIFFER when a capture replayed "ok" but exported no entity rows (the c16v
|
|
201
|
+
as-built, ADR-23): per-frame GPU divides by the frames that produced GPU data, while per-frame mesh/
|
|
202
|
+
shader rates divide by the frames that produced that entity -- both correct for their metric, on
|
|
203
|
+
different populations. ``frame_count_divergences`` surfaces the difference so the different-N
|
|
204
|
+
normalization is visible across reports rather than silent. Raw counts (no >=1 guard) so divergence
|
|
205
|
+
is detectable; the per-frame no-op guard stays in ``DrawAgg.frames`` / ``ShaderAgg.frames``.
|
|
206
|
+
"""
|
|
207
|
+
da = draw_aggregates(root, drops)
|
|
208
|
+
sa = shader_aggregates(root, drops)
|
|
209
|
+
ft = _frame_total_captures(root, drops)
|
|
210
|
+
keys = set(ft) | set(da.captures) | set(sa.captures)
|
|
211
|
+
return {
|
|
212
|
+
k: {
|
|
213
|
+
'frames': len(ft.get(k, ())),
|
|
214
|
+
'draw_frames': len(da.captures.get(k, ())),
|
|
215
|
+
'shader_frames': len(sa.captures.get(k, ())),
|
|
216
|
+
}
|
|
217
|
+
for k in keys
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def frame_count_divergences(root: str, drops: list) -> list:
|
|
222
|
+
"""``[(drop_key, area, frames, draw_frames, shader_frames), ...]`` for every (drop, area) where an
|
|
223
|
+
entity count that EXISTS (>0) differs from the frame_totals frame count -- i.e. a capture produced
|
|
224
|
+
GPU/draw data but not the matching entity rows (or vice versa). Sorted for deterministic logging.
|
|
225
|
+
Empty when every layer agrees (the uniform-capture case). Drives the render-time warning (D-15)."""
|
|
226
|
+
out = []
|
|
227
|
+
for (dk, area), c in sorted(frame_counts(root, drops).items()):
|
|
228
|
+
ftn, dfr, sfr = c['frames'], c['draw_frames'], c['shader_frames']
|
|
229
|
+
if (dfr and dfr != ftn) or (sfr and sfr != ftn):
|
|
230
|
+
out.append((dk, area, ftn, dfr, sfr))
|
|
231
|
+
return out
|
|
@@ -131,6 +131,12 @@ class ReportCfg: # c16 — report-presentation thresholds (
|
|
|
131
131
|
overdraw_reject_alarm_pct: float = 70.0
|
|
132
132
|
instancing_repeat_min: int = 4 # c16v — min mesh repeat PER FRAME (repeat + shader cost are per-frame rates)
|
|
133
133
|
gpu_regression_pct: float = 10.0
|
|
134
|
+
# H-41 (v027_1) — per-KPI trend regression thresholds; were baked in `trend_table.KPIS` literals.
|
|
135
|
+
# Trend-only (health's verdict has only a gpu trajectory rule). Defaults reproduce the old literals.
|
|
136
|
+
draws_regression_pct: float = 10.0
|
|
137
|
+
vbo_regression_pct: float = 15.0
|
|
138
|
+
ibo_regression_pct: float = 15.0
|
|
139
|
+
program_switches_regression_pct: float = 20.0
|
|
134
140
|
max_prerendered_runs: int = 10 # c16f — cap on pre-rendered older-run pages (per-run UX)
|
|
135
141
|
|
|
136
142
|
|
|
@@ -327,6 +333,10 @@ def _build_config(root: str | None) -> Config:
|
|
|
327
333
|
overdraw_reject_alarm_pct=rpt.get('overdraw_reject_alarm_pct', 70.0),
|
|
328
334
|
instancing_repeat_min=rpt.get('instancing_repeat_min', 4),
|
|
329
335
|
gpu_regression_pct=rpt.get('gpu_regression_pct', 10.0),
|
|
336
|
+
draws_regression_pct=rpt.get('draws_regression_pct', 10.0),
|
|
337
|
+
vbo_regression_pct=rpt.get('vbo_regression_pct', 15.0),
|
|
338
|
+
ibo_regression_pct=rpt.get('ibo_regression_pct', 15.0),
|
|
339
|
+
program_switches_regression_pct=rpt.get('program_switches_regression_pct', 20.0),
|
|
330
340
|
max_prerendered_runs=rpt.get('max_prerendered_runs', 10),
|
|
331
341
|
),
|
|
332
342
|
theme=ThemeCfg(tokens=tuple(theme_tokens.items())) if theme_tokens else None,
|
|
@@ -217,6 +217,9 @@ def build(root: str, *, out: str | None = None, light: bool = False,
|
|
|
217
217
|
shutil.rmtree(staging, ignore_errors=True)
|
|
218
218
|
|
|
219
219
|
if summary_file:
|
|
220
|
+
# The standalone one-pager is a DETACHED single file -- strip the tree-relative navigation that
|
|
221
|
+
# cannot resolve beside a lone HTML (R-21), so it no longer carries a dead run dropdown.
|
|
222
|
+
summary_bytes = _detach_summary(summary_bytes)
|
|
220
223
|
with open(summary_path, 'wb') as f:
|
|
221
224
|
f.write(summary_bytes)
|
|
222
225
|
else:
|
|
@@ -503,6 +506,30 @@ def _redact_text_files(entries: list[tuple[str, str]], *, mode: str) -> int:
|
|
|
503
506
|
return n
|
|
504
507
|
|
|
505
508
|
|
|
509
|
+
# Tree-relative navigation that only resolves inside the rendered tree -- dead in a detached one-pager.
|
|
510
|
+
# Each is a cleanly-delimited, non-nesting element generated by the chrome builders.
|
|
511
|
+
_DETACH_RES = (
|
|
512
|
+
# the run selector: its options point to run/<key>/summary.html siblings not bundled with a lone file
|
|
513
|
+
re.compile(rb'<rdc-ab-picker><label for="rdc-run-select">.*?</rdc-ab-picker>', re.S),
|
|
514
|
+
re.compile(rb'<nav class="crumb">.*?</nav>', re.S), # breadcrumb (root catalog / dashboard)
|
|
515
|
+
re.compile(rb'<a class="sb-link"[^>]*>.*?</a>', re.S), # summary-bar "dashboard" link
|
|
516
|
+
# the "viewing an older run / go to newest" nav banner (older-run one-pagers); its link points to a
|
|
517
|
+
# sibling page absent beside a lone file. Anchored on its title so the health alarm-banner is kept.
|
|
518
|
+
re.compile(rb'<rdc-alarm-banner\b[^>]*>(?:(?!</rdc-alarm-banner>).)*?viewing an older run'
|
|
519
|
+
rb'(?:(?!</rdc-alarm-banner>).)*?</rdc-alarm-banner>', re.S),
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def _detach_summary(html: bytes) -> bytes:
|
|
524
|
+
"""Make the standalone one-pager genuinely self-contained (R-21): strip the tree-relative navigation
|
|
525
|
+
that cannot work in a LONE file -- the run selector (a silently-dead dropdown), the breadcrumb, and
|
|
526
|
+
the summary-bar dashboard link. The page's own content (verdict, KPIs, movement, by-area) is
|
|
527
|
+
self-contained and untouched; the in-tree `_reports/summary.html` keeps its working nav."""
|
|
528
|
+
for rx in _DETACH_RES:
|
|
529
|
+
html = rx.sub(b'', html)
|
|
530
|
+
return html
|
|
531
|
+
|
|
532
|
+
|
|
506
533
|
def _redacted_summary_bytes(staging: str, summary_rel: str, *, newest: bool, target,
|
|
507
534
|
build_ts: str, shared: bool, redact_paths: str) -> bytes:
|
|
508
535
|
"""The standalone one-pager for a redacted bundle: self-contained (INLINE) + redacted.
|
|
@@ -6,7 +6,19 @@
|
|
|
6
6
|
connectedCallback(){
|
|
7
7
|
if (this._rdcUp) return;
|
|
8
8
|
this._rdcUp = true;
|
|
9
|
-
|
|
9
|
+
const run = () => {
|
|
10
|
+
try { this.init(); } catch(e) { console.error('rdc init error', this.tagName, e); }
|
|
11
|
+
};
|
|
12
|
+
// The component JS rides in <head> (adjacent to the CSS), so a custom element upgrades as its
|
|
13
|
+
// START tag is parsed -- BEFORE its light-DOM children (e.g. the run <select>) exist. Inits that
|
|
14
|
+
// querySelector a child would see nothing and bail. Defer to DOMContentLoaded while the document
|
|
15
|
+
// is still parsing so children are present; run immediately for elements created after load.
|
|
16
|
+
// (Mirrors the _wireRowDrill deferral below.)
|
|
17
|
+
if (document.readyState === 'loading'){
|
|
18
|
+
document.addEventListener('DOMContentLoaded', run, { once: true });
|
|
19
|
+
} else {
|
|
20
|
+
run();
|
|
21
|
+
}
|
|
10
22
|
}
|
|
11
23
|
init(){}
|
|
12
24
|
}
|
|
@@ -301,11 +301,11 @@ def _global_kpis(drops: list) -> list:
|
|
|
301
301
|
avg_gpu_frame = (total_gpu / n_frames) if n_frames else 0.0
|
|
302
302
|
avg_draws_frame = (total_draws / n_frames) if n_frames else 0.0
|
|
303
303
|
return [
|
|
304
|
-
{'label': '
|
|
305
|
-
{'label': '
|
|
306
|
-
{'label': '
|
|
307
|
-
{'label': '
|
|
308
|
-
{'label': 'areas',
|
|
304
|
+
{'label': 'pooled mean gpu / frame (s)', 'value': base.fmt_float(avg_gpu_frame, 4)},
|
|
305
|
+
{'label': 'total gpu (s) over captures', 'value': base.fmt_float(total_gpu, 3)},
|
|
306
|
+
{'label': 'pooled mean draws / frame', 'value': base.fmt_int(round(avg_draws_frame))},
|
|
307
|
+
{'label': 'total draws over captures', 'value': base.fmt_int(total_draws)},
|
|
308
|
+
{'label': 'areas', 'value': base.fmt_int(len(areas))},
|
|
309
309
|
]
|
|
310
310
|
|
|
311
311
|
|
|
@@ -351,6 +351,9 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
351
351
|
rc = base.run_context(drops, run_label=run_label, run_date=run_date)
|
|
352
352
|
cur = rc.current
|
|
353
353
|
cur_drops = [cur] if cur else []
|
|
354
|
+
# v027_4: per-area captured-frame counts (the single owner, D-15) so the mini cards can read
|
|
355
|
+
# per-frame and stay consistent with summary + the trend card (no bare cross-capture totals).
|
|
356
|
+
area_frames = {a: c['frames'] for (_dk, a), c in _agg.frame_counts(root, cur_drops).items()}
|
|
354
357
|
|
|
355
358
|
# c16f: a per-run dashboard lives at _reports/run/<key>/index.html; its sibling reports (instancing
|
|
356
359
|
# etc.) are pre-rendered there too, so their links stay bare. trend_table is NOT per-run (it is the
|
|
@@ -398,22 +401,23 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
398
401
|
*[base.el('a', {'href': href, 'data-link-kind': 'primary'}, lbl)
|
|
399
402
|
for href, lbl in _NAV]))
|
|
400
403
|
|
|
401
|
-
# Card: trend table - GPU
|
|
404
|
+
# Card: trend table - GPU PER FRAME per area (D-16: leads with the per-frame mean so the same area
|
|
405
|
+
# reads the SAME number here and on summary; the raw run total rides alongside as the labeled bridge).
|
|
402
406
|
top_a = top_a[:3]
|
|
403
407
|
chart_tt = base.figure(base.bar_chart(
|
|
404
|
-
[(
|
|
405
|
-
title='gpu
|
|
408
|
+
[(t[0], t[4]) for t in top_a], value_fmt=lambda v: f'{v:.4f}', width=280,
|
|
409
|
+
title='gpu / frame per area', desc='top areas by GPU per captured frame', chart_id='dash-tt'))
|
|
406
410
|
body_tt = _card_table(
|
|
407
411
|
top_a,
|
|
408
412
|
[
|
|
409
413
|
('area', lambda r: r[0], False),
|
|
410
|
-
('gpu
|
|
411
|
-
('
|
|
412
|
-
('
|
|
414
|
+
('mean gpu / frame', lambda r: base.fmt_float(r[4], 4), True),
|
|
415
|
+
('total gpu (s)', lambda r: base.fmt_float(r[1], 3), True),
|
|
416
|
+
('mean draws / frame', lambda r: base.fmt_int(round(r[3])), True),
|
|
413
417
|
],
|
|
414
|
-
caption='per-area GPU +
|
|
415
|
-
sub_tt = ('GPU
|
|
416
|
-
+ (f' worst: {top_a[0][0]} {base.fmt_float(top_a[0][
|
|
418
|
+
caption='per-area GPU per captured frame + the run total (mean = area total / area frames)')
|
|
419
|
+
sub_tt = ('GPU per frame per area in the current run.'
|
|
420
|
+
+ (f' worst: {top_a[0][0]} {base.fmt_float(top_a[0][4], 4)}s / frame' if top_a else ''))
|
|
417
421
|
cards.append(_card(tt_href, 'trend table', sub_tt, chart_tt, body_tt))
|
|
418
422
|
|
|
419
423
|
# Card: instancing - repeat per mesh (mini bars).
|
|
@@ -426,7 +430,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
426
430
|
[
|
|
427
431
|
('mesh', lambda r: r[0], False),
|
|
428
432
|
('repeat', lambda r: base.fmt_int(r[1]), True),
|
|
429
|
-
('
|
|
433
|
+
('median verts', lambda r: base.fmt_int(r[2]), True),
|
|
430
434
|
],
|
|
431
435
|
caption='most-repeated meshes')
|
|
432
436
|
sub_im = ('Repeated meshes worth instancing or batching.'
|
|
@@ -438,7 +442,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
438
442
|
top_p = _top_passes(cur_drops)
|
|
439
443
|
chart_pg = base.figure(base.bar_chart(
|
|
440
444
|
[(pl, g) for _, pl, g in top_p], value_fmt=lambda v: f'{v:.3f}', width=280,
|
|
441
|
-
title='gpu (s) per pass', desc='heaviest passes by GPU seconds', chart_id='dash-pg'))
|
|
445
|
+
title='total gpu (s) per pass', desc='heaviest passes by total GPU seconds', chart_id='dash-pg'))
|
|
442
446
|
body_pg = _card_table(
|
|
443
447
|
top_p,
|
|
444
448
|
[
|
|
@@ -447,9 +451,10 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
447
451
|
# so hover could never reveal it). The CSS clip now truncates the display + the td title=
|
|
448
452
|
# reveals the full value on hover - consistent with every other mini text column.
|
|
449
453
|
('marker', lambda r: base.scrub_chrome_text(r[1]), False),
|
|
450
|
-
('
|
|
454
|
+
# per-pass GPU is a cross-capture total (the pass report's native basis); labeled as such.
|
|
455
|
+
('total gpu (s)', lambda r: base.fmt_float(r[2], 3), True),
|
|
451
456
|
],
|
|
452
|
-
caption='heaviest passes by GPU time')
|
|
457
|
+
caption='heaviest passes by total GPU time')
|
|
453
458
|
sub_pg = ('Heaviest GPU passes.'
|
|
454
459
|
+ (f' top: {top_p[0][1]} {base.fmt_float(top_p[0][2], 3)}s in {top_p[0][0]}'
|
|
455
460
|
if top_p else ''))
|
|
@@ -503,10 +508,13 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
503
508
|
pa_rows,
|
|
504
509
|
[
|
|
505
510
|
('area', lambda r: r[0], False),
|
|
506
|
-
|
|
511
|
+
# per-frame to match summary's By-area + the trend card (D-16 consistency), not a bare total.
|
|
512
|
+
('mean draws / frame',
|
|
513
|
+
lambda r: base.fmt_int(round(base.per_frame(r[1]['n_draws'], area_frames.get(r[0], 0)))),
|
|
514
|
+
True),
|
|
507
515
|
('dominant', lambda r: r[1]['dominant_class'], False),
|
|
508
516
|
],
|
|
509
|
-
caption='top areas by
|
|
517
|
+
caption='top areas by mean draws per captured frame')
|
|
510
518
|
dom = class_totals.most_common(1)[0] if class_totals else None
|
|
511
519
|
sub_dc = ('Draw mix by class.'
|
|
512
520
|
+ (f' dominant: {dom[0]} {base.fmt_pct(100.0 * dom[1] / grand)}'
|
|
@@ -182,6 +182,15 @@ class RunContext:
|
|
|
182
182
|
def is_newest(self) -> bool:
|
|
183
183
|
return bool(self.current) and self.index == self.n_runs - 1
|
|
184
184
|
|
|
185
|
+
@property
|
|
186
|
+
def history(self) -> list:
|
|
187
|
+
"""Drops up to AND INCLUDING the current run (chronological) -- the data scope for cross-drop
|
|
188
|
+
CHARTS/TABLES on a per-run page, so an OLDER run's page never shows data for runs that came
|
|
189
|
+
AFTER it (ADR-35; R-22). The run picker still lists every run (from `drops`); only the rendered
|
|
190
|
+
data is scoped. Equals `drops` on the newest page (index == n_runs - 1)."""
|
|
191
|
+
i = self.index
|
|
192
|
+
return list(self.drops) if i < 0 else self.drops[:i + 1]
|
|
193
|
+
|
|
185
194
|
@property
|
|
186
195
|
def run_label(self) -> str:
|
|
187
196
|
"""current.key (e.g. '2026-06-01_r110788'); '' when there is no current run."""
|
|
@@ -7,12 +7,14 @@ Segments colored by draw_class. Below: raw-count table.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import os
|
|
10
|
+
import statistics
|
|
10
11
|
import sys
|
|
11
12
|
from collections import Counter, defaultdict
|
|
12
13
|
|
|
13
14
|
import pyarrow.parquet as papq
|
|
14
15
|
|
|
15
16
|
from . import base
|
|
17
|
+
from .. import aggregates as _agg
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
def _gather_from_drops(drops: list) -> tuple[dict, list, list, int]:
|
|
@@ -79,8 +81,11 @@ def _build_table(counts: dict, drop_keys: list) -> str:
|
|
|
79
81
|
caption='raw draw counts per class, per area and drop')
|
|
80
82
|
|
|
81
83
|
|
|
82
|
-
def _compute_kpis(counts: dict, areas: list) -> list:
|
|
83
|
-
"""Hero KPIs:
|
|
84
|
+
def _compute_kpis(counts: dict, areas: list, total_frames: int) -> list:
|
|
85
|
+
"""Hero KPIs (current run): mean draws / frame + the labeled raw total, n areas, the MEDIAN
|
|
86
|
+
prepass/opaque ratio across areas, dominant class. Q-12: lead with the per-frame mean (the
|
|
87
|
+
capture-count-independent number) and label the total. Q-11: `statistics.median` (not the
|
|
88
|
+
upper-middle `sorted[n//2]`), and the label names the estimator + population."""
|
|
84
89
|
total = sum(sum(cc.values()) for cc in counts.values())
|
|
85
90
|
ratios = []
|
|
86
91
|
class_totals: Counter = Counter()
|
|
@@ -90,14 +95,15 @@ def _compute_kpis(counts: dict, areas: list) -> list:
|
|
|
90
95
|
op = cc.get('opaque', 0)
|
|
91
96
|
if op:
|
|
92
97
|
ratios.append(cc.get('prepass', 0) / op)
|
|
93
|
-
median_ratio = (
|
|
94
|
-
if ratios else 0.0)
|
|
98
|
+
median_ratio = statistics.median(ratios) if ratios else 0.0
|
|
95
99
|
dominant_cls = (class_totals.most_common(1)[0][0]
|
|
96
100
|
if class_totals else '')
|
|
101
|
+
mean_draws = base.per_frame(total, total_frames) # per frame (no-op when frames<=1)
|
|
97
102
|
return [
|
|
98
|
-
{'label': '
|
|
103
|
+
{'label': 'mean draws / frame', 'value': base.fmt_int(round(mean_draws))},
|
|
104
|
+
{'label': 'total draws over captures', 'value': base.fmt_int(total)},
|
|
99
105
|
{'label': 'areas', 'value': base.fmt_int(len(areas))},
|
|
100
|
-
{'label': 'prepass/opaque (
|
|
106
|
+
{'label': 'median prepass / opaque (across areas)', 'value': base.fmt_float(median_ratio, 2)},
|
|
101
107
|
{'label': 'dominant class', 'value': dominant_cls or '-'},
|
|
102
108
|
]
|
|
103
109
|
|
|
@@ -112,9 +118,12 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
112
118
|
# table below keeps every run as the breakdown / comparison view.
|
|
113
119
|
rc = base.run_context(drops, run_label=run_label, run_date=run_date)
|
|
114
120
|
cur = rc.current
|
|
121
|
+
drops = rc.history # R-22: cross-drop data scoped to <= current (picker still lists all via rc)
|
|
115
122
|
counts, areas, drop_keys, total_captures = _gather_from_drops(drops)
|
|
116
123
|
cur_counts = {k: cc for k, cc in counts.items() if cur and k[1] == cur.key}
|
|
117
124
|
cur_areas = cur.areas if cur else []
|
|
125
|
+
# Q-12: per-frame mean draws needs the current run's captured-frame count (the single owner, D-15).
|
|
126
|
+
cur_frames = sum(v['frames'] for v in (_agg.frame_counts(root, [cur]) if cur else {}).values())
|
|
118
127
|
|
|
119
128
|
parts = []
|
|
120
129
|
|
|
@@ -183,7 +192,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
183
192
|
drops=len(drops), captures=total_captures, build_ts=build_ts or base.now_iso(),
|
|
184
193
|
crumb_depth=base.crumb_depth(ab, run=rc), ab=ab, root=root, report_key='draws_by_class',
|
|
185
194
|
sink=sink, theme=theme,
|
|
186
|
-
kpis=_compute_kpis(cur_counts, cur_areas), run=rc,
|
|
195
|
+
kpis=_compute_kpis(cur_counts, cur_areas, cur_frames), run=rc,
|
|
187
196
|
device=base.provenance_strip(*base.newest_drop_provenance(root, [cur] if cur else []), redact=redact))])
|
|
188
197
|
|
|
189
198
|
|
|
@@ -71,6 +71,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
71
71
|
# Run model (ADR-35): live candidates are meshes drawn in the CURRENT run; prior runs supply the
|
|
72
72
|
# per-drop comparison columns + the resolved-since section, never inflate the live list.
|
|
73
73
|
rc = base.run_context(drops, run_label=run_label, run_date=run_date)
|
|
74
|
+
drops = rc.history # R-22: cross-drop trend scoped to <= current (picker still lists all via rc)
|
|
74
75
|
cur = rc.current
|
|
75
76
|
bl = rc.baseline
|
|
76
77
|
ck = cur.key if cur else None
|
|
@@ -220,7 +221,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
220
221
|
if chart_items:
|
|
221
222
|
mbody.append(base.figure(
|
|
222
223
|
base.bar_chart(chart_items, title='estimated wasted indices',
|
|
223
|
-
desc='(max repeat - 1) x
|
|
224
|
+
desc='(max repeat - 1) x median indices, per mesh',
|
|
224
225
|
chart_id='inst-wasted'),
|
|
225
226
|
'estimated wasted indices (top meshes)'))
|
|
226
227
|
|
|
@@ -237,9 +238,9 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
237
238
|
cols += [
|
|
238
239
|
base.Column('areas', 'areas', clip='default'),
|
|
239
240
|
base.Column('dompass', 'dominant pass', clip='narrow'),
|
|
240
|
-
base.Column('ityp', 'indices
|
|
241
|
+
base.Column('ityp', 'median indices', numeric=True),
|
|
241
242
|
base.Column('wasted', 'wasted indices', numeric=True,
|
|
242
|
-
title='(max repeat - 1) x
|
|
243
|
+
title='(max repeat - 1) x median indices: index data re-submitted across repeats',
|
|
243
244
|
render=lambda value, row: base.heatmap_cell(value, 0, row['_maxw'],
|
|
244
245
|
text=base.fmt_int(value))),
|
|
245
246
|
]
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import time
|
|
6
6
|
|
|
7
|
+
from .. import aggregates as _agg
|
|
7
8
|
from .. import lint
|
|
8
9
|
from ..config import get_config
|
|
9
10
|
from ..html import template
|
|
@@ -43,6 +44,16 @@ def render_all_reports(root: str, log, *,
|
|
|
43
44
|
cache_out = reports_base.build_per_drop_cache(root)
|
|
44
45
|
log(f' built per-drop cache: {cache_out} ({time.monotonic()-t0:.1f}s)')
|
|
45
46
|
|
|
47
|
+
# D-15 (D-A4): one owner of every per-(drop, area) frame count. Per-frame GPU/draws divide by the
|
|
48
|
+
# frame_totals frame count; per-frame mesh/shader rates divide by the entity-capture count (c16v).
|
|
49
|
+
# They legitimately differ when a capture replayed "ok" but exported no entity rows -- surface that
|
|
50
|
+
# so cross-report per-frame normalization uses different N visibly, not silently (ADR-23, warn not
|
|
51
|
+
# assert: the divergence is a real data condition, present even in the synthetic fixture).
|
|
52
|
+
for dk, area, ftn, dfr, sfr in _agg.frame_count_divergences(root, reports_base.discover_drops(root)):
|
|
53
|
+
log(f' WARNING: frame-count divergence {area} {dk}: frame_totals={ftn} draws={dfr} '
|
|
54
|
+
f'shaders={sfr} -- per-frame GPU/draws and per-frame entity rates use different '
|
|
55
|
+
f'denominators (a capture replayed but exported partial entity data)')
|
|
56
|
+
|
|
46
57
|
for mod in all_reports():
|
|
47
58
|
try:
|
|
48
59
|
rep = mod.build(root, sink=sink, build_ts=build_ts, redact=redact, theme=theme)
|
|
@@ -133,8 +133,10 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
133
133
|
if drops is None:
|
|
134
134
|
drops = base.discover_drops(root)
|
|
135
135
|
# Run model (ADR-35): live render targets = those sampled in the CURRENT run; per-drop sample
|
|
136
|
-
# columns below
|
|
136
|
+
# columns below span the runs UP TO the current one (R-22: never runs that came after it; the run
|
|
137
|
+
# picker still lists every run). A representative bucket is the current run's, not the oldest.
|
|
137
138
|
rc = base.run_context(drops, run_label=run_label, run_date=run_date)
|
|
139
|
+
drops = rc.history # R-22: scope cross-drop data to <= current
|
|
138
140
|
cur = rc.current
|
|
139
141
|
ck = cur.key if cur else None
|
|
140
142
|
out_path = base.output_path(root, 'overdraw', ab, run=rc)
|
|
@@ -13,6 +13,7 @@ from collections import defaultdict
|
|
|
13
13
|
import pyarrow.parquet as papq
|
|
14
14
|
|
|
15
15
|
from . import base
|
|
16
|
+
from .. import aggregates as _agg
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def _aggregate(drops: list, ok_caps: set) -> dict:
|
|
@@ -68,9 +69,11 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
68
69
|
if drops is None:
|
|
69
70
|
drops = base.discover_drops(root)
|
|
70
71
|
# Run model (ADR-35): GPU headline + treemap + per-area ranking reflect the CURRENT run; the
|
|
71
|
-
# per-drop GPU comparison rows below
|
|
72
|
+
# per-drop GPU comparison rows below span the runs UP TO the current one (R-22: an older run's page
|
|
73
|
+
# must not show runs that came after it; the run picker still lists every run).
|
|
72
74
|
rc = base.run_context(drops, run_label=run_label, run_date=run_date)
|
|
73
75
|
cur = rc.current
|
|
76
|
+
drops = rc.history # R-22: scope cross-drop data to <= current
|
|
74
77
|
ck = cur.key if cur else None
|
|
75
78
|
out_path = base.output_path(root, 'pass_gpu', ab, run=rc)
|
|
76
79
|
out_dir = os.path.dirname(out_path)
|
|
@@ -96,10 +99,17 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
96
99
|
total_gpu += g
|
|
97
100
|
n_passes += 1
|
|
98
101
|
cur_areas_set.add(area)
|
|
102
|
+
# Q-10: lead with GPU PER FRAME (pooled over the run's captured frames, the summary/dashboard
|
|
103
|
+
# basis) so this hero shares a magnitude with the rest of the reports; the raw cross-capture total
|
|
104
|
+
# rides alongside as the labeled "total ... over captures".
|
|
105
|
+
fc = _agg.frame_counts(root, [cur]) if cur else {}
|
|
106
|
+
total_frames = sum(v['frames'] for v in fc.values())
|
|
107
|
+
gpu_per_frame = (total_gpu / total_frames) if total_frames else 0.0
|
|
99
108
|
kpis = [
|
|
100
|
-
{'label': '
|
|
101
|
-
{'label': '
|
|
102
|
-
{'label': '
|
|
109
|
+
{'label': 'gpu / frame (s)', 'value': base.fmt_float(gpu_per_frame, 4)},
|
|
110
|
+
{'label': 'total gpu (s) over captures', 'value': base.fmt_float(total_gpu, 3)},
|
|
111
|
+
{'label': 'areas', 'value': base.fmt_int(len(cur_areas_set))},
|
|
112
|
+
{'label': 'passes', 'value': base.fmt_int(n_passes)},
|
|
103
113
|
]
|
|
104
114
|
|
|
105
115
|
# Summary bar: top pass in the current run + area count
|
|
@@ -126,7 +136,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
126
136
|
parts.append(base.callout(
|
|
127
137
|
'info',
|
|
128
138
|
f'heaviest pass: {area} / {marker_short}',
|
|
129
|
-
f'{base.fmt_float(global_top_gpu, 3)}s GPU
|
|
139
|
+
f'{base.fmt_float(global_top_gpu, 3)}s GPU summed over the run\'s captures - '
|
|
130
140
|
f'profile this pass first.',
|
|
131
141
|
href=f'#{base.h(area)}', link_text='jump to area'))
|
|
132
142
|
|
|
@@ -183,7 +193,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
183
193
|
|
|
184
194
|
if len(drop_keys) >= 2:
|
|
185
195
|
cells = ['<div class="bar-row">',
|
|
186
|
-
'<span class="key" style="color: var(--text-2)">drops</span>',
|
|
196
|
+
'<span class="key" style="color: var(--text-2)">drops (total / drop)</span>',
|
|
187
197
|
'<div style="display:flex;gap:var(--sp-3);font:var(--fs-small) ui-monospace,monospace;align-items:center;color:var(--text-2)">']
|
|
188
198
|
prev_gpu = None
|
|
189
199
|
for i, k in enumerate(drop_keys):
|
|
@@ -119,14 +119,14 @@ def _links_block() -> str:
|
|
|
119
119
|
|
|
120
120
|
def _kpi_cards_block() -> str:
|
|
121
121
|
cards = [
|
|
122
|
-
base.kpi_card('
|
|
122
|
+
base.kpi_card('pooled mean draws / frame', base.fmt_int(28410),
|
|
123
123
|
delta_html='<span class="delta-pill neg">+4%</span>',
|
|
124
124
|
trend=base.trendline([3, 5, 4, 8, 6, 9, 7], tone='neg'),
|
|
125
|
-
note='5 areas - 142,050 total', tone='neg'),
|
|
126
|
-
base.kpi_card('
|
|
125
|
+
note='pooled across 5 frames, 5 areas - 142,050 total', tone='neg'),
|
|
126
|
+
base.kpi_card('pooled mean gpu / frame', base.fmt_float(12.8, 4),
|
|
127
127
|
delta_html='<span class="delta-pill pos">-1%</span>',
|
|
128
128
|
trend=base.trendline([9, 7, 8, 6, 6, 5, 5], tone='pos'),
|
|
129
|
-
note='0.064 s total', tone='pos'),
|
|
129
|
+
note='pooled across 5 frames - 0.064 s total', tone='pos'),
|
|
130
130
|
]
|
|
131
131
|
return ('<div data-page-kind="summary"><div class="kpi-strip">'
|
|
132
132
|
+ ''.join(cards) + '</div></div>')
|
|
@@ -71,6 +71,7 @@ def build(root: str, *, drops: list | None = None, ab=None,
|
|
|
71
71
|
# Run model (ADR-35): the hotlist ranks the CURRENT run's shaders; prior runs feed the per-drop
|
|
72
72
|
# comparison columns + the resolved-since section, never the cost ranking.
|
|
73
73
|
rc = base.run_context(drops, run_label=run_label, run_date=run_date)
|
|
74
|
+
drops = rc.history # R-22: cross-drop comparison scoped to <= current (picker still lists all via rc)
|
|
74
75
|
cur = rc.current
|
|
75
76
|
bl = rc.baseline
|
|
76
77
|
ck = cur.key if cur else None
|