perf(recover): replace bytes with strings in function for better performance (#4252)

Co-authored-by: huangzw <huangzw@2345.com>
This commit is contained in:
Name 2025-05-31 08:41:13 +08:00 committed by GitHub
parent 61c2b1c28f
commit 3c12d2a80e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 11 additions and 14 deletions

View File

@ -19,12 +19,9 @@ import (
"time" "time"
) )
var ( const dunno = "???"
dunno = []byte("???")
centerDot = []byte("·") var dunnoBytes = []byte(dunno)
dot = []byte(".")
slash = []byte("/")
)
// RecoveryFunc defines the function passable to CustomRecovery. // RecoveryFunc defines the function passable to CustomRecovery.
type RecoveryFunc func(c *Context, err any) type RecoveryFunc func(c *Context, err any)
@ -138,18 +135,18 @@ func stack(skip int) []byte {
func source(lines [][]byte, n int) []byte { func source(lines [][]byte, n int) []byte {
n-- // in stack trace, lines are 1-indexed but our array is 0-indexed n-- // in stack trace, lines are 1-indexed but our array is 0-indexed
if n < 0 || n >= len(lines) { if n < 0 || n >= len(lines) {
return dunno return dunnoBytes
} }
return bytes.TrimSpace(lines[n]) return bytes.TrimSpace(lines[n])
} }
// function returns, if possible, the name of the function containing the PC. // function returns, if possible, the name of the function containing the PC.
func function(pc uintptr) []byte { func function(pc uintptr) string {
fn := runtime.FuncForPC(pc) fn := runtime.FuncForPC(pc)
if fn == nil { if fn == nil {
return dunno return dunno
} }
name := []byte(fn.Name()) name := fn.Name()
// The name includes the path name to the package, which is unnecessary // The name includes the path name to the package, which is unnecessary
// since the file name is already included. Plus, it has center dots. // since the file name is already included. Plus, it has center dots.
// That is, we see // That is, we see
@ -158,13 +155,13 @@ func function(pc uintptr) []byte {
// *T.ptrmethod // *T.ptrmethod
// Also the package path might contain dot (e.g. code.google.com/...), // Also the package path might contain dot (e.g. code.google.com/...),
// so first eliminate the path prefix // so first eliminate the path prefix
if lastSlash := bytes.LastIndex(name, slash); lastSlash >= 0 { if lastSlash := strings.LastIndexByte(name, '/'); lastSlash >= 0 {
name = name[lastSlash+1:] name = name[lastSlash+1:]
} }
if period := bytes.Index(name, dot); period >= 0 { if period := strings.IndexByte(name, '.'); period >= 0 {
name = name[period+1:] name = name[period+1:]
} }
name = bytes.ReplaceAll(name, centerDot, dot) name = strings.ReplaceAll(name, "·", ".")
return name return name
} }

View File

@ -90,14 +90,14 @@ func TestPanicWithAbort(t *testing.T) {
func TestSource(t *testing.T) { func TestSource(t *testing.T) {
bs := source(nil, 0) bs := source(nil, 0)
assert.Equal(t, dunno, bs) assert.Equal(t, dunnoBytes, bs)
in := [][]byte{ in := [][]byte{
[]byte("Hello world."), []byte("Hello world."),
[]byte("Hi, gin.."), []byte("Hi, gin.."),
} }
bs = source(in, 10) bs = source(in, 10)
assert.Equal(t, dunno, bs) assert.Equal(t, dunnoBytes, bs)
bs = source(in, 1) bs = source(in, 1)
assert.Equal(t, []byte("Hello world."), bs) assert.Equal(t, []byte("Hello world."), bs)