cmd/compilebench: add object file size to package benchmarks

Protected by flag -obj.

Sample relevant output from compilecmp using this commit.

name       old obj-bytes     new obj-bytes     delta
Template          382k ± 0%         381k ± 0%   -0.23%  (p=0.002 n=6+6)
Unicode           203k ± 0%         203k ± 0%   -0.00%  (p=0.002 n=6+6)
GoTypes          1.18M ± 0%        1.17M ± 0%   -0.08%  (p=0.002 n=6+6)
Compiler         3.99M ± 0%        3.99M ± 0%   -0.08%  (p=0.002 n=6+6)
SSA              8.28M ± 0%        8.28M ± 0%   -0.02%  (p=0.002 n=6+6)
Flate             230k ± 0%         230k ± 0%   -0.05%  (p=0.002 n=6+6)
GoParser          287k ± 0%         287k ± 0%   -0.16%  (p=0.002 n=6+6)
Reflect          1.00M ± 0%        1.00M ± 0%   -0.01%  (p=0.002 n=6+6)
Tar               190k ± 0%         189k ± 0%   -0.24%  (p=0.002 n=6+6)
XML               416k ± 0%         415k ± 0%   -0.16%  (p=0.002 n=6+6)

name       old export-bytes  new export-bytes  delta
Template         19.0k ± 0%        18.2k ± 0%   -4.55%  (p=0.002 n=6+6)
Unicode          4.45k ± 0%        4.44k ± 0%   -0.11%  (p=0.002 n=6+6)
GoTypes          29.7k ± 0%        28.8k ± 0%   -3.12%  (p=0.002 n=6+6)
Compiler         75.6k ± 0%        72.5k ± 0%   -4.03%  (p=0.002 n=6+6)
SSA              76.2k ± 0%        74.8k ± 0%   -1.72%  (p=0.002 n=6+6)
Flate            4.98k ± 0%        4.87k ± 0%   -2.29%  (p=0.002 n=6+6)
GoParser         8.81k ± 0%        8.34k ± 0%   -5.30%  (p=0.002 n=6+6)
Reflect          6.25k ± 0%        6.16k ± 0%   -1.49%  (p=0.002 n=6+6)
Tar              9.49k ± 0%        9.03k ± 0%   -4.82%  (p=0.002 n=6+6)
XML              16.0k ± 0%        15.4k ± 0%   -4.03%  (p=0.002 n=6+6)


Change-Id: I3f5e6ec022cb02ad6937f7859c573ca1edc39fb7
Reviewed-on: https://go-review.googlesource.com/41053
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/cmd/compilebench/main.go b/cmd/compilebench/main.go
index 8bb5387..6869db5 100644
--- a/cmd/compilebench/main.go
+++ b/cmd/compilebench/main.go
@@ -34,6 +34,9 @@
 //	-memprofilerate rate
 //		Set runtime.MemProfileRate during compilation.
 //
+//	-obj
+//		Report object file statistics.
+//
 //	-run regexp
 //		Only run benchmarks with names matching regexp.
 //
@@ -60,6 +63,7 @@
 package main
 
 import (
+	"bytes"
 	"flag"
 	"fmt"
 	"go/build"
@@ -84,6 +88,7 @@
 
 var (
 	flagAlloc          = flag.Bool("alloc", false, "report allocations")
+	flagObj            = flag.Bool("obj", false, "report object file stats")
 	flagCompiler       = flag.String("compile", "", "use `exe` as the cmd/compile binary")
 	flagCompilerFlags  = flag.String("compileflags", "", "additional `flags` to pass to compile")
 	flagRun            = flag.String("run", "", "run benchmarks matching `regexp`")
@@ -268,7 +273,7 @@
 	}
 	end := time.Now()
 
-	var allocs, bytes int64
+	var allocs, allocbytes int64
 	if *flagAlloc || *flagMemprofile != "" {
 		out, err := ioutil.ReadFile(pkg.Dir + "/_compilebench_.memprof")
 		if err != nil {
@@ -285,7 +290,7 @@
 			}
 			switch f[1] {
 			case "TotalAlloc":
-				bytes = val
+				allocbytes = val
 			case "Mallocs":
 				allocs = val
 			}
@@ -317,11 +322,25 @@
 	wallns := end.Sub(start).Nanoseconds()
 	userns := cmd.ProcessState.UserTime().Nanoseconds()
 
+	fmt.Printf("%s 1 %d ns/op %d user-ns/op", name, wallns, userns)
 	if *flagAlloc {
-		fmt.Printf("%s 1 %d ns/op %d user-ns/op %d B/op %d allocs/op\n", name, wallns, userns, bytes, allocs)
-	} else {
-		fmt.Printf("%s 1 %d ns/op %d user-ns/op\n", name, wallns, userns)
+		fmt.Printf(" %d B/op %d allocs/op", allocbytes, allocs)
 	}
 
-	os.Remove(pkg.Dir + "/_compilebench_.o")
+	opath := pkg.Dir + "/_compilebench_.o"
+	if *flagObj {
+		// TODO(josharian): object files are big; just read enough to find what we seek.
+		data, err := ioutil.ReadFile(opath)
+		if err != nil {
+			log.Print(err)
+		}
+		// Find start of export data.
+		i := bytes.Index(data, []byte("\n$$B\n")) + len("\n$$B\n")
+		// Count bytes to end of export data.
+		nexport := bytes.Index(data[i:], []byte("\n$$\n"))
+		fmt.Printf(" %d object-bytes %d export-bytes", len(data), nexport)
+	}
+	fmt.Println()
+
+	os.Remove(opath)
 }