@@ -9,7 +9,6 @@ package runtime
9
9
10
10
import (
11
11
"internal/abi"
12
- "internal/goarch"
13
12
"internal/profilerecord"
14
13
"internal/runtime/atomic"
15
14
"runtime/internal/sys"
@@ -543,80 +542,36 @@ func saveblockevent(cycles, rate int64, skip int, which bucketType) {
543
542
gp := getg ()
544
543
mp := acquirem () // we must not be preempted while accessing profstack
545
544
546
- var nstk int
545
+ nstk := 1
547
546
if tracefpunwindoff () || gp .m .hasCgoOnStack () {
547
+ mp .profStack [0 ] = logicalStackSentinel
548
548
if gp .m .curg == nil || gp .m .curg == gp {
549
- nstk = callers (skip , mp .profStack )
549
+ nstk = callers (skip , mp .profStack [ 1 :] )
550
550
} else {
551
- nstk = gcallers (gp .m .curg , skip , mp .profStack )
551
+ nstk = gcallers (gp .m .curg , skip , mp .profStack [ 1 :] )
552
552
}
553
553
} else {
554
+ mp .profStack [0 ] = uintptr (skip )
554
555
if gp .m .curg == nil || gp .m .curg == gp {
555
556
if skip > 0 {
556
557
// We skip one fewer frame than the provided value for frame
557
558
// pointer unwinding because the skip value includes the current
558
559
// frame, whereas the saved frame pointer will give us the
559
560
// caller's return address first (so, not including
560
561
// saveblockevent)
561
- skip -= 1
562
+ mp . profStack [ 0 ] -= 1
562
563
}
563
- nstk = fpTracebackPartialExpand ( skip , unsafe .Pointer (getfp ()), mp .profStack )
564
+ nstk += fpTracebackPCs ( unsafe .Pointer (getfp ()), mp .profStack [ 1 :] )
564
565
} else {
565
- mp .profStack [0 ] = gp .m .curg .sched .pc
566
- nstk = 1 + fpTracebackPartialExpand ( skip , unsafe .Pointer (gp .m .curg .sched .bp ), mp .profStack [1 :])
566
+ mp .profStack [1 ] = gp .m .curg .sched .pc
567
+ nstk + = 1 + fpTracebackPCs ( unsafe .Pointer (gp .m .curg .sched .bp ), mp .profStack [2 :])
567
568
}
568
569
}
569
570
570
571
saveBlockEventStack (cycles , rate , mp .profStack [:nstk ], which )
571
572
releasem (mp )
572
573
}
573
574
574
- // fpTracebackPartialExpand records a call stack obtained starting from fp.
575
- // This function will skip the given number of frames, properly accounting for
576
- // inlining, and save remaining frames as "physical" return addresses. The
577
- // consumer should later use CallersFrames or similar to expand inline frames.
578
- func fpTracebackPartialExpand (skip int , fp unsafe.Pointer , pcBuf []uintptr ) int {
579
- var n int
580
- lastFuncID := abi .FuncIDNormal
581
- skipOrAdd := func (retPC uintptr ) bool {
582
- if skip > 0 {
583
- skip --
584
- } else if n < len (pcBuf ) {
585
- pcBuf [n ] = retPC
586
- n ++
587
- }
588
- return n < len (pcBuf )
589
- }
590
- for n < len (pcBuf ) && fp != nil {
591
- // return addr sits one word above the frame pointer
592
- pc := * (* uintptr )(unsafe .Pointer (uintptr (fp ) + goarch .PtrSize ))
593
-
594
- if skip > 0 {
595
- callPC := pc - 1
596
- fi := findfunc (callPC )
597
- u , uf := newInlineUnwinder (fi , callPC )
598
- for ; uf .valid (); uf = u .next (uf ) {
599
- sf := u .srcFunc (uf )
600
- if sf .funcID == abi .FuncIDWrapper && elideWrapperCalling (lastFuncID ) {
601
- // ignore wrappers
602
- } else if more := skipOrAdd (uf .pc + 1 ); ! more {
603
- return n
604
- }
605
- lastFuncID = sf .funcID
606
- }
607
- } else {
608
- // We've skipped the desired number of frames, so no need
609
- // to perform further inline expansion now.
610
- pcBuf [n ] = pc
611
- n ++
612
- }
613
-
614
- // follow the frame pointer to the next one
615
- fp = unsafe .Pointer (* (* uintptr )(fp ))
616
- }
617
- return n
618
- }
619
-
620
575
// lockTimer assists with profiling contention on runtime-internal locks.
621
576
//
622
577
// There are several steps between the time that an M experiences contention and
@@ -1120,34 +1075,10 @@ type BlockProfileRecord struct {
1120
1075
// the [testing] package's -test.blockprofile flag instead
1121
1076
// of calling BlockProfile directly.
1122
1077
func BlockProfile (p []BlockProfileRecord ) (n int , ok bool ) {
1123
- n , ok = blockProfileInternal (len (p ), func (r profilerecord.BlockProfileRecord ) {
1078
+ return blockProfileInternal (len (p ), func (r profilerecord.BlockProfileRecord ) {
1124
1079
copyBlockProfileRecord (& p [0 ], r )
1125
1080
p = p [1 :]
1126
1081
})
1127
- if ! ok {
1128
- return
1129
- }
1130
- expandFrames (p [:n ])
1131
- return
1132
- }
1133
-
1134
- func expandFrames (p []BlockProfileRecord ) {
1135
- expandedStack := makeProfStack ()
1136
- for i := range p {
1137
- cf := CallersFrames (p [i ].Stack ())
1138
- j := 0
1139
- for ; j < len (expandedStack ); j ++ {
1140
- f , more := cf .Next ()
1141
- // f.PC is a "call PC", but later consumers will expect
1142
- // "return PCs"
1143
- expandedStack [i ] = f .PC + 1
1144
- if ! more {
1145
- break
1146
- }
1147
- }
1148
- k := copy (p [i ].Stack0 [:], expandedStack [:j ])
1149
- clear (p [i ].Stack0 [k :])
1150
- }
1151
1082
}
1152
1083
1153
1084
// blockProfileInternal returns the number of records n in the profile. If there
@@ -1180,9 +1111,6 @@ func blockProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord
1180
1111
return
1181
1112
}
1182
1113
1183
- // copyBlockProfileRecord copies the sample values and call stack from src to dst.
1184
- // The call stack is copied as-is. The caller is responsible for handling inline
1185
- // expansion, needed when the call stack was collected with frame pointer unwinding.
1186
1114
func copyBlockProfileRecord (dst * BlockProfileRecord , src profilerecord.BlockProfileRecord ) {
1187
1115
dst .Count = src .Count
1188
1116
dst .Cycles = src .Cycles
@@ -1195,11 +1123,7 @@ func copyBlockProfileRecord(dst *BlockProfileRecord, src profilerecord.BlockProf
1195
1123
if asanenabled {
1196
1124
asanwrite (unsafe .Pointer (& dst .Stack0 [0 ]), unsafe .Sizeof (dst .Stack0 ))
1197
1125
}
1198
- // We just copy the stack here without inline expansion
1199
- // (needed if frame pointer unwinding is used)
1200
- // since this function is called under the profile lock,
1201
- // and doing something that might allocate can violate lock ordering.
1202
- i := copy (dst .Stack0 [:], src .Stack )
1126
+ i := fpunwindExpand (dst .Stack0 [:], src .Stack )
1203
1127
clear (dst .Stack0 [i :])
1204
1128
}
1205
1129
@@ -1218,15 +1142,10 @@ func pprof_blockProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok
1218
1142
// Most clients should use the [runtime/pprof] package
1219
1143
// instead of calling MutexProfile directly.
1220
1144
func MutexProfile (p []BlockProfileRecord ) (n int , ok bool ) {
1221
- n , ok = mutexProfileInternal (len (p ), func (r profilerecord.BlockProfileRecord ) {
1145
+ return mutexProfileInternal (len (p ), func (r profilerecord.BlockProfileRecord ) {
1222
1146
copyBlockProfileRecord (& p [0 ], r )
1223
1147
p = p [1 :]
1224
1148
})
1225
- if ! ok {
1226
- return
1227
- }
1228
- expandFrames (p [:n ])
1229
- return
1230
1149
}
1231
1150
1232
1151
// mutexProfileInternal returns the number of records n in the profile. If there
0 commit comments