sparkforensics-server 0.5.2 → 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/instrument-sans-latin-ext-wdth-normal-C5E2Gvlv.woff2 +0 -0
- package/public/assets/instrument-sans-latin-wdth-normal-BVScPF0l.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -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 -7
- package/public/docs/assets/{app.eYTPqTeq.js → app.1gvzd5Zb.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.DsZrQKQR.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
- package/public/docs/assets/chunks/{theme.DsTNE2pE.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.8bH1HnZp.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.WqY74T0T.js +1 -0
- 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.wj6Et6UD.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.CKjWG56Y.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.CZv_ZGOp.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.BUucRc0A.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.DC1YqXBp.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.DVGZOWvW.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.D9bu4j_c.js → contributor-guide_development-setup.md.B21ZTDhn.js} +3 -3
- 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/instrument-sans-latin-ext-wdth-normal.C5E2Gvlv.woff2 +0 -0
- package/public/docs/assets/instrument-sans-latin-wdth-normal.BVScPF0l.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2 +0 -0
- package/public/docs/assets/style.Cfxqlj0y.css +1 -0
- 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.C0pcQoNc.lean.js +1 -0
- 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_mcp-tools_get-run-summary.md.DpxZ4ZNp.js → user-guide_mcp-tools_get-run-summary.md.EhaIsele.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 -10
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -10
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -10
- package/public/docs/contributor-guide/architecture/board-widgets.html +6 -10
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -10
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -10
- package/public/docs/contributor-guide/architecture/detector-contract.html +6 -10
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -10
- package/public/docs/contributor-guide/architecture/drill-down.html +6 -10
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -10
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -10
- package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -10
- package/public/docs/contributor-guide/architecture/index.html +5 -9
- package/public/docs/contributor-guide/architecture/overview.html +6 -10
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -9
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -10
- package/public/docs/contributor-guide/architecture/state-and-history.html +5 -9
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -10
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -9
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -10
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -9
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -10
- package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -11
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -10
- package/public/docs/contributor-guide/contributing.html +6 -10
- package/public/docs/contributor-guide/development-setup.html +8 -12
- package/public/docs/contributor-guide/testing.html +9 -10
- package/public/docs/favicon.svg +2 -2
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +6 -10
- 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 -9
- package/public/docs/tuning-reference/aqe.html +5 -9
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -9
- package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -9
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -9
- package/public/docs/tuning-reference/bottleneck-failures.html +5 -9
- package/public/docs/tuning-reference/bottleneck-gc.html +5 -9
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -9
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -9
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -9
- package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -9
- package/public/docs/tuning-reference/bottleneck-skew.html +5 -9
- package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -9
- package/public/docs/tuning-reference/bottleneck-small-files.html +5 -9
- package/public/docs/tuning-reference/bottleneck-spill.html +5 -9
- package/public/docs/tuning-reference/bottleneck-straggler.html +5 -9
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -9
- package/public/docs/tuning-reference/bottleneck-utilization.html +5 -9
- package/public/docs/tuning-reference/caching.html +5 -9
- package/public/docs/tuning-reference/cluster-config.html +5 -9
- package/public/docs/tuning-reference/config.html +5 -9
- package/public/docs/tuning-reference/data-formats.html +5 -9
- package/public/docs/tuning-reference/index.html +5 -9
- package/public/docs/tuning-reference/intro.html +5 -9
- package/public/docs/tuning-reference/joins.html +5 -9
- package/public/docs/tuning-reference/memory-model.html +5 -9
- package/public/docs/tuning-reference/metrics.html +5 -9
- package/public/docs/tuning-reference/partitioning.html +5 -9
- package/public/docs/tuning-reference/pyspark.html +5 -9
- package/public/docs/tuning-reference/shuffle.html +5 -9
- package/public/docs/tuning-reference/spark-architecture.html +5 -9
- package/public/docs/tuning-reference/table-formats.html +5 -9
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -9
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -9
- package/public/docs/user-guide/alternative-log-retrieval.html +5 -9
- package/public/docs/user-guide/getting-started/ci-and-automation.html +17 -15
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -10
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -9
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -11
- package/public/docs/user-guide/getting-started.html +5 -9
- package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -15
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -11
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -10
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -9
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -10
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -9
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +6 -10
- package/public/docs/user-guide/mcp-tools/list-runs.html +5 -9
- package/public/docs/user-guide/mcp-tools.html +6 -10
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -9
- package/public/docs/user-guide/run-comparison.html +6 -10
- package/public/docs/user-guide/understanding-findings.html +6 -10
- package/public/export-template.html +46 -46
- package/public/favicon.svg +2 -2
- package/public/index.html +8 -10
- package/public/sample-runs/sample-run.ndjson.gz +0 -0
- package/vendor-core/allocation.js +126 -39
- package/vendor-core/analyzer.js +85 -58
- package/vendor-core/api-merge-writes.js +3 -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/delta-log-paths.js +10 -1
- package/vendor-core/detectors.js +1078 -416
- 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 +48 -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/docs-content/detection/util.md +6 -2
- package/vendor-core/effective-conf.js +7 -10
- package/vendor-core/efficiency-model.js +24 -16
- 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 +129 -39
- package/vendor-core/finding-types.js +108 -30
- 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 +28 -17
- 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/remediation.js +10 -5
- 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 +44 -11
- 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 +70 -23
- package/vendor-core/wall-clock.js +8 -0
- package/vendor-core/wasted-core-hours.js +12 -12
- package/vendor-core/write-targets.js +146 -14
- package/vendor-core/zstd-worker-client.js +1 -1
- package/vendor-core/zstd-worker.js +1 -1
- package/public/assets/AutoscalingChurn-8t3U3isq.js +0 -1
- package/public/assets/CacheUtilization-CJs9tTum.js +0 -1
- package/public/assets/CachingOpportunity-D1NcHs0V.js +0 -1
- package/public/assets/ColdStart-CdRJ9gD8.js +0 -1
- package/public/assets/ConfigAudit-B5Gbe5js.js +0 -1
- package/public/assets/CoreUsageArea-a--NTRGY.js +0 -1
- package/public/assets/Dashboard-C1hNeX49.js +0 -2
- package/public/assets/DisclosureContext-ZpE6CkHx.js +0 -1
- package/public/assets/DuplicatePlanSubtree-dobXdz7E.js +0 -1
- package/public/assets/ExecutorUtilization-D9grwi7t.js +0 -1
- package/public/assets/GcPressure-8-G2ri10.js +0 -1
- package/public/assets/IncompleteRun-B91lky7a.js +0 -1
- package/public/assets/JobFailures-BsWvBMyJ.js +0 -1
- package/public/assets/MemoryUtilization-BM5schZI.js +0 -1
- package/public/assets/OverBroadcast-DdN8JIJH.js +0 -1
- package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
- package/public/assets/PartitionSizing-CY5HDYtp.js +0 -1
- package/public/assets/PlanExplorer-DgHCDBD_.js +0 -1
- package/public/assets/PlanGraphRoute-DH3KJb8j.js +0 -1
- package/public/assets/RetryWaste-DOnE9vGF.js +0 -1
- package/public/assets/ShuffleIO-MMnDESkF.js +0 -1
- package/public/assets/Skew-BmZZJ5ms.js +0 -1
- package/public/assets/SlowHost-CsJzfEqo.js +0 -1
- package/public/assets/SmallFiles-BoK3R1Ex.js +0 -1
- package/public/assets/SpeculationWaste-CnVxB5AJ.js +0 -1
- package/public/assets/Spill-BhNicyBy.js +0 -1
- package/public/assets/StageFailed-mAhHU4l_.js +0 -1
- package/public/assets/StageFindingGroup-BEtPWcT0.js +0 -1
- package/public/assets/StageHeader-DJkYkrsU.js +0 -1
- package/public/assets/StageShape-BDxRknLp.js +0 -1
- package/public/assets/StageSlowness-BPRw-otN.js +0 -1
- package/public/assets/Straggler-CZCbnOWP.js +0 -1
- package/public/assets/TaskFailures-C57YcLFQ.js +0 -1
- package/public/assets/TinyTask-Bi84qU7n.js +0 -1
- package/public/assets/UnderBroadcast-DdQV7htE.js +0 -1
- package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
- package/public/assets/finding-anchor-Cl6_5hfV.js +0 -1
- package/public/assets/impact-sort-CssZ6MT2.js +0 -1
- package/public/assets/index-2h_TgUAb.css +0 -2
- package/public/assets/index-B-03mG7K.js +0 -14
- package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
- package/public/assets/react-vendor-DEdfrRTJ.js +0 -9
- package/public/assets/select-CQjNhprm.js +0 -1
- package/public/assets/usePagedRows-Dyl6T8Ok.js +0 -1
- package/public/assets/useRecentFiles-XZEnLlal.js +0 -11
- package/public/assets/useSortMode-Dhvit8dt.js +0 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.u_e5bQz4.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.DYgUpIJB.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.wj6Et6UD.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.CKjWG56Y.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.CZv_ZGOp.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.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.DC1YqXBp.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.js +0 -1
- package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
- package/public/docs/assets/contributor-guide_development-setup.md.D9bu4j_c.lean.js +0 -1
- package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
- package/public/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/public/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/public/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/public/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/public/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/public/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/public/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/public/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/public/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/public/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/public/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/public/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/public/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/public/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/public/docs/assets/style.tmDhD3c8.css +0 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.js +0 -23
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.lean.js +0 -1
- 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.C9YRruMT.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.lean.js +0 -1
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.8bH1HnZp.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
- /package/public/docs/assets/{user-guide_mcp-tools_get-run-summary.md.DpxZ4ZNp.lean.js → user-guide_mcp-tools_get-run-summary.md.EhaIsele.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,36 +30,93 @@
|
|
|
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.
|
|
36
42
|
// A finding with no remediation (older or hand-built data) keeps the property wording.
|
|
37
43
|
function switchAlreadyOn(finding , key ) {
|
|
38
|
-
return finding.remediation != null && !finding.remediation.some((r) => r.key === key);
|
|
44
|
+
return finding.remediation != null && !finding.remediation.some((r) => r.kind === 'conf' && r.key === key);
|
|
45
|
+
}
|
|
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';
|
|
39
52
|
}
|
|
40
53
|
|
|
54
|
+
// The properties an idle-capacity finding lowers once dynamic allocation is on, worded as its row
|
|
55
|
+
// does: the executor cap, and the floor when the row's remediation lowers it too.
|
|
56
|
+
function idleCapacityLowering(f ) {
|
|
57
|
+
const lowersFloor = f.remediation?.some((r) => r.kind === 'conf' && r.key === 'spark.dynamicAllocation.minExecutors');
|
|
58
|
+
return ` by lowering spark.dynamicAllocation.maxExecutors${lowersFloor ? ' and spark.dynamicAllocation.minExecutors' : ''}`;
|
|
59
|
+
}
|
|
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
|
+
|
|
41
84
|
const SKEW_JOIN_KEY = 'spark.sql.adaptive.skewJoin.enabled';
|
|
42
85
|
const SKEW_JOIN_ALREADY_ON = 'AQE skew-join handling is already on, so salt the key or repartition on a better key.';
|
|
43
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.';
|
|
44
87
|
|
|
45
88
|
// The skew-join generic line, worded per the row's remediation: AQE logged off, switch already on, or neither.
|
|
46
|
-
function skewJoinGeneric(f
|
|
89
|
+
function skewJoinGeneric(f , unset ) {
|
|
47
90
|
if (f.origin === 'inputScan') return 'Uneven input files: compact small files or split large ones (lower spark.sql.files.maxPartitionBytes).';
|
|
48
91
|
if (f.origin === 'other') return 'Work is uneven across tasks: salt the key or repartition on a better key.';
|
|
49
|
-
if (f.remediation?.some((r) => r.
|
|
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];
|
|
94
|
+
if (f.remediation?.some((r) => r.kind === 'conf' && r.key === 'spark.sql.adaptive.enabled')) return SKEW_JOIN_AQE_OFF;
|
|
50
95
|
return switchAlreadyOn(f, SKEW_JOIN_KEY) ? SKEW_JOIN_ALREADY_ON : unset;
|
|
51
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
|
+
|
|
52
111
|
const DYNAMIC_ALLOCATION_KEY = 'spark.dynamicAllocation.enabled';
|
|
53
112
|
|
|
54
|
-
// The
|
|
113
|
+
// The three configAudit DETECTORS entries share this row, one per audited property.
|
|
55
114
|
const CONFIG_AUDIT_PRESENTATION = {
|
|
56
115
|
name: 'config audit',
|
|
57
116
|
tag: 'CFG',
|
|
58
117
|
thresholdSummary: () => 'a Spark conf value outside the recommended range',
|
|
59
118
|
actionLabel(f) {
|
|
60
119
|
switch (f.property) {
|
|
61
|
-
case 'spark.shuffle.service.enabled': return 'Enable shuffle service';
|
|
62
|
-
case 'spark.dynamicAllocation.minExecutors': return 'Fix autoscaling bounds';
|
|
63
120
|
case 'spark.dynamicAllocation.maxExecutors': return 'Set max executors';
|
|
64
121
|
case 'spark.serializer': return 'Switch to Kryo';
|
|
65
122
|
case 'spark.executor.memoryOverhead': return 'Raise memory overhead';
|
|
@@ -68,11 +125,9 @@ const CONFIG_AUDIT_PRESENTATION = {
|
|
|
68
125
|
},
|
|
69
126
|
genericRecommendation(f) {
|
|
70
127
|
switch (f.property) {
|
|
71
|
-
case 'spark.shuffle.service.enabled': return 'Set spark.shuffle.service.enabled=true so shuffle data survives executor removal.';
|
|
72
|
-
case 'spark.dynamicAllocation.minExecutors': return 'Set the minimum executor bound at or below the maximum.';
|
|
73
128
|
case 'spark.dynamicAllocation.maxExecutors': return 'Set spark.dynamicAllocation.maxExecutors to cap cluster growth.';
|
|
74
129
|
case 'spark.serializer': return 'Consider spark.serializer=org.apache.spark.serializer.KryoSerializer for faster, smaller buffers.';
|
|
75
|
-
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.';
|
|
76
131
|
}
|
|
77
132
|
return undefined;
|
|
78
133
|
},
|
|
@@ -91,7 +146,7 @@ export const FINDING_PRESENTATION
|
|
|
91
146
|
skew: {
|
|
92
147
|
name: 'task skew',
|
|
93
148
|
tag: 'SKEW',
|
|
94
|
-
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`,
|
|
95
150
|
actionLabel: () => 'Fix task skew',
|
|
96
151
|
genericRecommendation: (f) => skewJoinGeneric(f,
|
|
97
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.'),
|
|
@@ -122,9 +177,14 @@ export const FINDING_PRESENTATION
|
|
|
122
177
|
tag: 'TINY',
|
|
123
178
|
thresholdSummary: (t) => `${t.minTasks}+ tasks with a median of ${t.maxP50}ms or less and a P95 of ${t.maxP95}ms or less`,
|
|
124
179
|
actionLabel: () => 'Coalesce small tasks',
|
|
125
|
-
genericRecommendation
|
|
126
|
-
|
|
127
|
-
|
|
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
|
+
},
|
|
128
188
|
},
|
|
129
189
|
|
|
130
190
|
shuffle: {
|
|
@@ -173,9 +233,15 @@ export const FINDING_PRESENTATION
|
|
|
173
233
|
thresholdSummary: (t) => `single-task disk spill above ${t.singleTaskDiskGiB} GiB`,
|
|
174
234
|
actionLabel: () => 'Reduce spill',
|
|
175
235
|
// The skew/volume classification isn't a Finding field, so one sentence covers both.
|
|
176
|
-
genericRecommendation
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
},
|
|
179
245
|
},
|
|
180
246
|
|
|
181
247
|
gc: {
|
|
@@ -213,7 +279,7 @@ export const FINDING_PRESENTATION
|
|
|
213
279
|
slowHost: {
|
|
214
280
|
name: 'slow executor host',
|
|
215
281
|
tag: 'HOST',
|
|
216
|
-
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)`,
|
|
217
283
|
actionLabel(f) {
|
|
218
284
|
if (f.variant === 'durationShare') return 'Fix data locality';
|
|
219
285
|
if (f.variant === 'multiDim') return 'Investigate degraded executor';
|
|
@@ -233,18 +299,28 @@ export const FINDING_PRESENTATION
|
|
|
233
299
|
tag: 'SLOW',
|
|
234
300
|
thresholdSummary: () => 'a stage running far longer than its peers, not attributable to a single slow host',
|
|
235
301
|
actionLabel: () => 'Profile slow stage',
|
|
236
|
-
genericRecommendation
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
+
},
|
|
241
312
|
},
|
|
242
313
|
straggler: {
|
|
243
314
|
name: 'straggling task',
|
|
244
315
|
tag: 'STRAG',
|
|
245
|
-
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',
|
|
246
317
|
actionLabel: () => 'Fix stragglers',
|
|
247
|
-
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.',
|
|
248
324
|
},
|
|
249
325
|
speculationWaste: {
|
|
250
326
|
name: 'speculation waste',
|
|
@@ -272,22 +348,20 @@ export const FINDING_PRESENTATION
|
|
|
272
348
|
case 'idleCores': return 'Reduce idle cores';
|
|
273
349
|
case 'wasteModel': return 'Right-size executor memory';
|
|
274
350
|
case 'memoryBand':
|
|
275
|
-
if (f.dataUnavailable) return '
|
|
276
|
-
return
|
|
351
|
+
if (f.dataUnavailable) return 'Executor heap peaks unavailable';
|
|
352
|
+
return 'Reduce executor memory';
|
|
277
353
|
}
|
|
278
354
|
return undefined;
|
|
279
355
|
},
|
|
280
356
|
genericRecommendation(f) {
|
|
281
357
|
switch (f.variant) {
|
|
282
358
|
case 'idleCores': return switchAlreadyOn(f, DYNAMIC_ALLOCATION_KEY)
|
|
283
|
-
?
|
|
284
|
-
: '
|
|
359
|
+
? `Dynamic allocation is already on, so reduce cluster size${idleCapacityLowering(f)}.`
|
|
360
|
+
: 'Either reduce cluster size (spark.executor.instances) or enable dynamic allocation.';
|
|
285
361
|
case 'wasteModel': return 'Review spark.executor.memory and executor count.';
|
|
286
362
|
case 'memoryBand':
|
|
287
363
|
if (f.dataUnavailable) return undefined;
|
|
288
|
-
return
|
|
289
|
-
? 'Memory may be too small: raise spark.executor.memory to avoid OOM/spill.'
|
|
290
|
-
: '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.';
|
|
291
365
|
}
|
|
292
366
|
return undefined;
|
|
293
367
|
},
|
|
@@ -298,8 +372,8 @@ export const FINDING_PRESENTATION
|
|
|
298
372
|
thresholdSummary: (t) => `average executor utilization below ${shareLabel(t.minUtil)}`,
|
|
299
373
|
actionLabel: () => 'Reduce cluster size',
|
|
300
374
|
genericRecommendation: (f) => (switchAlreadyOn(f, DYNAMIC_ALLOCATION_KEY)
|
|
301
|
-
?
|
|
302
|
-
: 'Consider reducing cluster size or enabling dynamic allocation.'),
|
|
375
|
+
? `Dynamic allocation is already on, so consider reducing cluster size${idleCapacityLowering(f)}.`
|
|
376
|
+
: 'Consider either reducing cluster size (spark.executor.instances) or enabling dynamic allocation.'),
|
|
303
377
|
},
|
|
304
378
|
coreLocality: {
|
|
305
379
|
name: 'core locality',
|
|
@@ -366,14 +440,30 @@ export const FINDING_PRESENTATION
|
|
|
366
440
|
? 'Repartition or coalesce before writing to raise the average file size.'
|
|
367
441
|
: 'Compact the upstream output so fewer, larger files are produced.'),
|
|
368
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
|
+
},
|
|
369
459
|
underBroadcast: {
|
|
370
460
|
name: 'missed broadcast join',
|
|
371
461
|
tag: 'PLAN',
|
|
372
|
-
thresholdSummary: () =>
|
|
462
|
+
thresholdSummary: (t) => `a join side its type can broadcast, between ${t.minSmallerSideBytes / 1048576} MiB and ${t.overBroadcastBytes / 1073741824} GiB, that skipped broadcast`,
|
|
373
463
|
actionLabel: () => 'Use broadcast join',
|
|
374
464
|
genericRecommendation: (f) => (f.broadcastThreshold === 'notLimiting'
|
|
375
|
-
? 'The threshold already admits the
|
|
376
|
-
:
|
|
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)}.`),
|
|
377
467
|
},
|
|
378
468
|
overBroadcast: {
|
|
379
469
|
name: 'oversized broadcast join',
|
|
@@ -382,9 +472,9 @@ export const FINDING_PRESENTATION
|
|
|
382
472
|
actionLabel: () => 'Fix oversized broadcast',
|
|
383
473
|
genericRecommendation: (f) => (f.broadcastThreshold === 'notLimiting'
|
|
384
474
|
? 'The configured threshold is below this broadcast, so remove the broadcast() hint that forced it.'
|
|
385
|
-
:
|
|
475
|
+
: f.broadcastThreshold === 'disabled'
|
|
386
476
|
? 'Automatic broadcast is already disabled, so remove the broadcast() hint that forced it.'
|
|
387
|
-
:
|
|
477
|
+
: `Check for a misapplied broadcast hint or a misconfigured ${broadcastThresholdKeyOf(f)}.`),
|
|
388
478
|
},
|
|
389
479
|
};
|
|
390
480
|
|