Also, avoid Region creation when tracing is disabled.
Unfortunate side-effect of this change is that we no longer trace
pre-existing regions in tracing, but we can add the feature in
the future when we find it useful and justifiable. Until then,
let's avoid the overhead from this low-level api use as much as
possible.
goos: linux
goarch: amd64
pkg: runtime/trace
// Trace disabled
BenchmarkStartRegion-12
2000000000 0.66 ns/op 0 B/op 0 allocs/op
BenchmarkNewTask-12
30000000 40.4 ns/op 56 B/op 2 allocs/op
// Trace enabled, -trace=/dev/null
BenchmarkStartRegion-12
5000000 287 ns/op 32 B/op 1 allocs/op
BenchmarkNewTask-12
5000000 283 ns/op 56 B/op 2 allocs/op
Also, skip other tests if tracing is already enabled.
Change-Id: Id3028d60b5642fcab4b09a74fd7d79361a3861e5
Reviewed-on: https://go-review.googlesource.com/109115
Reviewed-by: Peter Weinberger <pjw@google.com>
// defer trace.StartRegion(ctx, "myTracedRegion").End()
//
func StartRegion(ctx context.Context, regionType string) *Region {
+ if !IsEnabled() {
+ return noopRegion
+ }
id := fromContext(ctx).id
userRegion(id, regionStartCode, regionType)
return &Region{id, regionType}
regionType string
}
+var noopRegion = &Region{}
+
// End marks the end of the traced code region.
func (r *Region) End() {
+ if r == noopRegion {
+ return
+ }
userRegion(r.id, regionEndCode, r.regionType)
}
"testing"
)
+func BenchmarkStartRegion(b *testing.B) {
+ b.ReportAllocs()
+ ctx, task := NewTask(context.Background(), "benchmark")
+ defer task.End()
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ StartRegion(ctx, "region").End()
+ }
+ })
+}
+
+func BenchmarkNewTask(b *testing.B) {
+ b.ReportAllocs()
+ pctx, task := NewTask(context.Background(), "benchmark")
+ defer task.End()
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ _, task := NewTask(pctx, "task")
+ task.End()
+ }
+ })
+}
+
func TestUserTaskRegion(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
bgctx, cancel := context.WithCancel(context.Background())
defer cancel()
{trace.EvUserRegion, []string{"task0", "region1"}, []uint64{1}, false},
{trace.EvUserRegion, []string{"task0", "region0"}, []uint64{1}, false},
{trace.EvUserTaskEnd, []string{"task0"}, nil, false},
- {trace.EvUserRegion, []string{"", "pre-existing region"}, []uint64{1}, false},
+ // Currently, pre-existing region is not recorded to avoid allocations.
+ // {trace.EvUserRegion, []string{"", "pre-existing region"}, []uint64{1}, false},
{trace.EvUserRegion, []string{"", "post-existing region"}, []uint64{0}, false},
}
if !reflect.DeepEqual(got, want) {
// In particular that we strip bottom uninteresting frames like goexit,
// top uninteresting frames (runtime guts).
func TestTraceSymbolize(t *testing.T) {
- testenv.MustHaveGoBuild(t)
+ skipTraceSymbolizeTestIfNecessary(t)
buf := new(bytes.Buffer)
if err := Start(buf); err != nil {
}
}
+func skipTraceSymbolizeTestIfNecessary(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
+}
+
func dumpEventStacks(typ byte, events []*trace.Event) ([]byte, int) {
matched := 0
o := new(bytes.Buffer)
if race.Enabled {
t.Skip("skipping in race mode")
}
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
if testing.Short() {
t.Skip("skipping in short mode")
}
}
func TestTraceStartStop(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
buf := new(bytes.Buffer)
if err := Start(buf); err != nil {
t.Fatalf("failed to start tracing: %v", err)
}
func TestTraceDoubleStart(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
Stop()
buf := new(bytes.Buffer)
if err := Start(buf); err != nil {
}
func TestTrace(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
buf := new(bytes.Buffer)
if err := Start(buf); err != nil {
t.Fatalf("failed to start tracing: %v", err)
}
func TestTraceStress(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
var wg sync.WaitGroup
done := make(chan bool)
// Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine.
// And concurrently with all that start/stop trace 3 times.
func TestTraceStressStartStop(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
outerDone := make(chan bool)
}
func TestTraceFutileWakeup(t *testing.T) {
+ if IsEnabled() {
+ t.Skip("skipping because -test.trace is set")
+ }
buf := new(bytes.Buffer)
if err := Start(buf); err != nil {
t.Fatalf("failed to start tracing: %v", err)