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
package/public/favicon.svg
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
-
<rect width="32" height="32" rx="
|
|
3
|
-
<path d="M17.5 5 8 18h6.5l-1 9L24 14h-6.5l1-9z" fill="#
|
|
2
|
+
<rect width="32" height="32" rx="6" fill="#4f46e5"/>
|
|
3
|
+
<path d="M17.5 5 8 18h6.5l-1 9L24 14h-6.5l1-9z" fill="#eceafd"/>
|
|
4
4
|
</svg>
|
package/public/index.html
CHANGED
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
<meta property="og:url" content="https://shuffle-works.github.io/sparkforensics/">
|
|
11
11
|
<meta property="og:title" content="SparkForensics">
|
|
12
12
|
<meta property="og:description" content="Zero-backend browser dashboard that parses Apache Spark event logs to diagnose performance bottlenecks: skew, spill, GC pressure, stragglers, cache utilization, and more.">
|
|
13
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
14
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
15
|
-
<link href="https://fonts.googleapis.com/css2?family=Recursive:wght,CASL@400..700,0..1&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
16
13
|
<script>
|
|
17
14
|
try {
|
|
18
15
|
var stored = localStorage.getItem('shuffle-works-theme');
|
|
@@ -23,14 +20,15 @@
|
|
|
23
20
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
24
21
|
} catch (_) {}
|
|
25
22
|
</script>
|
|
26
|
-
<script type="module" crossorigin src="./assets/index-
|
|
23
|
+
<script type="module" crossorigin src="./assets/index-fDiwfuoO.js"></script>
|
|
27
24
|
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-hePW80VL.js">
|
|
28
|
-
<link rel="modulepreload" crossorigin href="./assets/
|
|
29
|
-
<link rel="modulepreload" crossorigin href="./assets/
|
|
30
|
-
<link rel="modulepreload" crossorigin href="./assets/
|
|
31
|
-
<link rel="modulepreload" crossorigin href="./assets/
|
|
32
|
-
<link rel="
|
|
33
|
-
<link rel="
|
|
25
|
+
<link rel="modulepreload" crossorigin href="./assets/react-vendor-C6KcUD36.js">
|
|
26
|
+
<link rel="modulepreload" crossorigin href="./assets/DisclosureContext-DK1_iz6J.js">
|
|
27
|
+
<link rel="modulepreload" crossorigin href="./assets/inertValue-L9VxV0VE.js">
|
|
28
|
+
<link rel="modulepreload" crossorigin href="./assets/button-DbpTz2yk.js">
|
|
29
|
+
<link rel="modulepreload" crossorigin href="./assets/composite-C9Nu2EI9.js">
|
|
30
|
+
<link rel="modulepreload" crossorigin href="./assets/useScrollLock-BCxn_dMp.js">
|
|
31
|
+
<link rel="stylesheet" crossorigin href="./assets/index-CaRVPvAT.css">
|
|
34
32
|
</head>
|
|
35
33
|
<body>
|
|
36
34
|
<div id="root"></div>
|
|
Binary file
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { computePeakConcurrentExecutorCount } from './core-count.js';
|
|
1
2
|
import { parseSparkMemoryMB } from './spark-memory.js';
|
|
2
|
-
|
|
3
|
+
import { effectiveSparkConf, executorOverheadSettings, } from './spark-conf.js';
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
const MS_PER_HOUR = 3_600_000;
|
|
7
|
+
const MS_PER_SECOND = 1000;
|
|
5
8
|
const MIB_PER_GIB = 1024;
|
|
6
9
|
// Spark's documented floor and factor for the default executor memory overhead
|
|
7
|
-
// (spark.executor.memoryOverhead = max(factor * executor memory, 384 MiB))
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
+
// (spark.executor.memoryOverhead = max(factor * executor memory, 384 MiB)), for a run whose
|
|
11
|
+
// Spark version does not read the factor or minimum properties.
|
|
12
|
+
const OVERHEAD_FALLBACK = { floorMB: 384, floorPct: 0.1 };
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
|
|
@@ -14,12 +17,29 @@ const DEFAULT_OVERHEAD_FACTOR = 0.1;
|
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
17
32
|
|
|
18
33
|
|
|
34
|
+
// The fields the allocation reads from the parsed model's executor events, so a detector's
|
|
35
|
+
// narrower event shapes qualify too.
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
19
39
|
|
|
20
|
-
|
|
21
|
-
|
|
40
|
+
|
|
22
41
|
|
|
42
|
+
|
|
23
43
|
|
|
24
44
|
|
|
25
45
|
/** The latest timestamp the log records: the application start and end and every stage and
|
|
@@ -36,71 +56,138 @@ export function lastObservedTimestamp(input ) {
|
|
|
36
56
|
return last;
|
|
37
57
|
}
|
|
38
58
|
|
|
39
|
-
// Spark's default executor memory when spark.executor.memory is unset.
|
|
40
|
-
const DEFAULT_EXECUTOR_MEMORY_MIB = 1024;
|
|
41
|
-
|
|
42
59
|
// One container's memory in MiB, as Spark requests it from the cluster manager: executor heap,
|
|
43
|
-
// plus overhead, plus off-heap and PySpark worker memory when configured.
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
|
|
60
|
+
// plus overhead, plus off-heap and PySpark worker memory when configured. Every setting is read
|
|
61
|
+
// from the run's effective conf (the logged value, else Spark's default for its version). Null when
|
|
62
|
+
// the log records no Spark properties (nothing to tell a default from a missing config) or a memory
|
|
63
|
+
// key it does record cannot be read.
|
|
64
|
+
function executorMemoryMiB(app ) {
|
|
47
65
|
const config = app?.config;
|
|
48
66
|
if (config == null) return null;
|
|
67
|
+
const layers = { sparkVersion: app?.sparkVersion, properties: config };
|
|
68
|
+
const conf = (key ) => effectiveSparkConf(layers, key)?.value;
|
|
49
69
|
// undefined: key absent; null: present but unreadable.
|
|
50
|
-
const mib = (key ) =>
|
|
51
|
-
|
|
70
|
+
const mib = (key ) => {
|
|
71
|
+
const value = conf(key);
|
|
72
|
+
return value === undefined ? undefined : parseSparkMemoryMB(value);
|
|
73
|
+
};
|
|
74
|
+
const heap = mib('spark.executor.memory');
|
|
52
75
|
if (heap == null) return null;
|
|
53
76
|
|
|
54
77
|
let overhead = mib('spark.executor.memoryOverhead');
|
|
55
78
|
if (overhead === undefined) overhead = mib('spark.yarn.executor.memoryOverhead'); // legacy key
|
|
56
79
|
if (overhead === undefined) {
|
|
57
|
-
const factor =
|
|
58
|
-
overhead = Math.max(
|
|
80
|
+
const { minMB, factor } = executorOverheadSettings(layers, OVERHEAD_FALLBACK);
|
|
81
|
+
overhead = Math.max(minMB, Math.round(heap * factor));
|
|
59
82
|
}
|
|
60
|
-
const offHeap =
|
|
83
|
+
const offHeap = conf('spark.memory.offHeap.enabled')?.toLowerCase() === 'true' ? mib('spark.memory.offHeap.size') ?? 0 : 0;
|
|
61
84
|
const pyspark = mib('spark.executor.pyspark.memory') ?? 0;
|
|
62
85
|
if (overhead === null || offHeap === null || pyspark === null) return null;
|
|
63
86
|
return heap + overhead + offHeap + pyspark;
|
|
64
87
|
}
|
|
65
88
|
|
|
89
|
+
// The logged `spark.dynamicAllocation.enabled`: a value the app set. Spark's default (off) is not a
|
|
90
|
+
// logged key, so a run that never set it reads null.
|
|
91
|
+
function loggedDynamicAllocation(app ) {
|
|
92
|
+
const effective = effectiveSparkConf({ sparkVersion: app?.sparkVersion, properties: app?.config }, 'spark.dynamicAllocation.enabled');
|
|
93
|
+
return effective == null || effective.source === 'default' ? null : effective.value.toLowerCase() === 'true' ? 'on' : 'off';
|
|
94
|
+
}
|
|
95
|
+
|
|
66
96
|
/** Allocated core-hours and memory GiB-hours from the executor lifecycle: each executor counts
|
|
67
97
|
* from its ExecutorAdded timestamp to its first later ExecutorRemoved timestamp. One with no
|
|
68
98
|
* removal closes at the application end when the log has one, else at the last timestamp the log
|
|
69
99
|
* records (a cut-off log). Cores are the ExecutorAdded event's Total Cores, else
|
|
70
|
-
* spark.executor.cores; memory per executor is
|
|
71
|
-
*
|
|
72
|
-
* else the larger of 384 MiB and spark.executor.memoryOverheadFactor, default 0.1, times the
|
|
73
|
-
* memory), plus spark.memory.offHeap.size when spark.memory.offHeap.enabled is true, plus
|
|
74
|
-
* spark.executor.pyspark.memory.
|
|
100
|
+
* spark.executor.cores; memory per executor is the container Spark requests (executorMemoryMiB).
|
|
101
|
+
* The executor counts and seconds come from the same alive intervals.
|
|
75
102
|
* Null, never 0, for a figure whose inputs the log lacks. */
|
|
76
103
|
export function computeAllocation(input ) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (e.kind !== 'removed') continue;
|
|
82
|
-
const times = removedAt.get(e.executorId);
|
|
83
|
-
if (times) times.push(e.timestamp); else removedAt.set(e.executorId, [e.timestamp]);
|
|
104
|
+
const dynamicAllocation = loggedDynamicAllocation(input.app);
|
|
105
|
+
const alive = aliveIntervals(input);
|
|
106
|
+
if (alive.length === 0) {
|
|
107
|
+
return { coreHours: null, memoryGbHours: null, dynamicAllocation, executorsPeak: null, executorsMean: null, executorCores: null, executorSeconds: null };
|
|
84
108
|
}
|
|
85
109
|
const closeAt = input.app?.endTime ?? lastObservedTimestamp(input);
|
|
86
|
-
const configuredCores = Number.parseInt(input.app?.config?.['spark.executor.cores'] ?? '', 10);
|
|
87
110
|
const memoryMiB = executorMemoryMiB(input.app);
|
|
88
111
|
|
|
89
112
|
let coreMs = 0;
|
|
90
113
|
let memoryMiBMs = 0;
|
|
114
|
+
let aliveMsTotal = 0;
|
|
91
115
|
let coresKnown = true;
|
|
92
|
-
const
|
|
93
|
-
for (const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const aliveMs = Math.max(0, (removal ?? closeAt ?? e.timestamp) - e.timestamp);
|
|
98
|
-
const cores = e.totalCores > 0 ? e.totalCores : Number.isFinite(configuredCores) ? configuredCores : null;
|
|
99
|
-
if (cores == null) coresKnown = false; else coreMs += cores * aliveMs;
|
|
116
|
+
const coreCounts = new Set ();
|
|
117
|
+
for (const { start, end, cores } of alive) {
|
|
118
|
+
const aliveMs = end - start;
|
|
119
|
+
aliveMsTotal += aliveMs;
|
|
120
|
+
if (cores == null) coresKnown = false; else { coreMs += cores * aliveMs; coreCounts.add(cores); }
|
|
100
121
|
memoryMiBMs += (memoryMiB ?? 0) * aliveMs;
|
|
101
122
|
}
|
|
123
|
+
const startTime = input.app?.startTime;
|
|
124
|
+
const windowMs = closeAt != null && startTime != null ? closeAt - startTime : 0;
|
|
125
|
+
const firstRemovals = alive.flatMap((a) => (a.removedAt == null ? [] : [{ executorId: a.executorId, timestamp: a.removedAt }]));
|
|
102
126
|
return {
|
|
103
127
|
coreHours: coresKnown ? coreMs / MS_PER_HOUR : null,
|
|
104
128
|
memoryGbHours: memoryMiB != null ? memoryMiBMs / MIB_PER_GIB / MS_PER_HOUR : null,
|
|
129
|
+
dynamicAllocation,
|
|
130
|
+
executorsPeak: computePeakConcurrentExecutorCount(alive.map((a) => ({ executorId: a.executorId, timestamp: a.start })), firstRemovals),
|
|
131
|
+
executorsMean: windowMs > 0 ? aliveMsTotal / windowMs : null,
|
|
132
|
+
executorCores: coresKnown && coreCounts.size === 1 ? [...coreCounts][0] : null,
|
|
133
|
+
executorSeconds: aliveMsTotal / MS_PER_SECOND,
|
|
105
134
|
};
|
|
106
135
|
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
// Each executor's alive interval: from its ExecutorAdded timestamp to its first later
|
|
147
|
+
// ExecutorRemoved timestamp, else the application end, else the last timestamp the log records.
|
|
148
|
+
// The one definition computeAllocation and allocatedCoreMsWithin share.
|
|
149
|
+
function aliveIntervals(input ) {
|
|
150
|
+
const removedAt = new Map ();
|
|
151
|
+
for (const e of input.executors.removed) {
|
|
152
|
+
const times = removedAt.get(e.executorId);
|
|
153
|
+
if (times) times.push(e.timestamp); else removedAt.set(e.executorId, [e.timestamp]);
|
|
154
|
+
}
|
|
155
|
+
const closeAt = input.app?.endTime ?? lastObservedTimestamp(input);
|
|
156
|
+
const configuredCores = Number.parseInt(effectiveSparkConf({ sparkVersion: input.app?.sparkVersion, properties: input.app?.config }, 'spark.executor.cores')?.value ?? '', 10);
|
|
157
|
+
const out = [];
|
|
158
|
+
const seen = new Set ();
|
|
159
|
+
for (const e of input.executors.added) {
|
|
160
|
+
if (seen.has(e.executorId)) continue; // a replayed ExecutorAdded is the same executor
|
|
161
|
+
seen.add(e.executorId);
|
|
162
|
+
const removal = (removedAt.get(e.executorId) ?? []).filter((t) => t >= e.timestamp).sort((a, b) => a - b)[0] ?? null;
|
|
163
|
+
out.push({
|
|
164
|
+
executorId: e.executorId,
|
|
165
|
+
start: e.timestamp,
|
|
166
|
+
end: Math.max(e.timestamp, removal ?? closeAt ?? e.timestamp),
|
|
167
|
+
removedAt: removal,
|
|
168
|
+
cores: e.totalCores != null && e.totalCores > 0 ? e.totalCores : Number.isFinite(configuredCores) ? configuredCores : null,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Allocated core-milliseconds: the figure behind `coreHours`, the capacity idle-core figures are
|
|
175
|
+
* measured against. Null when the log has no executor events or an executor's cores are unknown. */
|
|
176
|
+
export function allocatedCoreMs(input ) {
|
|
177
|
+
const { coreHours } = computeAllocation(input);
|
|
178
|
+
return coreHours != null && coreHours > 0 ? coreHours * MS_PER_HOUR : null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** The part of the allocated core-milliseconds held inside `windows` (disjoint, sorted
|
|
182
|
+
* intervals, such as the union of the stages' windows), counted from the same alive intervals as
|
|
183
|
+
* `allocatedCoreMs`. Null when `allocatedCoreMs` is. */
|
|
184
|
+
export function allocatedCoreMsWithin(input , windows ) {
|
|
185
|
+
if (allocatedCoreMs(input) == null) return null;
|
|
186
|
+
let coreMs = 0;
|
|
187
|
+
for (const { start, end, cores } of aliveIntervals(input)) {
|
|
188
|
+
for (const [from, to] of windows) {
|
|
189
|
+
coreMs += (cores ?? 0) * Math.max(0, Math.min(end, to) - Math.max(start, from));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return coreMs;
|
|
193
|
+
}
|
package/vendor-core/analyzer.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { DETECTORS, ENTRY_BY_TYPE, } from './detectors.js';
|
|
1
|
+
import { DETECTORS, ENTRY_BY_TYPE, hasStageOutsideSql, skewThresholdsFor, } from './detectors.js';
|
|
2
2
|
import { effectiveThresholds, findingTunedThresholds, overridesFor, tunedThresholdsNote } from './threshold-overrides.js';
|
|
3
3
|
import { computePeakConcurrentCores } from './core-count.js';
|
|
4
4
|
import { assertNever } from './assert-never.js';
|
|
5
5
|
import { estimateImpact, } from './impact-estimator.js';
|
|
6
6
|
import { computeOccupancy, } from './occupancy.js';
|
|
7
7
|
import { deriveImpactBand, IMPACT_FLOOR_PCT_CRIT, IMPACT_FLOOR_PCT_WARN, } from './impact-band.js';
|
|
8
|
-
import { IMPACT_BAND_ORDER } from './format-utils.js';
|
|
8
|
+
import { IMPACT_BAND_ORDER, MS_PER_CORE_HOUR } from './format-utils.js';
|
|
9
|
+
import { computeWastedCoreHours } from './wasted-core-hours.js';
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
@@ -17,7 +18,7 @@ const detectors = DETECTORS;
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
|
|
@@ -33,8 +34,8 @@ function fnv1a(str ) {
|
|
|
33
34
|
return (h >>> 0).toString(16).padStart(8, '0');
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
// The id hash's discriminator slots, in
|
|
37
|
-
//
|
|
37
|
+
// The id hash's discriminator slots, in join order: reordering or renaming one changes every
|
|
38
|
+
// finding id, which needs an EVIDENCE_SCHEMA_VERSION bump.
|
|
38
39
|
const DISCRIMINATOR_SLOTS = [
|
|
39
40
|
'host', 'executorId', 'rule', 'variant', 'dimension',
|
|
40
41
|
'direction', 'nodeName', 'rootName', 'subtreeSize', 'groupIndex', 'largerSideBytes',
|
|
@@ -43,16 +44,11 @@ const DISCRIMINATOR_SLOTS = [
|
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
// Per type, the fields that tell apart sibling findings sharing one location and metric; without
|
|
46
|
-
// them those siblings hash to one id:
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// uniqueness guarantee: rootName+subtreeSize can collide across groups),
|
|
52
|
-
// underBroadcast (value+largerSideBytes per node/side).
|
|
53
|
-
// memoryUtilization leaves out `rule`: one heap band per executor, so executorId is already
|
|
54
|
-
// unique and folding rule in risks id churn if band logic changes. partitionSizing keeps
|
|
55
|
-
// `rule`: a stage can emit several rules at once sharing stageId+metric.
|
|
47
|
+
// them those siblings hash to one id (see detector-contract.md, Finding ids). Notes:
|
|
48
|
+
// duplicatePlanSubtree's groupIndex is the real uniqueness guarantee (rootName+subtreeSize can
|
|
49
|
+
// collide across groups); memoryUtilization leaves out `rule` because its one heap band sits on
|
|
50
|
+
// the busiest executor, so executorId is already unique; partitionSizing keeps `rule` because a
|
|
51
|
+
// stage can emit several rules at once sharing stageId+metric.
|
|
56
52
|
const ID_DISCRIMINATORS = {
|
|
57
53
|
skew: [], stageShape: ['rule'], shuffle: [], partitionSizing: ['rule'], spill: [], gc: ['direction'],
|
|
58
54
|
slowHost: ['host', 'executorId', 'variant', 'dimension'], stageSlowness: [], stageFailed: ['variant'],
|
|
@@ -62,6 +58,8 @@ const ID_DISCRIMINATORS
|
|
|
62
58
|
cachingOpportunity: ['variant', 'relation', 'format', 'operator', 'executionIds'],
|
|
63
59
|
jobFailureRate: [], configAudit: [],
|
|
64
60
|
duplicatePlanSubtree: ['rootName', 'subtreeSize', 'groupIndex'], smallFiles: ['direction', 'nodeName'],
|
|
61
|
+
pythonUdf: [],
|
|
62
|
+
nestedLoopJoin: ['nodeName'],
|
|
65
63
|
underBroadcast: ['largerSideBytes'], overBroadcast: [],
|
|
66
64
|
};
|
|
67
65
|
|
|
@@ -88,35 +86,6 @@ export function findingId(f ) {
|
|
|
88
86
|
return fnv1a(`${f.type}|${locationKey(f)}|${f.metric ?? ''}|${f.value ?? f.valueText ?? ''}|${disc}`);
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
// skew (either branch) and straggler both claim the stage's replayed tail recovery
|
|
92
|
-
// (tailReplayRecoveryMs via tailRecoveryMs): the same slow-task tail reported by two detectors
|
|
93
|
-
// (see "Overlap caveat: skew / straggler" in impact-estimation/caveats-tuning-and-coverage.md). skew's branch only changes
|
|
94
|
-
// the fallback single-task delta on a stage without the replay, so every skew + straggler pair
|
|
95
|
-
// on a stage is flagged. Flags both sides via validationRequired (rather than suppressing
|
|
96
|
-
// either) so neither finding's own diagnostic value is lost; the flag rides the same
|
|
97
|
-
// confidence-caveat UI a reader already sees before trusting either finding's magnitude.
|
|
98
|
-
function overlapNote(otherType ) {
|
|
99
|
-
return `This overlaps with the ${otherType} finding on this stage: both measure the same slow-task tail, so don't add their recoverable-time figures together.`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function flagSkewStragglerOverlap(findings ) {
|
|
103
|
-
const skewStages = new Set(
|
|
104
|
-
findings.filter((f) => f.type === 'skew' && f.stageId != null).map((f) => f.stageId),
|
|
105
|
-
);
|
|
106
|
-
if (skewStages.size === 0) return;
|
|
107
|
-
const stragglerStages = new Set(
|
|
108
|
-
findings.filter((f) => f.type === 'straggler' && f.stageId != null).map((f) => f.stageId),
|
|
109
|
-
);
|
|
110
|
-
const overlapStages = new Set([...skewStages].filter((id) => stragglerStages.has(id)));
|
|
111
|
-
if (overlapStages.size === 0) return;
|
|
112
|
-
for (const f of findings) {
|
|
113
|
-
if (f.stageId == null || !overlapStages.has(f.stageId)) continue;
|
|
114
|
-
const note = f.type === 'skew' ? overlapNote('straggler') : f.type === 'straggler' ? overlapNote('skew') : null;
|
|
115
|
-
if (!note) continue;
|
|
116
|
-
f.validationRequired = [f.validationRequired, note].filter(Boolean).join(' ');
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
89
|
function push(out , entry , result , tuned = null) {
|
|
121
90
|
if (!result) return;
|
|
122
91
|
const detectorVersion = entry.version ?? 1;
|
|
@@ -176,6 +145,57 @@ function applySuppression(out ) {
|
|
|
176
145
|
return out.filter((f) => f.stageId == null || !dropped.get(f.type)?.has(f.stageId));
|
|
177
146
|
}
|
|
178
147
|
|
|
148
|
+
// Advice to lower spark.executor.memory (over-provisioned heap, low GC, idle memory-time) contradicts
|
|
149
|
+
// advice to raise it (high GC, spill, a GC-bound straggler tail) where a stage is short of memory.
|
|
150
|
+
// A stage-level lowering finding on the same stage as raising advice is dropped. A run-level one
|
|
151
|
+
// (heap, idle memory-time) stays, since other stages may well have memory to spare, but its advice
|
|
152
|
+
// to lower memory is replaced by a note naming the stages that ask for more.
|
|
153
|
+
const EXECUTOR_MEMORY_KEY = 'spark.executor.memory';
|
|
154
|
+
|
|
155
|
+
function changesExecutorMemory(f , direction ) {
|
|
156
|
+
return (f.remediation ?? []).some((r) => r.kind === 'conf' && r.key === EXECUTOR_MEMORY_KEY && r.direction === direction);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function reconcileExecutorMemoryAdvice(out ) {
|
|
160
|
+
const raising = out.filter((f) => changesExecutorMemory(f, 'increase'));
|
|
161
|
+
if (raising.length === 0) return out;
|
|
162
|
+
const raisingStages = new Set(raising.flatMap((f) => (f.stageId != null ? [f.stageId] : [])));
|
|
163
|
+
const stageList = [...raisingStages].sort((a, b) => a - b).join(', ');
|
|
164
|
+
const conflict = raisingStages.size > 0
|
|
165
|
+
? `Stage${raisingStages.size === 1 ? '' : 's'} ${stageList} ask${raisingStages.size === 1 ? 's' : ''} for more executor memory, so confirm before lowering it.`
|
|
166
|
+
: 'Other findings ask for more executor memory, so confirm before lowering it.';
|
|
167
|
+
const reconciled = [];
|
|
168
|
+
for (const f of out) {
|
|
169
|
+
if (!changesExecutorMemory(f, 'decrease') || changesExecutorMemory(f, 'increase')) { reconciled.push(f); continue; }
|
|
170
|
+
if (f.stageId != null) {
|
|
171
|
+
if (!raisingStages.has(f.stageId)) reconciled.push(f);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
reconciled.push({
|
|
175
|
+
...f,
|
|
176
|
+
recommendation: `${f.recommendation ?? ''} ${conflict}`.trim(),
|
|
177
|
+
remediation: (f.remediation ?? []).filter((r) => !(r.kind === 'conf' && r.key === EXECUTOR_MEMORY_KEY && r.direction === 'decrease')),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return reconciled;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// The run's idle core-ms (the Wasted core-hours figure), the ceiling for one stage's idle claim.
|
|
184
|
+
function runIdleCoreMs(
|
|
185
|
+
app ,
|
|
186
|
+
executorsAdded ,
|
|
187
|
+
executorsRemoved ,
|
|
188
|
+
runAggregates ,
|
|
189
|
+
) {
|
|
190
|
+
const { wastedCoreHours } = computeWastedCoreHours(
|
|
191
|
+
app,
|
|
192
|
+
executorsAdded ,
|
|
193
|
+
runAggregates,
|
|
194
|
+
executorsRemoved ,
|
|
195
|
+
);
|
|
196
|
+
return wastedCoreHours == null ? null : wastedCoreHours * MS_PER_CORE_HOUR;
|
|
197
|
+
}
|
|
198
|
+
|
|
179
199
|
// `app` widened to `SparkAppInfo | null` to match real callers (AppModel.app is
|
|
180
200
|
// nullable at the type level); every detector below tolerates a null app.
|
|
181
201
|
export function analyze(
|
|
@@ -203,6 +223,7 @@ export function analyze(
|
|
|
203
223
|
const impact = {
|
|
204
224
|
stages, totalCores, sql,
|
|
205
225
|
occupancy: computeOccupancy(stages , totalCores),
|
|
226
|
+
runIdleCoreMs: runIdleCoreMs(app, executorsAdded, executorsRemoved, runAggregates),
|
|
206
227
|
};
|
|
207
228
|
// The one cast from the posted-model types to the detector-side shapes: types.ts's Stage and
|
|
208
229
|
// SqlExecution carry a catch-all index signature, while every field DetectorStage/DetectorSqlExec
|
|
@@ -211,6 +232,7 @@ export function analyze(
|
|
|
211
232
|
app, jobs, executorsAdded, executorsRemoved, runAggregates, impact,
|
|
212
233
|
stages: stages ,
|
|
213
234
|
sql: sql ,
|
|
235
|
+
skewThresholds: skewThresholdsFor(thresholds),
|
|
214
236
|
};
|
|
215
237
|
const out = [];
|
|
216
238
|
for (const d of detectors) {
|
|
@@ -238,11 +260,10 @@ export function analyze(
|
|
|
238
260
|
assertNever(d);
|
|
239
261
|
}
|
|
240
262
|
}
|
|
241
|
-
const findings = applySuppression(out);
|
|
263
|
+
const findings = reconcileExecutorMemoryAdvice(applySuppression(out));
|
|
242
264
|
estimateImpact(findings, impact);
|
|
243
265
|
noteTunedThresholds(findings);
|
|
244
266
|
deriveImpactBand(findings, app, thresholds ? (type) => bandFloors(type, thresholds) : undefined);
|
|
245
|
-
flagSkewStragglerOverlap(findings);
|
|
246
267
|
// Ascending IMPACT_BAND_ORDER (critical 0 -> info 2) puts the worst band first;
|
|
247
268
|
// stable sort keeps DETECTORS declaration order within a band.
|
|
248
269
|
findings.sort((a, b) => IMPACT_BAND_ORDER[a.impactBand] - IMPACT_BAND_ORDER[b.impactBand]);
|
|
@@ -250,14 +271,17 @@ export function analyze(
|
|
|
250
271
|
}
|
|
251
272
|
|
|
252
273
|
// Memoizes auditConfig by `app` identity (like evidence-report.ts's jsonCache) so config detectors
|
|
253
|
-
// don't re-run when both the export and the report path audit the same app.
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
|
|
274
|
+
// don't re-run when both the export and the report path audit the same app. The one stage-dependent
|
|
275
|
+
// check reads only whether any stage ran outside SQL, so that flag is part of the cache entry: a
|
|
276
|
+
// hit with a different flag recomputes. WeakMap can't key on `null`, so that case skips the cache.
|
|
277
|
+
// Returns a fresh copy each call so a caller's in-place mutation (e.g. `.sort()`) can't corrupt the
|
|
278
|
+
// cached array.
|
|
279
|
+
const auditConfigCache = new WeakMap ();
|
|
257
280
|
|
|
258
|
-
function computeAuditConfig(app ) {
|
|
281
|
+
function computeAuditConfig(app , stages ) {
|
|
259
282
|
const out = [];
|
|
260
|
-
|
|
283
|
+
const target = { app, stages: stages };
|
|
284
|
+
for (const d of detectors) if (d.scope === 'config') push(out, d, d.withThresholds()(target));
|
|
261
285
|
// configAudit's estimate is unconditionally costOnly('none'): needs no stages/totalCores, so an
|
|
262
286
|
// empty context gives parity with analyze().
|
|
263
287
|
estimateImpact(out, { stages: new Map(), occupancy: new Map(), totalCores: 0 });
|
|
@@ -265,11 +289,14 @@ function computeAuditConfig(app ) {
|
|
|
265
289
|
return out.map((f) => ({ ...f, stageId: f.stageId ?? null }));
|
|
266
290
|
}
|
|
267
291
|
|
|
268
|
-
|
|
269
|
-
|
|
292
|
+
/** The configuration findings for a run. `stages` lets checks that apply only to some kinds of
|
|
293
|
+
* work (the serializer note needs RDD stages) see the run's work; without it they stay silent. */
|
|
294
|
+
export function auditConfig(app , stages ) {
|
|
295
|
+
if (app === null) return computeAuditConfig(app, stages);
|
|
296
|
+
const rddWork = hasStageOutsideSql(stages );
|
|
270
297
|
const cached = auditConfigCache.get(app);
|
|
271
|
-
if (cached) return cached.slice();
|
|
272
|
-
const
|
|
273
|
-
auditConfigCache.set(app,
|
|
274
|
-
return
|
|
298
|
+
if (cached?.rddWork === rddWork) return cached.findings.slice();
|
|
299
|
+
const findings = computeAuditConfig(app, stages);
|
|
300
|
+
auditConfigCache.set(app, { rddWork, findings });
|
|
301
|
+
return findings.slice();
|
|
275
302
|
}
|
|
@@ -74,6 +74,9 @@ export function apiMergeWrites(sql )
|
|
|
74
74
|
kind: resolved?.kind ?? null,
|
|
75
75
|
target: resolved?.target ?? null,
|
|
76
76
|
outputRows: null,
|
|
77
|
+
outputRowsSource: null,
|
|
78
|
+
outputBytes: null,
|
|
79
|
+
mergeRows: null,
|
|
77
80
|
raw: `Delta MERGE operation, executions ${span}${group.unclean ? ` (${group.unclean})` : ''}`,
|
|
78
81
|
};
|
|
79
82
|
});
|