sparkforensics-server 0.6.0 → 0.8.1
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.
- package/index.js +16 -7
- package/package.json +1 -1
- package/public/assets/AutoscalingChurn-DenWKTv-.js +1 -0
- package/public/assets/CacheUtilization-DLz7NdjV.js +1 -0
- package/public/assets/CachingOpportunity-zpQIqhzm.js +1 -0
- package/public/assets/ChartTheme-DAiARbLP.js +8 -0
- package/public/assets/ColdStart-C-9HjxWl.js +1 -0
- package/public/assets/ConfigAudit-D0V9tcrJ.js +1 -0
- package/public/assets/CoreUsageArea-yeerrljd.js +1 -0
- package/public/assets/Dashboard-DkUPrHKV.js +1 -0
- package/public/assets/DisclosureContext-DK1_iz6J.js +1 -0
- package/public/assets/DuplicatePlanSubtree-xDNDbCd3.js +1 -0
- package/public/assets/DurationHistogram-B6jsE0Ov.js +1 -0
- package/public/assets/EmptyState-C1uL40VU.js +1 -0
- package/public/assets/ExecutorUtilization-DXDZKmSc.js +1 -0
- package/public/assets/GcPressure-MRf7I4IG.js +1 -0
- package/public/assets/ImpactEstimate-Dm3xWbzV.js +1 -0
- package/public/assets/IncompleteRun-CaLOhMtf.js +1 -0
- package/public/assets/JobFailures-CzmzlvhO.js +1 -0
- package/public/assets/MemoryUtilization-AWUMUjCH.js +1 -0
- package/public/assets/NestedLoopJoin-C9sNr6Ss.js +1 -0
- package/public/assets/OverBroadcast-BOmRE6ca.js +1 -0
- package/public/assets/PartitionHint-BL2EmJfE.js +1 -0
- package/public/assets/PartitionSizing-BzBySvUq.js +1 -0
- package/public/assets/PlanExplorer-DdiQRcJU.js +1 -0
- package/public/assets/PlanGraphRoute-CIH9gBuR.js +1 -0
- package/public/assets/PlanView-B1hxzFRs.js +2 -0
- package/public/assets/PythonUdf-DvgCCueD.js +1 -0
- package/public/assets/RetryWaste-uXXu_CyM.js +1 -0
- package/public/assets/RowPagination-C-LzWkI5.js +1 -0
- package/public/assets/RowStatusCluster-Dbtmte7l.js +1 -0
- package/public/assets/ShuffleIO-nALwzC1_.js +1 -0
- package/public/assets/Skew-CHMEKgvk.js +1 -0
- package/public/assets/SlowHost-yyvjpHk6.js +1 -0
- package/public/assets/SmallFiles-y6odJ97n.js +1 -0
- package/public/assets/SpeculationWaste-C-SD2LOt.js +1 -0
- package/public/assets/Spill-DHTMmOup.js +1 -0
- package/public/assets/StageFailed-CQ3DxC9R.js +1 -0
- package/public/assets/StageFindingGroup-BgYLyj5q.js +1 -0
- package/public/assets/StageHeader-CIETkjVZ.js +1 -0
- package/public/assets/StagePill--P7PDd3s.js +1 -0
- package/public/assets/StageShape-BIv8vx_o.js +1 -0
- package/public/assets/StageSlowness-MMqzERxN.js +1 -0
- package/public/assets/Straggler-BgrY7AyW.js +1 -0
- package/public/assets/TaskFailures-BHHyKYTs.js +1 -0
- package/public/assets/TinyTask-DDScNhCl.js +1 -0
- package/public/assets/UnderBroadcast-CGIC04TI.js +1 -0
- package/public/assets/WidgetLeadSummary-CXFZP00C.js +1 -0
- package/public/assets/button-DbpTz2yk.js +1 -0
- package/public/assets/charts-vendor-CtTxwTeu.js +59 -0
- package/public/assets/composite-C9Nu2EI9.js +1 -0
- package/public/assets/d3-vendor-DNlD2-cz.js +1 -0
- package/public/assets/detector-registry-Bp8hrLua.js +2 -0
- package/public/assets/downsample-WmNM1qc9.js +1 -0
- package/public/assets/finding-anchor-Dr40LkS9.js +1 -0
- package/public/assets/findings-of-type-BL2u3RGZ.js +1 -0
- package/public/assets/impact-sort-mC5ISgX8.js +1 -0
- package/public/assets/inbox-KPU1Gppm.js +1 -0
- package/public/assets/index-CaRVPvAT.css +2 -0
- package/public/assets/index-fDiwfuoO.js +14 -0
- package/public/assets/inertValue-L9VxV0VE.js +1 -0
- package/public/assets/layout.worker-CLcBHxVp.js +3 -0
- package/public/assets/{parser-worker-CA5RxqKc.js → parser-worker-CRIOPMOW.js} +8 -8
- package/public/assets/plan-graph-vendor-Ce6d4HU6.js +7 -0
- package/public/assets/react-vendor-C6KcUD36.js +9 -0
- package/public/assets/select-BHqOqun5.js +1 -0
- package/public/assets/toggle-DPeN6aNa.js +1 -0
- package/public/assets/toggle-group-Kl3uyHSr.js +1 -0
- package/public/assets/usePagedRows-BafD6bEN.js +1 -0
- package/public/assets/useRecentFiles-DzJZAoOT.js +3 -0
- package/public/assets/useRegisterFieldControl-pQv-ZDoU.js +1 -0
- package/public/assets/useScrollLock-BCxn_dMp.js +1 -0
- package/public/assets/useSortMode-DjrAN-z4.js +1 -0
- package/public/docs/404.html +3 -3
- package/public/docs/assets/{app.CnWL6bKV.js → app.1gvzd5Zb.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.C0IBKeRQ.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
- package/public/docs/assets/chunks/{theme.BH-2HuRf.js → theme.C5lLqUv7.js} +2 -2
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.lean.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.js → contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.CHHgywoP.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.N4hhenrA.lean.js → contributor-guide_architecture_detector-contract.md.CHHgywoP.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.lean.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.lean.js → contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.K71YB-Rr.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation.md.DfvbqEUu.lean.js → contributor-guide_architecture_impact-estimation.md.K71YB-Rr.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.lean.js → contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_overview.md.nxkpOhgf.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js → contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.lean.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js → contributor-guide_architecture_worker-protocol.md.Br6OE7RW.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.Br6OE7RW.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.js} +2 -2
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.lean.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.lean.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_contributing.md.DBW4drtZ.js +1 -0
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.js +15 -0
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.lean.js +1 -0
- package/public/docs/assets/contributor-guide_testing.md.DpkozNoG.js +4 -0
- package/public/docs/assets/{contributor-guide_testing.md.By6XGR9a.lean.js → contributor-guide_testing.md.DpkozNoG.lean.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.js → index.md.lMm7SUMz.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.lean.js → index.md.lMm7SUMz.lean.js} +1 -1
- package/public/docs/assets/{style.CyK9Ss73.css → style.Cfxqlj0y.css} +1 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.js +29 -0
- package/public/docs/assets/{user-guide_getting-started_ci-and-automation.md.BEepbDDL.lean.js → user-guide_getting-started_ci-and-automation.md.C0pcQoNc.lean.js} +1 -1
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.js +1 -0
- package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.js} +2 -2
- package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.lean.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.js → user-guide_mcp-tools.md.49r3L2YE.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js → user-guide_mcp-tools_compare-runs.md.BQ_kIptC.js} +11 -6
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.BQ_kIptC.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.azCZXkH8.js +44 -0
- package/public/docs/assets/{user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.lean.js → user-guide_mcp-tools_diagnose-run.md.azCZXkH8.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.js} +2 -2
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.lean.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.js} +2 -1
- package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.lean.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.lean.js} +1 -1
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.lean.js +1 -0
- package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract.html +6 -6
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -6
- package/public/docs/contributor-guide/architecture/drill-down.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -6
- package/public/docs/contributor-guide/architecture/index.html +5 -5
- package/public/docs/contributor-guide/architecture/overview.html +6 -6
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -5
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -6
- package/public/docs/contributor-guide/architecture/state-and-history.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -7
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -6
- package/public/docs/contributor-guide/contributing.html +6 -6
- package/public/docs/contributor-guide/development-setup.html +8 -8
- package/public/docs/contributor-guide/testing.html +9 -6
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +6 -6
- package/public/docs/logo-dark.svg +1 -0
- package/public/docs/logo-light.svg +1 -0
- package/public/docs/tuning-reference/anti-patterns.html +5 -5
- package/public/docs/tuning-reference/aqe.html +5 -5
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -5
- package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -5
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -5
- package/public/docs/tuning-reference/bottleneck-failures.html +5 -5
- package/public/docs/tuning-reference/bottleneck-gc.html +5 -5
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -5
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -5
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -5
- package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -5
- package/public/docs/tuning-reference/bottleneck-skew.html +5 -5
- package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -5
- package/public/docs/tuning-reference/bottleneck-small-files.html +5 -5
- package/public/docs/tuning-reference/bottleneck-spill.html +5 -5
- package/public/docs/tuning-reference/bottleneck-straggler.html +5 -5
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -5
- package/public/docs/tuning-reference/bottleneck-utilization.html +5 -5
- package/public/docs/tuning-reference/caching.html +5 -5
- package/public/docs/tuning-reference/cluster-config.html +5 -5
- package/public/docs/tuning-reference/config.html +5 -5
- package/public/docs/tuning-reference/data-formats.html +5 -5
- package/public/docs/tuning-reference/index.html +5 -5
- package/public/docs/tuning-reference/intro.html +5 -5
- package/public/docs/tuning-reference/joins.html +5 -5
- package/public/docs/tuning-reference/memory-model.html +5 -5
- package/public/docs/tuning-reference/metrics.html +5 -5
- package/public/docs/tuning-reference/partitioning.html +5 -5
- package/public/docs/tuning-reference/pyspark.html +5 -5
- package/public/docs/tuning-reference/shuffle.html +5 -5
- package/public/docs/tuning-reference/spark-architecture.html +5 -5
- package/public/docs/tuning-reference/table-formats.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval.html +5 -5
- package/public/docs/user-guide/getting-started/ci-and-automation.html +16 -11
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -6
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -5
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -7
- package/public/docs/user-guide/getting-started.html +5 -5
- package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -11
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -7
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -6
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -6
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +5 -5
- package/public/docs/user-guide/mcp-tools/list-runs.html +5 -5
- package/public/docs/user-guide/mcp-tools.html +6 -6
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -5
- package/public/docs/user-guide/run-comparison.html +6 -6
- package/public/docs/user-guide/understanding-findings.html +6 -6
- package/public/export-template.html +45 -45
- package/public/index.html +8 -7
- package/public/sample-runs/sample-run.ndjson.gz +0 -0
- package/vendor-core/allocation.js +25 -23
- package/vendor-core/analyzer.js +85 -58
- package/vendor-core/api-merge-writes.js +2 -0
- package/vendor-core/aqe-skew.js +347 -0
- package/vendor-core/cli/budgets.js +6 -4
- package/vendor-core/cli/collect-run-pair.js +89 -0
- package/vendor-core/cli/collect-run-worker.js +16 -0
- package/vendor-core/cli/collect-run.js +1 -2
- package/vendor-core/cli/native-zstd.js +12 -16
- package/vendor-core/comparability.js +234 -0
- package/vendor-core/comparison-output.js +15 -7
- package/vendor-core/comparison-verdict.js +105 -25
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/core-time-series.js +0 -1
- package/vendor-core/core-usage-locality.js +1 -1
- package/vendor-core/detectors.js +1007 -380
- package/vendor-core/docs-config.js +0 -4
- package/vendor-core/docs-content/detection/cache.md +2 -1
- package/vendor-core/docs-content/detection/cfg.md +19 -11
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/gc.md +7 -3
- package/vendor-core/docs-content/detection/host.md +11 -1
- package/vendor-core/docs-content/detection/mem.md +17 -6
- package/vendor-core/docs-content/detection/part.md +3 -1
- package/vendor-core/docs-content/detection/plan.md +55 -13
- package/vendor-core/docs-content/detection/shfl.md +11 -5
- package/vendor-core/docs-content/detection/skew.md +47 -1
- package/vendor-core/docs-content/detection/slow.md +4 -2
- package/vendor-core/docs-content/detection/spec.md +6 -1
- package/vendor-core/docs-content/detection/spill.md +6 -3
- package/vendor-core/docs-content/detection/strag.md +19 -6
- package/vendor-core/docs-content/detection/tiny.md +9 -3
- package/vendor-core/effective-conf.js +7 -10
- package/vendor-core/efficiency-model.js +2 -2
- package/vendor-core/etl-phases.js +1 -2
- package/vendor-core/event-handlers.js +175 -57
- package/vendor-core/event-schemas.js +21 -16
- package/vendor-core/evidence-availability.js +9 -2
- package/vendor-core/evidence-report.js +118 -35
- package/vendor-core/executor-peaks.js +41 -0
- package/vendor-core/export-data.js +5 -5
- package/vendor-core/finding-identity.js +78 -0
- package/vendor-core/finding-presentation.js +116 -33
- package/vendor-core/finding-types.js +88 -21
- package/vendor-core/format-utils.js +14 -15
- package/vendor-core/html-export.js +1 -1
- package/vendor-core/impact-band.js +2 -2
- package/vendor-core/impact-format.js +47 -19
- package/vendor-core/impact-model.js +26 -15
- package/vendor-core/job-groups.js +4 -4
- package/vendor-core/mcp-server-factory.js +48 -12
- package/vendor-core/mcp-tools.js +179 -24
- package/vendor-core/median.js +2 -2
- package/vendor-core/nested-loop-join.js +73 -0
- package/vendor-core/occupancy.js +1 -2
- package/vendor-core/parser-worker.js +1 -1
- package/vendor-core/plan-graph-model.js +14 -22
- package/vendor-core/plan-node-detail.js +2 -3
- package/vendor-core/plan-summary.js +24 -19
- package/vendor-core/plan-tree-walk.js +6 -8
- package/vendor-core/python-stage.js +12 -1
- package/vendor-core/recommendation-rollup.js +13 -12
- package/vendor-core/redact.js +52 -46
- package/vendor-core/run-aggregates.js +6 -8
- package/vendor-core/run-comparison.js +226 -66
- package/vendor-core/run-identity.js +12 -0
- package/vendor-core/run-interpretation.js +21 -0
- package/vendor-core/run-metrics.js +2 -2
- package/vendor-core/run-output.js +32 -10
- package/vendor-core/run-totals.js +12 -0
- package/vendor-core/run-verdict.js +76 -3
- package/vendor-core/scaling-sim.js +3 -4
- package/vendor-core/snappy-block.js +2 -2
- package/vendor-core/spark-conf.js +168 -0
- package/vendor-core/sql-stages.js +2 -2
- package/vendor-core/stage-alignment.js +2 -12
- package/vendor-core/stage-identity.js +58 -3
- package/vendor-core/stage-label.js +14 -0
- package/vendor-core/stage-plan-nodes.js +17 -3
- package/vendor-core/stage-quantiles.js +141 -9
- package/vendor-core/stage-structure.js +17 -3
- package/vendor-core/threshold-overrides.js +9 -3
- package/vendor-core/types.js +58 -21
- package/vendor-core/wasted-core-hours.js +0 -1
- package/vendor-core/write-targets.js +114 -14
- package/vendor-core/zstd-worker-client.js +1 -1
- package/vendor-core/zstd-worker.js +1 -1
- package/public/assets/AutoscalingChurn-CRA2Mb7F.js +0 -1
- package/public/assets/CacheUtilization-Bh9OY_V9.js +0 -1
- package/public/assets/CachingOpportunity-oCiQwmTJ.js +0 -1
- package/public/assets/ColdStart-BJrtjfmn.js +0 -1
- package/public/assets/ConfigAudit-DMvKxySP.js +0 -1
- package/public/assets/CoreUsageArea-REC2zsKw.js +0 -1
- package/public/assets/Dashboard-BHZ76JCu.js +0 -2
- package/public/assets/DisclosureContext-OO7X1HAx.js +0 -1
- package/public/assets/DuplicatePlanSubtree-BgG-L-cK.js +0 -1
- package/public/assets/ExecutorUtilization-D2KhSVbY.js +0 -1
- package/public/assets/GcPressure-D1BTE8qh.js +0 -1
- package/public/assets/IncompleteRun-DD40xUpy.js +0 -1
- package/public/assets/JobFailures-YwNzCF19.js +0 -1
- package/public/assets/MemoryUtilization-9b8ee_3_.js +0 -1
- package/public/assets/OverBroadcast-CfctS8a8.js +0 -1
- package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
- package/public/assets/PartitionSizing-VG8kBgG5.js +0 -1
- package/public/assets/PlanExplorer-DmubTAOP.js +0 -1
- package/public/assets/PlanGraphRoute-DctPZjS0.js +0 -1
- package/public/assets/RetryWaste-CnpM8bB7.js +0 -1
- package/public/assets/ShuffleIO-D13vGmas.js +0 -1
- package/public/assets/Skew-DlagstYP.js +0 -1
- package/public/assets/SlowHost-cSkLRZ_e.js +0 -1
- package/public/assets/SmallFiles-B-kERMcq.js +0 -1
- package/public/assets/SpeculationWaste-DaysAzXO.js +0 -1
- package/public/assets/Spill-H44Gz4US.js +0 -1
- package/public/assets/StageFailed-DCfii9h_.js +0 -1
- package/public/assets/StageFindingGroup-BXJ0Mj5n.js +0 -1
- package/public/assets/StageHeader--oN2J-oD.js +0 -1
- package/public/assets/StageShape-IZ80CZiJ.js +0 -1
- package/public/assets/StageSlowness--BRIaBc1.js +0 -1
- package/public/assets/Straggler-Ctq0Df_o.js +0 -1
- package/public/assets/TaskFailures-Bks_gqhL.js +0 -1
- package/public/assets/TinyTask-BssfzGFB.js +0 -1
- package/public/assets/UnderBroadcast-DsScrxc-.js +0 -1
- package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
- package/public/assets/finding-anchor-BYW1oz5R.js +0 -1
- package/public/assets/impact-sort-xzy0g-Vh.js +0 -1
- package/public/assets/index-DhpRGMZc.css +0 -2
- package/public/assets/index-DwqkFUFk.js +0 -14
- package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
- package/public/assets/react-vendor-DfpuPQZf.js +0 -9
- package/public/assets/select-C8edjYTq.js +0 -1
- package/public/assets/usePagedRows-CsuUFeYx.js +0 -1
- package/public/assets/useRecentFiles-BvkKo3JN.js +0 -11
- package/public/assets/useSortMode-joX71BZN.js +0 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.tE5pz54z.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.N4hhenrA.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.DfvbqEUu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.js +0 -1
- package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
- package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.js +0 -15
- package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.lean.js +0 -1
- package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.BEepbDDL.js +0 -24
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +0 -23
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.lean.js +0 -1
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.lean.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.lean.js → contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_overview.md.C1sSvm9i.lean.js → contributor-guide_architecture_overview.md.nxkpOhgf.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js → contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.lean.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.lean.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.lean.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_contributing.md.CQMvGwFt.lean.js → contributor-guide_contributing.md.DBW4drtZ.lean.js} +0 -0
- /package/public/docs/assets/{user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.lean.js → user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.lean.js} +0 -0
- /package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.lean.js → user-guide_mcp-tools.md.49r3L2YE.lean.js} +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
/** Maps a finding's location in one run to a label shared by both runs. A stage or execution that
|
|
4
|
+
* pairs with one in the other run gets the same label on both sides; one that pairs with nothing
|
|
5
|
+
* gets a label no other run's location can equal. */
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/** The finding's rule, or its type when the detector emits no rule. */
|
|
12
|
+
export function findingRule(finding ) {
|
|
13
|
+
return 'rule' in finding && typeof finding.rule === 'string' ? finding.rule : finding.type;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The finding's band, `unknown` when the impact estimate could not grade it. */
|
|
17
|
+
export function findingBand(finding ) {
|
|
18
|
+
return finding.impactBand ?? 'unknown';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Location: stage, else SQL execution, else audited config property, else the whole run.
|
|
22
|
+
function findingLocation(finding , locator ) {
|
|
23
|
+
if (finding.stageId != null) return `stage:${locator.stage(finding.stageId)}`;
|
|
24
|
+
if ('executionId' in finding && typeof finding.executionId === 'number') return `execution:${locator.execution(finding.executionId)}`;
|
|
25
|
+
if (finding.type === 'configAudit') return `property:${finding.property}`;
|
|
26
|
+
return 'run';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The identity of a finding across two runs: its type, rule and location. Never its value or its
|
|
30
|
+
* impact band, which both move from run to run for the same problem (`findingId` hashes the value,
|
|
31
|
+
* so it matches only within one run). */
|
|
32
|
+
export function findingKey(finding , locator ) {
|
|
33
|
+
return `${finding.type}|${findingRule(finding)}|${findingLocation(finding, locator)}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
function groupByKey(findings , locator ) {
|
|
46
|
+
const groups = new Map ();
|
|
47
|
+
for (const finding of findings) {
|
|
48
|
+
const key = findingKey(finding, locator);
|
|
49
|
+
const group = groups.get(key);
|
|
50
|
+
if (group) group.push(finding); else groups.set(key, [finding]);
|
|
51
|
+
}
|
|
52
|
+
return groups;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Pairs two runs' findings by `findingKey`. A key several findings share (one detector firing per
|
|
56
|
+
* host on one run-level key, say) pairs one-to-one: same band first, then in catalog order, so only
|
|
57
|
+
* a count difference or a band no counterpart shares reads as a change. One diff feeds every
|
|
58
|
+
* comparison consumer: the verdict, the budgets and the dashboard. */
|
|
59
|
+
export function diffFindings(
|
|
60
|
+
baseline , candidate , baselineLocator , candidateLocator ,
|
|
61
|
+
) {
|
|
62
|
+
const base = groupByKey(baseline, baselineLocator), cand = groupByKey(candidate, candidateLocator);
|
|
63
|
+
const diff = { introduced: [], resolved: [], changed: [] };
|
|
64
|
+
for (const key of new Set([...base.keys(), ...cand.keys()])) {
|
|
65
|
+
const unpairedBase = [...(base.get(key) ?? [])], unpairedCand = [...(cand.get(key) ?? [])];
|
|
66
|
+
for (let i = unpairedBase.length - 1; i >= 0; i--) {
|
|
67
|
+
const j = unpairedCand.findIndex((f) => findingBand(f) === findingBand(unpairedBase[i]));
|
|
68
|
+
if (j < 0) continue;
|
|
69
|
+
unpairedBase.splice(i, 1);
|
|
70
|
+
unpairedCand.splice(j, 1);
|
|
71
|
+
}
|
|
72
|
+
const paired = Math.min(unpairedBase.length, unpairedCand.length);
|
|
73
|
+
for (let i = 0; i < paired; i++) diff.changed.push({ baseline: unpairedBase[i], candidate: unpairedCand[i] });
|
|
74
|
+
diff.resolved.push(...unpairedBase.slice(paired));
|
|
75
|
+
diff.introduced.push(...unpairedCand.slice(paired));
|
|
76
|
+
}
|
|
77
|
+
return diff;
|
|
78
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// detectors.ts is type-only, so it is erased at build time. A detector's scope, order and emits
|
|
9
9
|
// list stay on its DETECTORS entry; renderers get them through detectorInfoByType().
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
/** A share threshold as captions and caveats state it: 0.005 -> "0.5%", never float noise like 7.000000000000001%. */
|
|
31
31
|
export const shareLabel = (share ) => `${Math.round(share * 1e6) / 1e4}%`;
|
|
32
32
|
|
|
33
|
+
/** `n.toLocaleString('en-US')` for a whole number, without loading ICU (about 10 ms the first time it is
|
|
34
|
+
* used), which keeps the CLI's startup off that cost. Other values take the locale path. */
|
|
35
|
+
function groupThousands(n ) {
|
|
36
|
+
return Number.isSafeInteger(n) ? String(n).replace(/\B(?=(\d{3})+$)/g, ',') : n.toLocaleString('en-US');
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
// Whether the detector found `key` already logged on for this run. Its switchFix (detectors.ts)
|
|
34
40
|
// then worded the row's own text for that case and left the property out of the remediation, so
|
|
35
41
|
// a generic line reads the same decision and never recommends a switch the row says is on.
|
|
@@ -38,6 +44,13 @@ function switchAlreadyOn(finding , key )
|
|
|
38
44
|
return finding.remediation != null && !finding.remediation.some((r) => r.kind === 'conf' && r.key === key);
|
|
39
45
|
}
|
|
40
46
|
|
|
47
|
+
// The broadcast threshold properties a broadcast-sizing row's remediation names: the adaptive one when
|
|
48
|
+
// it governed the query, else (and for a row with none) spark.sql.autoBroadcastJoinThreshold.
|
|
49
|
+
function broadcastThresholdKeyOf(f ) {
|
|
50
|
+
const keys = (f.remediation ?? []).filter((r) => r.kind === 'conf').map((r) => r.key);
|
|
51
|
+
return keys.length ? keys.join(' or ') : 'spark.sql.autoBroadcastJoinThreshold';
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
// The properties an idle-capacity finding lowers once dynamic allocation is on, worded as its row
|
|
42
55
|
// does: the executor cap, and the floor when the row's remediation lowers it too.
|
|
43
56
|
function idleCapacityLowering(f ) {
|
|
@@ -45,28 +58,65 @@ function idleCapacityLowering(f ) {
|
|
|
45
58
|
return ` by lowering spark.dynamicAllocation.maxExecutors${lowersFloor ? ' and spark.dynamicAllocation.minExecutors' : ''}`;
|
|
46
59
|
}
|
|
47
60
|
|
|
61
|
+
// What a shuffle-reading stage's partition-count advice names, read from the row's remediation: the
|
|
62
|
+
// property ('property', also for a finding with no remediation), AQE's coalescing settings ('aqe',
|
|
63
|
+
// which leave spark.sql.shuffle.partitions out), or the stage's own repartition(n) ('code').
|
|
64
|
+
function partitionAdviceKind(f ) {
|
|
65
|
+
if (f.remediation == null || f.remediation.some((r) => r.kind === 'conf' && r.key === 'spark.sql.shuffle.partitions')) return 'property';
|
|
66
|
+
if (f.remediation.some((r) => r.kind === 'conf' && r.key.startsWith('spark.sql.adaptive.'))) return 'aqe';
|
|
67
|
+
return f.remediation.some((r) => r.kind === 'code') ? 'code' : 'property';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The skew-join line per AQE case, with no instance data (numbers, config values).
|
|
71
|
+
const AQE_SKEW_GENERIC = {
|
|
72
|
+
split: 'AQE skew-join handling already split the skewed partitions, so the imbalance that remains is not join skew: look for a GC pause, a slow host or an expensive key.',
|
|
73
|
+
evenReads: 'The shuffle reads are even, so the slow tail is not partition-size skew and AQE has nothing to split: look for a GC pause, a slow host or an expensive key.',
|
|
74
|
+
belowThreshold: 'The largest partition is under what AQE treats as skewed: lower the skew threshold or factor for this query.',
|
|
75
|
+
planShape: 'An operator sits between the join and its shuffle, so AQE skew-join handling cannot apply: salt the key or repartition on a better key.',
|
|
76
|
+
userRepartition: 'An explicit repartition feeds the join, so AQE leaves its shuffle alone: drop the repartition, or salt the key.',
|
|
77
|
+
joinType: 'The join type does not let AQE split the skewed side: put the skewed table on a splittable side, or salt the key.',
|
|
78
|
+
extraShuffle: 'AQE skipped the split because it would add a shuffle: set spark.sql.adaptive.forceOptimizeSkewedJoin to true if that shuffle is cheaper than the tail, or salt the key.',
|
|
79
|
+
notSplit: 'AQE did not split the skewed partition and the log does not say why: salt the key or repartition on a better key.',
|
|
80
|
+
};
|
|
81
|
+
// Before Spark 3.3 there is no forceOptimizeSkewedJoin, so an extraShuffle row carries a code fix.
|
|
82
|
+
const AQE_SKEW_EXTRA_SHUFFLE_NO_FORCE = 'AQE skipped the split because it would add a shuffle: salt the key or repartition on a better key.';
|
|
83
|
+
|
|
48
84
|
const SKEW_JOIN_KEY = 'spark.sql.adaptive.skewJoin.enabled';
|
|
49
85
|
const SKEW_JOIN_ALREADY_ON = 'AQE skew-join handling is already on, so salt the key or repartition on a better key.';
|
|
50
86
|
const SKEW_JOIN_AQE_OFF = 'AQE is off, so enable it (spark.sql.adaptive.enabled) for skew-join handling to apply; otherwise salt the key or repartition on a better key.';
|
|
51
87
|
|
|
52
88
|
// The skew-join generic line, worded per the row's remediation: AQE logged off, switch already on, or neither.
|
|
53
|
-
function skewJoinGeneric(f
|
|
89
|
+
function skewJoinGeneric(f , unset ) {
|
|
54
90
|
if (f.origin === 'inputScan') return 'Uneven input files: compact small files or split large ones (lower spark.sql.files.maxPartitionBytes).';
|
|
55
91
|
if (f.origin === 'other') return 'Work is uneven across tasks: salt the key or repartition on a better key.';
|
|
92
|
+
if (f.aqeSkew === 'extraShuffle' && !f.remediation?.some((r) => r.kind === 'conf')) return AQE_SKEW_EXTRA_SHUFFLE_NO_FORCE;
|
|
93
|
+
if (f.aqeSkew != null) return AQE_SKEW_GENERIC[f.aqeSkew];
|
|
56
94
|
if (f.remediation?.some((r) => r.kind === 'conf' && r.key === 'spark.sql.adaptive.enabled')) return SKEW_JOIN_AQE_OFF;
|
|
57
95
|
return switchAlreadyOn(f, SKEW_JOIN_KEY) ? SKEW_JOIN_ALREADY_ON : unset;
|
|
58
96
|
}
|
|
97
|
+
/** One line on what a straggler finding's slow tasks lost their time to, for the widget row; null
|
|
98
|
+
* when the log gave no cause (the finding then only knows their duration). */
|
|
99
|
+
export function stragglerCauseSummary(f ) {
|
|
100
|
+
const share = f.causeSharePct != null ? ` (${f.causeSharePct}% of their extra time)` : '';
|
|
101
|
+
switch (f.cause) {
|
|
102
|
+
case 'data': return `The slow tasks read more data${share}`;
|
|
103
|
+
case 'gc': return `GC${share}`;
|
|
104
|
+
case 'fetchWait': return `Waiting on shuffle fetches${share}`;
|
|
105
|
+
case 'host': return `Tasks piled on ${f.host ?? 'one host'}${share}`;
|
|
106
|
+
case 'unexplained': return 'Not data volume, GC, fetch wait or one host';
|
|
107
|
+
default: return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
59
111
|
const DYNAMIC_ALLOCATION_KEY = 'spark.dynamicAllocation.enabled';
|
|
60
112
|
|
|
61
|
-
// The
|
|
113
|
+
// The three configAudit DETECTORS entries share this row, one per audited property.
|
|
62
114
|
const CONFIG_AUDIT_PRESENTATION = {
|
|
63
115
|
name: 'config audit',
|
|
64
116
|
tag: 'CFG',
|
|
65
117
|
thresholdSummary: () => 'a Spark conf value outside the recommended range',
|
|
66
118
|
actionLabel(f) {
|
|
67
119
|
switch (f.property) {
|
|
68
|
-
case 'spark.shuffle.service.enabled': return 'Enable shuffle service';
|
|
69
|
-
case 'spark.dynamicAllocation.minExecutors': return 'Fix autoscaling bounds';
|
|
70
120
|
case 'spark.dynamicAllocation.maxExecutors': return 'Set max executors';
|
|
71
121
|
case 'spark.serializer': return 'Switch to Kryo';
|
|
72
122
|
case 'spark.executor.memoryOverhead': return 'Raise memory overhead';
|
|
@@ -75,11 +125,9 @@ const CONFIG_AUDIT_PRESENTATION = {
|
|
|
75
125
|
},
|
|
76
126
|
genericRecommendation(f) {
|
|
77
127
|
switch (f.property) {
|
|
78
|
-
case 'spark.shuffle.service.enabled': return 'Set spark.shuffle.service.enabled=true so shuffle data survives executor removal.';
|
|
79
|
-
case 'spark.dynamicAllocation.minExecutors': return 'Set the minimum executor bound at or below the maximum.';
|
|
80
128
|
case 'spark.dynamicAllocation.maxExecutors': return 'Set spark.dynamicAllocation.maxExecutors to cap cluster growth.';
|
|
81
129
|
case 'spark.serializer': return 'Consider spark.serializer=org.apache.spark.serializer.KryoSerializer for faster, smaller buffers.';
|
|
82
|
-
case 'spark.executor.memoryOverhead': return 'Raise executor memoryOverhead above
|
|
130
|
+
case 'spark.executor.memoryOverhead': return 'Raise executor memoryOverhead above the default Spark would have computed to avoid off-heap OOM-kills.';
|
|
83
131
|
}
|
|
84
132
|
return undefined;
|
|
85
133
|
},
|
|
@@ -98,7 +146,7 @@ export const FINDING_PRESENTATION
|
|
|
98
146
|
skew: {
|
|
99
147
|
name: 'task skew',
|
|
100
148
|
tag: 'SKEW',
|
|
101
|
-
thresholdSummary: (t) => `P95 task time over ${t.ratioWarn}× the median (the longest task on stages under ${t.minTasksForP95} tasks)`,
|
|
149
|
+
thresholdSummary: (t) => `P95 task time over ${t.ratioWarn}× the median (the longest task on stages under ${t.minTasksForP95} tasks), and the slow tasks read correspondingly more data`,
|
|
102
150
|
actionLabel: () => 'Fix task skew',
|
|
103
151
|
genericRecommendation: (f) => skewJoinGeneric(f,
|
|
104
152
|
'For join-driven skew, enable AQE skew-join handling (spark.sql.adaptive.skewJoin.enabled); otherwise salt the key or repartition on a better key.'),
|
|
@@ -129,9 +177,14 @@ export const FINDING_PRESENTATION
|
|
|
129
177
|
tag: 'TINY',
|
|
130
178
|
thresholdSummary: (t) => `${t.minTasks}+ tasks with a median of ${t.maxP50}ms or less and a P95 of ${t.maxP95}ms or less`,
|
|
131
179
|
actionLabel: () => 'Coalesce small tasks',
|
|
132
|
-
genericRecommendation
|
|
133
|
-
|
|
134
|
-
|
|
180
|
+
genericRecommendation(f) {
|
|
181
|
+
if (f.reads != null && f.reads !== 'shuffle') return 'Scheduler overhead may dominate: coalesce down to fewer, larger tasks.';
|
|
182
|
+
switch (partitionAdviceKind(f)) {
|
|
183
|
+
case 'aqe': return 'Scheduler overhead may dominate: AQE already coalesced the shuffle, so set spark.sql.adaptive.coalescePartitions.parallelismFirst to false or raise spark.sql.adaptive.advisoryPartitionSizeInBytes, or coalesce down to fewer, larger tasks.';
|
|
184
|
+
case 'code': return "Scheduler overhead may dominate: this stage's own repartition(n) or RDD parallelism sized it, so lower that count or coalesce down to fewer, larger tasks.";
|
|
185
|
+
default: return 'Scheduler overhead may dominate: lower spark.sql.shuffle.partitions, or coalesce down to fewer, larger tasks.';
|
|
186
|
+
}
|
|
187
|
+
},
|
|
135
188
|
},
|
|
136
189
|
|
|
137
190
|
shuffle: {
|
|
@@ -180,9 +233,15 @@ export const FINDING_PRESENTATION
|
|
|
180
233
|
thresholdSummary: (t) => `single-task disk spill above ${t.singleTaskDiskGiB} GiB`,
|
|
181
234
|
actionLabel: () => 'Reduce spill',
|
|
182
235
|
// The skew/volume classification isn't a Finding field, so one sentence covers both.
|
|
183
|
-
genericRecommendation
|
|
184
|
-
|
|
185
|
-
|
|
236
|
+
genericRecommendation(f) {
|
|
237
|
+
const skewFirst = 'If the spill is skew-driven, fix task skew first: adding memory will not help. Otherwise';
|
|
238
|
+
if (f.reads != null && f.reads !== 'shuffle') return `${skewFirst} increase executor memory or process less data per task.`;
|
|
239
|
+
switch (partitionAdviceKind(f)) {
|
|
240
|
+
case 'aqe': return `${skewFirst} lower spark.sql.adaptive.advisoryPartitionSizeInBytes so AQE's merged partitions are smaller, or increase executor memory.`;
|
|
241
|
+
case 'code': return `${skewFirst} raise this stage's own partition count (its repartition(n) or RDD parallelism), or increase executor memory.`;
|
|
242
|
+
default: return `${skewFirst} raise spark.sql.shuffle.partitions or increase executor memory.`;
|
|
243
|
+
}
|
|
244
|
+
},
|
|
186
245
|
},
|
|
187
246
|
|
|
188
247
|
gc: {
|
|
@@ -220,7 +279,7 @@ export const FINDING_PRESENTATION
|
|
|
220
279
|
slowHost: {
|
|
221
280
|
name: 'slow executor host',
|
|
222
281
|
tag: 'HOST',
|
|
223
|
-
thresholdSummary: (t) => `a host ${t.ratioWarn}× slower than its peers by mean task time (per-executor figures from ${t.ratioTiers[0]}
|
|
282
|
+
thresholdSummary: (t) => `a host ${t.ratioWarn}× slower than its peers by mean task time (per-executor figures from ${t.ratioTiers[0]}×, and only when the stage's own task-time spread cannot explain the gap)`,
|
|
224
283
|
actionLabel(f) {
|
|
225
284
|
if (f.variant === 'durationShare') return 'Fix data locality';
|
|
226
285
|
if (f.variant === 'multiDim') return 'Investigate degraded executor';
|
|
@@ -240,18 +299,28 @@ export const FINDING_PRESENTATION
|
|
|
240
299
|
tag: 'SLOW',
|
|
241
300
|
thresholdSummary: () => 'a stage running far longer than its peers, not attributable to a single slow host',
|
|
242
301
|
actionLabel: () => 'Profile slow stage',
|
|
243
|
-
genericRecommendation
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
302
|
+
genericRecommendation(f) {
|
|
303
|
+
if (f.reads === 'input') return 'Often too few or too uneven input partitions: check input file sizes and lower spark.sql.files.maxPartitionBytes, or look for a large per-task data volume driving heavy spill.';
|
|
304
|
+
if (f.reads === 'other') return 'Check what the stage computes and for a large per-task data volume driving heavy spill.';
|
|
305
|
+
const spill = 'or check for a large per-task data volume driving heavy shuffle and spill.';
|
|
306
|
+
switch (partitionAdviceKind(f)) {
|
|
307
|
+
case 'aqe': return `Often a partition-count problem: AQE coalesced the shuffle, so lower spark.sql.adaptive.advisoryPartitionSizeInBytes to get more tasks, ${spill}`;
|
|
308
|
+
case 'code': return `Often a partition-count problem: raise this stage's own partition count (its repartition(n) or RDD parallelism), ${spill}`;
|
|
309
|
+
default: return `Often a partition-count problem: raise spark.sql.shuffle.partitions, ${spill}`;
|
|
310
|
+
}
|
|
311
|
+
},
|
|
248
312
|
},
|
|
249
313
|
straggler: {
|
|
250
314
|
name: 'straggling task',
|
|
251
315
|
tag: 'STRAG',
|
|
252
|
-
thresholdSummary: () => 'one or more tasks finishing far after the rest of their stage',
|
|
316
|
+
thresholdSummary: () => 'one or more tasks finishing far after the rest of their stage, for a reason other than reading more data',
|
|
253
317
|
actionLabel: () => 'Fix stragglers',
|
|
254
|
-
genericRecommendation: (f) =>
|
|
318
|
+
genericRecommendation: (f) => f.cause === 'data' ? `Uneven data volume drives the slow tasks: ${skewJoinGeneric(f, 'for join-driven skew, enable AQE skew-join handling (spark.sql.adaptive.skewJoin.enabled); otherwise salt the key or repartition on a better key.')}`
|
|
319
|
+
: f.cause === 'gc' ? 'GC accounts for most of the slow tasks\' extra time: reduce object creation, use primitive types, avoid UDFs, increase executor memory.'
|
|
320
|
+
: f.cause === 'fetchWait' ? 'Waiting on shuffle fetches accounts for most of the slow tasks\' extra time: look for a slow or overloaded node serving shuffle blocks, executors lost mid-stage, or reducers fetching many small blocks.'
|
|
321
|
+
: f.cause === 'host' ? 'Most slow tasks ran on one host: check what it was running, and consider enabling spark.speculation to relaunch a lagging task automatically.'
|
|
322
|
+
: f.cause === 'unexplained' ? 'The slow tasks read no more data than the median task, and GC, shuffle fetch wait and one slow host do not account for their time: look at per-record cost (UDFs, regular expressions, a call out per row).'
|
|
323
|
+
: 'Nothing in the log attributes the slow tasks to data volume, GC, shuffle fetch wait or one host: check their input sizes, GC time and hosts before choosing a fix.',
|
|
255
324
|
},
|
|
256
325
|
speculationWaste: {
|
|
257
326
|
name: 'speculation waste',
|
|
@@ -279,8 +348,8 @@ export const FINDING_PRESENTATION
|
|
|
279
348
|
case 'idleCores': return 'Reduce idle cores';
|
|
280
349
|
case 'wasteModel': return 'Right-size executor memory';
|
|
281
350
|
case 'memoryBand':
|
|
282
|
-
if (f.dataUnavailable) return '
|
|
283
|
-
return
|
|
351
|
+
if (f.dataUnavailable) return 'Executor heap peaks unavailable';
|
|
352
|
+
return 'Reduce executor memory';
|
|
284
353
|
}
|
|
285
354
|
return undefined;
|
|
286
355
|
},
|
|
@@ -292,9 +361,7 @@ export const FINDING_PRESENTATION
|
|
|
292
361
|
case 'wasteModel': return 'Review spark.executor.memory and executor count.';
|
|
293
362
|
case 'memoryBand':
|
|
294
363
|
if (f.dataUnavailable) return undefined;
|
|
295
|
-
return
|
|
296
|
-
? 'Memory may be too small: raise spark.executor.memory to avoid OOM/spill.'
|
|
297
|
-
: 'Memory may be over-provisioned: consider reducing spark.executor.memory for cost savings.';
|
|
364
|
+
return 'Memory may be over-provisioned: consider reducing spark.executor.memory for cost savings.';
|
|
298
365
|
}
|
|
299
366
|
return undefined;
|
|
300
367
|
},
|
|
@@ -373,14 +440,30 @@ export const FINDING_PRESENTATION
|
|
|
373
440
|
? 'Repartition or coalesce before writing to raise the average file size.'
|
|
374
441
|
: 'Compact the upstream output so fewer, larger files are produced.'),
|
|
375
442
|
},
|
|
443
|
+
pythonUdf: {
|
|
444
|
+
name: 'row-at-a-time Python UDF',
|
|
445
|
+
tag: 'PLAN',
|
|
446
|
+
thresholdSummary: (t) => `over ${t.minBytesSent / 1048576} MiB sent to Python workers by stages running over ${t.minStageMs / 1000} s`,
|
|
447
|
+
actionLabel: () => 'Vectorize Python UDF',
|
|
448
|
+
genericRecommendation: () => 'Use Arrow-optimized Python UDFs (spark.sql.execution.pythonUDF.arrow.enabled, Spark 3.4 and later) or a pandas UDF instead of a row-at-a-time Python UDF.',
|
|
449
|
+
},
|
|
450
|
+
nestedLoopJoin: {
|
|
451
|
+
name: 'nested loop join',
|
|
452
|
+
tag: 'PLAN',
|
|
453
|
+
thresholdSummary: (t) => `a nested-loop or cartesian join with over ${groupThousands(t.minOutputRows)} output rows, at least ${t.minExpansion}x its larger input`,
|
|
454
|
+
actionLabel: (f) => (f.condition == null ? 'Confirm cross join' : 'Add an equi-join key'),
|
|
455
|
+
genericRecommendation: (f) => (f.condition == null
|
|
456
|
+
? 'Confirm the cross join is intended, or add a join key so the rows are matched instead of multiplied.'
|
|
457
|
+
: 'Add an equi-join key so Spark can use a hash or sort-merge join; for a range condition, bucket the range and join on the bucket as well.'),
|
|
458
|
+
},
|
|
376
459
|
underBroadcast: {
|
|
377
460
|
name: 'missed broadcast join',
|
|
378
461
|
tag: 'PLAN',
|
|
379
|
-
thresholdSummary: () =>
|
|
462
|
+
thresholdSummary: (t) => `a join side its type can broadcast, between ${t.minSmallerSideBytes / 1048576} MiB and ${t.overBroadcastBytes / 1073741824} GiB, that skipped broadcast`,
|
|
380
463
|
actionLabel: () => 'Use broadcast join',
|
|
381
464
|
genericRecommendation: (f) => (f.broadcastThreshold === 'notLimiting'
|
|
382
|
-
? 'The threshold already admits the
|
|
383
|
-
:
|
|
465
|
+
? 'The threshold already admits the build side, so it is not what stopped the broadcast: consider a broadcast() hint or collecting table statistics.'
|
|
466
|
+
: `This could have been a broadcast join: consider a broadcast() hint or raising ${broadcastThresholdKeyOf(f)}.`),
|
|
384
467
|
},
|
|
385
468
|
overBroadcast: {
|
|
386
469
|
name: 'oversized broadcast join',
|
|
@@ -389,9 +472,9 @@ export const FINDING_PRESENTATION
|
|
|
389
472
|
actionLabel: () => 'Fix oversized broadcast',
|
|
390
473
|
genericRecommendation: (f) => (f.broadcastThreshold === 'notLimiting'
|
|
391
474
|
? 'The configured threshold is below this broadcast, so remove the broadcast() hint that forced it.'
|
|
392
|
-
:
|
|
475
|
+
: f.broadcastThreshold === 'disabled'
|
|
393
476
|
? 'Automatic broadcast is already disabled, so remove the broadcast() hint that forced it.'
|
|
394
|
-
:
|
|
477
|
+
: `Check for a misapplied broadcast hint or a misconfigured ${broadcastThresholdKeyOf(f)}.`),
|
|
395
478
|
},
|
|
396
479
|
};
|
|
397
480
|
|
|
@@ -88,12 +88,20 @@
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
// ── Per-stage detectors ─────────────────────────────────────────────────────
|
|
92
|
-
|
|
93
91
|
/** What a skewed stage reads, which decides the fix: 'shuffleJoin' (a shuffle feeding a join, where
|
|
94
92
|
* AQE skew-join handling applies), 'inputScan' (uneven input files) or 'other'. */
|
|
95
93
|
|
|
96
94
|
|
|
95
|
+
/** What AQE skew-join handling did for a 'shuffleJoin' stage, read from the final plan and the
|
|
96
|
+
* effective conf: 'split' (it split the skewed partition, so the rest is not join skew),
|
|
97
|
+
* 'evenReads' (the shuffle reads are even, so no partition is skewed for AQE to split),
|
|
98
|
+
* 'belowThreshold' (the partition is under the effective skew threshold or factor), 'planShape' (an
|
|
99
|
+
* operator sits between the join and its shuffle), 'userRepartition' (the shuffle is an explicit
|
|
100
|
+
* repartition), 'joinType' (the join type does not let AQE split the skewed side),
|
|
101
|
+
* 'extraShuffle' (splitting would add a shuffle for the operator above the join) or 'notSplit'
|
|
102
|
+
* (nothing in the log explains it). */
|
|
103
|
+
|
|
104
|
+
|
|
97
105
|
/** What a stage reads, by the dominant side: a shuffle, input files, or neither. */
|
|
98
106
|
|
|
99
107
|
|
|
@@ -103,8 +111,23 @@
|
|
|
103
111
|
* enough, so the stage's own repartition(n) or RDD parallelism is). */
|
|
104
112
|
|
|
105
113
|
|
|
114
|
+
/** Why a stage's slow tail is slow (attributeTail in stage-quantiles.ts). 'data': the slow tasks
|
|
115
|
+
* read far more than the median task, so run time follows data volume. 'gc', 'fetchWait' and
|
|
116
|
+
* 'host': the tail's extra time is GC, shuffle fetch wait, or tasks piled on one host.
|
|
117
|
+
* 'unexplained': the slow tasks read no more than the median and none of those accounts for their
|
|
118
|
+
* time. 'unattributed': the stage has no data volume to compare and what data, GC, fetch wait and
|
|
119
|
+
* host do not explain is the largest share (or the stage has no tail attribution), so only the
|
|
120
|
+
* duration is known. */
|
|
121
|
+
|
|
122
|
+
|
|
106
123
|
|
|
107
124
|
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
108
131
|
|
|
109
132
|
|
|
110
133
|
|
|
@@ -123,8 +146,9 @@
|
|
|
123
146
|
|
|
124
147
|
|
|
125
148
|
|
|
126
|
-
|
|
149
|
+
|
|
127
150
|
|
|
151
|
+
|
|
128
152
|
|
|
129
153
|
|
|
130
154
|
|
|
@@ -155,6 +179,10 @@
|
|
|
155
179
|
|
|
156
180
|
|
|
157
181
|
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
158
186
|
|
|
159
187
|
|
|
160
188
|
|
|
@@ -185,11 +213,23 @@
|
|
|
185
213
|
|
|
186
214
|
|
|
187
215
|
|
|
188
|
-
|
|
216
|
+
|
|
217
|
+
|
|
189
218
|
|
|
190
219
|
|
|
191
|
-
|
|
220
|
+
|
|
221
|
+
|
|
192
222
|
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
193
233
|
|
|
194
234
|
|
|
195
235
|
|
|
@@ -211,8 +251,6 @@
|
|
|
211
251
|
|
|
212
252
|
|
|
213
253
|
|
|
214
|
-
|
|
215
|
-
// ── App-level detectors ─────────────────────────────────────────────────────
|
|
216
254
|
|
|
217
255
|
|
|
218
256
|
// valueText is always 'missing': the ApplicationEnd event the log lacks.
|
|
@@ -225,7 +263,7 @@
|
|
|
225
263
|
|
|
226
264
|
|
|
227
265
|
|
|
228
|
-
|
|
266
|
+
|
|
229
267
|
|
|
230
268
|
|
|
231
269
|
|
|
@@ -239,21 +277,24 @@
|
|
|
239
277
|
|
|
240
278
|
|
|
241
279
|
|
|
242
|
-
|
|
243
|
-
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
244
283
|
|
|
245
|
-
|
|
284
|
+
|
|
246
285
|
|
|
247
286
|
|
|
248
287
|
|
|
249
288
|
|
|
250
289
|
|
|
251
290
|
|
|
252
|
-
|
|
291
|
+
|
|
253
292
|
|
|
254
293
|
|
|
255
|
-
|
|
256
294
|
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
257
298
|
|
|
258
299
|
|
|
259
300
|
|
|
@@ -304,17 +345,13 @@
|
|
|
304
345
|
|
|
305
346
|
|
|
306
347
|
|
|
307
|
-
|
|
308
|
-
// ── Config-scope detectors ──────────────────────────────────────────────────
|
|
309
348
|
|
|
310
349
|
|
|
311
350
|
|
|
312
351
|
|
|
313
|
-
// valueText is the audited property's current value, or a note that it is unset
|
|
352
|
+
// valueText is the audited property's current value, or a note that it is unset.
|
|
314
353
|
|
|
315
354
|
|
|
316
|
-
// ── SQL-scope (Plan Advisor) detectors ──────────────────────────────────────
|
|
317
|
-
|
|
318
355
|
|
|
319
356
|
|
|
320
357
|
|
|
@@ -344,13 +381,41 @@
|
|
|
344
381
|
|
|
345
382
|
|
|
346
383
|
|
|
347
|
-
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
/** A BroadcastNestedLoopJoin or CartesianProduct whose output is far larger than both inputs.
|
|
394
|
+
* `nodeName` is the operator, `joinType` the Spark join type (null when the plan line has none)
|
|
395
|
+
* and `condition` the join condition with expression ids removed (null for a join without one).
|
|
396
|
+
* `leftRows` and `rightRows` are the input row counts the executors reported, null for a
|
|
397
|
+
* CartesianProduct, which re-reads its inputs so their counts are not row counts. */
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
/** How the effective broadcast threshold (spark.sql.autoBroadcastJoinThreshold, or its adaptive counterpart under AQE) relates to the finding: 'limits' (the
|
|
348
409
|
* property decided it, or is unknown), 'notLimiting' (already admits, or already below, the
|
|
349
410
|
* broadcast, so something else decided it) or 'disabled' (-1). */
|
|
350
411
|
|
|
351
412
|
|
|
352
413
|
|
|
414
|
+
|
|
353
415
|
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
354
419
|
|
|
355
420
|
|
|
356
421
|
|
|
@@ -360,8 +425,6 @@
|
|
|
360
425
|
|
|
361
426
|
|
|
362
427
|
|
|
363
|
-
// ── Unions ──────────────────────────────────────────────────────────────────
|
|
364
|
-
|
|
365
428
|
/** Public evidence fields per finding type: what a report row's `evidence` carries. */
|
|
366
429
|
|
|
367
430
|
|
|
@@ -390,6 +453,8 @@
|
|
|
390
453
|
|
|
391
454
|
|
|
392
455
|
|
|
456
|
+
|
|
457
|
+
|
|
393
458
|
|
|
394
459
|
|
|
395
460
|
|
|
@@ -421,6 +486,8 @@
|
|
|
421
486
|
|
|
422
487
|
|
|
423
488
|
|
|
489
|
+
|
|
490
|
+
|
|
424
491
|
|
|
425
492
|
|
|
426
493
|
|
|
@@ -14,9 +14,9 @@ const BOTTLENECK_WIDGET = {
|
|
|
14
14
|
coldStart: 'executor-timeline', utilization: 'executor-timeline', speculationWaste: 'executor-timeline',
|
|
15
15
|
} ;
|
|
16
16
|
|
|
17
|
-
// Cross-widget stage recurrence: how many distinct
|
|
18
|
-
//
|
|
19
|
-
//
|
|
17
|
+
// Cross-widget stage recurrence: how many distinct widget groups (skew, slowHost and straggler
|
|
18
|
+
// share task-skew) flag a stage. No production code calls it, and the group names in
|
|
19
|
+
// BOTTLENECK_WIDGET are labels, not ids of rendered widgets.
|
|
20
20
|
// `stageId` may be number|null|undefined: sql/config-scope findings never set it; `stageId == null`
|
|
21
21
|
// below treats both the same.
|
|
22
22
|
export function stageWidgetFrequency(catalog ) {
|
|
@@ -69,9 +69,7 @@ export function formatStageIdsLabel(stageIds , maxShown = DEFAU
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/** Worst (lowest IMPACT_BAND_ORDER) impact band across findings, undefined when empty. Shared by
|
|
72
|
-
* every widget that badges/colors a group of findings.
|
|
73
|
-
* @param {{ impactBand: 'critical' | 'warning' | 'info' }[]} findings
|
|
74
|
-
* @returns {'critical' | 'warning' | 'info' | undefined} */
|
|
72
|
+
* every widget that badges/colors a group of findings. */
|
|
75
73
|
export function worstImpactBand(
|
|
76
74
|
findings ,
|
|
77
75
|
) {
|
|
@@ -285,15 +283,16 @@ export function formatRawWaste(rawWaste ) {
|
|
|
285
283
|
}
|
|
286
284
|
}
|
|
287
285
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
286
|
+
/** A cost-only figure as core time. Task time summed over tasks (`ms`) is core time, and printing
|
|
287
|
+
* it as a duration beside wall-clock savings reads as run time it does not shorten. */
|
|
288
|
+
export function asCoreTime(rawWaste ) {
|
|
289
|
+
return rawWaste.unit === 'ms' ? { ...rawWaste, unit: 'coreMs' } : rawWaste;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// True when a formatted figure reads as zero, including a small nonzero value the fixed rounding
|
|
293
|
+
// collapsed (0.04 coreHours -> "0.0 core-h"). It tests the formatted text, so it holds for any unit.
|
|
294
|
+
// The fractional group must consume the whole decimal part before the terminator, so "0.5 core-h"
|
|
295
|
+
// does not match.
|
|
297
296
|
export function readsAsZero(formatted ) {
|
|
298
297
|
return /^0(\.0+)?(?:[^0-9.]|$)/.test(formatted);
|
|
299
298
|
}
|