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(time.Millisecond)
108 time.Sleep(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, _, err := parseTrace(t, buf)
130 t.Fatalf("failed to parse trace: %v", err)
133 // Now check that the stacks are correct.
138 type eventDesc struct {
143 {trace.EvGCStart, []frame{
145 {"runtime/trace_test.TestTraceSymbolize", 106},
146 {"testing.tRunner", 0},
148 {trace.EvGoStart, []frame{
149 {"runtime/trace_test.TestTraceSymbolize.func1", 37},
151 {trace.EvGoSched, []frame{
152 {"runtime/trace_test.TestTraceSymbolize", 107},
153 {"testing.tRunner", 0},
155 {trace.EvGoCreate, []frame{
156 {"runtime/trace_test.TestTraceSymbolize", 39},
157 {"testing.tRunner", 0},
159 {trace.EvGoStop, []frame{
160 {"runtime.block", 0},
161 {"runtime/trace_test.TestTraceSymbolize.func1", 38},
163 {trace.EvGoStop, []frame{
164 {"runtime.chansend1", 0},
165 {"runtime/trace_test.TestTraceSymbolize.func2", 42},
167 {trace.EvGoStop, []frame{
168 {"runtime.chanrecv1", 0},
169 {"runtime/trace_test.TestTraceSymbolize.func3", 46},
171 {trace.EvGoBlockRecv, []frame{
172 {"runtime.chanrecv1", 0},
173 {"runtime/trace_test.TestTraceSymbolize.func4", 50},
175 {trace.EvGoUnblock, []frame{
176 {"runtime.chansend1", 0},
177 {"runtime/trace_test.TestTraceSymbolize", 109},
178 {"testing.tRunner", 0},
180 {trace.EvGoBlockSend, []frame{
181 {"runtime.chansend1", 0},
182 {"runtime/trace_test.TestTraceSymbolize.func5", 54},
184 {trace.EvGoUnblock, []frame{
185 {"runtime.chanrecv1", 0},
186 {"runtime/trace_test.TestTraceSymbolize", 110},
187 {"testing.tRunner", 0},
189 {trace.EvGoBlockSelect, []frame{
190 {"runtime.selectgo", 0},
191 {"runtime/trace_test.TestTraceSymbolize.func6", 59},
193 {trace.EvGoUnblock, []frame{
194 {"runtime.selectgo", 0},
195 {"runtime/trace_test.TestTraceSymbolize", 111},
196 {"testing.tRunner", 0},
198 {trace.EvGoBlockSync, []frame{
199 {"sync.(*Mutex).Lock", 0},
200 {"runtime/trace_test.TestTraceSymbolize.func7", 67},
202 {trace.EvGoUnblock, []frame{
203 {"sync.(*Mutex).Unlock", 0},
204 {"runtime/trace_test.TestTraceSymbolize", 115},
205 {"testing.tRunner", 0},
207 {trace.EvGoBlockSync, []frame{
208 {"sync.(*WaitGroup).Wait", 0},
209 {"runtime/trace_test.TestTraceSymbolize.func8", 73},
211 {trace.EvGoUnblock, []frame{
212 {"sync.(*WaitGroup).Add", 0},
213 {"sync.(*WaitGroup).Done", 0},
214 {"runtime/trace_test.TestTraceSymbolize", 116},
215 {"testing.tRunner", 0},
217 {trace.EvGoBlockCond, []frame{
218 {"sync.(*Cond).Wait", 0},
219 {"runtime/trace_test.TestTraceSymbolize.func9", 78},
221 {trace.EvGoUnblock, []frame{
222 {"sync.(*Cond).Signal", 0},
223 {"runtime/trace_test.TestTraceSymbolize", 117},
224 {"testing.tRunner", 0},
226 {trace.EvGoSleep, []frame{
228 {"runtime/trace_test.TestTraceSymbolize", 108},
229 {"testing.tRunner", 0},
232 // Stacks for the following events are OS-dependent due to OS-specific code in net package.
233 if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
234 want = append(want, []eventDesc{
235 {trace.EvGoBlockNet, []frame{
236 {"net.(*netFD).accept", 0},
237 {"net.(*TCPListener).accept", 0},
238 {"net.(*TCPListener).Accept", 0},
239 {"runtime/trace_test.TestTraceSymbolize.func10", 86},
241 {trace.EvGoSysCall, []frame{
244 {"os.(*File).read", 0},
245 {"os.(*File).Read", 0},
246 {"runtime/trace_test.TestTraceSymbolize.func11", 101},
250 matched := make([]bool, len(want))
251 for _, ev := range events {
253 for i, w := range want {
254 if matched[i] || w.Type != ev.Type || len(w.Stk) != len(ev.Stk) {
258 for fi, f := range ev.Stk {
260 if wf.Fn != f.Fn || wf.Line != 0 && wf.Line != f.Line {
267 for i, m := range matched {
272 t.Errorf("did not match event %v at %v:%v", trace.EventDescriptions[w.Type].Name, w.Stk[0].Fn, w.Stk[0].Line)
273 t.Errorf("seen the following events of this type:")
274 for _, ev := range events {
275 if ev.Type != w.Type {
278 for _, f := range ev.Stk {
279 t.Logf(" %v:%v", f.Fn, f.Line)