Skip to content

Commit

Permalink
builder: add testing for -size=full
Browse files Browse the repository at this point in the history
This helps to make sure this feature continues to work and we won't
accidentally introduce regressions.
  • Loading branch information
aykevl authored and deadprogram committed Nov 26, 2024
1 parent ca80c52 commit ee6fcd7
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 25 deletions.
16 changes: 11 additions & 5 deletions builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ type BuildResult struct {
// correctly printing test results: the import path isn't always the same as
// the path listed on the command line.
ImportPath string

// Map from path to package name. It is needed to attribute binary size to
// the right Go package.
PackagePathMap map[string]string
}

// packageAction is the struct that is serialized to JSON and hashed, to work as
Expand Down Expand Up @@ -242,6 +246,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
return result, err
}

// Store which filesystem paths map to which package name.
result.PackagePathMap = make(map[string]string, len(lprogram.Packages))
for _, pkg := range lprogram.Sorted() {
result.PackagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
}

// Create the *ssa.Program. This does not yet build the entire SSA of the
// program so it's pretty fast and doesn't need to be parallelized.
program := lprogram.LoadSSA()
Expand Down Expand Up @@ -916,11 +926,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe

// Print code size if requested.
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
packagePathMap := make(map[string]string, len(lprogram.Packages))
for _, pkg := range lprogram.Sorted() {
packagePathMap[pkg.OriginalDir()] = pkg.Pkg.Path()
}
sizes, err := loadProgramSize(result.Executable, packagePathMap)
sizes, err := loadProgramSize(result.Executable, result.PackagePathMap)
if err != nil {
return err
}
Expand Down
88 changes: 68 additions & 20 deletions builder/sizes_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package builder

import (
"regexp"
"runtime"
"testing"
"time"
Expand Down Expand Up @@ -55,26 +56,7 @@ func TestBinarySize(t *testing.T) {
t.Parallel()

// Build the binary.
options := compileopts.Options{
Target: tc.target,
Opt: "z",
Semaphore: sema,
InterpTimeout: 60 * time.Second,
Debug: true,
VerifyIR: true,
}
target, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("could not load target:", err)
}
config := &compileopts.Config{
Options: &options,
Target: target,
}
result, err := Build(tc.path, "", t.TempDir(), config)
if err != nil {
t.Fatal("could not build:", err)
}
result := buildBinary(t, tc.target, tc.path)

// Check whether the size of the binary matches the expected size.
sizes, err := loadProgramSize(result.Executable, nil)
Expand All @@ -90,3 +72,69 @@ func TestBinarySize(t *testing.T) {
})
}
}

// Check that the -size=full flag attributes binary size to the correct package
// without filesystem paths and things like that.
func TestSizeFull(t *testing.T) {
tests := []string{
"microbit",
"wasip1",
}

libMatch := regexp.MustCompile(`^C [a-z -]+$`) // example: "C interrupt vector"
pkgMatch := regexp.MustCompile(`^[a-z/]+$`) // example: "internal/task"

for _, target := range tests {
target := target
t.Run(target, func(t *testing.T) {
t.Parallel()

// Build the binary.
result := buildBinary(t, target, "examples/serial")

// Check whether the binary doesn't contain any unexpected package
// names.
sizes, err := loadProgramSize(result.Executable, result.PackagePathMap)
if err != nil {
t.Fatal("could not read program size:", err)
}
for _, pkg := range sizes.sortedPackageNames() {
if pkg == "(padding)" || pkg == "(unknown)" {
// TODO: correctly attribute all unknown binary size.
continue
}
if libMatch.MatchString(pkg) {
continue
}
if pkgMatch.MatchString(pkg) {
continue
}
t.Error("unexpected package name in size output:", pkg)
}
})
}
}

func buildBinary(t *testing.T, targetString, pkgName string) BuildResult {
options := compileopts.Options{
Target: targetString,
Opt: "z",
Semaphore: sema,
InterpTimeout: 60 * time.Second,
Debug: true,
VerifyIR: true,
}
target, err := compileopts.LoadTarget(&options)
if err != nil {
t.Fatal("could not load target:", err)
}
config := &compileopts.Config{
Options: &options,
Target: target,
}
result, err := Build(pkgName, "", t.TempDir(), config)
if err != nil {
t.Fatal("could not build:", err)
}
return result
}

0 comments on commit ee6fcd7

Please sign in to comment.