Skip to content

Commit

Permalink
feat: bounded concurrency for binary inspection
Browse files Browse the repository at this point in the history
Uses a semaphore to bound concurrency to GOMAXPROCS value. Fixes #14.

On my system, a cached --dry-run goes from ~820ms to ~130ms, and an
uncached one that needs to hit the network goes from ~2s to ~300ms.

Benchmark results from my laptop:
```
$ hyperfine --warmup 1 'go-global-update --dry-run' './go-global-update-fork --dry-run'
Benchmark 1: go-global-update --dry-run
  Time (mean ± σ):     821.7 ms ±   7.7 ms    [User: 171.8 ms, System: 139.0 ms]
  Range (min … max):   806.2 ms … 832.8 ms    10 runs

Benchmark 2: ./go-global-update-fork --dry-run
  Time (mean ± σ):     129.5 ms ±   4.2 ms    [User: 152.8 ms, System: 187.8 ms]
  Range (min … max):   120.3 ms … 137.3 ms    22 runs
```

Results with no modcache (cleared via `go clean -modcache`):
```
hyperfine --prepare 'go clean -modcache' 'go-global-update --dry-run' './go-global-update-fork --dry-run'
Benchmark 1: go-global-update --dry-run
  Time (mean ± σ):      1.936 s ±  0.072 s    [User: 0.236 s, System: 0.243 s]
  Range (min … max):    1.875 s …  2.120 s    10 runs

Benchmark 2: ./go-global-update-fork --dry-run
  Time (mean ± σ):     303.4 ms ±  22.4 ms    [User: 193.1 ms, System: 261.4 ms]
  Range (min … max):   284.7 ms … 361.6 ms    10 runs
```
  • Loading branch information
mroth committed Aug 19, 2023
1 parent 3c56908 commit c61df6c
Showing 1 changed file with 29 additions and 13 deletions.
42 changes: 29 additions & 13 deletions internal/gobinaries/introspect_binaries.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
package gobinaries

import "fmt"
import (
"fmt"
"runtime"
"sync"
)

type IntrospectionResult struct {
Binary GoBinary
Error error
}

func IntrospectBinaries(introspecter *Introspecter, binaryNames []string) []IntrospectionResult {
var results []IntrospectionResult

for _, binaryName := range binaryNames {
binary, err := introspecter.Introspect(binaryName)
if err != nil {
err = fmt.Errorf("could not introspect binary %s: %w", binaryName, err)
}

results = append(results, IntrospectionResult{
Binary: binary,
Error: err,
})
results := make([]IntrospectionResult, len(binaryNames))

var wg sync.WaitGroup
semaphore := make(chan struct{}, runtime.GOMAXPROCS(0))
for i, binaryName := range binaryNames {
i, binaryName := i, binaryName

wg.Add(1)
semaphore <- struct{}{}
go func() {
defer wg.Done()
defer func() { <-semaphore }()

binary, err := introspecter.Introspect(binaryName)
if err != nil {
err = fmt.Errorf("could not introspect binary %s: %w", binaryName, err)
}

results[i] = IntrospectionResult{
Binary: binary,
Error: err,
}
}()
}
wg.Wait()

return results
}

0 comments on commit c61df6c

Please sign in to comment.