60
60
// today they write only the profile for the last benchmark executed.
61
61
//
62
62
// The default memory profiling rate is one profile sample per 512 kB
63
- // allocated (see `` go doc runtime.MemProfileRate'' ).
63
+ // allocated (see “ go doc runtime.MemProfileRate” ).
64
64
// Lowering the rate (for example, -memprofilerate 64000) produces
65
65
// a more fine-grained and therefore accurate profile, but it also incurs
66
66
// execution cost. For benchmark comparisons, never use timings
67
67
// obtained with a low -memprofilerate option.
68
68
//
69
- // Example
69
+ // # Example
70
70
//
71
71
// Assuming the base version of the compiler has been saved with
72
- // `` toolstash save,'' this sequence compares the old and new compiler:
72
+ // “ toolstash save,” this sequence compares the old and new compiler:
73
73
//
74
74
// compilebench -count 10 -compile $(toolstash -n compile) >old.txt
75
75
// compilebench -count 10 >new.txt
76
76
// benchstat old.txt new.txt
77
- //
78
77
package main
79
78
80
79
import (
81
80
"bytes"
82
81
"encoding/json"
83
82
"flag"
84
83
"fmt"
85
- exec "golang.org/x/sys/execabs"
86
84
"io/ioutil"
87
85
"log"
88
86
"os"
89
87
"path/filepath"
90
88
"regexp"
89
+ "runtime"
91
90
"strconv"
92
91
"strings"
93
92
"time"
93
+
94
+ exec "golang.org/x/sys/execabs"
94
95
)
95
96
96
97
var (
97
- goroot string
98
- compiler string
99
- linker string
100
- runRE * regexp.Regexp
101
- is6g bool
98
+ goroot string
99
+ compiler string
100
+ assembler string
101
+ linker string
102
+ runRE * regexp.Regexp
103
+ is6g bool
102
104
)
103
105
104
106
var (
105
107
flagGoCmd = flag .String ("go" , "go" , "path to \" go\" command" )
106
108
flagAlloc = flag .Bool ("alloc" , false , "report allocations" )
107
109
flagObj = flag .Bool ("obj" , false , "report object file stats" )
108
110
flagCompiler = flag .String ("compile" , "" , "use `exe` as the cmd/compile binary" )
111
+ flagAssembler = flag .String ("asm" , "" , "use `exe` as the cmd/asm binary" )
109
112
flagCompilerFlags = flag .String ("compileflags" , "" , "additional `flags` to pass to compile" )
110
113
flagLinker = flag .String ("link" , "" , "use `exe` as the cmd/link binary" )
111
114
flagLinkerFlags = flag .String ("linkflags" , "" , "additional `flags` to pass to link" )
@@ -116,6 +119,7 @@ var (
116
119
flagMemprofilerate = flag .Int64 ("memprofilerate" , - 1 , "set memory profile `rate`" )
117
120
flagPackage = flag .String ("pkg" , "" , "if set, benchmark the package at path `pkg`" )
118
121
flagShort = flag .Bool ("short" , false , "skip long-running benchmarks" )
122
+ flagTrace = flag .Bool ("trace" , false , "debug tracing of builds" )
119
123
)
120
124
121
125
type test struct {
@@ -178,6 +182,10 @@ func main() {
178
182
is6g = true
179
183
}
180
184
}
185
+ assembler = * flagAssembler
186
+ if assembler == "" {
187
+ _ , assembler = toolPath ("asm" )
188
+ }
181
189
182
190
linker = * flagLinker
183
191
if linker == "" && ! is6g { // TODO: Support 6l
@@ -238,8 +246,10 @@ func toolPath(names ...string) (found, path string) {
238
246
}
239
247
240
248
type Pkg struct {
241
- Dir string
242
- GoFiles []string
249
+ ImportPath string
250
+ Dir string
251
+ GoFiles []string
252
+ SFiles []string
243
253
}
244
254
245
255
func goList (dir string ) (* Pkg , error ) {
@@ -337,8 +347,30 @@ func (c compile) run(name string, count int) error {
337
347
return err
338
348
}
339
349
340
- args := []string {"-o" , "_compilebench_.o" }
350
+ // If this package has assembly files, we'll need to pass a symabis
351
+ // file to the compiler; call a helper to invoke the assembler
352
+ // to do that.
353
+ var symAbisFile string
354
+ var asmIncFile string
355
+ if len (pkg .SFiles ) != 0 {
356
+ symAbisFile = filepath .Join (pkg .Dir , "symabis" )
357
+ asmIncFile = filepath .Join (pkg .Dir , "go_asm.h" )
358
+ content := "\n "
359
+ if err := os .WriteFile (asmIncFile , []byte (content ), 0666 ); err != nil {
360
+ return fmt .Errorf ("os.WriteFile(%s) failed: %v" , asmIncFile , err )
361
+ }
362
+ defer os .Remove (symAbisFile )
363
+ defer os .Remove (asmIncFile )
364
+ if err := genSymAbisFile (pkg , symAbisFile , pkg .Dir ); err != nil {
365
+ return err
366
+ }
367
+ }
368
+
369
+ args := []string {"-o" , "_compilebench_.o" , "-p" , pkg .ImportPath }
341
370
args = append (args , strings .Fields (* flagCompilerFlags )... )
371
+ if symAbisFile != "" {
372
+ args = append (args , "-symabis" , symAbisFile )
373
+ }
342
374
args = append (args , pkg .GoFiles ... )
343
375
if err := runBuildCmd (name , count , pkg .Dir , compiler , args ); err != nil {
344
376
return err
@@ -429,6 +461,10 @@ func runBuildCmd(name string, count int, dir, tool string, args []string) error
429
461
preArgs = append (preArgs , "-cpuprofile" , "_compilebench_.cpuprof" )
430
462
}
431
463
}
464
+ if * flagTrace {
465
+ fmt .Fprintf (os .Stderr , "running: %s %+v\n " ,
466
+ tool , append (preArgs , args ... ))
467
+ }
432
468
cmd := exec .Command (tool , append (preArgs , args ... )... )
433
469
cmd .Dir = dir
434
470
cmd .Stdout = os .Stderr
@@ -511,3 +547,34 @@ func runBuildCmd(name string, count int, dir, tool string, args []string) error
511
547
512
548
return nil
513
549
}
550
+
551
+ // genSymAbisFile runs the assembler on the target packge asm files
552
+ // with "-gensymabis" to produce a symabis file that will feed into
553
+ // the Go source compilation. This is fairly hacky in that if the
554
+ // asm invocation convenion changes it will need to be updated
555
+ // (hopefully that will not be needed too frequently).
556
+ func genSymAbisFile (pkg * Pkg , symAbisFile , incdir string ) error {
557
+ args := []string {"-gensymabis" , "-o" , symAbisFile ,
558
+ "-p" , pkg .ImportPath ,
559
+ "-I" , filepath .Join (goroot , "pkg" , "include" ),
560
+ "-I" , incdir ,
561
+ "-D" , "GOOS_" + runtime .GOOS ,
562
+ "-D" , "GOARCH_" + runtime .GOARCH }
563
+ if pkg .ImportPath == "reflect" {
564
+ args = append (args , "-compiling-runtime" )
565
+ }
566
+ args = append (args , pkg .SFiles ... )
567
+ if * flagTrace {
568
+ fmt .Fprintf (os .Stderr , "running: %s %+v\n " ,
569
+ assembler , args )
570
+ }
571
+ cmd := exec .Command (assembler , args ... )
572
+ cmd .Dir = pkg .Dir
573
+ cmd .Stdout = os .Stderr
574
+ cmd .Stderr = os .Stderr
575
+ err := cmd .Run ()
576
+ if err != nil {
577
+ return fmt .Errorf ("assembling to produce symabis file: %v" , err )
578
+ }
579
+ return nil
580
+ }
0 commit comments