@@ -612,8 +612,9 @@ func TestTraceCPUProfile(t *testing.T) {
612
612
pprof .Do (ctx , pprof .Labels ("tracing" , "on" ), func (ctx context.Context ) {
613
613
cpuHogger (cpuHog1 , & salt1 , dur )
614
614
})
615
- // Be sure the execution trace's view, when filtered to this goroutine,
616
- // gets many more samples than the CPU profiler when filtered by label.
615
+ // Be sure the execution trace's view, when filtered to this goroutine
616
+ // via the explicit goroutine ID in each event, gets many more samples
617
+ // than the CPU profiler when filtered to this goroutine via labels.
617
618
cpuHogger (cpuHog1 , & salt1 , dur )
618
619
}()
619
620
@@ -625,8 +626,12 @@ func TestTraceCPUProfile(t *testing.T) {
625
626
if err != nil {
626
627
t .Fatalf ("failed to parse CPU profile: %v" , err )
627
628
}
629
+ // Examine the CPU profiler's view. Filter it to only include samples from
630
+ // the single test goroutine. Use labels to execute that filter: they should
631
+ // apply to all work done while that goroutine is getg().m.curg, and they
632
+ // should apply to no other goroutines.
628
633
pprofSamples := 0
629
- pprofStacks := make (map [string ]int ) // CPU profiler's view, filtered to include the label
634
+ pprofStacks := make (map [string ]int )
630
635
for _ , s := range prof .Sample {
631
636
if s .Label ["tracing" ] != nil {
632
637
samples := int (s .Value [0 ])
@@ -645,8 +650,13 @@ func TestTraceCPUProfile(t *testing.T) {
645
650
t .Skipf ("CPU profile did not include any samples while tracing was active\n %s" , prof )
646
651
}
647
652
653
+ // Examine the execution tracer's view of the CPU profile samples. Filter it
654
+ // to only include samples from the single test goroutine. Use the goroutine
655
+ // ID that was recorded in the events: that should reflect getg().m.curg,
656
+ // same as the profiler's labels (even when the M is using its g0 stack).
657
+ totalTraceSamples := 0
648
658
traceSamples := 0
649
- traceStacks := make (map [string ]int ) // Execution tracer's view, filtered to this goroutine
659
+ traceStacks := make (map [string ]int )
650
660
events , _ := parseTrace (t , buf )
651
661
var hogRegion * trace.Event
652
662
for _ , ev := range events {
@@ -661,32 +671,51 @@ func TestTraceCPUProfile(t *testing.T) {
661
671
t .Fatalf ("execution trace did not close cpuHogger region" )
662
672
}
663
673
for _ , ev := range events {
664
- if ev .Type == trace .EvCPUSample && ev .G == hogRegion .G {
665
- traceSamples ++
666
- var fns []string
667
- for _ , frame := range ev .Stk {
668
- if frame .Fn != "runtime.goexit" {
669
- fns = append (fns , fmt .Sprintf ("%s:%d" , frame .Fn , frame .Line ))
674
+ if ev .Type == trace .EvCPUSample {
675
+ totalTraceSamples ++
676
+ if ev .G == hogRegion .G {
677
+ traceSamples ++
678
+ var fns []string
679
+ for _ , frame := range ev .Stk {
680
+ if frame .Fn != "runtime.goexit" {
681
+ fns = append (fns , fmt .Sprintf ("%s:%d" , frame .Fn , frame .Line ))
682
+ }
670
683
}
684
+ stack := strings .Join (fns , " " )
685
+ traceStacks [stack ]++
671
686
}
672
- stack := strings .Join (fns , " " )
673
- traceStacks [stack ]++
674
687
}
675
688
}
689
+
690
+ // The execution trace may drop CPU profile samples if the profiling buffer
691
+ // overflows. Based on the size of profBufWordCount, that takes a bit over
692
+ // 1900 CPU samples or 19 thread-seconds at a 100 Hz sample rate. If we've
693
+ // hit that case, then we definitely have at least one full buffer's worth
694
+ // of CPU samples, so we'll call that success.
695
+ overflowed := totalTraceSamples >= 1900
676
696
if traceSamples < pprofSamples {
677
- t .Errorf ("exectution trace did not include all CPU profile samples; %d in profile, %d in trace" , pprofSamples , traceSamples )
697
+ t .Logf ("exectution trace did not include all CPU profile samples; %d in profile, %d in trace" , pprofSamples , traceSamples )
698
+ if ! overflowed {
699
+ t .Fail ()
700
+ }
678
701
}
679
702
680
703
for stack , traceSamples := range traceStacks {
681
704
pprofSamples := pprofStacks [stack ]
682
705
delete (pprofStacks , stack )
683
706
if traceSamples < pprofSamples {
684
- t .Errorf ("execution trace did not include all CPU profile samples for stack %q; %d in profile, %d in trace" ,
707
+ t .Logf ("execution trace did not include all CPU profile samples for stack %q; %d in profile, %d in trace" ,
685
708
stack , pprofSamples , traceSamples )
709
+ if ! overflowed {
710
+ t .Fail ()
711
+ }
686
712
}
687
713
}
688
714
for stack , pprofSamples := range pprofStacks {
689
- t .Errorf ("CPU profile included %d samples at stack %q not present in execution trace" , pprofSamples , stack )
715
+ t .Logf ("CPU profile included %d samples at stack %q not present in execution trace" , pprofSamples , stack )
716
+ if ! overflowed {
717
+ t .Fail ()
718
+ }
690
719
}
691
720
692
721
if t .Failed () {
@@ -726,6 +755,10 @@ func cpuHog1(x int) int {
726
755
func cpuHog0 (x , n int ) int {
727
756
foo := x
728
757
for i := 0 ; i < n ; i ++ {
758
+ if i % 1000 == 0 {
759
+ // Spend time in mcall, stored as gp.m.curg, with g0 running
760
+ runtime .Gosched ()
761
+ }
729
762
if foo > 0 {
730
763
foo *= foo
731
764
} else {
0 commit comments