aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2022-09-19 21:48:10 -0400
committerGopher Robot <gobot@golang.org>2022-09-29 16:23:56 +0000
commit2ff5fbfbd4539d321043e6b84691ecb131402030 (patch)
tree834ff22108a009d309babb4d1019ed458aa1108a /src
parent9861e8b2fd83dec24a6ced44998dca52abd6ccff (diff)
downloadgo-2ff5fbfbd4539d321043e6b84691ecb131402030.tar.xz
cmd/compile: limit goroutine count to parallelism
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 <cuong.manhle.vn@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Russ Cox <rsc@golang.org> Auto-Submit: Russ Cox <rsc@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/gc/compile.go44
1 files changed, 31 insertions, 13 deletions
diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go
index 00504451a8..cbd48e0956 100644
--- a/src/cmd/compile/internal/gc/compile.go
+++ b/src/cmd/compile/internal/gc/compile.go
@@ -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
}
}