Source file
src/cmd/trace/trace_test.go
1
2
3
4
5
6
7 package main
8
9 import (
10 "context"
11 "internal/trace"
12 "internal/trace/traceviewer"
13 "internal/trace/traceviewer/format"
14 "io"
15 rtrace "runtime/trace"
16 "strings"
17 "sync"
18 "testing"
19 "time"
20 )
21
22
23 type stacks map[uint64][]*trace.Frame
24
25
26
27 func (s *stacks) add(fname string) uint64 {
28 if *s == nil {
29 *s = make(map[uint64][]*trace.Frame)
30 }
31
32 id := uint64(len(*s))
33 (*s)[id] = []*trace.Frame{{Fn: fname}}
34 return id
35 }
36
37
38
39
40
41 func TestGoroutineCount(t *testing.T) {
42 w := trace.NewWriter()
43 w.Emit(trace.EvBatch, 0, 0)
44 w.Emit(trace.EvFrequency, 1)
45
46 var s stacks
47
48
49
50
51
52 w.Emit(trace.EvGoCreate, 1, 10, s.add("pkg.f1"), s.add("main.f1"))
53 w.Emit(trace.EvGoWaiting, 1, 10)
54
55
56 w.Emit(trace.EvGoCreate, 1, 20, s.add("pkg.f2"), s.add("main.f2"))
57 w.Emit(trace.EvGoInSyscall, 1, 20)
58
59
60 w.Emit(trace.EvGoCreate, 1, 30, s.add("pkg.f3"), s.add("main.f3"))
61
62 w.Emit(trace.EvProcStart, 2, 0)
63
64
65 w.Emit(trace.EvGoCreate, 1, 40, s.add("pkg.f4"), s.add("main.f4"))
66 w.Emit(trace.EvGoStartLocal, 1, 40)
67 w.Emit(trace.EvGoSched, 1, s.add("main.f4"))
68
69 res, err := trace.Parse(w, "")
70 if err != nil {
71 t.Fatalf("failed to parse test trace: %v", err)
72 }
73 res.Stacks = s
74
75 params := &traceParams{
76 parsed: res,
77 endTime: int64(1<<63 - 1),
78 }
79
80
81
82 c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
83 c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
84 if ev.Name == "Goroutines" {
85 cnt := ev.Arg.(*format.GoroutineCountersArg)
86 if cnt.Runnable+cnt.Running > 2 {
87 t.Errorf("goroutine count=%+v; want no more than 2 goroutines in runnable/running state", cnt)
88 }
89 t.Logf("read %+v %+v", ev, cnt)
90 }
91 }
92
93
94 if err := generateTrace(params, c); err != nil {
95 t.Fatalf("generateTrace failed: %v", err)
96 }
97 }
98
99 func TestGoroutineFilter(t *testing.T) {
100
101
102
103 var s stacks
104
105 w := trace.NewWriter()
106 w.Emit(trace.EvBatch, 0, 0)
107 w.Emit(trace.EvFrequency, 1)
108
109
110 w.Emit(trace.EvGoCreate, 1, 10, s.add("pkg.f1"), s.add("main.f1"))
111 w.Emit(trace.EvGoWaiting, 1, 10)
112
113
114 w.Emit(trace.EvGoCreate, 1, 20, s.add("pkg.f2"), s.add("main.f2"))
115 w.Emit(trace.EvGoStartLocal, 1, 20)
116 w.Emit(trace.EvGoUnblockLocal, 1, 10, s.add("pkg.f2"))
117 w.Emit(trace.EvGoEnd, 1)
118
119
120 w.Emit(trace.EvGoStartLocal, 1, 10)
121 w.Emit(trace.EvGoBlock, 1, s.add("pkg.f3"))
122
123 res, err := trace.Parse(w, "")
124 if err != nil {
125 t.Fatalf("failed to parse test trace: %v", err)
126 }
127 res.Stacks = s
128
129 params := &traceParams{
130 parsed: res,
131 endTime: int64(1<<63 - 1),
132 gs: map[uint64]bool{10: true},
133 }
134
135 c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
136 if err := generateTrace(params, c); err != nil {
137 t.Fatalf("generateTrace failed: %v", err)
138 }
139 }
140
141 func TestPreemptedMarkAssist(t *testing.T) {
142 w := trace.NewWriter()
143 w.Emit(trace.EvBatch, 0, 0)
144 w.Emit(trace.EvFrequency, 1)
145
146 var s stacks
147
148 w.Emit(trace.EvGoCreate, 1, 9999, s.add("pkg.f1"), s.add("main.f1"))
149 w.Emit(trace.EvGoStartLocal, 1, 9999)
150 w.Emit(trace.EvGCMarkAssistStart, 1, s.add("main.f1"))
151 w.Emit(trace.EvGoPreempt, 1, s.add("main.f1"))
152 w.Emit(trace.EvGoStartLocal, 1, 9999)
153 w.Emit(trace.EvGCMarkAssistDone, 1)
154 w.Emit(trace.EvGoBlock, 1, s.add("main.f2"))
155
156 res, err := trace.Parse(w, "")
157 if err != nil {
158 t.Fatalf("failed to parse test trace: %v", err)
159 }
160 res.Stacks = s
161
162 params := &traceParams{
163 parsed: res,
164 endTime: int64(1<<63 - 1),
165 }
166
167 c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
168
169 marks := 0
170 c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
171 if strings.Contains(ev.Name, "MARK ASSIST") {
172 marks++
173 }
174 }
175 if err := generateTrace(params, c); err != nil {
176 t.Fatalf("generateTrace failed: %v", err)
177 }
178
179 if marks != 2 {
180 t.Errorf("Got %v MARK ASSIST events, want %v", marks, 2)
181 }
182 }
183
184 func TestFoo(t *testing.T) {
185 prog0 := func() {
186 ctx, task := rtrace.NewTask(context.Background(), "ohHappyDay")
187 rtrace.Log(ctx, "", "log before task ends")
188 task.End()
189 rtrace.Log(ctx, "", "log after task ends")
190 }
191 if err := traceProgram(t, prog0, "TestFoo"); err != nil {
192 t.Fatalf("failed to trace the program: %v", err)
193 }
194 res, err := parseTrace()
195 if err != nil {
196 t.Fatalf("failed to parse the trace: %v", err)
197 }
198 annotRes, _ := analyzeAnnotations()
199 var task *taskDesc
200 for _, t := range annotRes.tasks {
201 if t.name == "ohHappyDay" {
202 task = t
203 break
204 }
205 }
206 if task == nil {
207 t.Fatal("failed to locate expected task event")
208 }
209
210 params := &traceParams{
211 parsed: res,
212 mode: traceviewer.ModeTaskOriented,
213 startTime: task.firstTimestamp() - 1,
214 endTime: task.lastTimestamp() + 1,
215 tasks: []*taskDesc{task},
216 }
217
218 c := traceviewer.ViewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
219
220 var logBeforeTaskEnd, logAfterTaskEnd bool
221 c.ConsumeViewerEvent = func(ev *format.Event, _ bool) {
222 if ev.Name == "log before task ends" {
223 logBeforeTaskEnd = true
224 }
225 if ev.Name == "log after task ends" {
226 logAfterTaskEnd = true
227 }
228 }
229 if err := generateTrace(params, c); err != nil {
230 t.Fatalf("generateTrace failed: %v", err)
231 }
232 if !logBeforeTaskEnd {
233 t.Error("failed to find 'log before task ends'")
234 }
235 if !logAfterTaskEnd {
236 t.Error("failed to find 'log after task ends'")
237 }
238
239 }
240
241 func TestDirectSemaphoreHandoff(t *testing.T) {
242 prog0 := func() {
243 var mu sync.Mutex
244 var wg sync.WaitGroup
245 mu.Lock()
246
247
248
249 for i := 0; i < 2; i++ {
250 wg.Add(1)
251 go func() {
252 defer wg.Done()
253 for i := 0; i < 100; i++ {
254 mu.Lock()
255 time.Sleep(100 * time.Microsecond)
256 mu.Unlock()
257 }
258 }()
259 }
260 mu.Unlock()
261 wg.Wait()
262 }
263 if err := traceProgram(t, prog0, "TestDirectSemaphoreHandoff"); err != nil {
264 t.Fatalf("failed to trace the program: %v", err)
265 }
266 _, err := parseTrace()
267 if err != nil {
268 t.Fatalf("failed to parse the trace: %v", err)
269 }
270 }
271
View as plain text