sparkforensics-server 0.5.1 → 0.6.0
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/package.json +1 -1
- package/public/assets/AutoscalingChurn-CRA2Mb7F.js +1 -0
- package/public/assets/CacheUtilization-Bh9OY_V9.js +1 -0
- package/public/assets/CachingOpportunity-oCiQwmTJ.js +1 -0
- package/public/assets/{ColdStart-B38OiAOp.js → ColdStart-BJrtjfmn.js} +1 -1
- package/public/assets/ConfigAudit-DMvKxySP.js +1 -0
- package/public/assets/CoreUsageArea-REC2zsKw.js +1 -0
- package/public/assets/Dashboard-BHZ76JCu.js +2 -0
- package/public/assets/DisclosureContext-OO7X1HAx.js +1 -0
- package/public/assets/{DuplicatePlanSubtree-BqS2A2j4.js → DuplicatePlanSubtree-BgG-L-cK.js} +1 -1
- package/public/assets/ExecutorUtilization-D2KhSVbY.js +1 -0
- package/public/assets/{GcPressure-CT1yzR_s.js → GcPressure-D1BTE8qh.js} +1 -1
- package/public/assets/{IncompleteRun-C7Qkjtjn.js → IncompleteRun-DD40xUpy.js} +1 -1
- package/public/assets/{JobFailures-WHl3ELfh.js → JobFailures-YwNzCF19.js} +1 -1
- package/public/assets/MemoryUtilization-9b8ee_3_.js +1 -0
- package/public/assets/{OverBroadcast-6oSSAQ_R.js → OverBroadcast-CfctS8a8.js} +1 -1
- package/public/assets/PartitionSizing-VG8kBgG5.js +1 -0
- package/public/assets/{PlanExplorer-DcxmiQWL.js → PlanExplorer-DmubTAOP.js} +1 -1
- package/public/assets/PlanGraphRoute-DctPZjS0.js +1 -0
- package/public/assets/RetryWaste-CnpM8bB7.js +1 -0
- package/public/assets/{ShuffleIO-CRhrYNE0.js → ShuffleIO-D13vGmas.js} +1 -1
- package/public/assets/Skew-DlagstYP.js +1 -0
- package/public/assets/SlowHost-cSkLRZ_e.js +1 -0
- package/public/assets/{SmallFiles-C082c2rd.js → SmallFiles-B-kERMcq.js} +1 -1
- package/public/assets/{SpeculationWaste-BS2vpadr.js → SpeculationWaste-DaysAzXO.js} +1 -1
- package/public/assets/Spill-H44Gz4US.js +1 -0
- package/public/assets/{StageFailed-D3ac9Sou.js → StageFailed-DCfii9h_.js} +1 -1
- package/public/assets/StageFindingGroup-BXJ0Mj5n.js +1 -0
- package/public/assets/{StageHeader-pI1nTwVf.js → StageHeader--oN2J-oD.js} +1 -1
- package/public/assets/StageShape-IZ80CZiJ.js +1 -0
- package/public/assets/{StageSlowness-BaNyfNvL.js → StageSlowness--BRIaBc1.js} +1 -1
- package/public/assets/Straggler-Ctq0Df_o.js +1 -0
- package/public/assets/TaskFailures-Bks_gqhL.js +1 -0
- package/public/assets/{TinyTask-8_5lpq_2.js → TinyTask-BssfzGFB.js} +1 -1
- package/public/assets/{UnderBroadcast-DJ0XSwth.js → UnderBroadcast-DsScrxc-.js} +1 -1
- package/public/assets/{finding-anchor-Cys8Z6Yn.js → finding-anchor-BYW1oz5R.js} +1 -1
- package/public/assets/{impact-sort-BTQndbof.js → impact-sort-xzy0g-Vh.js} +1 -1
- package/public/assets/index-DhpRGMZc.css +2 -0
- package/public/assets/index-DwqkFUFk.js +14 -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/{parser-worker-DmeCnLWU.js → parser-worker-CA5RxqKc.js} +8 -8
- package/public/assets/react-vendor-DfpuPQZf.js +9 -0
- package/public/assets/{select-DIYN6D3y.js → select-C8edjYTq.js} +1 -1
- package/public/assets/{usePagedRows-BxvdFnPk.js → usePagedRows-CsuUFeYx.js} +1 -1
- package/public/assets/useRecentFiles-BvkKo3JN.js +11 -0
- package/public/assets/{useSortMode-B8SRfAoG.js → useSortMode-joX71BZN.js} +1 -1
- package/public/docs/404.html +3 -7
- package/public/docs/assets/{app.D2GqAkhy.js → app.CnWL6bKV.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.tE5pz54z.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.BS4cSmtW.js → VPLocalSearchBox.C0IBKeRQ.js} +1 -1
- package/public/docs/assets/chunks/{theme.BuxVpb0H.js → theme.BH-2HuRf.js} +2 -2
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.8bH1HnZp.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.wj6Et6UD.js → contributor-guide_architecture_detector-contract.md.N4hhenrA.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.DfvbqEUu.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation.md.CZv_ZGOp.lean.js → contributor-guide_architecture_impact-estimation.md.DfvbqEUu.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.js → contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.js} +1 -1
- 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.Cwm1jHmn.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_state-and-history_run-comparison-internals.md.uuAKpY0Y.lean.js → contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.js} +1 -1
- package/public/docs/assets/{contributor-guide_development-setup.md.D9bu4j_c.js → contributor-guide_development-setup.md.DQdzera7.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.CyK9Ss73.css +1 -0
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.BEepbDDL.js +24 -0
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.BEepbDDL.lean.js +1 -0
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.CPowlb2q.js → user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js} +3 -2
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.CPowlb2q.lean.js → user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.Dq5Azk8G.js → user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js} +2 -2
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.Dq5Azk8G.lean.js → user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.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.BUALkohi.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +1 -0
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.DSXGu2tA.js +1 -0
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.DSXGu2tA.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.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 +4 -8
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -10
- package/public/docs/contributor-guide/architecture/board-widgets.html +4 -8
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +4 -8
- 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 +4 -8
- package/public/docs/contributor-guide/architecture/drill-down.html +4 -8
- 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 +4 -8
- package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -10
- package/public/docs/contributor-guide/architecture/index.html +4 -8
- package/public/docs/contributor-guide/architecture/overview.html +4 -8
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +4 -8
- 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 +4 -8
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +4 -8
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +4 -8
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +4 -8
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +4 -8
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +4 -8
- package/public/docs/contributor-guide/architecture/widget-rendering.html +4 -8
- 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 +4 -8
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +4 -8
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol.html +4 -8
- package/public/docs/contributor-guide/contributing.html +4 -8
- package/public/docs/contributor-guide/development-setup.html +6 -10
- package/public/docs/contributor-guide/testing.html +4 -8
- package/public/docs/favicon.svg +2 -2
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +4 -8
- package/public/docs/tuning-reference/anti-patterns.html +4 -8
- package/public/docs/tuning-reference/aqe.html +4 -8
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +4 -8
- package/public/docs/tuning-reference/bottleneck-cold-start.html +4 -8
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +4 -8
- package/public/docs/tuning-reference/bottleneck-failures.html +4 -8
- package/public/docs/tuning-reference/bottleneck-gc.html +4 -8
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +4 -8
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +4 -8
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +4 -8
- package/public/docs/tuning-reference/bottleneck-shuffle.html +4 -8
- package/public/docs/tuning-reference/bottleneck-skew.html +4 -8
- package/public/docs/tuning-reference/bottleneck-slow-host.html +4 -8
- package/public/docs/tuning-reference/bottleneck-small-files.html +4 -8
- package/public/docs/tuning-reference/bottleneck-spill.html +4 -8
- package/public/docs/tuning-reference/bottleneck-straggler.html +4 -8
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +4 -8
- package/public/docs/tuning-reference/bottleneck-utilization.html +4 -8
- package/public/docs/tuning-reference/caching.html +4 -8
- package/public/docs/tuning-reference/cluster-config.html +4 -8
- package/public/docs/tuning-reference/config.html +4 -8
- package/public/docs/tuning-reference/data-formats.html +4 -8
- package/public/docs/tuning-reference/index.html +5 -9
- package/public/docs/tuning-reference/intro.html +4 -8
- package/public/docs/tuning-reference/joins.html +4 -8
- package/public/docs/tuning-reference/memory-model.html +4 -8
- package/public/docs/tuning-reference/metrics.html +4 -8
- package/public/docs/tuning-reference/partitioning.html +4 -8
- package/public/docs/tuning-reference/pyspark.html +4 -8
- package/public/docs/tuning-reference/shuffle.html +4 -8
- package/public/docs/tuning-reference/spark-architecture.html +4 -8
- package/public/docs/tuning-reference/table-formats.html +4 -8
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +4 -8
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +4 -8
- package/public/docs/user-guide/alternative-log-retrieval.html +4 -8
- package/public/docs/user-guide/getting-started/ci-and-automation.html +11 -13
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +4 -8
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +4 -8
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +4 -8
- package/public/docs/user-guide/getting-started.html +4 -8
- package/public/docs/user-guide/mcp-tools/compare-runs.html +8 -11
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +4 -8
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -10
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +4 -8
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +4 -8
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +4 -8
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +6 -10
- package/public/docs/user-guide/mcp-tools/list-runs.html +4 -8
- package/public/docs/user-guide/mcp-tools.html +4 -8
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +6 -10
- 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 +4 -7
- package/vendor-core/allocation.js +105 -20
- package/vendor-core/api-merge-writes.js +1 -0
- package/vendor-core/cli/budgets.js +62 -2
- package/vendor-core/cli/regression-budgets.js +35 -0
- package/vendor-core/comparison-output.js +2 -1
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/delta-log-paths.js +10 -1
- package/vendor-core/detectors.js +290 -92
- package/vendor-core/docs-content/detection/chrn.md +3 -1
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/mem.md +1 -1
- package/vendor-core/docs-content/detection/plan.md +9 -2
- package/vendor-core/docs-content/detection/shfl.md +8 -2
- package/vendor-core/docs-content/detection/skew.md +12 -5
- package/vendor-core/docs-content/detection/slow.md +6 -2
- package/vendor-core/docs-content/detection/spill.md +4 -1
- package/vendor-core/docs-content/detection/strag.md +5 -3
- package/vendor-core/docs-content/detection/tiny.md +3 -2
- package/vendor-core/docs-content/detection/util.md +6 -2
- package/vendor-core/efficiency-model.js +22 -14
- package/vendor-core/evidence-report.js +11 -11
- package/vendor-core/finding-presentation.js +52 -19
- package/vendor-core/finding-types.js +71 -16
- package/vendor-core/impact-model.js +2 -2
- package/vendor-core/mcp-server-factory.js +6 -2
- package/vendor-core/mcp-tools.js +10 -1
- package/vendor-core/median.js +8 -0
- package/vendor-core/remediation.js +10 -5
- package/vendor-core/run-comparison.js +2 -0
- package/vendor-core/run-output.js +14 -3
- package/vendor-core/sequence-alignment.js +83 -0
- package/vendor-core/stage-alignment.js +387 -63
- package/vendor-core/stage-quantiles.js +3 -1
- package/vendor-core/stage-structure.js +83 -0
- package/vendor-core/types.js +12 -2
- package/vendor-core/wall-clock.js +8 -0
- package/vendor-core/wasted-core-hours.js +12 -11
- package/vendor-core/write-targets.js +32 -0
- package/public/assets/AutoscalingChurn-5hDGIXi4.js +0 -1
- package/public/assets/CacheUtilization-CT2SCnJJ.js +0 -1
- package/public/assets/CachingOpportunity-D_O_WkbH.js +0 -1
- package/public/assets/ConfigAudit-BoplryCH.js +0 -1
- package/public/assets/CoreUsageArea-csgwNxkl.js +0 -1
- package/public/assets/Dashboard-BgKodJl2.js +0 -2
- package/public/assets/DisclosureContext-B0siMVdg.js +0 -1
- package/public/assets/ExecutorUtilization-Dp52QGWo.js +0 -1
- package/public/assets/MemoryUtilization-D8IUDHJI.js +0 -1
- package/public/assets/PartitionSizing-BwdFL-mw.js +0 -1
- package/public/assets/PlanGraphRoute-pqnHTt4i.js +0 -1
- package/public/assets/RetryWaste-BTbeHkJc.js +0 -1
- package/public/assets/Skew-DSNXRG9V.js +0 -1
- package/public/assets/SlowHost-B7Lwu2EU.js +0 -1
- package/public/assets/Spill-B4DVKHXx.js +0 -1
- package/public/assets/StageFindingGroup-D9naK109.js +0 -1
- package/public/assets/StageShape-eO5le8iG.js +0 -1
- package/public/assets/Straggler-D5Fnok_y.js +0 -1
- package/public/assets/TaskFailures-BWnC-K_G.js +0 -1
- package/public/assets/index-BcqTLKFp.css +0 -2
- package/public/assets/index-DCeWge12.js +0 -13
- package/public/assets/react-vendor-DEdfrRTJ.js +0 -9
- package/public/assets/useRecentFiles-C3Ov47U7.js +0 -11
- package/public/docs/assets/chunks/@localSearchIndexroot.D4OdkQjy.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_detector-contract_threshold-tables.md.fkPBXsU2.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_state-and-history_run-comparison-internals.md.uuAKpY0Y.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.Dk08VS7n.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.DpnfKz3x.js +0 -22
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.DpnfKz3x.lean.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.B6aNtDYF.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.B6aNtDYF.lean.js +0 -1
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.XBzQ1oEU.js +0 -1
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.XBzQ1oEU.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.Dqt2H_C1.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.Dqt2H_C1.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.CQgn1t_M.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.lean.js → contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.wj6Et6UD.lean.js → contributor-guide_architecture_detector-contract.md.N4hhenrA.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.fkPBXsU2.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.Dk08VS7n.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.lean.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_development-setup.md.D9bu4j_c.lean.js → contributor-guide_development-setup.md.DQdzera7.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
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
Executors are stood up and torn down again before they can do useful work:
|
|
4
4
|
re-provisioning churn rather than normal scale-down. Raise
|
|
5
5
|
`spark.dynamicAllocation.executorIdleTimeout`, or widen the
|
|
6
|
-
`minExecutors`/`maxExecutors` bounds to reduce flapping.
|
|
6
|
+
`minExecutors`/`maxExecutors` bounds to reduce flapping. With dynamic
|
|
7
|
+
allocation off (`evidence.dynamicAllocation` is `off`) none of those applies:
|
|
8
|
+
the churn is executor loss or preemption, and `remediation` is empty. Self-flags a
|
|
7
9
|
confidence that scales with how far the short-lived-executor share sits
|
|
8
10
|
past the threshold.
|
|
@@ -3,4 +3,5 @@
|
|
|
3
3
|
The first stage waited more than 30 s for an executor. Keep a warm pool of
|
|
4
4
|
executors, or, with dynamic allocation, raise
|
|
5
5
|
`spark.dynamicAllocation.minExecutors`/`initialExecutors` so the app doesn't
|
|
6
|
-
scale up from zero.
|
|
6
|
+
scale up from zero. With dynamic allocation off (`evidence.dynamicAllocation`
|
|
7
|
+
is `off`) no executor-count property applies and `remediation` is empty.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
### `MEM`: Memory utilization {#mem}
|
|
2
2
|
|
|
3
3
|
Executor memory or core capacity may be over- or under-provisioned: more
|
|
4
|
-
than 50% of
|
|
4
|
+
than 50% of allocated core time ran no task, an executor's heap peaked above
|
|
5
5
|
95% of its allocation, or it stayed below 70%. Some
|
|
6
6
|
detail here needs `spark.eventLog.logStageExecutorMetrics=true` on the run
|
|
7
7
|
being analyzed; without it, per-executor memory usage can't be broken down.
|
|
@@ -11,7 +11,14 @@ this tag:
|
|
|
11
11
|
under 3 MB. Compact upstream output, or coalesce before writing.
|
|
12
12
|
- Under-broadcast: the smaller side of a Sort Merge Join looks well under
|
|
13
13
|
the broadcast threshold; consider a `broadcast()` hint or raising
|
|
14
|
-
`spark.sql.autoBroadcastJoinThreshold`.
|
|
14
|
+
`spark.sql.autoBroadcastJoinThreshold`. When the effective threshold
|
|
15
|
+
(logged, else Spark's 10 MiB) already admits the smaller side
|
|
16
|
+
(`evidence.broadcastThreshold` is `notLimiting`), the threshold is not what
|
|
17
|
+
stopped the broadcast, so `remediation` is empty and the advice is a hint or
|
|
18
|
+
table statistics.
|
|
15
19
|
- Over-broadcast: a broadcast exceeds the 1 GB threshold; check for a
|
|
16
20
|
misapplied broadcast hint or a misconfigured
|
|
17
|
-
`spark.sql.autoBroadcastJoinThreshold`.
|
|
21
|
+
`spark.sql.autoBroadcastJoinThreshold`. When the effective threshold is
|
|
22
|
+
below the broadcast or auto-broadcast is disabled (`evidence.broadcastThreshold`
|
|
23
|
+
is `notLimiting` or `disabled`), a hint forced it: remove the hint, and
|
|
24
|
+
`remediation` is empty.
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
### `SHFL`: Shuffle I/O {#shfl}
|
|
2
2
|
|
|
3
3
|
Tasks move a large amount of intermediate data between stages. Raise
|
|
4
|
-
`spark.sql.shuffle.partitions`, or add a broadcast join.
|
|
5
|
-
|
|
4
|
+
`spark.sql.shuffle.partitions`, or add a broadcast join. The partition-count
|
|
5
|
+
advice follows the effective conf (`evidence.partitions`): `raise` when the
|
|
6
|
+
property limits the stage, `sufficient` when the tasks already read a good
|
|
7
|
+
size each, `aqeCoalesced` when AQE merged the partitions (lower
|
|
8
|
+
`spark.sql.adaptive.advisoryPartitionSizeInBytes`), and `ownPartitioning` when
|
|
9
|
+
the property is already high enough (the stage's own `repartition(n)` or RDD
|
|
10
|
+
parallelism limits it). Only flagged on stages that take at least 0.5% of the
|
|
11
|
+
run.
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
### `SKEW`: Task skew {#skew}
|
|
2
2
|
|
|
3
3
|
A small number of tasks take much longer than their peers in the same
|
|
4
|
-
stage.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
stage. The fix depends on what the stage reads, which the finding's
|
|
5
|
+
`evidence.origin` records. A stage that reads a shuffle feeding a join
|
|
6
|
+
(`shuffleJoin`) gets AQE skew-join handling
|
|
7
|
+
(`spark.sql.adaptive.skewJoin.enabled`), unless the run's effective conf
|
|
8
|
+
already has it; otherwise salt the key or repartition on a better key. A
|
|
9
|
+
stage that reads files with uneven sizes (`inputScan`) gets compaction of
|
|
10
|
+
small files or a lower `spark.sql.files.maxPartitionBytes`. Any other stage
|
|
11
|
+
(`other`) gets the salting advice and no conf, as a `code` entry in
|
|
12
|
+
`remediation`; so does a join stage whose skew-join handling is already on. Flagged when P95 task time
|
|
13
|
+
(the longest task, on a stage with fewer than 20 tasks) exceeds 3x the median
|
|
14
|
+
and the recoverable tail is at least 0.5% of the run. The median is the
|
|
15
|
+
textbook one: on an even task count, the mean of the two middle values.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
### `SLOW`: Stage slowness {#slow}
|
|
2
2
|
|
|
3
3
|
A stage ran for 15 minutes or more and no slow host was flagged on it. It
|
|
4
|
-
can appear alongside other findings on the same stage.
|
|
4
|
+
can appear alongside other findings on the same stage. On a stage that reads a
|
|
5
|
+
shuffle, often a partition-count problem: raise parallelism via
|
|
5
6
|
`spark.sql.shuffle.partitions` or `spark.default.parallelism`, or check for a
|
|
6
|
-
large per-task data volume driving heavy shuffle and spill.
|
|
7
|
+
large per-task data volume driving heavy shuffle and spill. On a stage that
|
|
8
|
+
reads input files and no shuffle, check input file sizes and lower
|
|
9
|
+
`spark.sql.files.maxPartitionBytes`. `evidence.reads` says which case
|
|
10
|
+
applied (`shuffle`, `input` or `other`).
|
|
@@ -4,4 +4,7 @@ Tasks are writing data out of memory, which slows execution. Two spill
|
|
|
4
4
|
patterns get flagged differently: skew spill, where a few heavy tasks spill
|
|
5
5
|
while most don't (rebalance partitioning), and volume spill, where most
|
|
6
6
|
tasks spill because the data genuinely exceeds available memory (add
|
|
7
|
-
partitions or executor memory).
|
|
7
|
+
partitions or executor memory). `spark.sql.shuffle.partitions` is suggested
|
|
8
|
+
only for a stage that reads a shuffle; `evidence.reads` says what the stage
|
|
9
|
+
reads (`shuffle`, `input` or `other`). Only flagged on stages that take at
|
|
10
|
+
least 0.5% of the run.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
### `STRAG`: Straggler tasks {#strag}
|
|
2
2
|
|
|
3
3
|
A few tasks run much slower than the rest of their stage. Rule out a GC
|
|
4
|
-
pause or a slow shuffle fetch before assuming a hardware issue
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
pause or a slow shuffle fetch before assuming a hardware issue. If uneven
|
|
5
|
+
data is the cause, the advice is the one a skew finding gives for the same
|
|
6
|
+
stage (`evidence.origin`, see `SKEW`): AQE skew-join handling for a shuffle
|
|
7
|
+
feeding a join, file sizes for a scan, salting otherwise. Only flagged on
|
|
8
|
+
stages that take at least 0.5% of the run.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
### `TINY`: Tiny tasks {#tiny}
|
|
2
2
|
|
|
3
3
|
Many very short tasks add scheduling overhead out of proportion to the work
|
|
4
|
-
each one does. Repartition to fewer, larger tasks
|
|
5
|
-
|
|
4
|
+
each one does. Repartition to fewer, larger tasks; a stage that reads a shuffle
|
|
5
|
+
(`evidence.reads` is `shuffle`) can also lower `spark.sql.shuffle.partitions`.
|
|
6
|
+
Only flagged on stages that take at least 0.5% of the run.
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
### `UTIL`: Low utilization {#util}
|
|
2
2
|
|
|
3
|
-
Allocated executors sit idle for a large share of the application run
|
|
4
|
-
|
|
3
|
+
Allocated executors sit idle for a large share of the application run: under
|
|
4
|
+
60% of the core time the run allocated (cores times the time each executor was
|
|
5
|
+
alive) ran a task. Consider a smaller cluster. With dynamic allocation off,
|
|
6
|
+
either lower `spark.executor.instances` or enable dynamic allocation; the two are
|
|
7
|
+
alternatives. With it on, lower `spark.dynamicAllocation.maxExecutors`, and
|
|
8
|
+
`spark.dynamicAllocation.minExecutors` too when the run sets it above 0.
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// §5 Efficiency/wastage model. DESIGN SPIKE:
|
|
2
2
|
// decomposes available compute-hours into driver-bound vs executor-bound waste, plus two floors.
|
|
3
|
-
import {
|
|
3
|
+
import { stageWindows } from './wall-clock.js';
|
|
4
|
+
import { allocatedCoreMs, allocatedCoreMsWithin } from './allocation.js';
|
|
4
5
|
import { computePeakConcurrentCores } from './core-count.js';
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
export function computeEfficiencyModel({ app, stages, executorsAdded, executorsRemoved, runAggregates }
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
|
|
@@ -18,23 +19,25 @@ export function computeEfficiencyModel({ app, stages, executorsAdded, executorsR
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
{
|
|
21
|
-
// Capacity is the
|
|
22
|
-
// use, so the Unused core time tile matches the verdict's
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
22
|
+
// Capacity is the run's allocation (cores x time alive, metrics.allocation.coreHours), the one the
|
|
23
|
+
// utilization and idle-cores detectors use, so the Unused core time tile matches the verdict's
|
|
24
|
+
// idle figure. Peak concurrent cores times the whole run would count cores the run never held
|
|
25
|
+
// under dynamic allocation. Null without executor cores: no capacity, so no figure.
|
|
26
|
+
const input = { app, stages, executors: { added: executorsAdded, removed: executorsRemoved } };
|
|
27
|
+
const allocatedMs = allocatedCoreMs(input);
|
|
28
|
+
// Split by where the allocated cores were held, from the same alive intervals: inside the union
|
|
29
|
+
// of the stages' windows, or outside it (startup, gaps between stages, after the last stage).
|
|
30
|
+
// Executors that join after startup hold no cores there, so spreading the allocation evenly
|
|
31
|
+
// over the run would bill the driver for cores that never existed.
|
|
32
|
+
const allocatedActiveCoreMs = allocatedMs == null ? 0 : allocatedCoreMsWithin(input, stageWindows(stages)) ?? 0;
|
|
28
33
|
|
|
29
|
-
const availableComputeHours =
|
|
34
|
+
const availableComputeHours = (allocatedMs ?? 0) / 3600000;
|
|
30
35
|
|
|
31
|
-
// Driver-bound: cores
|
|
32
|
-
const
|
|
33
|
-
const driverWasteHours = totalCores * (driverIdleMs / 3600000);
|
|
36
|
+
// Driver-bound: cores held while no stage was active (startup, gaps, idle).
|
|
37
|
+
const driverWasteHours = Math.max(0, (allocatedMs ?? 0) - allocatedActiveCoreMs) / 3600000;
|
|
34
38
|
|
|
35
39
|
// Executor-bound: allocated capacity beyond busy cores during stagesActive. Tasks only run in
|
|
36
40
|
// active windows, so whole-run busyCoreMs already lives inside stagesActive.
|
|
37
|
-
const allocatedActiveCoreMs = totalCores * wc.stagesActive;
|
|
38
41
|
const busyCoreMs = runAggregates?.busyCoreMs ?? 0;
|
|
39
42
|
const executorWasteHours = Math.max(0, allocatedActiveCoreMs - busyCoreMs) / 3600000;
|
|
40
43
|
|
|
@@ -44,6 +47,11 @@ export function computeEfficiencyModel({ app, stages, executorsAdded, executorsR
|
|
|
44
47
|
let totalTaskMs = 0;
|
|
45
48
|
const perStage = runAggregates?.perStage ?? {};
|
|
46
49
|
for (const k of Object.keys(perStage)) totalTaskMs += perStage[k].totalTaskDurationSum;
|
|
50
|
+
// The floor is the least time the work takes on the widest the cluster ever was: peak concurrent
|
|
51
|
+
// cores (not the allocation), summing every addition (computeTotalCores) would count a replaced
|
|
52
|
+
// executor's cores alongside its replacement's. `app ?? {}`: callers tolerate a null app
|
|
53
|
+
// (malformed logs); `app!` would crash on app.resources.
|
|
54
|
+
const totalCores = computePeakConcurrentCores(app ?? {}, executorsAdded, executorsRemoved);
|
|
47
55
|
const floorZeroSkewMs = totalCores > 0 ? totalTaskMs / totalCores : 0;
|
|
48
56
|
|
|
49
57
|
let dominantWaste = null;
|
|
@@ -180,29 +180,29 @@ export const EVIDENCE_SCHEMA_VERSION = 5;
|
|
|
180
180
|
// module (stageShape's totalCores, utilization's unrounded fraction) is left off both, so it never
|
|
181
181
|
// reaches the report; adding, renaming or dropping a key here changes the report contract.
|
|
182
182
|
const EVIDENCE_KEYS = {
|
|
183
|
-
skew: [],
|
|
183
|
+
skew: ['origin'],
|
|
184
184
|
stageShape: ['rule'],
|
|
185
|
-
shuffle: [],
|
|
186
|
-
partitionSizing: ['rule'],
|
|
187
|
-
spill: ['spillMagnitude'],
|
|
185
|
+
shuffle: ['partitions'],
|
|
186
|
+
partitionSizing: ['rule', 'origin', 'partitions'],
|
|
187
|
+
spill: ['spillMagnitude', 'reads'],
|
|
188
188
|
gc: ['direction'],
|
|
189
189
|
slowHost: ['variant', 'host', 'hostTaskShare', 'hostMeanMs', 'dimension', 'executorId', 'execMaxValue'],
|
|
190
|
-
stageSlowness: [],
|
|
190
|
+
stageSlowness: ['reads'],
|
|
191
191
|
stageFailed: ['variant', 'numTasks', 'memoryBytesSpilled', 'failedTaskDetails'],
|
|
192
192
|
failures: ['failedTasks', 'dominantReason', 'dominantError', 'failureGroups', 'otherFailedTasks'],
|
|
193
|
-
straggler: ['unit', 'speculativeTasks', 'stragglerCount'],
|
|
193
|
+
straggler: ['unit', 'speculativeTasks', 'stragglerCount', 'origin'],
|
|
194
194
|
speculationWaste: [],
|
|
195
195
|
retryWaste: ['numTasks', 'memoryBytesSpilled', 'retriedTaskDetails'],
|
|
196
|
-
tinyTask: [],
|
|
196
|
+
tinyTask: ['reads'],
|
|
197
197
|
incompleteRun: [],
|
|
198
|
-
coldStart: [],
|
|
198
|
+
coldStart: ['dynamicAllocation'],
|
|
199
199
|
utilization: ['cpuUtilizationPct'],
|
|
200
200
|
memoryUtilization: ['variant', 'rule', 'executorId', 'heap', 'dataUnavailable'],
|
|
201
201
|
cacheUtilization: [
|
|
202
202
|
'variant', 'rddId', 'rddName', 'memorySize', 'diskSize', 'numCachedPartitions', 'numPartitions', 'dataUnavailable',
|
|
203
203
|
],
|
|
204
204
|
coreLocality: ['nonLocalTaskCount'],
|
|
205
|
-
autoscalingChurn: ['shortLivedExecutorCount'],
|
|
205
|
+
autoscalingChurn: ['shortLivedExecutorCount', 'dynamicAllocation'],
|
|
206
206
|
cachingOpportunity: ['variant', 'relation', 'format', 'relations', 'operator', 'executionIds', 'totalReadBytes'],
|
|
207
207
|
jobFailureRate: ['failedJobs', 'totalJobs', 'failedTasks', 'totalTasks', 'avgJobDurationMs', 'taskFailureRate'],
|
|
208
208
|
configAudit: ['property'],
|
|
@@ -211,8 +211,8 @@ const EVIDENCE_KEYS = {
|
|
|
211
211
|
'groupIndex',
|
|
212
212
|
],
|
|
213
213
|
smallFiles: ['executionId', 'stageIds', 'fileCount', 'direction', 'nodeName'],
|
|
214
|
-
underBroadcast: ['executionId', 'stageIds', 'largerSideBytes'],
|
|
215
|
-
overBroadcast: ['executionId', 'stageIds'],
|
|
214
|
+
underBroadcast: ['executionId', 'stageIds', 'largerSideBytes', 'broadcastThreshold'],
|
|
215
|
+
overBroadcast: ['executionId', 'stageIds', 'broadcastThreshold'],
|
|
216
216
|
} ;
|
|
217
217
|
|
|
218
218
|
// The other direction: an evidence field EVIDENCE_KEYS doesn't list fails here.
|
|
@@ -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
|
|
|
@@ -35,7 +35,14 @@ export const shareLabel = (share ) => `${Math.round(share * 1e6)
|
|
|
35
35
|
// a generic line reads the same decision and never recommends a switch the row says is on.
|
|
36
36
|
// A finding with no remediation (older or hand-built data) keeps the property wording.
|
|
37
37
|
function switchAlreadyOn(finding , key ) {
|
|
38
|
-
return finding.remediation != null && !finding.remediation.some((r) => r.key === key);
|
|
38
|
+
return finding.remediation != null && !finding.remediation.some((r) => r.kind === 'conf' && r.key === key);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// The properties an idle-capacity finding lowers once dynamic allocation is on, worded as its row
|
|
42
|
+
// does: the executor cap, and the floor when the row's remediation lowers it too.
|
|
43
|
+
function idleCapacityLowering(f ) {
|
|
44
|
+
const lowersFloor = f.remediation?.some((r) => r.kind === 'conf' && r.key === 'spark.dynamicAllocation.minExecutors');
|
|
45
|
+
return ` by lowering spark.dynamicAllocation.maxExecutors${lowersFloor ? ' and spark.dynamicAllocation.minExecutors' : ''}`;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
48
|
const SKEW_JOIN_KEY = 'spark.sql.adaptive.skewJoin.enabled';
|
|
@@ -43,8 +50,10 @@ const SKEW_JOIN_ALREADY_ON = 'AQE skew-join handling is already on, so salt the
|
|
|
43
50
|
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
51
|
|
|
45
52
|
// The skew-join generic line, worded per the row's remediation: AQE logged off, switch already on, or neither.
|
|
46
|
-
function skewJoinGeneric(f
|
|
47
|
-
if (f.
|
|
53
|
+
function skewJoinGeneric(f , unset ) {
|
|
54
|
+
if (f.origin === 'inputScan') return 'Uneven input files: compact small files or split large ones (lower spark.sql.files.maxPartitionBytes).';
|
|
55
|
+
if (f.origin === 'other') return 'Work is uneven across tasks: salt the key or repartition on a better key.';
|
|
56
|
+
if (f.remediation?.some((r) => r.kind === 'conf' && r.key === 'spark.sql.adaptive.enabled')) return SKEW_JOIN_AQE_OFF;
|
|
48
57
|
return switchAlreadyOn(f, SKEW_JOIN_KEY) ? SKEW_JOIN_ALREADY_ON : unset;
|
|
49
58
|
}
|
|
50
59
|
const DYNAMIC_ALLOCATION_KEY = 'spark.dynamicAllocation.enabled';
|
|
@@ -120,8 +129,9 @@ export const FINDING_PRESENTATION
|
|
|
120
129
|
tag: 'TINY',
|
|
121
130
|
thresholdSummary: (t) => `${t.minTasks}+ tasks with a median of ${t.maxP50}ms or less and a P95 of ${t.maxP95}ms or less`,
|
|
122
131
|
actionLabel: () => 'Coalesce small tasks',
|
|
123
|
-
|
|
124
|
-
|
|
132
|
+
genericRecommendation: (f) => (f.reads != null && f.reads !== 'shuffle'
|
|
133
|
+
? 'Scheduler overhead may dominate: coalesce down to fewer, larger tasks.'
|
|
134
|
+
: 'Scheduler overhead may dominate: lower spark.sql.shuffle.partitions, or coalesce down to fewer, larger tasks.'),
|
|
125
135
|
},
|
|
126
136
|
|
|
127
137
|
shuffle: {
|
|
@@ -129,7 +139,14 @@ export const FINDING_PRESENTATION
|
|
|
129
139
|
tag: 'SHFL',
|
|
130
140
|
thresholdSummary: (t) => `stage shuffle read above ${t.minBytes / 1048576} MiB`,
|
|
131
141
|
actionLabel: () => 'Reduce shuffle size',
|
|
132
|
-
genericRecommendation: () =>
|
|
142
|
+
genericRecommendation: (f) => {
|
|
143
|
+
switch (f.partitions) {
|
|
144
|
+
case 'sufficient': return 'The tasks are already a good size, so more partitions will not help: use a broadcast join for the smaller side.';
|
|
145
|
+
case 'aqeCoalesced': return 'AQE coalesced the shuffle: lower spark.sql.adaptive.advisoryPartitionSizeInBytes, or use a broadcast join for the smaller side.';
|
|
146
|
+
case 'ownPartitioning': return "spark.sql.shuffle.partitions is already high enough, so raise this stage's own partition count (its repartition(n) or RDD parallelism), or use a broadcast join for the smaller side.";
|
|
147
|
+
default: return 'Raise spark.sql.shuffle.partitions, or use a broadcast join for the smaller side.';
|
|
148
|
+
}
|
|
149
|
+
},
|
|
133
150
|
},
|
|
134
151
|
partitionSizing: {
|
|
135
152
|
name: 'partition sizing',
|
|
@@ -146,7 +163,9 @@ export const FINDING_PRESENTATION
|
|
|
146
163
|
genericRecommendation(f) {
|
|
147
164
|
switch (f.rule) {
|
|
148
165
|
case 'shufflePartitionSkew': return skewJoinGeneric(f, 'For join skew, enable AQE skew-join handling (spark.sql.adaptive.skewJoin.enabled); otherwise salt the key or repartition on a better key.');
|
|
149
|
-
case 'lowShuffleParallelism':
|
|
166
|
+
case 'lowShuffleParallelism':
|
|
167
|
+
if (f.partitions === 'aqeCoalesced') return 'AQE coalesced the shuffle into few tasks: lower spark.sql.adaptive.advisoryPartitionSizeInBytes so each partition is smaller.';
|
|
168
|
+
return switchAlreadyOn(f, 'spark.sql.shuffle.partitions')
|
|
150
169
|
? "spark.sql.shuffle.partitions is already high enough, so raise this stage's own partition count (its repartition(n) or RDD parallelism) so each partition is smaller."
|
|
151
170
|
: 'Raise spark.sql.shuffle.partitions so each partition is smaller.';
|
|
152
171
|
case 'maxPartitionTooBig': return 'Repartition to break up the oversized partition before this stage.';
|
|
@@ -161,7 +180,9 @@ export const FINDING_PRESENTATION
|
|
|
161
180
|
thresholdSummary: (t) => `single-task disk spill above ${t.singleTaskDiskGiB} GiB`,
|
|
162
181
|
actionLabel: () => 'Reduce spill',
|
|
163
182
|
// The skew/volume classification isn't a Finding field, so one sentence covers both.
|
|
164
|
-
genericRecommendation: () =>
|
|
183
|
+
genericRecommendation: (f) => (f.reads != null && f.reads !== 'shuffle'
|
|
184
|
+
? 'If the spill is skew-driven, fix task skew first: adding memory will not help. Otherwise increase executor memory or process less data per task.'
|
|
185
|
+
: 'If the spill is skew-driven, fix task skew first: adding memory will not help. Otherwise raise spark.sql.shuffle.partitions or increase executor memory.'),
|
|
165
186
|
},
|
|
166
187
|
|
|
167
188
|
gc: {
|
|
@@ -219,14 +240,18 @@ export const FINDING_PRESENTATION
|
|
|
219
240
|
tag: 'SLOW',
|
|
220
241
|
thresholdSummary: () => 'a stage running far longer than its peers, not attributable to a single slow host',
|
|
221
242
|
actionLabel: () => 'Profile slow stage',
|
|
222
|
-
genericRecommendation: () =>
|
|
243
|
+
genericRecommendation: (f) => f.reads === 'input'
|
|
244
|
+
? '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.'
|
|
245
|
+
: f.reads === 'other'
|
|
246
|
+
? 'Check what the stage computes and for a large per-task data volume driving heavy spill.'
|
|
247
|
+
: 'Often a partition-count problem: raise parallelism via spark.sql.shuffle.partitions or spark.default.parallelism, or check for a large per-task data volume driving heavy shuffle and spill.',
|
|
223
248
|
},
|
|
224
249
|
straggler: {
|
|
225
250
|
name: 'straggling task',
|
|
226
251
|
tag: 'STRAG',
|
|
227
252
|
thresholdSummary: () => 'one or more tasks finishing far after the rest of their stage',
|
|
228
253
|
actionLabel: () => 'Fix stragglers',
|
|
229
|
-
genericRecommendation: () =>
|
|
254
|
+
genericRecommendation: (f) => `Rule out a GC pause or a slow shuffle fetch before assuming a hardware issue. If uneven data is the cause: ${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.')}`,
|
|
230
255
|
},
|
|
231
256
|
speculationWaste: {
|
|
232
257
|
name: 'speculation waste',
|
|
@@ -240,7 +265,9 @@ export const FINDING_PRESENTATION
|
|
|
240
265
|
tag: 'COLD',
|
|
241
266
|
thresholdSummary: (t) => `the first stage waiting over ${t.gapSeconds}s for an executor`,
|
|
242
267
|
actionLabel: () => 'Pre-warm cluster',
|
|
243
|
-
genericRecommendation: () =>
|
|
268
|
+
genericRecommendation: (f) => (f.dynamicAllocation === 'off'
|
|
269
|
+
? 'Keep a warm pool of idle executors: dynamic allocation is off, so no executor-count property applies.'
|
|
270
|
+
: 'Keep a warm pool of idle executors, or if using dynamic allocation, raise the minimum/initial executor count so it does not scale up from zero.'),
|
|
244
271
|
},
|
|
245
272
|
|
|
246
273
|
memoryUtilization: {
|
|
@@ -260,8 +287,8 @@ export const FINDING_PRESENTATION
|
|
|
260
287
|
genericRecommendation(f) {
|
|
261
288
|
switch (f.variant) {
|
|
262
289
|
case 'idleCores': return switchAlreadyOn(f, DYNAMIC_ALLOCATION_KEY)
|
|
263
|
-
?
|
|
264
|
-
: '
|
|
290
|
+
? `Dynamic allocation is already on, so reduce cluster size${idleCapacityLowering(f)}.`
|
|
291
|
+
: 'Either reduce cluster size (spark.executor.instances) or enable dynamic allocation.';
|
|
265
292
|
case 'wasteModel': return 'Review spark.executor.memory and executor count.';
|
|
266
293
|
case 'memoryBand':
|
|
267
294
|
if (f.dataUnavailable) return undefined;
|
|
@@ -278,8 +305,8 @@ export const FINDING_PRESENTATION
|
|
|
278
305
|
thresholdSummary: (t) => `average executor utilization below ${shareLabel(t.minUtil)}`,
|
|
279
306
|
actionLabel: () => 'Reduce cluster size',
|
|
280
307
|
genericRecommendation: (f) => (switchAlreadyOn(f, DYNAMIC_ALLOCATION_KEY)
|
|
281
|
-
?
|
|
282
|
-
: 'Consider reducing cluster size or enabling dynamic allocation.'),
|
|
308
|
+
? `Dynamic allocation is already on, so consider reducing cluster size${idleCapacityLowering(f)}.`
|
|
309
|
+
: 'Consider either reducing cluster size (spark.executor.instances) or enabling dynamic allocation.'),
|
|
283
310
|
},
|
|
284
311
|
coreLocality: {
|
|
285
312
|
name: 'core locality',
|
|
@@ -322,7 +349,9 @@ export const FINDING_PRESENTATION
|
|
|
322
349
|
tag: 'CHRN',
|
|
323
350
|
thresholdSummary: (t) => `over ${shareLabel(t.warningPct)} of executors living under ${t.shortLivedMs / 60000} minutes`,
|
|
324
351
|
actionLabel: () => 'Reduce autoscaling churn',
|
|
325
|
-
genericRecommendation: () =>
|
|
352
|
+
genericRecommendation: (f) => (f.dynamicAllocation === 'off'
|
|
353
|
+
? 'Dynamic allocation is off, so the churn comes from executors lost or preempted: check the cluster manager\'s preemption and executor-loss logs.'
|
|
354
|
+
: 'This looks like wasteful re-provisioning rather than normal scale-down: consider raising spark.dynamicAllocation.executorIdleTimeout or widening the minExecutors/maxExecutors bounds to reduce flapping.'),
|
|
326
355
|
},
|
|
327
356
|
|
|
328
357
|
configAudit: CONFIG_AUDIT_PRESENTATION,
|
|
@@ -349,14 +378,18 @@ export const FINDING_PRESENTATION
|
|
|
349
378
|
tag: 'PLAN',
|
|
350
379
|
thresholdSummary: () => 'a join below the configured size floor that skipped broadcast',
|
|
351
380
|
actionLabel: () => 'Use broadcast join',
|
|
352
|
-
genericRecommendation: () =>
|
|
381
|
+
genericRecommendation: (f) => (f.broadcastThreshold === 'notLimiting'
|
|
382
|
+
? 'The threshold already admits the smaller side, so it is not what stopped the broadcast: consider a broadcast() hint or collecting table statistics.'
|
|
383
|
+
: 'This could have been a broadcast join: consider a broadcast() hint or raising spark.sql.autoBroadcastJoinThreshold.'),
|
|
353
384
|
},
|
|
354
385
|
overBroadcast: {
|
|
355
386
|
name: 'oversized broadcast join',
|
|
356
387
|
tag: 'PLAN',
|
|
357
388
|
thresholdSummary: (t) => `a broadcast over ${t.overBroadcastBytes / 1073741824} GiB`,
|
|
358
389
|
actionLabel: () => 'Fix oversized broadcast',
|
|
359
|
-
genericRecommendation: (f) => (
|
|
390
|
+
genericRecommendation: (f) => (f.broadcastThreshold === 'notLimiting'
|
|
391
|
+
? 'The configured threshold is below this broadcast, so remove the broadcast() hint that forced it.'
|
|
392
|
+
: switchAlreadyOn(f, 'spark.sql.autoBroadcastJoinThreshold')
|
|
360
393
|
? 'Automatic broadcast is already disabled, so remove the broadcast() hint that forced it.'
|
|
361
394
|
: 'Check for a misapplied broadcast hint or a misconfigured spark.sql.autoBroadcastJoinThreshold.'),
|
|
362
395
|
},
|
|
@@ -10,16 +10,27 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
/** One concrete change a finding's fix makes, alongside its prose `recommendation`.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
13
|
+
/** One concrete change a finding's fix makes, alongside its prose `recommendation`. Entries are
|
|
14
|
+
* applied together unless the recommendation words them as alternatives ("either ... or"), as an
|
|
15
|
+
* idle-capacity finding does with dynamic allocation off: then a consumer applies one. */
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/** A Spark property the detector already names; `suggested` is null when it computes no value.
|
|
19
|
+
* Sizes carry a Spark unit suffix ("384m"), counts are plain numbers, switches are booleans. */
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
|
|
27
|
+
/** A fix no Spark property makes: the job's code or data has to change. `hint` is the same
|
|
28
|
+
* wording the finding's `recommendation` gives. */
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
23
34
|
// The columns every finding carries, whatever its detector.
|
|
24
35
|
|
|
25
36
|
|
|
@@ -79,7 +90,22 @@
|
|
|
79
90
|
|
|
80
91
|
// ── Per-stage detectors ─────────────────────────────────────────────────────
|
|
81
92
|
|
|
82
|
-
|
|
93
|
+
/** What a skewed stage reads, which decides the fix: 'shuffleJoin' (a shuffle feeding a join, where
|
|
94
|
+
* AQE skew-join handling applies), 'inputScan' (uneven input files) or 'other'. */
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
/** What a stage reads, by the dominant side: a shuffle, input files, or neither. */
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/** Why a shuffle finding's partition-count advice is or is not given: 'raise' (the property limits
|
|
101
|
+
* the stage), 'sufficient' (tasks are already a good size), 'aqeCoalesced' (AQE merged the
|
|
102
|
+
* partitions, so the advisory size is the lever) or 'ownPartitioning' (the property is already high
|
|
103
|
+
* enough, so the stage's own repartition(n) or RDD parallelism is). */
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
83
109
|
|
|
84
110
|
|
|
85
111
|
|
|
@@ -90,16 +116,24 @@
|
|
|
90
116
|
|
|
91
117
|
|
|
92
118
|
|
|
93
|
-
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
94
122
|
|
|
95
123
|
|
|
96
124
|
|
|
97
125
|
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
98
130
|
|
|
99
131
|
|
|
100
132
|
|
|
101
133
|
|
|
102
134
|
|
|
135
|
+
|
|
136
|
+
|
|
103
137
|
|
|
104
138
|
|
|
105
139
|
|
|
@@ -124,7 +158,10 @@
|
|
|
124
158
|
|
|
125
159
|
|
|
126
160
|
|
|
127
|
-
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
128
165
|
|
|
129
166
|
|
|
130
167
|
|
|
@@ -151,6 +188,8 @@
|
|
|
151
188
|
|
|
152
189
|
|
|
153
190
|
|
|
191
|
+
|
|
192
|
+
|
|
154
193
|
|
|
155
194
|
|
|
156
195
|
|
|
@@ -167,7 +206,10 @@
|
|
|
167
206
|
|
|
168
207
|
|
|
169
208
|
|
|
170
|
-
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
171
213
|
|
|
172
214
|
|
|
173
215
|
// ── App-level detectors ─────────────────────────────────────────────────────
|
|
@@ -176,7 +218,10 @@
|
|
|
176
218
|
// valueText is always 'missing': the ApplicationEnd event the log lacks.
|
|
177
219
|
|
|
178
220
|
|
|
179
|
-
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
180
225
|
|
|
181
226
|
|
|
182
227
|
|
|
@@ -184,11 +229,12 @@
|
|
|
184
229
|
|
|
185
230
|
|
|
186
231
|
|
|
187
|
-
|
|
188
|
-
|
|
232
|
+
|
|
233
|
+
|
|
189
234
|
|
|
190
235
|
|
|
191
236
|
|
|
237
|
+
|
|
192
238
|
|
|
193
239
|
|
|
194
240
|
|
|
@@ -202,11 +248,10 @@
|
|
|
202
248
|
|
|
203
249
|
|
|
204
250
|
|
|
205
|
-
|
|
206
|
-
|
|
251
|
+
|
|
252
|
+
|
|
207
253
|
|
|
208
|
-
|
|
209
|
-
|
|
254
|
+
|
|
210
255
|
|
|
211
256
|
|
|
212
257
|
|
|
@@ -231,6 +276,8 @@
|
|
|
231
276
|
|
|
232
277
|
|
|
233
278
|
|
|
279
|
+
|
|
280
|
+
|
|
234
281
|
|
|
235
282
|
|
|
236
283
|
|
|
@@ -296,13 +343,21 @@
|
|
|
296
343
|
|
|
297
344
|
|
|
298
345
|
|
|
346
|
+
|
|
347
|
+
/** How the effective spark.sql.autoBroadcastJoinThreshold relates to the finding: 'limits' (the
|
|
348
|
+
* property decided it, or is unknown), 'notLimiting' (already admits, or already below, the
|
|
349
|
+
* broadcast, so something else decided it) or 'disabled' (-1). */
|
|
350
|
+
|
|
299
351
|
|
|
300
352
|
|
|
301
353
|
|
|
354
|
+
|
|
302
355
|
|
|
303
356
|
|
|
304
357
|
|
|
305
|
-
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
306
361
|
|
|
307
362
|
|
|
308
363
|
// ── Unions ──────────────────────────────────────────────────────────────────
|