Skip to content

Commit

Permalink
cmd/compile: limit goroutine count to parallelism
Browse files Browse the repository at this point in the history
When the compiler crashes, it is not uncommon to see many hundreds
of goroutines all blocked waiting their turn to be one of the nWorkers
goroutines that is allowed to run. All these goroutine stacks are not a
terribly efficient use of memory, and they also make the crash dumps
hard to read.

Introduce a manager goroutine to hand out work to at most nWorker
goroutines, maintaining pending work in a local slice, rather than
having all those blocked goroutines hanging around waiting to run.

Change-Id: I46cb4e1afd6392805f359e14554ebc17d538bcba
Reviewed-on: https://go-review.googlesource.com/c/go/+/431956
Reviewed-by: Cuong Manh Le <[email protected]>
Reviewed-by: Cherry Mui <[email protected]>
Run-TryBot: Russ Cox <[email protected]>
Auto-Submit: Russ Cox <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
  • Loading branch information
rsc authored and gopherbot committed Sep 29, 2022
1 parent 9861e8b commit 2ff5fbf
Showing 1 changed file with 31 additions and 13 deletions.
44 changes: 31 additions & 13 deletions src/cmd/compile/internal/gc/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,20 +126,38 @@ func compileFunctions() {
}

if nWorkers := base.Flag.LowerC; nWorkers > 1 {
// For concurrent builds, we create a goroutine per task, but
// require them to hold a unique worker ID while performing work
// to limit parallelism.
workerIDs := make(chan int, nWorkers)
for i := 0; i < nWorkers; i++ {
workerIDs <- i
}

// For concurrent builds, we allow the work queue
// to grow arbitrarily large, but only nWorkers work items
// can be running concurrently.
workq := make(chan func(int))
done := make(chan int)
go func() {
ids := make([]int, nWorkers)
for i := range ids {
ids[i] = i
}
var pending []func(int)
for {
select {
case work := <-workq:
pending = append(pending, work)
case id := <-done:
ids = append(ids, id)
}
for len(pending) > 0 && len(ids) > 0 {
work := pending[len(pending)-1]
id := ids[len(ids)-1]
pending = pending[:len(pending)-1]
ids = ids[:len(ids)-1]
go func() {
work(id)
done <- id
}()
}
}
}()
queue = func(work func(int)) {
go func() {
worker := <-workerIDs
work(worker)
workerIDs <- worker
}()
workq <- work
}
}

Expand Down

0 comments on commit 2ff5fbf

Please sign in to comment.