Skip to content

Commit e9ad5de

Browse files
committed
runtime: provide a knob to control profile precision.
Provide envvar GO_PPROF_PRECISION=0,1,2,3,4 values to control the profiling precision. Values 0-3 are pass through, and 4 indicates automatic search for the best precision that works on the system. The value 4 is not guaraneed to work on all systems. The default is arbitrary skid with value 0.
1 parent fa6231d commit e9ad5de

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

src/runtime/cpuprof.go

+19-4
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ const (
4040
type profilePCPrecision uint8
4141

4242
const (
43-
_CPUPROF_IP_ARBITRARY_SKID profilePCPrecision = iota
44-
_CPUPROF_IP_CONSTANT_SKID
43+
_CPUPROF_IP_ARBITRARY_SKID, _CPUPROF_IP_FIRST_PRECISION profilePCPrecision = iota, iota
44+
_CPUPROF_IP_CONSTANT_SKID = iota
4545
_CPUPROF_IP_SUGGEST_NO_SKID
46-
_CPUPROF_IP_NO_SKID
46+
_CPUPROF_IP_NO_SKID, _CPUPROF_IP_LAST_PRECISION = iota, iota
47+
_CPUPROF_IP_BEST_AVAILABLE_SKID = iota
4748
)
4849

4950
// cpuProfileConfig holds different settings under which CPU samples can be produced.
@@ -138,7 +139,21 @@ func sanitizeCPUProfileConfig(profConfig *cpuProfileConfig) {
138139
if profConfig == nil {
139140
return
140141
}
141-
profConfig.preciseIP = _CPUPROF_IP_ARBITRARY_SKID
142+
precision := _CPUPROF_IP_ARBITRARY_SKID
143+
switch gogetenv("GO_PPROF_PRECISION") {
144+
case "0":
145+
precision = _CPUPROF_IP_ARBITRARY_SKID
146+
case "1":
147+
precision = _CPUPROF_IP_CONSTANT_SKID
148+
case "2":
149+
precision = _CPUPROF_IP_SUGGEST_NO_SKID
150+
case "3":
151+
precision = _CPUPROF_IP_NO_SKID
152+
case "4":
153+
precision = _CPUPROF_IP_BEST_AVAILABLE_SKID
154+
default:
155+
}
156+
atomic.Store8((*uint8)(&profConfig.preciseIP), uint8(precision))
142157
profConfig.isSampleIPIncluded = false
143158
profConfig.isSampleThreadIDIncluded = false
144159
profConfig.isSampleAddrIncluded = false

src/runtime/os_linux.go

+19-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package runtime
66

77
import (
8+
"runtime/internal/atomic"
89
"runtime/internal/sys"
910
"unsafe"
1011
)
@@ -543,9 +544,25 @@ func setThreadPMUProfiler(eventId cpuEvent, profConfig *cpuProfileConfig) {
543544

544545
// profConfig != nil
545546
var perfAttr perfEventAttr
547+
var fd int32
548+
initialPrecision := profilePCPrecision(atomic.Load8((*uint8)(&profConfig.preciseIP)))
546549
perfAttrInit(eventId, profConfig, &perfAttr)
547-
fd := perfEventOpen(&perfAttr, 0, -1, -1, uintptr(0))
548-
if fd < 0 {
550+
if initialPrecision != _CPUPROF_IP_BEST_AVAILABLE_SKID {
551+
fd = perfEventOpen(&perfAttr, 0, -1, -1, uintptr(0))
552+
} else {
553+
// auto detect precision
554+
for p := _CPUPROF_IP_LAST_PRECISION; p >= int(_CPUPROF_IP_FIRST_PRECISION); p-- {
555+
perfAttr.setPrecision(profilePCPrecision(p))
556+
fd = perfEventOpen(&perfAttr, 0, -1, -1, uintptr(0))
557+
if fd >= 0 {
558+
// Set the precision to a value that worked.
559+
atomic.Store8((*uint8)(&profConfig.preciseIP), uint8(p))
560+
break
561+
}
562+
}
563+
}
564+
565+
if fd < 0 {
549566
//dont print because a filed perfEventOpen can be enabled later.
550567
//perfEventOpen can fail due to interrupted system call.
551568
//println("Linux perf event open failed")

src/runtime/perf_linux.go

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ func perfEventOpen(attr *perfEventAttr, pid uintptr, cpu, groupFd int32, flags u
1111

1212
const perfDataPages = 2 // use 2^n data pages
1313

14+
func (perfAttr *perfEventAttr) setPrecision(precision profilePCPrecision) {
15+
perfAttr.bits &^= (uint64(3) << 15)
16+
perfAttr.bits |= uint64(precision) << 15
17+
}
18+
1419
func perfAttrInit(eventId cpuEvent, profConfig *cpuProfileConfig, perfAttr *perfEventAttr) {
1520
perfAttr._type = perfEventOpt[eventId]._type
1621
perfAttr.size = uint32(unsafe.Sizeof(*perfAttr))

0 commit comments

Comments
 (0)