Skip to content

Commit 4c20f7f

Browse files
committed
cmd/cgo: run gcc to get errors and debug info in parallel
This change kicks off the work to load the debug info when processing each file, and then waits for all the files to be processed before starting the single-goroutined part that processes them. The processing is very order dependent so we won't try to make it concurrent. Though in a later CL we can wait for only the relevant package to have been processed concurrently before doing the single-goroutined processing for it instead of waiting for all packages to be processed concurrently before the single goroutine section. We use a par.Queue to make sure we're not running too many gcc compiles at the same time. The change to cmd/dist makes the par package available to cgo. Fixes golang#75167 Change-Id: I6a6a6964fb7f3a3684118b5ee66f1ad856b3ee59 Reviewed-on: https://go-review.googlesource.com/c/go/+/699020 Reviewed-by: Michael Matloob <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent 5dcedd6 commit 4c20f7f

File tree

3 files changed

+28
-13
lines changed

3 files changed

+28
-13
lines changed

src/cmd/cgo/gcc.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,16 +183,16 @@ func splitQuoted(s string) (r []string, err error) {
183183
return args, err
184184
}
185185

186-
// Translate rewrites f.AST, the original Go input, to remove
187-
// references to the imported package C, replacing them with
188-
// references to the equivalent Go types, functions, and variables.
189-
func (p *Package) Translate(f *File) {
186+
// loadDebug runs gcc to load debug information for the File. The debug
187+
// information will be saved to the debugs field of the file, and be
188+
// processed when Translate is called on the file later.
189+
// loadDebug is called concurrently with different files.
190+
func (f *File) loadDebug(p *Package) {
190191
for _, cref := range f.Ref {
191192
// Convert C.ulong to C.unsigned long, etc.
192193
cref.Name.C = cname(cref.Name.Go)
193194
}
194195

195-
var debugs []*debug // debug data from iterations of gccDebug
196196
ft := fileTypedefs{typedefs: make(map[string]bool)}
197197
numTypedefs := -1
198198
for len(ft.typedefs) > numTypedefs {
@@ -211,7 +211,7 @@ func (p *Package) Translate(f *File) {
211211
}
212212
needType := p.guessKinds(f)
213213
if len(needType) > 0 {
214-
debugs = append(debugs, p.loadDWARF(f, &ft, needType))
214+
f.debugs = append(f.debugs, p.loadDWARF(f, &ft, needType))
215215
}
216216

217217
// In godefs mode we're OK with the typedefs, which
@@ -221,10 +221,16 @@ func (p *Package) Translate(f *File) {
221221
break
222222
}
223223
}
224+
}
224225

226+
// Translate rewrites f.AST, the original Go input, to remove
227+
// references to the imported package C, replacing them with
228+
// references to the equivalent Go types, functions, and variables.
229+
// Preconditions: File.loadDebug must be called prior to translate.
230+
func (p *Package) Translate(f *File) {
225231
var conv typeConv
226232
conv.Init(p.PtrSize, p.IntSize)
227-
for _, d := range debugs {
233+
for _, d := range f.debugs {
228234
p.recordTypes(f, d, &conv)
229235
}
230236
p.prepareNames(f)
@@ -283,6 +289,7 @@ func (f *File) loadDefines(gccOptions []string) bool {
283289
// guessKinds tricks gcc into revealing the kind of each
284290
// name xxx for the references C.xxx in the Go input.
285291
// The kind is either a constant, type, or variable.
292+
// guessKinds is called concurrently with different files.
286293
func (p *Package) guessKinds(f *File) []*Name {
287294
// Determine kinds for names we already know about,
288295
// like #defines or 'struct foo', before bothering with gcc.
@@ -526,6 +533,7 @@ func (p *Package) guessKinds(f *File) []*Name {
526533
// loadDWARF parses the DWARF debug information generated
527534
// by gcc to learn the details of the constants, variables, and types
528535
// being referred to as C.xxx.
536+
// loadDwarf is called concurrently with different files.
529537
func (p *Package) loadDWARF(f *File, ft *fileTypedefs, names []*Name) *debug {
530538
// Extract the types from the DWARF section of an object
531539
// from a well-formed C program. Gcc only generates DWARF info
@@ -1789,6 +1797,7 @@ func gccTmp() string {
17891797

17901798
// gccCmd returns the gcc command line to use for compiling
17911799
// the input.
1800+
// gccCommand is called concurrently for different files.
17921801
func (p *Package) gccCmd(ofile string) []string {
17931802
c := append(gccBaseCmd,
17941803
"-w", // no warnings
@@ -1832,6 +1841,7 @@ func (p *Package) gccCmd(ofile string) []string {
18321841

18331842
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
18341843
// returns the corresponding DWARF data and, if present, debug data block.
1844+
// gccDebug is called concurrently with different C programs.
18351845
func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
18361846
ofile := gccTmp()
18371847
runGcc(stdin, p.gccCmd(ofile))
@@ -2222,6 +2232,7 @@ func gccDefines(stdin []byte, gccOptions []string) string {
22222232
// gccErrors runs gcc over the C program stdin and returns
22232233
// the errors that gcc prints. That is, this function expects
22242234
// gcc to fail.
2235+
// gccErrors is called concurrently with different C programs.
22252236
func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
22262237
// TODO(rsc): require failure
22272238
args := p.gccCmd(gccTmp())

src/cmd/cgo/main.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"cmd/internal/edit"
3131
"cmd/internal/hash"
3232
"cmd/internal/objabi"
33+
"cmd/internal/par"
3334
"cmd/internal/telemetry/counter"
3435
)
3536

@@ -74,6 +75,8 @@ type File struct {
7475
NoCallbacks map[string]bool // C function names that with #cgo nocallback directive
7576
NoEscapes map[string]bool // C function names that with #cgo noescape directive
7677
Edit *edit.Buffer
78+
79+
debugs []*debug // debug data from iterations of gccDebug. Initialized by File.loadDebug.
7780
}
7881

7982
func (f *File) offset(p token.Pos) int {
@@ -391,7 +394,7 @@ func main() {
391394
h := hash.New32()
392395
io.WriteString(h, *importPath)
393396
var once sync.Once
394-
var wg sync.WaitGroup
397+
q := par.NewQueue(runtime.GOMAXPROCS(0))
395398
fs := make([]*File, len(goFiles))
396399
for i, input := range goFiles {
397400
if *srcDir != "" {
@@ -413,9 +416,7 @@ func main() {
413416
fatalf("%s", err)
414417
}
415418

416-
wg.Add(1)
417-
go func() {
418-
defer wg.Done()
419+
q.Add(func() {
419420
// Apply trimpath to the file path. The path won't be read from after this point.
420421
input, _ = objabi.ApplyRewrites(input, *trimpath)
421422
if strings.ContainsAny(input, "\r\n") {
@@ -436,10 +437,12 @@ func main() {
436437
})
437438

438439
fs[i] = f
439-
}()
440+
441+
f.loadDebug(p)
442+
})
440443
}
441444

442-
wg.Wait()
445+
<-q.Idle()
443446

444447
cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
445448

src/cmd/dist/buildtool.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var bootstrapDirs = []string{
4949
"cmd/internal/macho",
5050
"cmd/internal/obj/...",
5151
"cmd/internal/objabi",
52+
"cmd/internal/par",
5253
"cmd/internal/pgo",
5354
"cmd/internal/pkgpath",
5455
"cmd/internal/quoted",

0 commit comments

Comments
 (0)