2014-11-27 08:06:42 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"debug/elf"
|
2015-05-13 06:14:26 +08:00
|
|
|
"debug/macho"
|
2014-11-27 08:06:42 +08:00
|
|
|
"fmt"
|
|
|
|
"os"
|
2015-05-13 06:14:26 +08:00
|
|
|
"sort"
|
2014-11-27 08:06:42 +08:00
|
|
|
"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)) && f.Sections[sym.Section].Name == ".text" {
|
|
|
|
m[sym.Name] = float64(sym.Size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
2015-05-13 06:14:26 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2014-11-27 08:06:42 +08:00
|
|
|
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 main() {
|
|
|
|
var cmp func(string) map[string]float64
|
|
|
|
switch os.Args[1] {
|
|
|
|
case "symsizes":
|
|
|
|
cmp = symsizes
|
|
|
|
|
2015-05-13 06:14:26 +08:00
|
|
|
case "macho_symsizes":
|
|
|
|
cmp = macho_symsizes
|
|
|
|
|
2014-11-27 08:06:42 +08:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|