Skip to content

Commit 5795b8e

Browse files
committed
stack: Enable race detection
Embeds the race results inside Goroutine. Update both console output and html output to print out the detected data race.
1 parent a38f090 commit 5795b8e

11 files changed

Lines changed: 376 additions & 184 deletions

File tree

internal/htmlstack/data.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/htmlstack/goroutines.tpl

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@
134134
.created {
135135
white-space: nowrap;
136136
}
137+
.race {
138+
font-weight: 700;
139+
color: #600;
140+
}
137141
.topright {
138142
float: right;
139143
}
@@ -203,20 +207,39 @@ document.addEventListener("DOMContentLoaded", ready);
203207
{{- /* Only shown when augment query parameter is not specified */ -}}
204208
<a class=button id=augment href="?augment=1">Analyse sources</a>
205209
</div>
206-
{{- range $i, $e := .Buckets -}}
207-
{{$l := len $e.IDs}}
208-
<h1>Signature #{{$i}}: <span class="{{routineClass $e}}">{{$l}} routine{{if ne 1 $l}}s{{end}}: <span class="state">{{$e.State}}</span>
209-
{{- if $e.SleepMax -}}
210-
{{- if ne $e.SleepMin $e.SleepMax}} <span class="sleep">[{{$e.SleepMin}}~{{$e.SleepMax}} mins]</span>
211-
{{- else}} <span class="sleep">[{{$e.SleepMax}} mins]</span>
210+
{{- if .Buckets -}}
211+
{{- range $i, $e := .Buckets -}}
212+
{{$l := len $e.IDs}}
213+
<h1>Signature #{{$i}}: <span class="{{bucketClass $e}}">{{$l}} routine{{if ne 1 $l}}s{{end}}: <span class="state">{{$e.State}}</span>
214+
{{- if $e.SleepMax -}}
215+
{{- if ne $e.SleepMin $e.SleepMax}} <span class="sleep">[{{$e.SleepMin}}~{{$e.SleepMax}} mins]</span>
216+
{{- else}} <span class="sleep">[{{$e.SleepMax}} mins]</span>
217+
{{- end -}}
212218
{{- end -}}
219+
</h1>
220+
{{if $e.Locked}} <span class="locked">[locked]</span>
221+
{{- end -}}
222+
{{- if $e.CreatedBy.Calls}} <span class="created">Created by: {{template "RenderCall" index $e.CreatedBy.Calls 0}}</span>
223+
{{- end -}}
224+
{{template "RenderCalls" $e.Signature.Stack}}
213225
{{- end -}}
214-
</h1>
215-
{{if $e.Locked}} <span class="locked">[locked]</span>
216-
{{- end -}}
217-
{{- if $e.CreatedBy.Calls}} <span class="created">Created by: {{template "RenderCall" index $e.CreatedBy.Calls 0}}</span>
226+
{{- else -}}
227+
{{- range $i, $e := .Routines -}}
228+
<h1>Routine {{$e.ID}}: <span class="{{routineClass $e}}">: <span class="state">{{$e.State}}</span>
229+
{{- if $e.SleepMax -}}
230+
{{- if ne $e.SleepMin $e.SleepMax}} <span class="sleep">[{{$e.SleepMin}}~{{$e.SleepMax}} mins]</span>
231+
{{- else}} <span class="sleep">[{{$e.SleepMax}} mins]</span>
232+
{{- end -}}
233+
{{- end -}}
234+
</h1>
235+
{{if $e.Locked}} <span class="locked">[locked]</span>
236+
{{- end -}}
237+
{{if $e.RaceAddr}} <span class="race">Race {{if $e.RaceWrite}}write{{else}}read{{end}} @ {{$e.RaceAddr}}</span><br>
238+
{{- end -}}
239+
{{- if $e.CreatedBy.Calls}} <span class="created">Created by: {{template "RenderCall" index $e.CreatedBy.Calls 0}}</span>
240+
{{- end -}}
241+
{{template "RenderCalls" $e.Signature.Stack}}
218242
{{- end -}}
219-
{{template "RenderCalls" $e.Signature.Stack}}
220243
{{- end -}}
221244
</div>
222245
<p>

internal/htmlstack/htmlstack.go

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,22 @@ import (
2121
"github.com/maruel/panicparse/v2/stack"
2222
)
2323

24-
// Write writes buckets as HTML to the writer.
25-
func Write(w io.Writer, buckets []*stack.Bucket, needsEnv, live bool) error {
24+
// WriteBuckets writes buckets as HTML to the writer.
25+
func WriteBuckets(w io.Writer, buckets []*stack.Bucket, needsEnv, live bool) error {
2626
m := template.FuncMap{
27-
"funcClass": funcClass,
28-
"minus": minus,
29-
"pkgURL": pkgURL,
30-
"srcURL": srcURL,
31-
"symbol": symbol,
27+
"bucketClass": func(bucket *stack.Bucket) template.HTML { return "Routine" },
28+
"funcClass": funcClass,
29+
"minus": minus,
30+
"pkgURL": pkgURL,
31+
"routineClass": func(bucket *stack.Goroutine) template.HTML { return "Routine" },
32+
"srcURL": srcURL,
33+
"symbol": symbol,
3234
// Needs to be a function and not a variable, otherwise it is not
3335
// accessible inside inner templates.
3436
"isDebug": isDebug,
3537
}
3638
if len(buckets) > 1 {
37-
m["routineClass"] = routineClass
38-
} else {
39-
m["routineClass"] = func(bucket *stack.Bucket) template.HTML { return "Routine" }
39+
m["bucketClass"] = bucketClass
4040
}
4141
t, err := template.New("t").Funcs(m).Parse(indexHTML)
4242
if err != nil {
@@ -56,6 +56,41 @@ func Write(w io.Writer, buckets []*stack.Bucket, needsEnv, live bool) error {
5656
return t.Execute(w, data)
5757
}
5858

59+
// WriteGoroutines writes a race as HTML to the writer.
60+
func WriteGoroutines(w io.Writer, goroutines []*stack.Goroutine, needsEnv, live bool) error {
61+
m := template.FuncMap{
62+
"bucketClass": func(bucket *stack.Bucket) template.HTML { return "Routine" },
63+
"funcClass": funcClass,
64+
"minus": minus,
65+
"pkgURL": pkgURL,
66+
"srcURL": srcURL,
67+
"symbol": symbol,
68+
"routineClass": func(bucket *stack.Goroutine) template.HTML { return "Routine" },
69+
// Needs to be a function and not a variable, otherwise it is not
70+
// accessible inside inner templates.
71+
"isDebug": isDebug,
72+
}
73+
if len(goroutines) > 1 {
74+
m["routineClass"] = routineClass
75+
}
76+
t, err := template.New("t").Funcs(m).Parse(indexHTML)
77+
if err != nil {
78+
return err
79+
}
80+
data := map[string]interface{}{
81+
"Routines": goroutines,
82+
"Favicon": favicon,
83+
"GOMAXPROCS": runtime.GOMAXPROCS(0),
84+
"GOPATH": os.Getenv("GOPATH"),
85+
"GOROOT": runtime.GOROOT(),
86+
"Live": live,
87+
"NeedsEnv": needsEnv,
88+
"Now": time.Now().Truncate(time.Second),
89+
"Version": runtime.Version(),
90+
}
91+
return t.Execute(w, data)
92+
}
93+
5994
//
6095

6196
var reMethodSymbol = regexp.MustCompile(`^\(\*?([^)]+)\)(\..+)$`)
@@ -232,7 +267,14 @@ func symbol(f *stack.Func) template.URL {
232267
return template.URL(url.QueryEscape(s))
233268
}
234269

235-
func routineClass(bucket *stack.Bucket) template.HTML {
270+
func bucketClass(bucket *stack.Bucket) template.HTML {
271+
if bucket.First {
272+
return "RoutineFirst"
273+
}
274+
return "Routine"
275+
}
276+
277+
func routineClass(bucket *stack.Goroutine) template.HTML {
236278
if bucket.First {
237279
return "RoutineFirst"
238280
}

0 commit comments

Comments
 (0)