Skip to content

build: prepare bounded parallel compilation#2174

Open
zhouguangyuan0718 wants to merge 2 commits into
xgo-dev:mainfrom
zhouguangyuan0718:agent/parallel-build-pr0
Open

build: prepare bounded parallel compilation#2174
zhouguangyuan0718 wants to merge 2 commits into
xgo-dev:mainfrom
zhouguangyuan0718:agent/parallel-build-pr0

Conversation

@zhouguangyuan0718

Copy link
Copy Markdown
Contributor

Summary

  • map Go build -p to typed LLGo parallelism and use it for the SSA build worker pool
  • split package frontend/backend stages while keeping LLVM backend execution serial
  • make cache dependency collection include alternate-package imports and initialize package build state explicitly

Validation

  • GOCACHE=/private/tmp/llgo-pr0-gocache go test ./internal/build ./internal/goflags ./cmd/internal/flags -count=1
  • GOCACHE=/private/tmp/llgo-pr0-gocache go test ./internal/build -run TestModuleHookReceivesMainPackageModule -count=1

This is PR0 of the staged parallel-build refactor. Later PRs will stack on this branch.

@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: build: prepare bounded parallel compilation

This is a clean, well-documented preparatory refactor. The buildOnePackage extraction preserves the semantics of the old buildOne closure across all PkgKind cases and needRuntime/needPyInit propagation; the bounded SSA worker pool is free of deadlocks/double-builds; effectiveDependencies correctly fixes the stale-cache case for alt-package imports; and the doc comments accurately match the code (including the "ssa.Package.Build is thread-safe" claim, which holds for the pinned x/tools).

One notable finding is flagged inline. A few minor observations follow.

Minor observations

  • internal/build/build.go (buildSSAPkgs, ~L2036): the dedup keeps the first ssaBuildEntry per *ssa.Package pointer. Entries are concatenated as altEntries, pkgEntries, depEntries; alt entries carry fixOrder:false while ordinary ones carry fixOrder:true. Alt and ordinary packages currently have disjoint pointers, so this is not reachable today, but fixSSAOrder coverage relies on that invariant rather than on the dedup itself. Consider OR-ing fixOrder across duplicate entries (or documenting the invariant) to keep it robust against future changes.

  • internal/build/build.go (parallelism, ~L21 vs Do, ~L29): parallelism() guards c != nil, but Do dereferences conf unconditionally, so the nil check is effectively dead. Minor inconsistency — either drop the dead guard or document that Do requires a non-nil conf.

  • internal/build/build.go (Config.Parallel doc) vs internal/goflags/gobuild.go (parseBuildParallel): the field doc says "Zero uses GOMAXPROCS," but -p=0 is rejected as "must be a positive integer." That's fine (omitting -p leaves the zero default → GOMAXPROCS), but a one-line note that -p must be >= 1 while the unset default means GOMAXPROCS would avoid confusion.

  • internal/build/build.go (buildSSAPkgs, ~L2046): the jobs channel is unbuffered, so each dispatch blocks on a worker wake-up. For the common many-tiny-packages case a small buffer (e.g. make(chan ssaBuildEntry, workers)) would cut hand-off stalls. Optional.

Scope note: the parallelism here covers only ssa.Package.Build(); the dominant frontend/LLVM compile pipeline (buildOnePackagecompilePackageModule) is still serial. This matches the stated intent ("prepare"), so measurable speedup is deferred to a follow-up — flagging only so the "parallel compilation" framing isn't read as already delivering wall-clock gains. Worth a -race run over the concurrent SSA build path to lock in the thread-safety claim.

"gcflags",
"gccgoflags",
"ldflags",
"p",

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.

Adding "p" to argumentListFlagNames has an asymmetric side effect in flag files.

This list is used both by normalizeBuildFlags (so -p 3-p=3, which parseBuildParallel needs) and by wholeLineValueFlag in this file, which treats the entire remainder of a flags-file line as a single value. That greedy behavior is correct for genuine argument-list flags like -ldflags, but -p takes a single integer.

Consequence: a flags-file line combining -p with other flags, e.g.

-p=4 -trimpath

is collapsed into the single token -p=4 -trimpath. strconv.Atoi("4 -trimpath") then fails with -p must be a positive integer, got "4 -trimpath", and -trimpath is silently swallowed. The equivalent command-line form works because normalizeBuildFlags processes each arg independently.

Suggestion: allow -p to be normalized without adding it to the whole-line argumentListFlagNames set — e.g. a separate list for wholeLineValueFlag, or special-case -p so it only claims the single following integer. A test covering -p combined with other flags on one flags-file line would guard this.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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