From 9cdceede1597e55291f71cda020ecb4eb91f2c85 Mon Sep 17 00:00:00 2001 From: Jamie Wong Date: Wed, 21 Jun 2023 15:25:16 -0700 Subject: [PATCH] Support showing pprof lines from the pprof Line object (take 2) (#430) The previous behavior was to use the StartLine of a function as the line number to show in speedscope. However, the Line object has more precise line information, and we should only fallback to StartLine if we don't have this more detailed information. Looking at the [documentation for the pprof proto](https://github.com/google/pprof/tree/main/proto#general-structure-of-a-profile), this is more how it intends to interpret line information: > location: A unique place in the program, commonly mapped to a single instruction address. It has a unique nonzero id, to be referenced from the samples. It contains source information in the form of lines, and a mapping id that points to a binary. > function: A program function as defined in the program source. It has a unique nonzero id, referenced from the location lines. It contains a human-readable name for the function (eg a C++ demangled name), a system name (eg a C++ mangled name), the name of the corresponding source file, and other function attributes. Here is a sample profile that had line-level info on the Line object of the profile: Before: Screen Shot 2022-11-03 at 11 17 11 AM After: Screen Shot 2022-11-03 at 11 17 22 AM --- src/import/__snapshots__/pprof.test.ts.snap | 50 ++++++++++----------- src/import/pprof.ts | 8 +++- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/import/__snapshots__/pprof.test.ts.snap b/src/import/__snapshots__/pprof.test.ts.snap index 69517d5..42f2d38 100644 --- a/src/import/__snapshots__/pprof.test.ts.snap +++ b/src/import/__snapshots__/pprof.test.ts.snap @@ -7,7 +7,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.main:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 198, "name": "runtime.main", "selfWeight": 0, "totalWeight": 1360000000, @@ -16,7 +16,7 @@ Object { "col": undefined, "file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go", "key": "main.main:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0", - "line": 0, + "line": 49, "name": "main.main", "selfWeight": 0, "totalWeight": 1360000000, @@ -25,7 +25,7 @@ Object { "col": undefined, "file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go", "key": "main.delta:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0", - "line": 0, + "line": 28, "name": "main.delta", "selfWeight": 220000000, "totalWeight": 580000000, @@ -34,7 +34,7 @@ Object { "col": undefined, "file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go", "key": "main.beta:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0", - "line": 0, + "line": 18, "name": "main.beta", "selfWeight": 390000000, "totalWeight": 390000000, @@ -43,7 +43,7 @@ Object { "col": undefined, "file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go", "key": "main.alpha:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0", - "line": 0, + "line": 11, "name": "main.alpha", "selfWeight": 480000000, "totalWeight": 480000000, @@ -52,7 +52,7 @@ Object { "col": undefined, "file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go", "key": "main.gamma:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0", - "line": 0, + "line": 34, "name": "main.gamma", "selfWeight": 270000000, "totalWeight": 270000000, @@ -61,7 +61,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s", "key": "runtime.morestack:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:0", - "line": 0, + "line": 480, "name": "runtime.morestack", "selfWeight": 0, "totalWeight": 110000000, @@ -70,7 +70,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go", "key": "runtime.newstack:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go:0", - "line": 0, + "line": 957, "name": "runtime.newstack", "selfWeight": 0, "totalWeight": 110000000, @@ -79,7 +79,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/duff_amd64.s", "key": "runtime.duffcopy:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/duff_amd64.s:0", - "line": 0, + "line": 412, "name": "runtime.duffcopy", "selfWeight": 110000000, "totalWeight": 110000000, @@ -88,7 +88,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go", "key": "runtime.timerproc:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go:0", - "line": 0, + "line": 247, "name": "runtime.timerproc", "selfWeight": 0, "totalWeight": 10000000, @@ -97,7 +97,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go", "key": "runtime.goroutineReady:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go:0", - "line": 0, + "line": 125, "name": "runtime.goroutineReady", "selfWeight": 0, "totalWeight": 10000000, @@ -106,7 +106,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.goready:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 301, "name": "runtime.goready", "selfWeight": 0, "totalWeight": 10000000, @@ -115,7 +115,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s", "key": "runtime.systemstack:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:0", - "line": 0, + "line": 409, "name": "runtime.systemstack", "selfWeight": 0, "totalWeight": 10000000, @@ -124,7 +124,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.goready.func1:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 302, "name": "runtime.goready.func1", "selfWeight": 0, "totalWeight": 10000000, @@ -133,7 +133,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.ready:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 608, "name": "runtime.ready", "selfWeight": 0, "totalWeight": 10000000, @@ -142,7 +142,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.wakep:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 2083, "name": "runtime.wakep", "selfWeight": 0, "totalWeight": 10000000, @@ -151,7 +151,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.startm:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 2017, "name": "runtime.startm", "selfWeight": 0, "totalWeight": 10000000, @@ -160,7 +160,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/lock_sema.go", "key": "runtime.notewakeup:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/lock_sema.go:0", - "line": 0, + "line": 147, "name": "runtime.notewakeup", "selfWeight": 0, "totalWeight": 10000000, @@ -169,7 +169,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go", "key": "runtime.semawakeup:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go:0", - "line": 0, + "line": 36, "name": "runtime.semawakeup", "selfWeight": 0, "totalWeight": 10000000, @@ -178,7 +178,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go", "key": "runtime.mach_semrelease:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go:0", - "line": 0, + "line": 465, "name": "runtime.mach_semrelease", "selfWeight": 0, "totalWeight": 10000000, @@ -187,7 +187,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s", "key": "runtime.mach_semaphore_signal:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s:0", - "line": 0, + "line": 558, "name": "runtime.mach_semaphore_signal", "selfWeight": 10000000, "totalWeight": 10000000, @@ -196,7 +196,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.mstart:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 1193, "name": "runtime.mstart", "selfWeight": 0, "totalWeight": 20000000, @@ -205,7 +205,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.mstart1:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 1227, "name": "runtime.mstart1", "selfWeight": 0, "totalWeight": 20000000, @@ -214,7 +214,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go", "key": "runtime.sysmon:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0", - "line": 0, + "line": 4221, "name": "runtime.sysmon", "selfWeight": 0, "totalWeight": 20000000, @@ -223,7 +223,7 @@ Object { "col": undefined, "file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s", "key": "runtime.usleep:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s:0", - "line": 0, + "line": 418, "name": "runtime.usleep", "selfWeight": 20000000, "totalWeight": 20000000, diff --git a/src/import/pprof.ts b/src/import/pprof.ts index eb271eb..d21f64f 100644 --- a/src/import/pprof.ts +++ b/src/import/pprof.ts @@ -2,6 +2,7 @@ import {perftools} from './profile.proto.js' import {FrameInfo, StackListProfileBuilder, Profile} from '../lib/profile' import {lastOf} from '../lib/utils' import {TimeFormatter, ByteFormatter} from '../lib/value-formatters' +import Long from 'long' interface SampleType { type: string @@ -100,7 +101,12 @@ export function importAsPprofProfile(rawProfile: ArrayBuffer): Profile | null { if (lastLine == null) return null if (lastLine.functionId) { - return frameInfoByFunctionID.get(i32(lastLine.functionId)) || null + let funcFrame = frameInfoByFunctionID.get(i32(lastLine.functionId)) + const line = lastLine.line instanceof Long ? lastLine.line.toNumber() : lastLine.line + if (line && line > 0 && funcFrame != null) { + funcFrame.line = line + } + return funcFrame || null } else { return null }