Skip to content

Commit

Permalink
Use llvm-symbolizer's JSON output to provide function start lines
Browse files Browse the repository at this point in the history
When analyzing a perf.data profile converted automatically via perf_to_profile via pprof -raw perf.data, no function start lines (s=0) are present in any of the locations. With 813a5fb, this can be easily solved by using the same JSON frame data from llvm-symbolizer to provide StartLine for Function.start_line. This solves #823.
  • Loading branch information
insilications committed Sep 1, 2024
1 parent da1f7e9 commit a088559
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 17 deletions.
9 changes: 5 additions & 4 deletions driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,11 @@ type ObjFile interface {

// A Frame describes a single line in a source file.
type Frame struct {
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in file
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in file
StartLine int // start line of function (if available)
}

// A Sym describes a single symbol in an object file.
Expand Down
11 changes: 6 additions & 5 deletions internal/binutils/addr2liner_llvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,18 +151,19 @@ func (d *llvmSymbolizer) readCodeFrames() ([]plugin.Frame, error) {
Address string `json:"Address"`
ModuleName string `json:"ModuleName"`
Symbol []struct {
Line int `json:"Line"`
Column int `json:"Column"`
FunctionName string `json:"FunctionName"`
FileName string `json:"FileName"`
Line int `json:"Line"`
Column int `json:"Column"`
FunctionName string `json:"FunctionName"`
FileName string `json:"FileName"`
StartLine int `json:"StartLine"`
} `json:"Symbol"`
}
if err := json.Unmarshal([]byte(line), &frame); err != nil {
return nil, err
}
var stack []plugin.Frame
for _, s := range frame.Symbol {
stack = append(stack, plugin.Frame{Func: s.FunctionName, File: s.FileName, Line: s.Line, Column: s.Column})
stack = append(stack, plugin.Frame{Func: s.FunctionName, File: s.FileName, Line: s.Line, Column: s.Column, StartLine: s.StartLine})
}
return stack, nil
}
Expand Down
7 changes: 4 additions & 3 deletions internal/binutils/binutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ func TestObjFile(t *testing.T) {
t.Fatalf("SourceLine: unexpected error %v", err)
}
wantFrames := []plugin.Frame{
{Func: "main", File: "/tmp/hello.c", Line: 3},
{Func: "main", File: "/tmp/hello.c", Line: 3, StartLine: 3},
}
if !reflect.DeepEqual(gotFrames, wantFrames) {
t.Fatalf("SourceLine for main: got %v; want %v\n", gotFrames, wantFrames)
Expand Down Expand Up @@ -461,8 +461,8 @@ func TestLLVMSymbolizer(t *testing.T) {
frames []plugin.Frame
}{
{0x10, false, []plugin.Frame{
{Func: "Inlined_0x10", File: "foo.h", Line: 0, Column: 0},
{Func: "Func_0x10", File: "foo.c", Line: 2, Column: 1},
{Func: "Inlined_0x10", File: "foo.h", Line: 0, Column: 0, StartLine: 0},
{Func: "Func_0x10", File: "foo.c", Line: 2, Column: 1, StartLine: 2},
}},
{0x20, true, []plugin.Frame{
{Func: "foo_0x20", File: "0x20 8"},
Expand All @@ -480,6 +480,7 @@ func TestLLVMSymbolizer(t *testing.T) {
defer symbolizer.rw.close()

frames, err := symbolizer.addrInfo(c.addr)
t.Logf("EITA expect %v; got %v\n", c.frames, frames)
if err != nil {
t.Fatalf("LLVM: unexpected error %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/binutils/testdata/fake-llvm-symbolizer
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ while read line; do
addr=$3
case ${kind} in
CODE)
echo "{\"Address\":\"${addr}\",\"ModuleName\":\"${fname}\",\"Symbol\":[{\"Column\":0,\"FileName\":\"${fname}.h\",\"FunctionName\":\"Inlined_${addr}\",\"Line\":0},{\"Column\":1,\"FileName\":\"${fname}.c\",\"FunctionName\":\"Func_${addr}\",\"Line\":2}]}"
echo "{\"Address\":\"${addr}\",\"ModuleName\":\"${fname}\",\"Symbol\":[{\"Column\":0,\"FileName\":\"${fname}.h\",\"FunctionName\":\"Inlined_${addr}\",\"Line\":0,\"StartLine\":0},{\"Column\":1,\"FileName\":\"${fname}.c\",\"FunctionName\":\"Func_${addr}\",\"Line\":2,\"StartLine\":2}]}"
;;
DATA)
echo "{\"Address\":\"${addr}\",\"ModuleName\":\"${fname}\",\"Data\":{\"Name\":\"${fname}_${addr}\",\"Size\":\"0x8\",\"Start\":\"${addr}\"}}"
Expand Down
9 changes: 5 additions & 4 deletions internal/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,11 @@ type ObjFile interface {

// A Frame describes a location in a single line in a source file.
type Frame struct {
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in line (if available)
Func string // name of function
File string // source file name
Line int // line in file
Column int // column in line (if available)
StartLine int // start line of function (if available)
}

// A Sym describes a single symbol in an object file.
Expand Down
1 change: 1 addition & 0 deletions internal/symbolizer/symbolizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ func symbolizeOneMapping(m *profile.Mapping, locs []*profile.Location, obj plugi
Name: frame.Func,
SystemName: frame.Func,
Filename: frame.File,
StartLine: int64(frame.StartLine),
})
l.Line[i] = profile.Line{
Function: f,
Expand Down

0 comments on commit a088559

Please sign in to comment.