Skip to content

build: guard and verify deadcode test-main roots - #2388

Closed
cpunion wants to merge 2 commits into
xgo-dev:mainfrom
cpunion:codex/guard-deadcode-test-entry
Closed

build: guard and verify deadcode test-main roots#2388
cpunion wants to merge 2 commits into
xgo-dev:mainfrom
cpunion:codex/guard-deadcode-test-entry

Conversation

@cpunion

@cpunion cpunion commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Skip global method-table pruning when main.main is absent from package metadata.
  • Retain weak method tables and print a verbose diagnostic on that fail-safe path.
  • Add an end-to-end generated test-main regression covering both main.init and main.main roots.
  • Verify that live interface methods remain callable while an unrelated dead method is removed from the linked test binary.

Motivation

#2370 restored the generated test main to the main ABI identity. Before that fix, whole-program method analysis could not resolve the executable roots and could remove methods required by testing.M.Run. The resulting binary was smaller but invalid; the reproduced Dustin_humanize binary crashed at startup with unreachable method called.

This PR makes the metadata invariant fail-safe. It also prevents the opposite regression: merely disabling method pruning would retain the dead method and fail the new symbol assertion.

The normal post-#2370 path is unchanged, so this PR is a correctness guard and regression test rather than a size optimization.

Size validation

Published Linux Bent results for Dustin_humanize:

Build Size Result
Pre-#2370, missing roots 3,586,976 B Crashes during testing.M.Run
#2370, correct roots with deadcode drop 3,803,824 B Passes
#2370, deadcode drop disabled 5,244,456 B Passes

Correct test-main deadcode drop removes 1,440,632 B, or 27.5%, relative to disabling deadcode drop. The old result was another 216,848 B smaller only because it removed live code.

For the new regression fixture on macOS arm64:

Build Size
Deadcode drop disabled 4,659,632 B
Deadcode drop enabled 3,466,784 B

That is a reduction of 1,192,848 B, or 25.6%. The optimized binary passes, retains the init-only and test-only live methods, and does not contain deadAnswer.Drop.

Testing

  • go test -tags=dev ./internal/build ./internal/deadcode ./internal/meta -count=1
  • Targeted coverage: applyDeadcodeDropOverrides 91.7%, hasDCEExecutableRoot 100%
  • Pre-build: preserve main package identity for test builds #2370 reproduction: the new fixture fails during testing.M.Run
  • CI: 41 checks passed, with one expected release check skipped
  • Codecov: all modified and coverable lines are covered

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: guard deadcode pruning when main.main is absent

The guard is small, well-scoped, and correct in intent: when the Go executable entry root is missing from package metadata (as with generated test mains), it skips method pruning rather than emitting a smaller binary that crashes at startup. The helper name reads cleanly, the verbose diagnostic matches the check, and the new tests assert on concrete IR/diagnostic output. Performance and security passes found nothing of concern.

Two substantive points below. Both are non-blocking.

Also worth a brief comment (minor): the guard keys only on main.main while dceEntryRootCandidates seeds both main.init and main.main; and the os.Stderr swap in TestApplyDeadcodeDropOverridesSkipsMissingGoEntryRoot is safe only because no test in this package uses t.Parallel(). Neither needs changing today.

Comment thread internal/build/build.go Outdated
Comment thread internal/build/build.go
@cpunion
cpunion force-pushed the codex/guard-deadcode-test-entry branch from 3d026cf to 5a5595f Compare August 22, 2026 04:26
@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Aug 22, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

e17231d927c5 | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Build vs base Run vs base
Linux cprintf 19288 B 0 B / +0.0% 274.683 ms +11.49 ms / +4.4% (worse) 1.156 ms +90.42 us / +8.5% (worse)
Linux cprintf-lto 19120 B 0 B / +0.0% 301.392 ms +35.27 ms / +13.3% (worse) 1.076 ms +3.518 us / +0.3% (worse)
Linux fmtprintf 1866216 B 0 B / +0.0% 2.223 s +1.675 ms / +0.1% (worse) 2.755 ms -27.45 us / -1.0% (better)
Linux fmtprintf-lto 1779144 B 0 B / +0.0% 10.906 s -89.12 ms / -0.8% (better) 2.718 ms -42.04 us / -1.5% (better)
Linux println 68776 B 0 B / +0.0% 267.248 ms +9.02 ms / +3.5% (worse) 1.339 ms -2.145 us / -0.2% (better)
Linux println-lto 62464 B 0 B / +0.0% 426.608 ms -25.67 ms / -5.7% (better) 1.325 ms -27.58 us / -2.0% (better)
macOS cprintf 84672 B 0 B / +0.0% 628.444 ms +112.6 ms / +21.8% (worse) 5.876 ms +2.212 ms / +60.3% (worse)
macOS cprintf-lto 100912 B 0 B / +0.0% 552.838 ms +75.37 ms / +15.8% (worse) 4.728 ms +1.147 ms / +32.0% (worse)
macOS fmtprintf 1909296 B 0 B / +0.0% 3.256 s -55.04 ms / -1.7% (better) 16.186 ms +1.888 ms / +13.2% (worse)
macOS fmtprintf-lto 1626224 B 0 B / +0.0% 19.648 s +206 ms / +1.1% (worse) 6.662 ms +607.1 us / +10.0% (worse)
macOS println 121360 B 0 B / +0.0% 461.662 ms -61.6 ms / -11.8% (better) 5.857 ms +1.274 ms / +27.8% (worse)
macOS println-lto 128528 B 0 B / +0.0% 602.652 ms -25.68 ms / -4.1% (better) 4.255 ms +524.9 us / +14.1% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 9.542 ns/op +0.006 ns/op / +0.1% (worse)
Linux BenchmarkMergeCompilerFlags 111.100 ns/op -1 ns/op / -0.9% (better)
Linux BenchmarkMergeLinkerFlags 72.560 ns/op -0.5 ns/op / -0.7% (better)
Linux BenchmarkChannelBuffered 28.230 ns/op +0.11 ns/op / +0.4% (worse)
Linux BenchmarkChannelHandoff 19149 ns/op -331 ns/op / -1.7% (better)
Linux BenchmarkDefer 35.010 ns/op -0.25 ns/op / -0.7% (better)
Linux BenchmarkDirectCall 1.364 ns/op 0 ns/op / +0.0%
Linux BenchmarkGlobalRead 1.364 ns/op -0.001 ns/op / -0.1% (better)
Linux BenchmarkGlobalWrite 2.179 ns/op 0 ns/op / +0.0%
Linux BenchmarkGoroutine 23742 ns/op -645 ns/op / -2.6% (better)
Linux BenchmarkInterfaceCall 6.824 ns/op +0.004 ns/op / +0.1% (worse)
Linux BenchmarkRuntimeGetG 1.638 ns/op 0 ns/op / +0.0%
macOS BenchmarkLookupPCRandom 14.030 ns/op +2.29 ns/op / +19.5% (worse)
macOS BenchmarkMergeCompilerFlags 121.400 ns/op +5.3 ns/op / +4.6% (worse)
macOS BenchmarkMergeLinkerFlags 75.550 ns/op -2.37 ns/op / -3.0% (better)
macOS BenchmarkChannelBuffered 24.260 ns/op -4.89 ns/op / -16.8% (better)
macOS BenchmarkChannelHandoff 7581 ns/op -1716 ns/op / -18.5% (better)
macOS BenchmarkDefer 34.780 ns/op -5.53 ns/op / -13.7% (better)
macOS BenchmarkDirectCall 1.105 ns/op -0.231 ns/op / -17.3% (better)
macOS BenchmarkGlobalRead 1.285 ns/op +0.074 ns/op / +6.1% (worse)
macOS BenchmarkGlobalWrite 1.174 ns/op -0.64 ns/op / -35.3% (better)
macOS BenchmarkGoroutine 49409 ns/op -5804 ns/op / -10.5% (better)
macOS BenchmarkInterfaceCall 6.196 ns/op -1.646 ns/op / -21.0% (better)
macOS BenchmarkRuntimeGetG 2.263 ns/op -0.549 ns/op / -19.5% (better)

Compared with 8b630ab55b1b measured in the same runner job.

@cpunion cpunion changed the title build: guard deadcode test-main reachability build: guard and verify deadcode test-main roots Aug 22, 2026
@cpunion cpunion closed this Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant