blob: 6d18e7d5d16a0f15ba957e7ff3363f1c454895fa [file] [log] [blame]
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"net/http"
"os"
"runtime/trace"
"strings"
"testing"
"testing/synctest"
"time"
"internal/trace/testtrace"
)
// Regression test for go.dev/issue/74850.
func TestSyscallProfile74850(t *testing.T) {
testtrace.MustHaveSyscallEvents(t)
var buf bytes.Buffer
err := trace.Start(&buf)
if err != nil {
t.Fatalf("start tracing: %v", err)
}
synctest.Test(t, func(t *testing.T) {
go hidden1(t)
go hidden2(t)
go visible(t)
synctest.Wait()
time.Sleep(1 * time.Millisecond)
synctest.Wait()
})
trace.Stop()
if t.Failed() {
return
}
parsed, err := parseTrace(&buf, int64(buf.Len()))
if err != nil {
t.Fatalf("parsing trace: %v", err)
}
records, err := pprofByGoroutine(computePprofSyscall(), parsed)(&http.Request{})
if err != nil {
t.Fatalf("failed to generate pprof: %v\n", err)
}
for _, r := range records {
t.Logf("Record: n=%d, total=%v", r.Count, r.Time)
for _, f := range r.Stack {
t.Logf("\t%s", f.Func)
t.Logf("\t\t%s:%d @ 0x%x", f.File, f.Line, f.PC)
}
}
if len(records) == 0 {
t.Error("empty profile")
}
// Make sure we see the right frames.
wantSymbols := []string{"cmd/trace.visible", "cmd/trace.hidden1", "cmd/trace.hidden2"}
haveSymbols := make([]bool, len(wantSymbols))
for _, r := range records {
for _, f := range r.Stack {
for i, s := range wantSymbols {
if strings.Contains(f.Func, s) {
haveSymbols[i] = true
}
}
}
}
for i, have := range haveSymbols {
if !have {
t.Errorf("expected %s in syscall profile", wantSymbols[i])
}
}
}
func stat(t *testing.T) {
_, err := os.Stat(".")
if err != nil {
t.Errorf("os.Stat: %v", err)
}
}
func hidden1(t *testing.T) {
stat(t)
}
func hidden2(t *testing.T) {
stat(t)
stat(t)
}
func visible(t *testing.T) {
stat(t)
time.Sleep(1 * time.Millisecond)
}