sparkforensics-server 0.6.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +16 -7
- package/package.json +1 -1
- package/public/assets/AutoscalingChurn-DenWKTv-.js +1 -0
- package/public/assets/CacheUtilization-DLz7NdjV.js +1 -0
- package/public/assets/CachingOpportunity-zpQIqhzm.js +1 -0
- package/public/assets/ChartTheme-DAiARbLP.js +8 -0
- package/public/assets/ColdStart-C-9HjxWl.js +1 -0
- package/public/assets/ConfigAudit-D0V9tcrJ.js +1 -0
- package/public/assets/CoreUsageArea-yeerrljd.js +1 -0
- package/public/assets/Dashboard-DkUPrHKV.js +1 -0
- package/public/assets/DisclosureContext-DK1_iz6J.js +1 -0
- package/public/assets/DuplicatePlanSubtree-xDNDbCd3.js +1 -0
- package/public/assets/DurationHistogram-B6jsE0Ov.js +1 -0
- package/public/assets/EmptyState-C1uL40VU.js +1 -0
- package/public/assets/ExecutorUtilization-DXDZKmSc.js +1 -0
- package/public/assets/GcPressure-MRf7I4IG.js +1 -0
- package/public/assets/ImpactEstimate-Dm3xWbzV.js +1 -0
- package/public/assets/IncompleteRun-CaLOhMtf.js +1 -0
- package/public/assets/JobFailures-CzmzlvhO.js +1 -0
- package/public/assets/MemoryUtilization-AWUMUjCH.js +1 -0
- package/public/assets/NestedLoopJoin-C9sNr6Ss.js +1 -0
- package/public/assets/OverBroadcast-BOmRE6ca.js +1 -0
- package/public/assets/PartitionHint-BL2EmJfE.js +1 -0
- package/public/assets/PartitionSizing-BzBySvUq.js +1 -0
- package/public/assets/PlanExplorer-DdiQRcJU.js +1 -0
- package/public/assets/PlanGraphRoute-CIH9gBuR.js +1 -0
- package/public/assets/PlanView-B1hxzFRs.js +2 -0
- package/public/assets/PythonUdf-DvgCCueD.js +1 -0
- package/public/assets/RetryWaste-uXXu_CyM.js +1 -0
- package/public/assets/RowPagination-C-LzWkI5.js +1 -0
- package/public/assets/RowStatusCluster-Dbtmte7l.js +1 -0
- package/public/assets/ShuffleIO-nALwzC1_.js +1 -0
- package/public/assets/Skew-CHMEKgvk.js +1 -0
- package/public/assets/SlowHost-yyvjpHk6.js +1 -0
- package/public/assets/SmallFiles-y6odJ97n.js +1 -0
- package/public/assets/SpeculationWaste-C-SD2LOt.js +1 -0
- package/public/assets/Spill-DHTMmOup.js +1 -0
- package/public/assets/StageFailed-CQ3DxC9R.js +1 -0
- package/public/assets/StageFindingGroup-BgYLyj5q.js +1 -0
- package/public/assets/StageHeader-CIETkjVZ.js +1 -0
- package/public/assets/StagePill--P7PDd3s.js +1 -0
- package/public/assets/StageShape-BIv8vx_o.js +1 -0
- package/public/assets/StageSlowness-MMqzERxN.js +1 -0
- package/public/assets/Straggler-BgrY7AyW.js +1 -0
- package/public/assets/TaskFailures-BHHyKYTs.js +1 -0
- package/public/assets/TinyTask-DDScNhCl.js +1 -0
- package/public/assets/UnderBroadcast-CGIC04TI.js +1 -0
- package/public/assets/WidgetLeadSummary-CXFZP00C.js +1 -0
- package/public/assets/button-DbpTz2yk.js +1 -0
- package/public/assets/charts-vendor-CtTxwTeu.js +59 -0
- package/public/assets/composite-C9Nu2EI9.js +1 -0
- package/public/assets/d3-vendor-DNlD2-cz.js +1 -0
- package/public/assets/detector-registry-Bp8hrLua.js +2 -0
- package/public/assets/downsample-WmNM1qc9.js +1 -0
- package/public/assets/finding-anchor-Dr40LkS9.js +1 -0
- package/public/assets/findings-of-type-BL2u3RGZ.js +1 -0
- package/public/assets/impact-sort-mC5ISgX8.js +1 -0
- package/public/assets/inbox-KPU1Gppm.js +1 -0
- package/public/assets/index-CaRVPvAT.css +2 -0
- package/public/assets/index-fDiwfuoO.js +14 -0
- package/public/assets/inertValue-L9VxV0VE.js +1 -0
- package/public/assets/layout.worker-CLcBHxVp.js +3 -0
- package/public/assets/{parser-worker-CA5RxqKc.js → parser-worker-CRIOPMOW.js} +8 -8
- package/public/assets/plan-graph-vendor-Ce6d4HU6.js +7 -0
- package/public/assets/react-vendor-C6KcUD36.js +9 -0
- package/public/assets/select-BHqOqun5.js +1 -0
- package/public/assets/toggle-DPeN6aNa.js +1 -0
- package/public/assets/toggle-group-Kl3uyHSr.js +1 -0
- package/public/assets/usePagedRows-BafD6bEN.js +1 -0
- package/public/assets/useRecentFiles-DzJZAoOT.js +3 -0
- package/public/assets/useRegisterFieldControl-pQv-ZDoU.js +1 -0
- package/public/assets/useScrollLock-BCxn_dMp.js +1 -0
- package/public/assets/useSortMode-DjrAN-z4.js +1 -0
- package/public/docs/404.html +3 -3
- package/public/docs/assets/{app.CnWL6bKV.js → app.1gvzd5Zb.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.C0IBKeRQ.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
- package/public/docs/assets/chunks/{theme.BH-2HuRf.js → theme.C5lLqUv7.js} +2 -2
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.lean.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.js → contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.CHHgywoP.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.N4hhenrA.lean.js → contributor-guide_architecture_detector-contract.md.CHHgywoP.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.lean.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.lean.js → contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.K71YB-Rr.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation.md.DfvbqEUu.lean.js → contributor-guide_architecture_impact-estimation.md.K71YB-Rr.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.lean.js → contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_overview.md.nxkpOhgf.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js → contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.lean.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js → contributor-guide_architecture_worker-protocol.md.Br6OE7RW.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.Br6OE7RW.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.lean.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.js} +1 -1
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.js} +2 -2
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.lean.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.lean.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_contributing.md.DBW4drtZ.js +1 -0
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.js +15 -0
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.lean.js +1 -0
- package/public/docs/assets/contributor-guide_testing.md.DpkozNoG.js +4 -0
- package/public/docs/assets/{contributor-guide_testing.md.By6XGR9a.lean.js → contributor-guide_testing.md.DpkozNoG.lean.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.js → index.md.lMm7SUMz.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.lean.js → index.md.lMm7SUMz.lean.js} +1 -1
- package/public/docs/assets/{style.CyK9Ss73.css → style.Cfxqlj0y.css} +1 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.js +29 -0
- package/public/docs/assets/{user-guide_getting-started_ci-and-automation.md.BEepbDDL.lean.js → user-guide_getting-started_ci-and-automation.md.C0pcQoNc.lean.js} +1 -1
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.js +1 -0
- package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.js} +2 -2
- package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.lean.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.js → user-guide_mcp-tools.md.49r3L2YE.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js → user-guide_mcp-tools_compare-runs.md.BQ_kIptC.js} +11 -6
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.BQ_kIptC.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.azCZXkH8.js +44 -0
- package/public/docs/assets/{user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.lean.js → user-guide_mcp-tools_diagnose-run.md.azCZXkH8.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.js} +2 -2
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.lean.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.js} +2 -1
- package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.lean.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.lean.js} +1 -1
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.lean.js +1 -0
- package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -6
- package/public/docs/contributor-guide/architecture/board-widgets.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -6
- package/public/docs/contributor-guide/architecture/detector-contract.html +6 -6
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -6
- package/public/docs/contributor-guide/architecture/drill-down.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -6
- package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -6
- package/public/docs/contributor-guide/architecture/index.html +5 -5
- package/public/docs/contributor-guide/architecture/overview.html +6 -6
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -5
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -6
- package/public/docs/contributor-guide/architecture/state-and-history.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -5
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -6
- package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -7
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -6
- package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -6
- package/public/docs/contributor-guide/contributing.html +6 -6
- package/public/docs/contributor-guide/development-setup.html +8 -8
- package/public/docs/contributor-guide/testing.html +9 -6
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +6 -6
- package/public/docs/logo-dark.svg +1 -0
- package/public/docs/logo-light.svg +1 -0
- package/public/docs/tuning-reference/anti-patterns.html +5 -5
- package/public/docs/tuning-reference/aqe.html +5 -5
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -5
- package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -5
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -5
- package/public/docs/tuning-reference/bottleneck-failures.html +5 -5
- package/public/docs/tuning-reference/bottleneck-gc.html +5 -5
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -5
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -5
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -5
- package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -5
- package/public/docs/tuning-reference/bottleneck-skew.html +5 -5
- package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -5
- package/public/docs/tuning-reference/bottleneck-small-files.html +5 -5
- package/public/docs/tuning-reference/bottleneck-spill.html +5 -5
- package/public/docs/tuning-reference/bottleneck-straggler.html +5 -5
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -5
- package/public/docs/tuning-reference/bottleneck-utilization.html +5 -5
- package/public/docs/tuning-reference/caching.html +5 -5
- package/public/docs/tuning-reference/cluster-config.html +5 -5
- package/public/docs/tuning-reference/config.html +5 -5
- package/public/docs/tuning-reference/data-formats.html +5 -5
- package/public/docs/tuning-reference/index.html +5 -5
- package/public/docs/tuning-reference/intro.html +5 -5
- package/public/docs/tuning-reference/joins.html +5 -5
- package/public/docs/tuning-reference/memory-model.html +5 -5
- package/public/docs/tuning-reference/metrics.html +5 -5
- package/public/docs/tuning-reference/partitioning.html +5 -5
- package/public/docs/tuning-reference/pyspark.html +5 -5
- package/public/docs/tuning-reference/shuffle.html +5 -5
- package/public/docs/tuning-reference/spark-architecture.html +5 -5
- package/public/docs/tuning-reference/table-formats.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -5
- package/public/docs/user-guide/alternative-log-retrieval.html +5 -5
- package/public/docs/user-guide/getting-started/ci-and-automation.html +16 -11
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -6
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -5
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -7
- package/public/docs/user-guide/getting-started.html +5 -5
- package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -11
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -7
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -6
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -6
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +5 -5
- package/public/docs/user-guide/mcp-tools/list-runs.html +5 -5
- package/public/docs/user-guide/mcp-tools.html +6 -6
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -5
- package/public/docs/user-guide/run-comparison.html +6 -6
- package/public/docs/user-guide/understanding-findings.html +6 -6
- package/public/export-template.html +45 -45
- package/public/index.html +8 -7
- package/public/sample-runs/sample-run.ndjson.gz +0 -0
- package/vendor-core/allocation.js +25 -23
- package/vendor-core/analyzer.js +85 -58
- package/vendor-core/api-merge-writes.js +2 -0
- package/vendor-core/aqe-skew.js +347 -0
- package/vendor-core/cli/budgets.js +6 -4
- package/vendor-core/cli/collect-run-pair.js +89 -0
- package/vendor-core/cli/collect-run-worker.js +16 -0
- package/vendor-core/cli/collect-run.js +1 -2
- package/vendor-core/cli/native-zstd.js +12 -16
- package/vendor-core/comparability.js +234 -0
- package/vendor-core/comparison-output.js +15 -7
- package/vendor-core/comparison-verdict.js +105 -25
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/core-time-series.js +0 -1
- package/vendor-core/core-usage-locality.js +1 -1
- package/vendor-core/detectors.js +1007 -380
- package/vendor-core/docs-config.js +0 -4
- package/vendor-core/docs-content/detection/cache.md +2 -1
- package/vendor-core/docs-content/detection/cfg.md +19 -11
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/gc.md +7 -3
- package/vendor-core/docs-content/detection/host.md +11 -1
- package/vendor-core/docs-content/detection/mem.md +17 -6
- package/vendor-core/docs-content/detection/part.md +3 -1
- package/vendor-core/docs-content/detection/plan.md +55 -13
- package/vendor-core/docs-content/detection/shfl.md +11 -5
- package/vendor-core/docs-content/detection/skew.md +47 -1
- package/vendor-core/docs-content/detection/slow.md +4 -2
- package/vendor-core/docs-content/detection/spec.md +6 -1
- package/vendor-core/docs-content/detection/spill.md +6 -3
- package/vendor-core/docs-content/detection/strag.md +19 -6
- package/vendor-core/docs-content/detection/tiny.md +9 -3
- package/vendor-core/effective-conf.js +7 -10
- package/vendor-core/efficiency-model.js +2 -2
- package/vendor-core/etl-phases.js +1 -2
- package/vendor-core/event-handlers.js +175 -57
- package/vendor-core/event-schemas.js +21 -16
- package/vendor-core/evidence-availability.js +9 -2
- package/vendor-core/evidence-report.js +118 -35
- package/vendor-core/executor-peaks.js +41 -0
- package/vendor-core/export-data.js +5 -5
- package/vendor-core/finding-identity.js +78 -0
- package/vendor-core/finding-presentation.js +116 -33
- package/vendor-core/finding-types.js +88 -21
- package/vendor-core/format-utils.js +14 -15
- package/vendor-core/html-export.js +1 -1
- package/vendor-core/impact-band.js +2 -2
- package/vendor-core/impact-format.js +47 -19
- package/vendor-core/impact-model.js +26 -15
- package/vendor-core/job-groups.js +4 -4
- package/vendor-core/mcp-server-factory.js +48 -12
- package/vendor-core/mcp-tools.js +179 -24
- package/vendor-core/median.js +2 -2
- package/vendor-core/nested-loop-join.js +73 -0
- package/vendor-core/occupancy.js +1 -2
- package/vendor-core/parser-worker.js +1 -1
- package/vendor-core/plan-graph-model.js +14 -22
- package/vendor-core/plan-node-detail.js +2 -3
- package/vendor-core/plan-summary.js +24 -19
- package/vendor-core/plan-tree-walk.js +6 -8
- package/vendor-core/python-stage.js +12 -1
- package/vendor-core/recommendation-rollup.js +13 -12
- package/vendor-core/redact.js +52 -46
- package/vendor-core/run-aggregates.js +6 -8
- package/vendor-core/run-comparison.js +226 -66
- package/vendor-core/run-identity.js +12 -0
- package/vendor-core/run-interpretation.js +21 -0
- package/vendor-core/run-metrics.js +2 -2
- package/vendor-core/run-output.js +32 -10
- package/vendor-core/run-totals.js +12 -0
- package/vendor-core/run-verdict.js +76 -3
- package/vendor-core/scaling-sim.js +3 -4
- package/vendor-core/snappy-block.js +2 -2
- package/vendor-core/spark-conf.js +168 -0
- package/vendor-core/sql-stages.js +2 -2
- package/vendor-core/stage-alignment.js +2 -12
- package/vendor-core/stage-identity.js +58 -3
- package/vendor-core/stage-label.js +14 -0
- package/vendor-core/stage-plan-nodes.js +17 -3
- package/vendor-core/stage-quantiles.js +141 -9
- package/vendor-core/stage-structure.js +17 -3
- package/vendor-core/threshold-overrides.js +9 -3
- package/vendor-core/types.js +58 -21
- package/vendor-core/wasted-core-hours.js +0 -1
- package/vendor-core/write-targets.js +114 -14
- package/vendor-core/zstd-worker-client.js +1 -1
- package/vendor-core/zstd-worker.js +1 -1
- package/public/assets/AutoscalingChurn-CRA2Mb7F.js +0 -1
- package/public/assets/CacheUtilization-Bh9OY_V9.js +0 -1
- package/public/assets/CachingOpportunity-oCiQwmTJ.js +0 -1
- package/public/assets/ColdStart-BJrtjfmn.js +0 -1
- package/public/assets/ConfigAudit-DMvKxySP.js +0 -1
- package/public/assets/CoreUsageArea-REC2zsKw.js +0 -1
- package/public/assets/Dashboard-BHZ76JCu.js +0 -2
- package/public/assets/DisclosureContext-OO7X1HAx.js +0 -1
- package/public/assets/DuplicatePlanSubtree-BgG-L-cK.js +0 -1
- package/public/assets/ExecutorUtilization-D2KhSVbY.js +0 -1
- package/public/assets/GcPressure-D1BTE8qh.js +0 -1
- package/public/assets/IncompleteRun-DD40xUpy.js +0 -1
- package/public/assets/JobFailures-YwNzCF19.js +0 -1
- package/public/assets/MemoryUtilization-9b8ee_3_.js +0 -1
- package/public/assets/OverBroadcast-CfctS8a8.js +0 -1
- package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
- package/public/assets/PartitionSizing-VG8kBgG5.js +0 -1
- package/public/assets/PlanExplorer-DmubTAOP.js +0 -1
- package/public/assets/PlanGraphRoute-DctPZjS0.js +0 -1
- package/public/assets/RetryWaste-CnpM8bB7.js +0 -1
- package/public/assets/ShuffleIO-D13vGmas.js +0 -1
- package/public/assets/Skew-DlagstYP.js +0 -1
- package/public/assets/SlowHost-cSkLRZ_e.js +0 -1
- package/public/assets/SmallFiles-B-kERMcq.js +0 -1
- package/public/assets/SpeculationWaste-DaysAzXO.js +0 -1
- package/public/assets/Spill-H44Gz4US.js +0 -1
- package/public/assets/StageFailed-DCfii9h_.js +0 -1
- package/public/assets/StageFindingGroup-BXJ0Mj5n.js +0 -1
- package/public/assets/StageHeader--oN2J-oD.js +0 -1
- package/public/assets/StageShape-IZ80CZiJ.js +0 -1
- package/public/assets/StageSlowness--BRIaBc1.js +0 -1
- package/public/assets/Straggler-Ctq0Df_o.js +0 -1
- package/public/assets/TaskFailures-Bks_gqhL.js +0 -1
- package/public/assets/TinyTask-BssfzGFB.js +0 -1
- package/public/assets/UnderBroadcast-DsScrxc-.js +0 -1
- package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
- package/public/assets/finding-anchor-BYW1oz5R.js +0 -1
- package/public/assets/impact-sort-xzy0g-Vh.js +0 -1
- package/public/assets/index-DhpRGMZc.css +0 -2
- package/public/assets/index-DwqkFUFk.js +0 -14
- package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
- package/public/assets/react-vendor-DfpuPQZf.js +0 -9
- package/public/assets/select-C8edjYTq.js +0 -1
- package/public/assets/usePagedRows-CsuUFeYx.js +0 -1
- package/public/assets/useRecentFiles-BvkKo3JN.js +0 -11
- package/public/assets/useSortMode-joX71BZN.js +0 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.tE5pz54z.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.N4hhenrA.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.DfvbqEUu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.js +0 -1
- package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
- package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.js +0 -15
- package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.lean.js +0 -1
- package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.BEepbDDL.js +0 -24
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +0 -23
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.lean.js +0 -1
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.lean.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.lean.js → contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_overview.md.C1sSvm9i.lean.js → contributor-guide_architecture_overview.md.nxkpOhgf.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js → contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.lean.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.lean.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.lean.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_contributing.md.CQMvGwFt.lean.js → contributor-guide_contributing.md.DBW4drtZ.lean.js} +0 -0
- /package/public/docs/assets/{user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.lean.js → user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.lean.js} +0 -0
- /package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.lean.js → user-guide_mcp-tools.md.49r3L2YE.lean.js} +0 -0
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
JobEndEventSchema,
|
|
8
8
|
StageSubmittedEventSchema,
|
|
9
9
|
StageExecutorMetricsEventSchema,
|
|
10
|
+
StageCompletedEventSchema,
|
|
10
11
|
TaskEndEventSchema,
|
|
11
12
|
SqlExecutionStartEventSchema,
|
|
12
13
|
SqlAdaptiveExecutionUpdateEventSchema,
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
ExecutorAddedEventSchema,
|
|
16
17
|
ExecutorRemovedEventSchema,
|
|
17
18
|
BlockUpdatedEventSchema,
|
|
19
|
+
MAX_ACCUMULABLES_PER_TASK,
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
} from './event-schemas.js';
|
|
@@ -24,6 +26,8 @@ import { finalizeStage } from './stage-quantiles.js';
|
|
|
24
26
|
import { MAX_FAILURE_DETAILS_PER_STAGE, extractTaskFailureDetail, taskFailureKey, } from './task-failure.js';
|
|
25
27
|
import { computeRunAggregates } from './run-aggregates.js';
|
|
26
28
|
import { parseSparkMemoryMB } from './spark-memory.js';
|
|
29
|
+
import { effectiveSparkConf } from './spark-conf.js';
|
|
30
|
+
import { DRIVER_EXECUTOR_ID } from './executor-peaks.js';
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
|
|
@@ -51,6 +55,9 @@ import { parseSparkMemoryMB } from './spark-memory.js';
|
|
|
51
55
|
|
|
52
56
|
|
|
53
57
|
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
54
61
|
|
|
55
62
|
|
|
56
63
|
|
|
@@ -130,6 +137,8 @@ const MAX_TASK_SAMPLES = 20;
|
|
|
130
137
|
|
|
131
138
|
|
|
132
139
|
|
|
140
|
+
|
|
141
|
+
|
|
133
142
|
|
|
134
143
|
|
|
135
144
|
|
|
@@ -202,6 +211,8 @@ const MAX_TASK_SAMPLES = 20;
|
|
|
202
211
|
|
|
203
212
|
|
|
204
213
|
|
|
214
|
+
|
|
215
|
+
|
|
205
216
|
|
|
206
217
|
|
|
207
218
|
|
|
@@ -226,12 +237,21 @@ const MAX_TASK_SAMPLES = 20;
|
|
|
226
237
|
|
|
227
238
|
|
|
228
239
|
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
229
243
|
|
|
230
244
|
|
|
231
245
|
|
|
232
246
|
|
|
233
247
|
|
|
234
248
|
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
235
255
|
|
|
236
256
|
|
|
237
257
|
|
|
@@ -241,22 +261,18 @@ const MAX_TASK_SAMPLES = 20;
|
|
|
241
261
|
|
|
242
262
|
|
|
243
263
|
// Splits decompressed byte chunks into NDJSON lines. Each chunk is decoded whole in one streaming
|
|
244
|
-
// TextDecoder.decode call (per-line decode
|
|
245
|
-
//
|
|
264
|
+
// TextDecoder.decode call (per-line decode is ~8x slower), then newlines are found with
|
|
265
|
+
// String.prototype.indexOf on that fresh, flat decoded text.
|
|
246
266
|
// A '\n' char is exactly the 0x0A byte (0x0A never occurs inside a UTF-8 multibyte sequence), and
|
|
247
267
|
// `{ stream: true }` reassembles a character split across a chunk boundary, so no byte-to-UTF-16
|
|
248
268
|
// offset mapping is needed. Only the first line of a chunk joins the carried-over `pending` text.
|
|
249
269
|
//
|
|
250
|
-
// Measured 2026-09-23 against the previous raw-byte-scan version (identical output): 3.5s -> 2.8s
|
|
251
|
-
// on that 3.5GB all-ASCII log, 0.37s -> 0.18s on 93MB of synthetic 2/3/4-byte-heavy NDJSON.
|
|
252
|
-
//
|
|
253
270
|
// A SQL UI event's physicalPlanDescription value (see stripPlanDescription) that is still open
|
|
254
271
|
// when a chunk ends is cut off the pending line, and the following bytes are dropped up to its
|
|
255
|
-
// closing quote without being decoded
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
// value inside a single chunk.
|
|
272
|
+
// closing quote without being decoded, so the value is never decoded, joined or scanned as text.
|
|
273
|
+
// A chunk longer than MAX_DECODE_SLICE is decoded in slices of that size, so the skip also applies
|
|
274
|
+
// within one chunk: Node's native zstd emits whole frames that can hold a value entirely.
|
|
275
|
+
// Figures: worker-protocol.md, "Decoder and parser calibration".
|
|
260
276
|
const MAX_DECODE_SLICE = 512 * 1024;
|
|
261
277
|
|
|
262
278
|
// A line joined from text decoded in more than one slice is a V8 cons string, which the first
|
|
@@ -438,10 +454,13 @@ export function createState() {
|
|
|
438
454
|
skippedLines: 0,
|
|
439
455
|
unreadableSqlStarts: new Set(),
|
|
440
456
|
accumState: new Map(),
|
|
457
|
+
executorAccumState: new Map(),
|
|
441
458
|
rddInfo: new Map(),
|
|
442
459
|
rddBlocks: new Map(),
|
|
443
460
|
rddBlockUpdates: 0,
|
|
444
461
|
taskAccumStages: new Map(),
|
|
462
|
+
lastTaskAccumIds: new Map(),
|
|
463
|
+
executorPeakMetrics: new Map(),
|
|
445
464
|
pendingAdaptiveUpdates: new Map(),
|
|
446
465
|
resolvedPlanExecutions: new Set(),
|
|
447
466
|
evidenceInputs: {
|
|
@@ -480,36 +499,45 @@ export function normalizeSparkProperties(
|
|
|
480
499
|
|
|
481
500
|
export { parseSparkMemoryMB };
|
|
482
501
|
|
|
483
|
-
// Derive an allocated-resource summary from the Spark config map
|
|
484
|
-
//
|
|
485
|
-
|
|
502
|
+
// Derive an allocated-resource summary from the Spark config map, each setting as the run's
|
|
503
|
+
// effective conf has it (the logged value, else Spark's default for `sparkVersion`). A key with no
|
|
504
|
+
// fixed default degrades to null, not a guess, and so does every key of a log that recorded no
|
|
505
|
+
// Spark properties at all: there is nothing to tell a default from a missing config.
|
|
506
|
+
export function extractResources(config , sparkVersion ) {
|
|
486
507
|
const cfg = config ?? {};
|
|
508
|
+
const recorded = Object.keys(cfg).length > 0;
|
|
509
|
+
const value = (k ) => (recorded ? effectiveSparkConf({ sparkVersion, properties: cfg }, k)?.value : undefined);
|
|
487
510
|
const int = (k ) => {
|
|
488
|
-
|
|
489
|
-
|
|
511
|
+
const v = value(k);
|
|
512
|
+
if (v == null) return null;
|
|
513
|
+
const n = parseInt(v, 10);
|
|
490
514
|
return Number.isFinite(n) ? n : null;
|
|
491
515
|
};
|
|
492
|
-
const memMB = (k ) =>
|
|
493
|
-
const bool = (k ) => (
|
|
516
|
+
const memMB = (k ) => parseSparkMemoryMB(value(k));
|
|
517
|
+
const bool = (k ) => { const v = value(k); return v != null ? v.toLowerCase() === 'true' : null; };
|
|
494
518
|
return {
|
|
495
519
|
executor: {
|
|
520
|
+
// The executor size stays the logged one: Spark's 1g default does not apply to a local-mode run,
|
|
521
|
+
// which has no separate executor JVM, and the log does not say which master it ran under.
|
|
496
522
|
memory: cfg['spark.executor.memory'] ?? null,
|
|
497
|
-
memoryMB:
|
|
498
|
-
memoryOverhead:
|
|
523
|
+
memoryMB: cfg['spark.executor.memory'] != null ? parseSparkMemoryMB(cfg['spark.executor.memory']) : null,
|
|
524
|
+
memoryOverhead: value('spark.executor.memoryOverhead') ?? null,
|
|
499
525
|
memoryOverheadMB: memMB('spark.executor.memoryOverhead'),
|
|
500
526
|
cores: int('spark.executor.cores'),
|
|
501
527
|
instances: int('spark.executor.instances'),
|
|
502
528
|
},
|
|
503
529
|
driver: {
|
|
504
|
-
memory:
|
|
530
|
+
memory: value('spark.driver.memory') ?? null,
|
|
505
531
|
memoryMB: memMB('spark.driver.memory'),
|
|
506
|
-
memoryOverhead:
|
|
532
|
+
memoryOverhead: value('spark.driver.memoryOverhead') ?? null,
|
|
507
533
|
memoryOverheadMB: memMB('spark.driver.memoryOverhead'),
|
|
508
534
|
cores: int('spark.driver.cores'),
|
|
509
535
|
},
|
|
510
536
|
dynamicAllocationEnabled: bool('spark.dynamicAllocation.enabled'),
|
|
511
537
|
shuffleServiceEnabled: bool('spark.shuffle.service.enabled'),
|
|
538
|
+
// The serializer a run set: Spark's default is reported as unset.
|
|
512
539
|
serializer: cfg['spark.serializer'] ?? null,
|
|
540
|
+
stageExecutorMetricsLogging: bool('spark.eventLog.logStageExecutorMetrics'),
|
|
513
541
|
};
|
|
514
542
|
}
|
|
515
543
|
|
|
@@ -600,12 +628,45 @@ function taskRecordOf(event , failure
|
|
|
600
628
|
executorRunTime: m['Executor Run Time'] ?? 0,
|
|
601
629
|
executorCpuTime: m['Executor CPU Time'] ?? 0,
|
|
602
630
|
inputBytes: inp['Bytes Read'] ?? 0,
|
|
631
|
+
inputRecords: inp['Records Read'] ?? 0,
|
|
632
|
+
shuffleReadRecords: sr['Total Records Read'] ?? 0,
|
|
603
633
|
outputBytes: out['Bytes Written'] ?? 0,
|
|
604
634
|
outputRecords: out['Records Written'] ?? null,
|
|
605
635
|
};
|
|
606
636
|
}
|
|
607
637
|
|
|
608
|
-
|
|
638
|
+
// Max-folds the TaskEnd's executor metrics into the executor's run peak. Spark polls them at
|
|
639
|
+
// executor heartbeat (spark.executor.metrics.pollingInterval defaults to 0), so a peak is a lower
|
|
640
|
+
// bound. All-zero rows (local mode) carry no measurement and are skipped.
|
|
641
|
+
function foldTaskExecutorMetrics(event , state ) {
|
|
642
|
+
const raw = event['Task Executor Metrics'];
|
|
643
|
+
const executorId = event['Task Info']?.['Executor ID'];
|
|
644
|
+
if (!raw || executorId == null) return;
|
|
645
|
+
let peaks ;
|
|
646
|
+
let measured = false;
|
|
647
|
+
for (const [sparkName, ourName] of EXECUTOR_METRIC_FIELDS) {
|
|
648
|
+
const value = raw[sparkName];
|
|
649
|
+
if (typeof value !== 'number' || !(value > 0)) continue;
|
|
650
|
+
measured = true;
|
|
651
|
+
peaks ??= state.executorPeakMetrics.get(executorId) ?? {};
|
|
652
|
+
if (value > (peaks[ourName] ?? 0)) peaks[ourName] = value;
|
|
653
|
+
}
|
|
654
|
+
if (!measured || !peaks) return;
|
|
655
|
+
state.executorPeakMetrics.set(executorId, peaks);
|
|
656
|
+
if (executorId !== DRIVER_EXECUTOR_ID) state.evidenceInputs.executorMetricRows++;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function sameIds(a , b ) {
|
|
660
|
+
if (b === undefined || a.length !== b.length) return false;
|
|
661
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// `accumulableIds`, when given, are the event's accumulator IDs, which then are not in the event.
|
|
666
|
+
export function accumulateTask(
|
|
667
|
+
event , state , accumulableIds ,
|
|
668
|
+
) {
|
|
669
|
+
foldTaskExecutorMetrics(event, state);
|
|
609
670
|
const stageId = event['Stage ID'];
|
|
610
671
|
const stage = state.stages.get(stageId);
|
|
611
672
|
if (!stage) return null;
|
|
@@ -623,10 +684,13 @@ export function accumulateTask(event , state
|
|
|
623
684
|
|
|
624
685
|
state.evidenceInputs.taskRecords++;
|
|
625
686
|
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
687
|
+
const ids = accumulableIds ?? (event['Task Info']?.Accumulables ?? []).map((acc) => acc.ID);
|
|
688
|
+
if (!sameIds(ids, state.lastTaskAccumIds.get(stageId))) {
|
|
689
|
+
state.lastTaskAccumIds.set(stageId, ids);
|
|
690
|
+
for (const id of ids) {
|
|
691
|
+
if (!state.taskAccumStages.has(id)) state.taskAccumStages.set(id, new Set());
|
|
692
|
+
state.taskAccumStages.get(id) .add(stageId);
|
|
693
|
+
}
|
|
630
694
|
}
|
|
631
695
|
|
|
632
696
|
const info = event['Task Info'] ?? {};
|
|
@@ -695,32 +759,40 @@ function accountLateSpeculativeLoser(event ,
|
|
|
695
759
|
return true;
|
|
696
760
|
}
|
|
697
761
|
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
// Driver-side values (DriverAccumUpdates) win over executor-side ones (StageCompleted
|
|
765
|
+
// accumulables); a metric has one of the two sources, so the order only matters for a log that
|
|
766
|
+
// carries both.
|
|
698
767
|
export function resolvePlanTree(
|
|
699
768
|
rootInfo ,
|
|
700
769
|
accumMap ,
|
|
701
770
|
taskAccumStages ,
|
|
702
771
|
executionStageIds ,
|
|
703
772
|
executionId ,
|
|
773
|
+
executorAccumMap ,
|
|
704
774
|
) {
|
|
705
775
|
const seen = new WeakSet ();
|
|
706
776
|
const nodeMap = new WeakMap ();
|
|
707
777
|
let nextId = 0;
|
|
708
|
-
// Prefixed with the owning SQL execution so PlanNode.id is globally unique
|
|
709
|
-
//
|
|
710
|
-
//
|
|
711
|
-
//
|
|
712
|
-
// threading execution scope through separately. No executionId (e.g. the
|
|
713
|
-
// legacy unit tests below) falls back to the old unprefixed "n0", "n1", ...
|
|
714
|
-
// shape.
|
|
778
|
+
// Prefixed with the owning SQL execution so PlanNode.id is globally unique: two executions'
|
|
779
|
+
// trees can each produce a node named "n1", and a consumer keying off id alone (e.g. a
|
|
780
|
+
// findings-by-nodeId index) must tell them apart. No executionId (hand-built trees in tests)
|
|
781
|
+
// leaves ids unprefixed: "n0", "n1", ...
|
|
715
782
|
const idPrefix = executionId != null ? `e${executionId}:` : '';
|
|
716
783
|
|
|
717
784
|
function computeMetricsAndStageIds(info )
|
|
718
|
-
|
|
785
|
+
|
|
719
786
|
|
|
720
787
|
{
|
|
721
|
-
const metrics = (info.metrics ?? []).reduce
|
|
722
|
-
if (m.accumulatorId
|
|
788
|
+
const metrics = (info.metrics ?? []).reduce ((acc, m) => {
|
|
789
|
+
if (m.accumulatorId === undefined) return acc;
|
|
790
|
+
if (accumMap.has(m.accumulatorId)) {
|
|
723
791
|
acc.push({ name: m.name, value: accumMap.get(m.accumulatorId) , metricType: m.metricType });
|
|
792
|
+
} else if (executorAccumMap?.has(m.accumulatorId) && m.metricType !== 'average') {
|
|
793
|
+
// An 'average' metric's accumulator holds a sum of per-task averages (scaled by 10), so
|
|
794
|
+
// its total is not the average the SQL tab shows; that needs the per-task values.
|
|
795
|
+
acc.push({ name: m.name, value: executorAccumMap.get(m.accumulatorId) , metricType: m.metricType, executorSide: true });
|
|
724
796
|
}
|
|
725
797
|
return acc;
|
|
726
798
|
}, []);
|
|
@@ -826,17 +898,20 @@ const EXECUTOR_METRIC_FIELD_MAP = {
|
|
|
826
898
|
MajorGCCount: 'majorGCCount', MajorGCTime: 'majorGCTime', TotalGCTime: 'totalGCTime',
|
|
827
899
|
ConcurrentGCCount: 'concurrentGCCount', ConcurrentGCTime: 'concurrentGCTime',
|
|
828
900
|
};
|
|
901
|
+
const EXECUTOR_METRIC_FIELDS = Object.entries(EXECUTOR_METRIC_FIELD_MAP);
|
|
829
902
|
|
|
830
903
|
export function startApplication(event , state ) {
|
|
831
904
|
const config = state.pendingConfig ?? {};
|
|
832
905
|
state.app = {
|
|
833
906
|
id: event['App ID'],
|
|
834
907
|
name: event['App Name'],
|
|
908
|
+
// Only in cluster-mode logs: Spark writes no attempt id for a client or local run.
|
|
909
|
+
...(event['App Attempt ID'] ? { attemptId: event['App Attempt ID'] } : {}),
|
|
835
910
|
startTime: event['Timestamp'],
|
|
836
911
|
endTime: null,
|
|
837
912
|
sparkVersion: state.pendingSparkVersion ?? event['Spark Version'] ?? null,
|
|
838
913
|
config,
|
|
839
|
-
resources: state.pendingResources ?? extractResources(config),
|
|
914
|
+
resources: state.pendingResources ?? extractResources(config, state.pendingSparkVersion ?? event['Spark Version']),
|
|
840
915
|
rddInfo: state.rddInfo,
|
|
841
916
|
};
|
|
842
917
|
return appMessage(state);
|
|
@@ -845,7 +920,7 @@ export function startApplication(event
|
|
|
845
920
|
export function updateEnvironment(event , state ) {
|
|
846
921
|
state.evidenceInputs.environmentUpdates++;
|
|
847
922
|
const config = normalizeSparkProperties(event['Spark Properties']);
|
|
848
|
-
const resources = extractResources(config);
|
|
923
|
+
const resources = extractResources(config, state.app?.sparkVersion ?? state.pendingSparkVersion);
|
|
849
924
|
// EnvironmentUpdate normally precedes ApplicationStart: stash the config so ApplicationStart can
|
|
850
925
|
// attach it. If it arrives after (a mid-run update), apply live and re-post the app.
|
|
851
926
|
if (state.app) {
|
|
@@ -1112,10 +1187,11 @@ export function recordStageExecutorMetrics(event
|
|
|
1112
1187
|
if (!stage) return null;
|
|
1113
1188
|
const raw = event['Executor Metrics'] ?? {};
|
|
1114
1189
|
const metrics = {};
|
|
1115
|
-
for (const [sparkName, ourName] of
|
|
1190
|
+
for (const [sparkName, ourName] of EXECUTOR_METRIC_FIELDS) {
|
|
1116
1191
|
if (raw[sparkName] != null) metrics[ourName] = raw[sparkName];
|
|
1117
1192
|
}
|
|
1118
|
-
|
|
1193
|
+
// A row for the driver's own heap is no executor measurement: the heap-peak finding leaves it out too.
|
|
1194
|
+
if (Object.keys(metrics).length > 0 && event['Executor ID'] !== DRIVER_EXECUTOR_ID) {
|
|
1119
1195
|
state.evidenceInputs.executorMetricRows++;
|
|
1120
1196
|
}
|
|
1121
1197
|
stage.executorMetrics.set(event['Executor ID'], metrics);
|
|
@@ -1132,6 +1208,7 @@ export function startSqlExecution(event
|
|
|
1132
1208
|
hadAdaptiveUpdate: false,
|
|
1133
1209
|
};
|
|
1134
1210
|
if (event.rootExecutionId !== undefined) exec.rootExecutionId = event.rootExecutionId;
|
|
1211
|
+
if (event.modifiedConfigs !== undefined && Object.keys(event.modifiedConfigs).length > 0) exec.modifiedConfigs = event.modifiedConfigs;
|
|
1135
1212
|
if (event.physicalPlanDescription && KEPT_ARGUMENTS.test(event.physicalPlanDescription)) {
|
|
1136
1213
|
exec.commandArguments = event.physicalPlanDescription;
|
|
1137
1214
|
}
|
|
@@ -1140,6 +1217,7 @@ export function startSqlExecution(event
|
|
|
1140
1217
|
state.resolvedPlanExecutions.delete(exec.id);
|
|
1141
1218
|
if (sparkPlanInfo !== null) {
|
|
1142
1219
|
state.accumState.set(exec.id, new Map());
|
|
1220
|
+
state.executorAccumState.set(exec.id, new Map());
|
|
1143
1221
|
}
|
|
1144
1222
|
return { type: 'sql', data: exec };
|
|
1145
1223
|
}
|
|
@@ -1157,14 +1235,17 @@ export function endSqlExecution(
|
|
|
1157
1235
|
const planInfo = exec?.sparkPlanInfo ?? null;
|
|
1158
1236
|
if (!planInfo || !planInfo.nodeName) {
|
|
1159
1237
|
state.accumState.delete(event.executionId);
|
|
1238
|
+
state.executorAccumState.delete(event.executionId);
|
|
1160
1239
|
return exec ? { type: 'sql', data: { ...exec } } : null;
|
|
1161
1240
|
}
|
|
1162
1241
|
|
|
1163
1242
|
const accumMap = state.accumState.get(event.executionId) ?? new Map ();
|
|
1164
1243
|
const planTree = resolvePlanTree(
|
|
1165
1244
|
planInfo, accumMap, state.taskAccumStages, state.sqlExecStages.get(event.executionId), event.executionId,
|
|
1245
|
+
state.executorAccumState.get(event.executionId),
|
|
1166
1246
|
);
|
|
1167
1247
|
state.accumState.delete(event.executionId);
|
|
1248
|
+
state.executorAccumState.delete(event.executionId);
|
|
1168
1249
|
// The resolved tree is all anything downstream reads; the raw plan (often megabytes per
|
|
1169
1250
|
// execution under AQE) would otherwise stay live for the rest of the parse.
|
|
1170
1251
|
exec .sparkPlanInfo = null;
|
|
@@ -1174,6 +1255,24 @@ export function endSqlExecution(
|
|
|
1174
1255
|
return { type: 'sqlPlan', data: { executionId: event.executionId, planTree } };
|
|
1175
1256
|
}
|
|
1176
1257
|
|
|
1258
|
+
// Keeps the latest total of every SQL metric accumulator a stage reports, for the execution that
|
|
1259
|
+
// ran the stage. A stage's accumulables hold each accumulator's running total across all stages
|
|
1260
|
+
// and attempts, so a later stage overwrites an earlier one rather than adding to it (Spark's
|
|
1261
|
+
// DAGScheduler.updateAccumulators merges into the driver-side accumulator and records its value;
|
|
1262
|
+
// the SQL tab sums the same task updates). Spark writes the value as a decimal string.
|
|
1263
|
+
export function recordStageSqlAccumulables(info , state ) {
|
|
1264
|
+
const accumulables = info.Accumulables;
|
|
1265
|
+
if (!accumulables || accumulables.length === 0) return;
|
|
1266
|
+
const executionId = state.stageToSqlExec.get(info['Stage ID']);
|
|
1267
|
+
const totals = executionId === undefined ? undefined : state.executorAccumState.get(executionId);
|
|
1268
|
+
if (!totals) return;
|
|
1269
|
+
for (const acc of accumulables) {
|
|
1270
|
+
if (acc.Metadata !== 'sql') continue;
|
|
1271
|
+
const value = typeof acc.Value === 'string' ? Number(acc.Value) : acc.Value;
|
|
1272
|
+
if (typeof value === 'number' && Number.isFinite(value)) totals.set(acc.ID, value);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1177
1276
|
export function applyDriverAccumUpdates(event , state ) {
|
|
1178
1277
|
const { executionId, accumUpdates } = event;
|
|
1179
1278
|
if (!state.accumState.has(executionId)) return null; // late update, discard
|
|
@@ -1266,6 +1365,7 @@ export function processEvent(event , state ) {
|
|
|
1266
1365
|
const id = info['Stage ID'];
|
|
1267
1366
|
const stage = state.stages.get(id);
|
|
1268
1367
|
if (!stage) return null;
|
|
1368
|
+
recordStageSqlAccumulables(info, state);
|
|
1269
1369
|
stage.completedAt = info['Completion Time'] ?? 0;
|
|
1270
1370
|
// Older Spark (seen on 1.x-2.0 logs) posts StageSubmitted before the stage's submission
|
|
1271
1371
|
// time is set; StageCompleted carries it. Without this backfill submittedAt stays 0 and
|
|
@@ -1321,9 +1421,8 @@ const KNOWN_EVENT_TYPES = new Set(
|
|
|
1321
1421
|
);
|
|
1322
1422
|
|
|
1323
1423
|
// SQLExecutionStart and SQLAdaptiveExecutionUpdate carry `physicalPlanDescription`, Spark's text
|
|
1324
|
-
// rendering of the plan. The plan tree comes from sparkPlanInfo,
|
|
1325
|
-
//
|
|
1326
|
-
// string value out before JSON.parse halves the parse cost of those lines.
|
|
1424
|
+
// rendering of the plan. The plan tree comes from sparkPlanInfo, so the description's string value
|
|
1425
|
+
// is cut out before JSON.parse (worker-protocol.md, "Decoder and parser calibration").
|
|
1327
1426
|
//
|
|
1328
1427
|
// One exception: a Delta write command's node prints only its bare name in sparkPlanInfo, and its
|
|
1329
1428
|
// target table appears only on its `Arguments:` line of the description. When the description is
|
|
@@ -1435,13 +1534,25 @@ const ACCUMULABLE_ID_KEY = '"ID":';
|
|
|
1435
1534
|
const MAX_ACCUMULABLE_ID_DIGITS = 15;
|
|
1436
1535
|
|
|
1437
1536
|
// Parses a TaskEnd line with its Task Info Accumulables array reduced to the `{ID}` entries
|
|
1438
|
-
// accumulateTask reads, or returns null for the caller to parse the line whole. That array is
|
|
1439
|
-
// of TaskEnd bytes
|
|
1537
|
+
// accumulateTask reads, or returns null for the caller to parse the line whole. That array is most
|
|
1538
|
+
// of a TaskEnd line's bytes (worker-protocol.md, "Decoder and parser calibration").
|
|
1440
1539
|
// The IDs are read with a string scan and the array is cut out before JSON.parse, but only when
|
|
1441
1540
|
// every entry has Spark's flat form (`{"ID":n,...}`, ID first, no nested array): any `{` that
|
|
1442
1541
|
// doesn't open `{"ID":n` or any `[` in the array (updatedBlockStatuses) falls back. A `]` inside a
|
|
1443
1542
|
// Name string cuts the array short and leaves invalid JSON, which falls back too.
|
|
1444
1543
|
export function parseTaskEnd(line ) {
|
|
1544
|
+
const split = splitTaskEnd(line);
|
|
1545
|
+
if (!split) return null;
|
|
1546
|
+
split.parsed['Task Info'] .Accumulables = split.ids.map((ID) => ({ ID }));
|
|
1547
|
+
return split.parsed;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
|
|
1552
|
+
// parseTaskEnd's work with the IDs left apart from the parsed event, whose Accumulables is empty:
|
|
1553
|
+
// the scan already read the IDs as digits, so parseAndDispatch hands them straight to accumulateTask
|
|
1554
|
+
// instead of validating them again.
|
|
1555
|
+
function splitTaskEnd(line ) {
|
|
1445
1556
|
if (!line.startsWith(TASK_END_PREFIX)) return null;
|
|
1446
1557
|
const keyAt = line.indexOf(ACCUMULABLES_KEY);
|
|
1447
1558
|
if (keyAt === -1) return null;
|
|
@@ -1461,6 +1572,7 @@ export function parseTaskEnd(line ) {
|
|
|
1461
1572
|
if (after !== 0x2c && after !== 0x7d) return null; // `,` or `}`
|
|
1462
1573
|
ids.push(id);
|
|
1463
1574
|
}
|
|
1575
|
+
if (ids.length > MAX_ACCUMULABLES_PER_TASK) return null; // the schema rejects it: parse whole
|
|
1464
1576
|
let parsed ;
|
|
1465
1577
|
try {
|
|
1466
1578
|
parsed = JSON.parse(line.slice(0, from) + line.slice(close));
|
|
@@ -1469,8 +1581,7 @@ export function parseTaskEnd(line ) {
|
|
|
1469
1581
|
}
|
|
1470
1582
|
const info = parsed?.['Task Info'];
|
|
1471
1583
|
if (!info || !Array.isArray(info.Accumulables) || info.Accumulables.length !== 0) return null;
|
|
1472
|
-
|
|
1473
|
-
return parsed;
|
|
1584
|
+
return { parsed: parsed , ids };
|
|
1474
1585
|
}
|
|
1475
1586
|
|
|
1476
1587
|
const ADAPTIVE_UPDATE_PREFIX =
|
|
@@ -1481,16 +1592,14 @@ const MAX_EXECUTION_ID_DIGITS = 20;
|
|
|
1481
1592
|
|
|
1482
1593
|
// An AQE update replaces its execution's whole plan, and nothing reads a plan an update replaced:
|
|
1483
1594
|
// only the last one before SQLExecutionEnd is resolved. So while the execution is open, only its
|
|
1484
|
-
// latest update is kept, as unparsed text, and superseded ones are never parsed
|
|
1485
|
-
//
|
|
1486
|
-
// cut. Returns false (parse it now, as any other line) unless the line is Spark's compact form
|
|
1595
|
+
// latest update is kept, as unparsed text, and superseded ones are never parsed (figures:
|
|
1596
|
+
// worker-protocol.md, "Decoder and parser calibration"). Returns false (parse it now, as any other line) unless the line is Spark's compact form
|
|
1487
1597
|
// ending in an object-valued `sparkPlanInfo`, its last field: a null-plan update keeps the
|
|
1488
1598
|
// previous plan, so it can't supersede one. Trade-off: a malformed superseded update is never
|
|
1489
|
-
// seen, so it
|
|
1599
|
+
// seen, so it does not count as a skipped line.
|
|
1490
1600
|
//
|
|
1491
1601
|
// These updates span decode slices, so `line` is a cons string: the prefix and suffix checks read
|
|
1492
|
-
// `joined`'s flat pieces instead, or a superseded update is copied flat only to be dropped
|
|
1493
|
-
// copies of 1.1 MB on that log). A piece too short to hold what is checked falls back to `line`.
|
|
1602
|
+
// `joined`'s flat pieces instead, or a superseded update is copied flat only to be dropped. A piece too short to hold what is checked falls back to `line`.
|
|
1494
1603
|
function deferAdaptiveUpdate(
|
|
1495
1604
|
line , state , emit , joined ,
|
|
1496
1605
|
) {
|
|
@@ -1548,8 +1657,11 @@ function noteUnreadableSqlStart(line , state ) {
|
|
|
1548
1657
|
function parseAndDispatch(line , state , emit ) {
|
|
1549
1658
|
if (line.startsWith(BLOCK_UPDATED_PREFIX) && !line.includes(RDD_BLOCK_ID_FRAGMENT)) return;
|
|
1550
1659
|
let parsed ;
|
|
1660
|
+
let taskEndIds ;
|
|
1551
1661
|
try {
|
|
1552
|
-
|
|
1662
|
+
const split = splitTaskEnd(line);
|
|
1663
|
+
if (split) ({ parsed, ids: taskEndIds } = split);
|
|
1664
|
+
else parsed = JSON.parse(stripPlanDescription(line));
|
|
1553
1665
|
} catch {
|
|
1554
1666
|
state.skippedLines++;
|
|
1555
1667
|
noteUnreadableSqlStart(line, state);
|
|
@@ -1573,7 +1685,9 @@ function parseAndDispatch(line , state , emit
|
|
|
1573
1685
|
}
|
|
1574
1686
|
let msg ;
|
|
1575
1687
|
try {
|
|
1576
|
-
msg =
|
|
1688
|
+
msg = taskEndIds && result.data.Event === 'SparkListenerTaskEnd'
|
|
1689
|
+
? accumulateTask(result.data, state, taskEndIds)
|
|
1690
|
+
: processEvent(result.data, state);
|
|
1577
1691
|
} catch (err) {
|
|
1578
1692
|
// processEvent's switch is exhaustive over the schema-validated union (assertNever default), so
|
|
1579
1693
|
// this is unreachable for any event that got this far. If it fires it's a handler bug, not
|
|
@@ -1623,11 +1737,14 @@ export function collectLateAttemptWork(state )
|
|
|
1623
1737
|
}
|
|
1624
1738
|
|
|
1625
1739
|
export function emitParseCompletion(state , emit , linesProcessed ) {
|
|
1626
|
-
// Executions that never ended
|
|
1740
|
+
// Executions that never ended still apply their latest deferred AQE update.
|
|
1627
1741
|
for (const executionId of [...state.pendingAdaptiveUpdates.keys()]) flushAdaptiveUpdate(executionId, state, emit);
|
|
1628
1742
|
emit({ type: 'progress', pct: 1, linesProcessed });
|
|
1629
1743
|
emit({ type: 'stageLateAttemptWork', data: collectLateAttemptWork(state) });
|
|
1630
|
-
emit({
|
|
1744
|
+
emit({
|
|
1745
|
+
type: 'runAggregates',
|
|
1746
|
+
data: { ...computeRunAggregates(state.taskStore), executorPeakMetrics: Object.fromEntries(state.executorPeakMetrics) },
|
|
1747
|
+
});
|
|
1631
1748
|
emit({ type: 'stageSpeculationWaste', data: collectLateSpeculationWaste(state) });
|
|
1632
1749
|
emit({ type: 'stageExecutorMetrics', data: collectStageExecutorMetrics(state) });
|
|
1633
1750
|
emit(appMessage(state));
|
|
@@ -1637,4 +1754,5 @@ export function emitParseCompletion(state , emit
|
|
|
1637
1754
|
...(state.unreadableSqlStarts.size > 0 ? { unreadableSqlExecutions: [...state.unreadableSqlStarts].sort((a, b) => a - b) } : {}),
|
|
1638
1755
|
});
|
|
1639
1756
|
state.accumState.clear();
|
|
1757
|
+
state.executorAccumState.clear();
|
|
1640
1758
|
}
|