@@ -72,15 +72,24 @@ func cpuHog2(x int) int {
72
72
return foo
73
73
}
74
74
75
+ // Return a list of functions that we don't want to ever appear in CPU
76
+ // profiles. For gccgo, that list includes the sigprof handler itself.
77
+ func avoidFunctions () []string {
78
+ if runtime .Compiler == "gccgo" {
79
+ return []string {"runtime.sigprof" }
80
+ }
81
+ return nil
82
+ }
83
+
75
84
func TestCPUProfile (t * testing.T ) {
76
- testCPUProfile (t , stackContains , []string {"runtime/pprof.cpuHog1" }, func (dur time.Duration ) {
85
+ testCPUProfile (t , stackContains , []string {"runtime/pprof.cpuHog1" }, avoidFunctions (), func (dur time.Duration ) {
77
86
cpuHogger (cpuHog1 , & salt1 , dur )
78
87
})
79
88
}
80
89
81
90
func TestCPUProfileMultithreaded (t * testing.T ) {
82
91
defer runtime .GOMAXPROCS (runtime .GOMAXPROCS (2 ))
83
- testCPUProfile (t , stackContains , []string {"runtime/pprof.cpuHog1" , "runtime/pprof.cpuHog2" }, func (dur time.Duration ) {
92
+ testCPUProfile (t , stackContains , []string {"runtime/pprof.cpuHog1" , "runtime/pprof.cpuHog2" }, avoidFunctions (), func (dur time.Duration ) {
84
93
c := make (chan int )
85
94
go func () {
86
95
cpuHogger (cpuHog1 , & salt1 , dur )
@@ -92,7 +101,7 @@ func TestCPUProfileMultithreaded(t *testing.T) {
92
101
}
93
102
94
103
func TestCPUProfileInlining (t * testing.T ) {
95
- testCPUProfile (t , stackContains , []string {"runtime/pprof.inlinedCallee" , "runtime/pprof.inlinedCaller" }, func (dur time.Duration ) {
104
+ testCPUProfile (t , stackContains , []string {"runtime/pprof.inlinedCallee" , "runtime/pprof.inlinedCaller" }, avoidFunctions (), func (dur time.Duration ) {
96
105
cpuHogger (inlinedCaller , & salt1 , dur )
97
106
})
98
107
}
@@ -132,7 +141,7 @@ func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []*profile.Loca
132
141
133
142
// testCPUProfile runs f under the CPU profiler, checking for some conditions specified by need,
134
143
// as interpreted by matches.
135
- func testCPUProfile (t * testing.T , matches matchFunc , need []string , f func (dur time.Duration )) {
144
+ func testCPUProfile (t * testing.T , matches matchFunc , need []string , avoid [] string , f func (dur time.Duration )) {
136
145
switch runtime .GOOS {
137
146
case "darwin" :
138
147
switch runtime .GOARCH {
@@ -171,7 +180,7 @@ func testCPUProfile(t *testing.T, matches matchFunc, need []string, f func(dur t
171
180
f (duration )
172
181
StopCPUProfile ()
173
182
174
- if profileOk (t , need , matches , prof , duration ) {
183
+ if profileOk (t , matches , need , avoid , prof , duration ) {
175
184
return
176
185
}
177
186
@@ -218,11 +227,13 @@ func stackContains(spec string, count uintptr, stk []*profile.Location, labels m
218
227
219
228
type matchFunc func (spec string , count uintptr , stk []* profile.Location , labels map [string ][]string ) bool
220
229
221
- func profileOk (t * testing.T , need []string , matches matchFunc , prof bytes.Buffer , duration time.Duration ) (ok bool ) {
230
+ func profileOk (t * testing.T , matches matchFunc , need []string , avoid [] string , prof bytes.Buffer , duration time.Duration ) (ok bool ) {
222
231
ok = true
223
232
224
- // Check that profile is well formed and contains need.
233
+ // Check that profile is well formed, contains 'need', and does not contain
234
+ // anything from 'avoid'.
225
235
have := make ([]uintptr , len (need ))
236
+ avoidSamples := make ([]uintptr , len (avoid ))
226
237
var samples uintptr
227
238
var buf bytes.Buffer
228
239
parseProfile (t , prof .Bytes (), func (count uintptr , stk []* profile.Location , labels map [string ][]string ) {
@@ -234,6 +245,15 @@ func profileOk(t *testing.T, need []string, matches matchFunc, prof bytes.Buffer
234
245
have [i ] += count
235
246
}
236
247
}
248
+ for i , name := range avoid {
249
+ for _ , loc := range stk {
250
+ for _ , line := range loc .Line {
251
+ if strings .Contains (line .Function .Name , name ) {
252
+ avoidSamples [i ] += count
253
+ }
254
+ }
255
+ }
256
+ }
237
257
fmt .Fprintf (& buf , "\n " )
238
258
})
239
259
t .Logf ("total %d CPU profile samples collected:\n %s" , samples , buf .String ())
@@ -256,6 +276,14 @@ func profileOk(t *testing.T, need []string, matches matchFunc, prof bytes.Buffer
256
276
ok = false
257
277
}
258
278
279
+ for i , name := range avoid {
280
+ bad := avoidSamples [i ]
281
+ if bad != 0 {
282
+ t .Logf ("found %d samples in avoid-function %s\n " , bad , name )
283
+ ok = false
284
+ }
285
+ }
286
+
259
287
if len (need ) == 0 {
260
288
return ok
261
289
}
@@ -323,6 +351,9 @@ func TestCPUProfileWithFork(t *testing.T) {
323
351
// If it did, it would see inconsistent state and would either record an incorrect stack
324
352
// or crash because the stack was malformed.
325
353
func TestGoroutineSwitch (t * testing.T ) {
354
+ if runtime .Compiler == "gccgo" {
355
+ t .Skip ("not applicable for gccgo" )
356
+ }
326
357
// How much to try. These defaults take about 1 seconds
327
358
// on a 2012 MacBook Pro. The ones in short mode take
328
359
// about 0.1 seconds.
@@ -382,7 +413,7 @@ func fprintStack(w io.Writer, stk []*profile.Location) {
382
413
383
414
// Test that profiling of division operations is okay, especially on ARM. See issue 6681.
384
415
func TestMathBigDivide (t * testing.T ) {
385
- testCPUProfile (t , nil , nil , func (duration time.Duration ) {
416
+ testCPUProfile (t , nil , nil , nil , func (duration time.Duration ) {
386
417
t := time .After (duration )
387
418
pi := new (big.Int )
388
419
for {
@@ -411,7 +442,7 @@ func stackContainsAll(spec string, count uintptr, stk []*profile.Location, label
411
442
}
412
443
413
444
func TestMorestack (t * testing.T ) {
414
- testCPUProfile (t , stackContainsAll , []string {"runtime.newstack,runtime/pprof.growstack" }, func (duration time.Duration ) {
445
+ testCPUProfile (t , stackContainsAll , []string {"runtime.newstack,runtime/pprof.growstack" }, avoidFunctions (), func (duration time.Duration ) {
415
446
t := time .After (duration )
416
447
c := make (chan bool )
417
448
for {
@@ -913,7 +944,7 @@ func stackContainsLabeled(spec string, count uintptr, stk []*profile.Location, l
913
944
}
914
945
915
946
func TestCPUProfileLabel (t * testing.T ) {
916
- testCPUProfile (t , stackContainsLabeled , []string {"runtime/pprof.cpuHogger;key=value" }, func (dur time.Duration ) {
947
+ testCPUProfile (t , stackContainsLabeled , []string {"runtime/pprof.cpuHogger;key=value" }, avoidFunctions (), func (dur time.Duration ) {
917
948
Do (context .Background (), Labels ("key" , "value" ), func (context.Context ) {
918
949
cpuHogger (cpuHog1 , & salt1 , dur )
919
950
})
@@ -924,7 +955,7 @@ func TestLabelRace(t *testing.T) {
924
955
// Test the race detector annotations for synchronization
925
956
// between settings labels and consuming them from the
926
957
// profile.
927
- testCPUProfile (t , stackContainsLabeled , []string {"runtime/pprof.cpuHogger;key=value" }, func (dur time.Duration ) {
958
+ testCPUProfile (t , stackContainsLabeled , []string {"runtime/pprof.cpuHogger;key=value" }, nil , func (dur time.Duration ) {
928
959
start := time .Now ()
929
960
var wg sync.WaitGroup
930
961
for time .Since (start ) < dur {
0 commit comments