Skip to content

Commit d63a359

Browse files
committed
x/telemetry/counter: fix stack computation
The line number computation in stack counters was wrong (thank you Russ), and has been changed. There is no longer a special case for 386s. Part of the issue for 386s is golang/go#60673 but it is not relevant for this. Change-Id: Iccc9a43ac05d94df2aa7915bfc3d4d74e4d2ff6a Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/501596 Run-TryBot: Peter Weinberger <[email protected]> Reviewed-by: Jamal Carvalho <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 33f6895 commit d63a359

File tree

3 files changed

+48
-108
lines changed

3 files changed

+48
-108
lines changed

counter/counter_test.go

Lines changed: 24 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66

77
package counter
88

9-
// Missing any tests of concurrent uses of a counter.
10-
// This is a TODO.
9+
// Builders at
10+
// https://build.golang.org/?repo=golang.org%2fx%2ftelemetry
1111

1212
import (
1313
"encoding/hex"
1414
"fmt"
15-
"log"
1615
"os"
1716
"path/filepath"
1817
"reflect"
@@ -26,9 +25,10 @@ import (
2625
)
2726

2827
func TestBasic(t *testing.T) {
29-
if runtime.GOOS == "openbsd" {
30-
t.Skip("broken for openbsd")
28+
if runtime.GOOS == "openbsd" || runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
29+
t.Skip("broken for openbsd etc")
3130
}
31+
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
3232
setup(t)
3333
defer restore()
3434
var f file
@@ -66,14 +66,19 @@ func TestBasic(t *testing.T) {
6666
// this is needed in Windows so that the generated testing.go file
6767
// can clean up the temporary test directory
6868
func close(f *file) {
69+
if f == nil {
70+
// telemetry might have been off
71+
return
72+
}
6973
f.current.Load().f.Close()
7074
mmap.Munmap(f.current.Load().mapping)
7175
}
7276

7377
func TestLarge(t *testing.T) {
74-
if runtime.GOOS == "openbsd" {
75-
t.Skip("broken for openbsd")
78+
if runtime.GOOS == "openbsd" || runtime.GOOS == "js" || runtime.GOOS == "wasip1" {
79+
t.Skip("broken for openbsd etc")
7680
}
81+
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
7782
setup(t)
7883
defer restore()
7984
var f file
@@ -118,6 +123,7 @@ func TestLarge(t *testing.T) {
118123
}
119124

120125
func TestRepeatedNew(t *testing.T) {
126+
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
121127
setup(t)
122128
defer restore()
123129
var f file
@@ -155,6 +161,7 @@ func hexDump(data []byte) string {
155161
}
156162

157163
func TestNewFile(t *testing.T) {
164+
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
158165
setup(t)
159166
defer restore()
160167
year, month, day := time.Now().Date()
@@ -209,7 +216,8 @@ func TestNewFile(t *testing.T) {
209216
}
210217
days := (then.Sub(now)) / (24 * time.Hour)
211218
if days <= 7 || days > 14 {
212-
t.Errorf("days = %d, want 7 < days <= 14", days)
219+
// this fails on Solaris, but only once, so print i.
220+
t.Errorf("%d: days = %d, want 7 < days <= 14", i, days)
213221
}
214222
close(&f)
215223
// remove the file for the next iteration of the loop
@@ -218,6 +226,7 @@ func TestNewFile(t *testing.T) {
218226
}
219227

220228
func TestRotate(t *testing.T) {
229+
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
221230
year, month, day := time.Now().Date()
222231
now := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
223232
setup(t)
@@ -272,9 +281,6 @@ func TestRotate(t *testing.T) {
272281
}
273282

274283
func TestStack(t *testing.T) {
275-
if runtime.GOARCH == "386" && runtime.GOOS == "linux" {
276-
t.Skip("some bad line numbers for linux-386")
277-
}
278284
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
279285
setup(t)
280286
defer restore()
@@ -287,20 +293,19 @@ func TestStack(t *testing.T) {
287293
if len(names) != 2 {
288294
t.Fatalf("got %d names, want 2", len(names))
289295
}
290-
// each name should be 6 lines, and the two names should
291-
// differ only in the second line. The last few lines should
292-
// be blank.
296+
// each name should be 4 lines, and the two names should
297+
// differ only in the second line.
293298
n0 := strings.Split(names[0], "\n")
294299
n1 := strings.Split(names[1], "\n")
295-
if len(n0) != 6 || len(n1) != 6 {
296-
t.Fatalf("got %d and %d lines, want 6 (%q,%q)", len(n0), len(n1), n0, n1)
300+
if len(n0) != 4 || len(n1) != 4 {
301+
t.Errorf("got %d and %d lines, want 4 (%q,%q)", len(n0), len(n1), n0, n1)
297302
}
298-
for i := 0; i < 6; i++ { // loop generated by copilot (from comment?)
303+
for i := 0; i < 4 && i < len(n0) && i < len(n1); i++ {
299304
if i == 1 {
300305
continue
301306
}
302307
if n0[i] != n1[i] {
303-
t.Fatalf("line %d differs:\n%s\n%s", i, n0[i], n1[i])
308+
t.Errorf("line %d differs:\n%s\n%s", i, n0[i], n1[i])
304309
}
305310
}
306311
oldnames := make(map[string]bool)
@@ -318,7 +323,7 @@ func TestStack(t *testing.T) {
318323
}
319324
// expect 5 new names, one for each level of recursion
320325
if len(newnames) != 5 {
321-
t.Fatalf("got %d new names, want 5", len(newnames))
326+
t.Errorf("got %d new names, want 5", len(newnames))
322327
}
323328
// look inside. old names should have a count of 1, new ones 2
324329
for _, ct := range c.Counters() {
@@ -362,78 +367,3 @@ func restore() {
362367
func (f *file) New(name string) *Counter {
363368
return &Counter{name: name, file: f}
364369
}
365-
366-
// This checks the computation of of line numbers for creating
367-
// stack counters. It is named after the strangest system,
368-
// but will provide a timely warning if the runtime changes how it
369-
// computes line numbers.
370-
func TestLinux386(t *testing.T) {
371-
t.Logf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
372-
x := infoFromHere(0)
373-
if msg, wanted := check(0, x); msg != "" {
374-
t.Errorf("got %q, wanted %s", msg, wanted)
375-
}
376-
x = deeper()
377-
if msg, wanted := check(1, x); msg != "" {
378-
t.Errorf("got %q, wanted %s", msg, wanted)
379-
}
380-
}
381-
382-
var ans = []string{
383-
"GOOS freebsd GARCH amd64: 3 7",
384-
"GOOS linux GARCH amd64: 3 7",
385-
"GOOS linux GARCH arm64: 3 7",
386-
"GOOS linux GARCH 386: 2 6",
387-
"GOOS openbsd GARCH amd64: 3 7",
388-
"GOOS windows GARCH amd64: 3 7",
389-
"GOOS darwin GARCH amd64: 3 7",
390-
"GOOS darwin GARCH arm64: 3 7",
391-
}
392-
393-
func check(n int, got string) (string, string) {
394-
const prefix = "golang.org/x/telemetry/counter.TestLinux386:"
395-
start := fmt.Sprintf("GOOS %s GARCH %s", runtime.GOOS, runtime.GOARCH)
396-
if !strings.HasPrefix(got, prefix) {
397-
return got, "doesn't start with " + prefix
398-
}
399-
for _, a := range ans {
400-
before, after, ok := strings.Cut(a, ":")
401-
if !ok {
402-
return got, "bad ans, no colon"
403-
}
404-
if before == start {
405-
flds := strings.Fields(after)
406-
if prefix+flds[n] == got {
407-
return "", ""
408-
}
409-
return got, flds[n]
410-
}
411-
}
412-
return got, fmt.Sprintf("%s not found", start)
413-
}
414-
415-
func deeper() string {
416-
log.SetFlags(log.Lshortfile)
417-
x := infoFromHere(1)
418-
return x
419-
}
420-
421-
// the code from file.go that creates stack counter names
422-
func infoFromHere(w int) string {
423-
pcs := make([]uintptr, 4)
424-
n := runtime.Callers(2, pcs)
425-
pcs = pcs[:n]
426-
locs := make([]string, n)
427-
frs := runtime.CallersFrames(pcs)
428-
for i := 0; i < n; i++ {
429-
fr, more := frs.Next()
430-
_, pcline := fr.Func.FileLine(pcs[i])
431-
entryptr := fr.Func.Entry()
432-
_, entryline := fr.Func.FileLine(entryptr)
433-
locs[i] = fmt.Sprintf("%s:%d", fr.Function, pcline-entryline)
434-
if !more {
435-
break
436-
}
437-
}
438-
return locs[w]
439-
}

counter/doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
// are implemented as a set of regular counters whose names
1919
// are the concatenation of the name and the stack trace. There is an upper
2020
// limit on the size of this name, about 256 bytes. If the name is too long
21-
// the counter will be silently ignored.)
21+
// the stack will be truncated and "truncated" appended.)
2222
//
2323
// Counter files are turned into reports by the upload package.
2424
// This happens weekly, except for the first time a counter file is

counter/stackcounter.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package counter
66

77
import (
88
"fmt"
9-
"log"
109
"runtime"
1110
"strings"
1211
"sync"
@@ -53,32 +52,43 @@ func (c *StackCounter) Inc() {
5352
defer c.mu.Unlock()
5453
for _, s := range c.stacks {
5554
if eq(s.pcs, pcs) {
56-
s.counter.Inc()
55+
if s.counter != nil {
56+
s.counter.Inc()
57+
}
5758
return
5859
}
5960
}
6061
// have to create the new counter's name, and the new counter itself
61-
locs := make([]string, c.depth)
62+
locs := make([]string, 0, c.depth)
6263
frs := runtime.CallersFrames(pcs)
63-
for i := 0; i < n; i++ {
64+
for i := 0; ; i++ {
6465
fr, more := frs.Next()
65-
_, pcline := fr.Func.FileLine(pcs[i])
66-
entryptr := fr.Func.Entry()
67-
_, entryline := fr.Func.FileLine(entryptr)
68-
locs[i] = fmt.Sprintf("%s:%d", fr.Function, pcline-entryline)
69-
if pcline-entryline < 0 {
70-
// should never happen, remove before production TODO(pjw)
71-
log.Printf("i=%d, f=%s, pcline=%d entryLine=%d", i, fr.Function, pcline, entryline)
72-
log.Printf("pcs[i]=%x, entryptr=%x", pcs[i], entryptr)
66+
pcline := fr.Line
67+
entryptr := fr.Entry
68+
var locline string
69+
if fr.Func != nil {
70+
_, entryline := fr.Func.FileLine(entryptr)
71+
if pcline >= entryline {
72+
// anything else is unexpected
73+
locline = fmt.Sprintf("%s:%d", fr.Function, pcline-entryline)
74+
} else {
75+
locline = fmt.Sprintf("%s:??%d", fr.Function, pcline)
76+
}
77+
} else {
78+
// might happen if the function is non-Go code or is fully inlined.
79+
locline = fmt.Sprintf("%s:?%d", fr.Function, pcline)
7380
}
81+
locs = append(locs, locline)
7482
if !more {
7583
break
7684
}
7785
}
7886

7987
name := c.name + "\n" + strings.Join(locs, "\n")
8088
if len(name) > maxNameLen {
81-
return // fails silently, every time
89+
const bad = "\ntruncated\n"
90+
name = name[:maxNameLen-len(bad)] + bad
91+
8292
}
8393
ctr := New(name)
8494
c.stacks = append(c.stacks, stack{pcs: pcs, counter: ctr})

0 commit comments

Comments
 (0)