@@ -33,7 +33,6 @@ import (
3333 "os"
3434 "os/exec"
3535 "path/filepath"
36- "runtime"
3736 "strconv"
3837 "strings"
3938 "sync"
@@ -46,16 +45,20 @@ import (
4645 "github.com/arduino/go-properties-orderedmap"
4746)
4847
49- func PrintProgressIfProgressEnabledAndMachineLogger (ctx * types.Context ) {
48+ func PrintProgressIfProgressEnabledAndMachineLogger (ctx * types.Context , progressEnabled bool , stepSize float64 ) {
5049
51- if ! ctx .Progress .PrintEnabled {
50+ var mut sync.Mutex
51+ if ! progressEnabled {
5252 return
5353 }
5454
5555 log := ctx .GetLogger ()
5656 if log .Name () == "machine" {
57+ mut .Lock ()
5758 log .Println (constants .LOG_LEVEL_INFO , constants .MSG_PROGRESS , strconv .FormatFloat (ctx .Progress .Progress , 'f' , 2 , 32 ))
58- ctx .Progress .Progress += ctx .Progress .Steps
59+ ctx .Progress .Progress += stepSize
60+ log .Flush ()
61+ mut .Unlock ()
5962 }
6063}
6164
@@ -170,61 +173,57 @@ func compileFilesWithRecipe(ctx *types.Context, sourcePath *paths.Path, sources
170173 if len (sources ) == 0 {
171174 return objectFiles , nil
172175 }
173- var objectFilesMux sync. Mutex
174- var errors [] error
175- var errorsMux sync. Mutex
176+ objectFilesChan := make ( chan * paths. Path )
177+ errorsChan := make ( chan error )
178+ doneChan := make ( chan struct {})
176179
177- ctx .Progress .Steps = ctx .Progress .Steps / float64 (len (sources ))
180+ stepSize := ctx .Progress .Steps / float64 (len (sources ))
181+ var wg sync.WaitGroup
178182
179- queue := make (chan * paths.Path )
180- job := func (source * paths.Path ) {
181- PrintProgressIfProgressEnabledAndMachineLogger (ctx )
182- objectFile , err := compileFileWithRecipe (ctx , sourcePath , source , buildPath , buildProperties , includes , recipe )
183- if err != nil {
184- errorsMux .Lock ()
185- errors = append (errors , err )
186- errorsMux .Unlock ()
187- } else {
188- objectFilesMux .Lock ()
189- objectFiles .Add (objectFile )
190- objectFilesMux .Unlock ()
183+ // Split jobs into batches of N jobs each; wait for the completion of a batch to start the next
184+ par := ctx .Jobs
185+
186+ go func () {
187+ for total := 0 ; total < len (sources ); total += par {
188+ for i := total ; i < total + par && i < len (sources ); i ++ {
189+ wg .Add (1 )
190+ go func (source * paths.Path ) {
191+ defer wg .Done ()
192+ go PrintProgressIfProgressEnabledAndMachineLogger (ctx , true , stepSize )
193+ objectFile , err := compileFileWithRecipe (ctx , sourcePath , source , buildPath , buildProperties , includes , recipe )
194+ if err != nil {
195+ errorsChan <- err
196+ } else {
197+ objectFilesChan <- objectFile
198+ }
199+ }(sources [i ])
200+ }
201+ wg .Wait ()
191202 }
192- }
193203
194- // Spawn jobs runners
195- var wg sync.WaitGroup
196- jobs := ctx .Jobs
197- if jobs == 0 {
198- jobs = runtime .NumCPU ()
199- }
200- for i := 0 ; i < jobs ; i ++ {
201- wg .Add (1 )
202- go func () {
203- for source := range queue {
204- job (source )
205- }
206- wg .Done ()
207- }()
208- }
204+ doneChan <- struct {}{}
205+ }()
206+
207+ go func () {
208+ wg .Wait ()
209+ doneChan <- struct {}{}
210+ }()
209211
210- // Feed jobs until error or done
211- for _ , source := range sources {
212- errorsMux .Lock ()
213- gotError := len (errors ) > 0
214- errorsMux .Unlock ()
215- if gotError {
216- break
212+ for {
213+ select {
214+ case objectFile := <- objectFilesChan :
215+ objectFiles .Add (objectFile )
216+ case err := <- errorsChan :
217+ return nil , i18n .WrapError (err )
218+ case <- doneChan :
219+ close (objectFilesChan )
220+ for objectFile := range objectFilesChan {
221+ objectFiles .Add (objectFile )
222+ }
223+ objectFiles .Sort ()
224+ return objectFiles , nil
217225 }
218- queue <- source
219- }
220- close (queue )
221- wg .Wait ()
222- if len (errors ) > 0 {
223- // output the first error
224- return nil , i18n .WrapError (errors [0 ])
225226 }
226- objectFiles .Sort ()
227- return objectFiles , nil
228227}
229228
230229func compileFileWithRecipe (ctx * types.Context , sourcePath * paths.Path , source * paths.Path , buildPath * paths.Path , buildProperties * properties.Map , includes []string , recipe string ) (* paths.Path , error ) {
0 commit comments