})
}
- // We queue up a goroutine per function that needs to be
- // compiled, but require them to grab an available worker ID
- // before doing any substantial work to limit parallelism.
- workerIDs := make(chan int, base.Flag.LowerC)
- for i := 0; i < base.Flag.LowerC; i++ {
- workerIDs <- i
+ // By default, we perform work right away on the current goroutine
+ // as the solo worker.
+ queue := func(work func(int)) {
+ work(0)
+ }
+
+ 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
+ }
+
+ queue = func(work func(int)) {
+ go func() {
+ worker := <-workerIDs
+ work(worker)
+ workerIDs <- worker
+ }()
+ }
}
var wg sync.WaitGroup
- var asyncCompile func(*ir.Func)
- asyncCompile = func(fn *ir.Func) {
- wg.Add(1)
- go func() {
- worker := <-workerIDs
- ssagen.Compile(fn, worker)
- workerIDs <- worker
-
- // Done compiling fn. Schedule it's closures for compilation.
- for _, closure := range fn.Closures {
- asyncCompile(closure)
- }
- wg.Done()
- }()
+ var compile func([]*ir.Func)
+ compile = func(fns []*ir.Func) {
+ wg.Add(len(fns))
+ for _, fn := range fns {
+ fn := fn
+ queue(func(worker int) {
+ ssagen.Compile(fn, worker)
+ compile(fn.Closures)
+ wg.Done()
+ })
+ }
}
types.CalcSizeDisabled = true // not safe to calculate sizes concurrently
base.Ctxt.InParallel = true
- for _, fn := range compilequeue {
- asyncCompile(fn)
- }
+
+ compile(compilequeue)
compilequeue = nil
wg.Wait()
+
base.Ctxt.InParallel = false
types.CalcSizeDisabled = false
}