benchcomp: Add macho_symsizes mode for comparing Mach-O object symbol sizes.

llvm-svn: 237199
GitOrigin-RevId: dd90dc8aa95dbcd59a6dbfa1d192047c9d996008
diff --git a/utils/benchcomp/main.go b/utils/benchcomp/main.go
index c7e91c2..433add5 100644
--- a/utils/benchcomp/main.go
+++ b/utils/benchcomp/main.go
@@ -3,8 +3,10 @@
 import (
 	"bufio"
 	"debug/elf"
+	"debug/macho"
 	"fmt"
 	"os"
+	"sort"
 	"strconv"
 	"strings"
 )
@@ -27,6 +29,50 @@
 	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)
 
@@ -70,6 +116,9 @@
 	case "symsizes":
 		cmp = symsizes
 
+	case "macho_symsizes":
+		cmp = macho_symsizes
+
 	case "benchns":
 		cmp = func(path string) map[string]float64 {
 			return benchnums(path, "ns/op")