blob: a050f7bdd5fb0d2e9e0bf170049bcce42bd043e7 [file] [log] [blame]
package main
import (
"bufio"
"debug/elf"
"debug/macho"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func symsizes(path string) map[string]float64 {
m := make(map[string]float64)
f, err := elf.Open(path)
if err != nil {
panic(err.Error())
}
syms, err := f.Symbols()
if err != nil {
panic(err.Error())
}
for _, sym := range syms {
if sym.Section < elf.SectionIndex(len(f.Sections)) && strings.HasPrefix(f.Sections[sym.Section].Name, ".text") {
m[sym.Name] = float64(sym.Size)
}
}
return m
}
type bySectionThenOffset []macho.Symbol
func (syms bySectionThenOffset) Len() int {
return len(syms)
}
func (syms bySectionThenOffset) Less(i, j int) bool {
if syms[i].Sect < syms[j].Sect {
return true
}
if syms[i].Sect > syms[j].Sect {
return false
}
return syms[i].Value < syms[j].Value
}
func (syms bySectionThenOffset) Swap(i, j int) {
syms[i], syms[j] = syms[j], syms[i]
}
func macho_symsizes(path string) map[string]float64 {
m := make(map[string]float64)
f, err := macho.Open(path)
if err != nil {
panic(err.Error())
}
syms := make([]macho.Symbol, len(f.Symtab.Syms))
copy(syms, f.Symtab.Syms)
sort.Sort(bySectionThenOffset(syms))
for i, sym := range syms {
if sym.Sect == 0 {
continue
}
var nextOffset uint64
if i == len(syms)-1 || syms[i+1].Sect != sym.Sect {
nextOffset = f.Sections[sym.Sect-1].Size
} else {
nextOffset = syms[i+1].Value
}
m[sym.Name] = float64(nextOffset - sym.Value)
}
return m
}
func benchnums(path, stat string) map[string]float64 {
m := make(map[string]float64)
fh, err := os.Open(path)
if err != nil {
panic(err.Error())
}
scanner := bufio.NewScanner(fh)
for scanner.Scan() {
elems := strings.Split(scanner.Text(), "\t")
if !strings.HasPrefix(elems[0], "Benchmark") || len(elems) < 3 {
continue
}
var s string
for _, elem := range elems[2:] {
selems := strings.Split(strings.TrimSpace(elem), " ")
if selems[1] == stat {
s = selems[0]
}
}
if s != "" {
ns, err := strconv.ParseFloat(s, 64)
if err != nil {
panic(scanner.Text() + " ---- " + err.Error())
}
m[elems[0]] = ns
}
}
if err := scanner.Err(); err != nil {
panic(err)
}
return m
}
func ninja_logs(path string) map[string]float64 {
m := make(map[string]float64)
fh, err := os.Open(path)
if err != nil {
panic(err.Error())
}
scanner := bufio.NewScanner(fh)
for scanner.Scan() {
elems := strings.Split(scanner.Text(), "\t")
if len(elems) < 4 {
continue
}
begin, err := strconv.ParseInt(elems[0], 10, 64)
if err != nil {
continue
}
end, err := strconv.ParseInt(elems[1], 10, 64)
if err != nil {
panic(err.Error())
}
m[elems[3]] = float64(end-begin)
}
return m
}
func main() {
var cmp func(string) map[string]float64
switch os.Args[1] {
case "symsizes":
cmp = symsizes
case "macho_symsizes":
cmp = macho_symsizes
case "benchns":
cmp = func(path string) map[string]float64 {
return benchnums(path, "ns/op")
}
case "benchallocs":
cmp = func(path string) map[string]float64 {
return benchnums(path, "allocs/op")
}
case "ninja_logs":
cmp = ninja_logs
}
syms1 := cmp(os.Args[2])
syms2 := cmp(os.Args[3])
for n, z1 := range syms1 {
if z2, ok := syms2[n]; ok && z2 != 0 {
fmt.Printf("%s %f %f %f\n", n, z1, z2, z1/z2)
}
}
}