1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
20 // TestTraceSymbolize tests symbolization and that events has proper stacks.
21 // In particular that we strip bottom uninteresting frames like goexit,
22 // top uninteresting frames (runtime guts).
23 func TestTraceSymbolize(t *testing.T) {
24 testenv.MustHaveGoBuild(t)
26 buf := new(bytes.Buffer)
27 if err := Start(buf); err != nil {
28 t.Fatalf("failed to start tracing: %v", err)
30 defer Stop() // in case of early return
32 // Now we will do a bunch of things for which we verify stacks later.
33 // It is impossible to ensure that a goroutine has actually blocked
34 // on a channel, in a select or otherwise. So we kick off goroutines
35 // that need to block first in the hope that while we are executing
36 // the rest of the test, they will block.
48 done1 := make(chan bool)
52 done2 := make(chan bool)
75 cv := sync.NewCond(&sync.Mutex{})
81 ln, err := net.Listen("tcp", "127.0.0.1:0")
83 t.Fatalf("failed to listen: %v", err)
88 t.Fatalf("failed to accept: %v", err)
92 rp, wp, err := os.Pipe()
94 t.Fatalf("failed to create a pipe: %v", err)
98 pipeReadDone := make(chan bool)
105 time.Sleep(100 * time.Millisecond)
108 time.Sleep(100 * time.Millisecond) // the last chance for the goroutines above to block
118 c, err := net.Dial("tcp", ln.Addr().String())
120 t.Fatalf("failed to dial: %v", err)
128 events, _ := parseTrace(t, buf)
130 // Now check that the stacks are correct.
135 type eventDesc struct {
140 {trace.EvGCStart, []frame{
142 {"runtime/trace_test.TestTraceSymbolize", 106},
143 {"testing.tRunner", 0},
145 {trace.EvGoStart, []frame{
146 {"runtime/trace_test.TestTraceSymbolize.func1", 37},
148 {trace.EvGoSched, []frame{
149 {"runtime/trace_test.TestTraceSymbolize", 107},
150 {"testing.tRunner", 0},
152 {trace.EvGoCreate, []frame{
153 {"runtime/trace_test.TestTraceSymbolize", 39},
154 {"testing.tRunner", 0},
156 {trace.EvGoStop, []frame{
157 {"runtime.block", 0},
158 {"runtime/trace_test.TestTraceSymbolize.func1", 38},
160 {trace.EvGoStop, []frame{
161 {"runtime.chansend1", 0},
162 {"runtime/trace_test.TestTraceSymbolize.func2", 42},
164 {trace.EvGoStop, []frame{
165 {"runtime.chanrecv1", 0},
166 {"runtime/trace_test.TestTraceSymbolize.func3", 46},
168 {trace.EvGoBlockRecv, []frame{
169 {"runtime.chanrecv1", 0},
170 {"runtime/trace_test.TestTraceSymbolize.func4", 50},
172 {trace.EvGoUnblock, []frame{
173 {"runtime.chansend1", 0},
174 {"runtime/trace_test.TestTraceSymbolize", 109},
175 {"testing.tRunner", 0},
177 {trace.EvGoBlockSend, []frame{
178 {"runtime.chansend1", 0},
179 {"runtime/trace_test.TestTraceSymbolize.func5", 54},
181 {trace.EvGoUnblock, []frame{
182 {"runtime.chanrecv1", 0},
183 {"runtime/trace_test.TestTraceSymbolize", 110},
184 {"testing.tRunner", 0},
186 {trace.EvGoBlockSelect, []frame{
187 {"runtime.selectgo", 0},
188 {"runtime/trace_test.TestTraceSymbolize.func6", 59},
190 {trace.EvGoUnblock, []frame{
191 {"runtime.selectgo", 0},
192 {"runtime/trace_test.TestTraceSymbolize", 111},
193 {"testing.tRunner", 0},
195 {trace.EvGoBlockSync, []frame{
196 {"sync.(*Mutex).Lock", 0},
197 {"runtime/trace_test.TestTraceSymbolize.func7", 67},
199 {trace.EvGoUnblock, []frame{
200 {"sync.(*Mutex).Unlock", 0},
201 {"runtime/trace_test.TestTraceSymbolize", 115},
202 {"testing.tRunner", 0},
204 {trace.EvGoBlockSync, []frame{
205 {"sync.(*WaitGroup).Wait", 0},
206 {"runtime/trace_test.TestTraceSymbolize.func8", 73},
208 {trace.EvGoUnblock, []frame{
209 {"sync.(*WaitGroup).Add", 0},
210 {"sync.(*WaitGroup).Done", 0},
211 {"runtime/trace_test.TestTraceSymbolize", 116},
212 {"testing.tRunner", 0},
214 {trace.EvGoBlockCond, []frame{
215 {"sync.(*Cond).Wait", 0},
216 {"runtime/trace_test.TestTraceSymbolize.func9", 78},
218 {trace.EvGoUnblock, []frame{
219 {"sync.(*Cond).Signal", 0},
220 {"runtime/trace_test.TestTraceSymbolize", 117},
221 {"testing.tRunner", 0},
223 {trace.EvGoSleep, []frame{
225 {"runtime/trace_test.TestTraceSymbolize", 108},
226 {"testing.tRunner", 0},
229 // Stacks for the following events are OS-dependent due to OS-specific code in net package.
230 if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
231 want = append(want, []eventDesc{
232 {trace.EvGoBlockNet, []frame{
233 {"net.(*netFD).accept", 0},
234 {"net.(*TCPListener).accept", 0},
235 {"net.(*TCPListener).Accept", 0},
236 {"runtime/trace_test.TestTraceSymbolize.func10", 86},
238 {trace.EvGoSysCall, []frame{
241 {"os.(*File).read", 0},
242 {"os.(*File).Read", 0},
243 {"runtime/trace_test.TestTraceSymbolize.func11", 101},
247 matched := make([]bool, len(want))
248 for _, ev := range events {
250 for i, w := range want {
251 if matched[i] || w.Type != ev.Type || len(w.Stk) != len(ev.Stk) {
255 for fi, f := range ev.Stk {
257 if wf.Fn != f.Fn || wf.Line != 0 && wf.Line != f.Line {
264 for i, m := range matched {
269 t.Errorf("did not match event %v at %v:%v", trace.EventDescriptions[w.Type].Name, w.Stk[0].Fn, w.Stk[0].Line)
270 t.Errorf("seen the following events of this type:")
271 for _, ev := range events {
272 if ev.Type != w.Type {
275 for _, f := range ev.Stk {
276 t.Logf(" %v:%v", f.Fn, f.Line)