9
9
"bytes"
10
10
"context"
11
11
gosql "database/sql"
12
- "flag"
13
12
"fmt"
14
13
"io"
15
14
"os"
@@ -44,25 +43,28 @@ const (
44
43
nodes = 3
45
44
)
46
45
47
- var profileFlag = flag .String ("profile" , "" ,
48
- "if set, CPU and heap profiles are collected with the given file name prefix" )
49
-
50
46
// BenchmarkTPCC runs TPC-C transactions against a single warehouse. Both the
51
47
// optimized and literal implementations of our TPC-C workload are benchmarked.
52
48
// There are benchmarks for running each transaction individually, as well as a
53
49
// "default" mix that runs the standard mix of TPC-C transactions.
54
50
//
55
- // CPU and heap profiles can be collected by passing the "-profile" flag with a
56
- // prefix for the profile file names. The profile names will include the
57
- // benchmark names, e.g., "foo_tpcc_literal_new_order.cpu" and
58
- // "foo_tpcc_literal_new_order.mem" will be created when running the benchmark:
51
+ // If CPU or heap profiles are requested with the "-test.cpuprofile" or
52
+ // "-test.memprofile" flags, the benchmark will "hijack" the standard profiles
53
+ // and create new profiles that omit CPU samples and allocations made during the
54
+ // setup phase of the benchmark.
55
+ //
56
+ // The profile names will include the prefix of the profile flags and the
57
+ // benchmark names. For example, the profiles "foo_tpcc_literal_new_order.cpu"
58
+ // and "foo_tpcc_literal_new_order.mem" will be created when running the
59
+ // benchmark:
59
60
//
60
61
// ./dev bench pkg/bench/tpcc -f BenchmarkTPCC/literal/new_order \
61
- // --test-args '-test.benchtime=30s -profile =foo'
62
+ // --test-args '-test.cpuprofile=foo.cpu -test.memprofile =foo.mem '
62
63
//
63
- // These profiles will omit CPU samples and allocations made during the setup
64
- // phase of the benchmark, unlike profiles collected with the "-test.cpuprofile"
65
- // and "-test.memprofile" flags.
64
+ // NB: The "foo.cpu" file will not be created because we must stop the global
65
+ // CPU profiler in order to collect profiles that omit setup samples. The
66
+ // "foo.mem" file will created and include all allocations made during the
67
+ // entire duration of the benchmark.
66
68
func BenchmarkTPCC (b * testing.B ) {
67
69
defer log .Scope (b ).Close (b )
68
70
@@ -237,17 +239,41 @@ func (f doneFn) Stop(b testing.TB) {
237
239
}
238
240
239
241
func startCPUProfile (b testing.TB ) doneFn {
240
- prefix := * profileFlag
241
- if prefix == "" {
242
+ var cpuProfFile string
243
+ if err := sniffarg .DoEnv ("test.cpuprofile" , & cpuProfFile ); err != nil {
244
+ b .Fatal (err )
245
+ }
246
+ if cpuProfFile == "" {
247
+ // Not CPU profile requested.
242
248
return func (b testing.TB ) {}
243
249
}
244
250
245
- fileName := profileFileName (b , prefix , "cpu" )
251
+ prefix := profilePrefix (cpuProfFile )
252
+
253
+ // Hijack the harness's profile to make a clean profile.
254
+ // The flag is set, so likely a CPU profile started by the Go harness is
255
+ // running (unless -count is specified, but StopCPUProfile is idempotent).
256
+ runtimepprof .StopCPUProfile ()
257
+
258
+ var outputDir string
259
+ if err := sniffarg .DoEnv ("test.outputdir" , & outputDir ); err != nil {
260
+ b .Fatal (err )
261
+ }
262
+ if outputDir != "" {
263
+ cpuProfFile = filepath .Join (outputDir , cpuProfFile )
264
+ }
265
+
266
+ // Remove the harness's profile file to avoid confusion.
267
+ _ = os .Remove (cpuProfFile )
268
+
269
+ // Create a new profile file.
270
+ fileName := profileFileName (b , outputDir , prefix , "cpu" )
246
271
f , err := os .OpenFile (fileName , os .O_WRONLY | os .O_CREATE | os .O_TRUNC , 0644 )
247
272
if err != nil {
248
273
b .Fatal (err )
249
274
}
250
275
276
+ // Start profiling.
251
277
if err := runtimepprof .StartCPUProfile (f ); err != nil {
252
278
b .Fatal (err )
253
279
}
@@ -261,12 +287,27 @@ func startCPUProfile(b testing.TB) doneFn {
261
287
}
262
288
263
289
func startAllocsProfile (b testing.TB ) doneFn {
264
- prefix := * profileFlag
265
- if prefix == "" {
290
+ var memProfFile string
291
+ if err := sniffarg .DoEnv ("test.memprofile" , & memProfFile ); err != nil {
292
+ b .Fatal (err )
293
+ }
294
+ if memProfFile == "" {
295
+ // No heap profile requested.
266
296
return func (b testing.TB ) {}
267
297
}
268
298
269
- fileName := profileFileName (b , prefix , "mem" )
299
+ prefix := profilePrefix (memProfFile )
300
+
301
+ var outputDir string
302
+ if err := sniffarg .DoEnv ("test.outputdir" , & outputDir ); err != nil {
303
+ b .Fatal (err )
304
+ }
305
+ if outputDir != "" {
306
+ memProfFile = filepath .Join (outputDir , memProfFile )
307
+ }
308
+
309
+ // Create a new profile file.
310
+ fileName := profileFileName (b , outputDir , prefix , "mem" )
270
311
diffAllocs := diffProfile (b , func () []byte {
271
312
p := runtimepprof .Lookup ("allocs" )
272
313
var buf bytes.Buffer
@@ -295,13 +336,13 @@ func diffProfile(b testing.TB, take func() []byte) func(testing.TB) []byte {
295
336
if baseBytes == nil {
296
337
return func (tb testing.TB ) []byte { return nil }
297
338
}
298
- pBase , err := profile .ParseData (baseBytes )
299
- if err != nil {
300
- b .Fatal (err )
301
- }
302
-
303
339
return func (b testing.TB ) []byte {
304
- pNew , err := profile .ParseData (take ())
340
+ newBytes := take ()
341
+ pBase , err := profile .ParseData (baseBytes )
342
+ if err != nil {
343
+ b .Fatal (err )
344
+ }
345
+ pNew , err := profile .ParseData (newBytes )
305
346
if err != nil {
306
347
b .Fatal (err )
307
348
}
@@ -321,12 +362,15 @@ func diffProfile(b testing.TB, take func() []byte) func(testing.TB) []byte {
321
362
}
322
363
}
323
364
324
- func profileFileName ( b testing. TB , prefix , suffix string ) string {
325
- var outputDir string
326
- if err := sniffarg . DoEnv ( "test.outputdir" , & outputDir ); err != nil {
327
- b . Fatal ( err )
365
+ func profilePrefix ( profileArg string ) string {
366
+ i := strings . Index ( profileArg , "." )
367
+ if i == - 1 {
368
+ return profileArg
328
369
}
370
+ return profileArg [:i ]
371
+ }
329
372
373
+ func profileFileName (b testing.TB , outputDir , prefix , suffix string ) string {
330
374
saniRE := regexp .MustCompile (`\W+` )
331
375
testName := strings .TrimPrefix (b .Name (), "Benchmark" )
332
376
testName = strings .ToLower (testName )
0 commit comments