cmd/cgo: parallelize loadDefines calls

```
export CC="zig cc -target x86_64-linux"
hyperfine '../pkg/tool/darwin_arm64/cgo -objdir /tmp net/cgo_linux.go net/cgo_resnew.go net/cgo_socknew.go net/cgo_unix_cgo.go net/cgo_unix_cgo_res.go'
```

**Before**
```
  Time (mean ± sig):      1.293 s ±  0.017 s    [User: 0.472 s, System: 0.451 s]
  Range (min ... max):    1.263 s ...  1.316 s    10 runs

```

**After**
```
  Time (mean ±sig):     986.5 ms ±  22.6 ms    [User: 487.0 ms, System: 519.5 ms]
  Range (min ... max):   950.7 ms ... 1022.2 ms    10 runs

```

The version after changes is 25% faster for 5 input files (std "net" package).
I also tried to make CC artifictially slower (wrapper with sleep 0.2) and it showes same 25% performance increase.

Change-Id: I7a26fdc8d8a23b0df9bc71d30b96e82e2ddb943b
Reviewed-on: https://go-review.googlesource.com/c/go/+/581336
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Michael Podtserkovskii 2024-04-18 12:28:13 +01:00 committed by Gopher Robot
parent 3d4daa38a7
commit d555358bf8
2 changed files with 39 additions and 23 deletions

View file

@ -193,7 +193,6 @@ func (p *Package) Translate(f *File) {
var conv typeConv var conv typeConv
conv.Init(p.PtrSize, p.IntSize) conv.Init(p.PtrSize, p.IntSize)
p.loadDefines(f)
p.typedefs = map[string]bool{} p.typedefs = map[string]bool{}
p.typedefList = nil p.typedefList = nil
numTypedefs := -1 numTypedefs := -1
@ -233,12 +232,14 @@ func (p *Package) Translate(f *File) {
// loadDefines coerces gcc into spitting out the #defines in use // loadDefines coerces gcc into spitting out the #defines in use
// in the file f and saves relevant renamings in f.Name[name].Define. // in the file f and saves relevant renamings in f.Name[name].Define.
func (p *Package) loadDefines(f *File) { // Returns true if env:CC is Clang
func (f *File) loadDefines(gccOptions []string) bool {
var b bytes.Buffer var b bytes.Buffer
b.WriteString(builtinProlog) b.WriteString(builtinProlog)
b.WriteString(f.Preamble) b.WriteString(f.Preamble)
stdout := p.gccDefines(b.Bytes()) stdout := gccDefines(b.Bytes(), gccOptions)
var gccIsClang bool
for _, line := range strings.Split(stdout, "\n") { for _, line := range strings.Split(stdout, "\n") {
if len(line) < 9 || line[0:7] != "#define" { if len(line) < 9 || line[0:7] != "#define" {
continue continue
@ -261,7 +262,7 @@ func (p *Package) loadDefines(f *File) {
} }
if key == "__clang__" { if key == "__clang__" {
p.GccIsClang = true gccIsClang = true
} }
if n := f.Name[key]; n != nil { if n := f.Name[key]; n != nil {
@ -271,6 +272,7 @@ func (p *Package) loadDefines(f *File) {
n.Define = val n.Define = val
} }
} }
return gccIsClang
} }
// guessKinds tricks gcc into revealing the kind of each // guessKinds tricks gcc into revealing the kind of each
@ -1722,7 +1724,7 @@ func checkGCCBaseCmd() ([]string, error) {
} }
// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
func (p *Package) gccMachine() []string { func gccMachine() []string {
switch goarch { switch goarch {
case "amd64": case "amd64":
if goos == "darwin" { if goos == "darwin" {
@ -1795,7 +1797,7 @@ func (p *Package) gccCmd() []string {
} }
c = append(c, p.GccOptions...) c = append(c, p.GccOptions...)
c = append(c, p.gccMachine()...) c = append(c, gccMachine()...)
if goos == "aix" { if goos == "aix" {
c = append(c, "-maix64") c = append(c, "-maix64")
c = append(c, "-mcmodel=large") c = append(c, "-mcmodel=large")
@ -2187,10 +2189,10 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
// and returns the corresponding standard output, which is the // and returns the corresponding standard output, which is the
// #defines that gcc encountered while processing the input // #defines that gcc encountered while processing the input
// and its included files. // and its included files.
func (p *Package) gccDefines(stdin []byte) string { func gccDefines(stdin []byte, gccOptions []string) string {
base := append(gccBaseCmd, "-E", "-dM", "-xc") base := append(gccBaseCmd, "-E", "-dM", "-xc")
base = append(base, p.gccMachine()...) base = append(base, gccMachine()...)
stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) stdout, _ := runGcc(stdin, append(append(base, gccOptions...), "-"))
return stdout return stdout
} }

View file

@ -24,6 +24,7 @@ import (
"runtime" "runtime"
"sort" "sort"
"strings" "strings"
"sync"
"cmd/internal/edit" "cmd/internal/edit"
"cmd/internal/notsha256" "cmd/internal/notsha256"
@ -390,6 +391,8 @@ func main() {
// Use the beginning of the notsha256 of the input to disambiguate. // Use the beginning of the notsha256 of the input to disambiguate.
h := notsha256.New() h := notsha256.New()
io.WriteString(h, *importPath) io.WriteString(h, *importPath)
var once sync.Once
var wg sync.WaitGroup
fs := make([]*File, len(goFiles)) fs := make([]*File, len(goFiles))
for i, input := range goFiles { for i, input := range goFiles {
if *srcDir != "" { if *srcDir != "" {
@ -411,6 +414,9 @@ func main() {
fatalf("%s", err) fatalf("%s", err)
} }
wg.Add(1)
go func() {
defer wg.Done()
// Apply trimpath to the file path. The path won't be read from after this point. // Apply trimpath to the file path. The path won't be read from after this point.
input, _ = objabi.ApplyRewrites(input, *trimpath) input, _ = objabi.ApplyRewrites(input, *trimpath)
if strings.ContainsAny(input, "\r\n") { if strings.ContainsAny(input, "\r\n") {
@ -425,9 +431,17 @@ func main() {
f.Edit = edit.NewBuffer(b) f.Edit = edit.NewBuffer(b)
f.ParseGo(input, b) f.ParseGo(input, b)
f.ProcessCgoDirectives() f.ProcessCgoDirectives()
gccIsClang := f.loadDefines(p.GccOptions)
once.Do(func() {
p.GccIsClang = gccIsClang
})
fs[i] = f fs[i] = f
}()
} }
wg.Wait()
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6]) cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
if *objDir == "" { if *objDir == "" {