devtools/src/jehanne/cmd/profile/profile.go

132 lines
2.4 KiB
Go

package main
import (
"bytes"
"debug/elf"
"encoding/binary"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
)
type Header struct {
Sz byte
_ byte
Core uint16
_ uint16
Ver byte
Sig byte
Time uint64
}
type pc uint64
type Record struct {
Header
pcs []pc
}
type Symbol struct {
Addr uint64
Name string
}
type Symbols []*Symbol
func (s Symbols) Len() int { return len(s) }
func (s Symbols) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ByAddress struct{ Symbols }
func (s ByAddress) Less(i, j int) bool { return s.Symbols[i].Addr < s.Symbols[j].Addr }
var (
profile = flag.String("profile", "", "name of file containing profile data")
debug = flag.Bool("d", false, "Debug printing")
kernel = flag.String("kernel", "", "kernel to profile against")
symbolTable []*Symbol
)
func loadSymbols(kernel *elf.File) {
syms, err := kernel.Symbols()
if err != nil {
fmt.Println(err)
return
}
for _, sym := range syms {
value := sym.Value | 0xffffffff00000000
symbolTable = append(symbolTable, &Symbol{value, sym.Name})
}
sort.Sort(ByAddress{symbolTable})
}
func findFunction(pc pc) string {
addr := uint64(pc)
var prevSym *Symbol
for _, sym := range symbolTable {
if sym.Addr > addr && prevSym != nil {
return prevSym.Name
}
prevSym = sym
}
return "*** Not Found ***"
}
func main() {
flag.Parse()
kernelElf, err := elf.Open(*kernel)
if err != nil {
fmt.Println(err)
return
}
loadSymbols(kernelElf)
backtraces, err := ioutil.ReadFile(*profile)
if err != nil {
fmt.Println(err)
return
}
b := bytes.NewBuffer(backtraces)
var numRecords int
var records []Record
for {
var h Header
if err := binary.Read(b, binary.LittleEndian, &h); err != nil {
if err == io.EOF {
break
}
fmt.Fprintf(os.Stderr, "header: %v\n", err)
os.Exit(1)
}
if *debug {
fmt.Fprintf(os.Stderr, "%d: %v\n", numRecords, h)
}
if h.Sig != 0xee {
fmt.Fprintf(os.Stderr, "Record %d: sig is 0x%x, not 0xee", numRecords, h.Sig)
os.Exit(1)
}
pcs := make([]pc, h.Sz)
if err := binary.Read(b, binary.LittleEndian, pcs); err != nil {
fmt.Fprintf(os.Stderr, "data: %v\n", err)
os.Exit(1)
}
numRecords++
records = append(records, Record{Header: h, pcs: pcs})
}
for _, r := range records {
fmt.Printf("0x%x: ", r.Time)
for _, pc := range r.pcs {
fmt.Printf("[0x%x, %s] ", pc, findFunction(pc))
}
fmt.Printf("\n")
}
}