aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2022-09-30 15:17:58 +0200
committerRon Evans <[email protected]>2023-03-13 22:57:02 +0100
commit0e94553b26a3d49b472cd7b09c74c6f217185bb2 (patch)
tree9f780e134d00a50f8f3401337c0ab63b141f5c1b
parente6580bfff4f5b919aa139b61db07bc874d10f1fa (diff)
downloadtinygo-0e94553b26a3d49b472cd7b09c74c6f217185bb2.tar.gz
tinygo-0e94553b26a3d49b472cd7b09c74c6f217185bb2.zip
builder: add test to check for changes in binary size
This test only applies when using the built-in LLVM version. This way, we have a stable LLVM version to test against. Distribution versions of LLVM (especially Debian) tend to be patched in a way that affect the results.
-rw-r--r--.github/workflows/build-macos.yml2
-rw-r--r--.github/workflows/windows.yml2
-rw-r--r--builder/sizes_test.go92
3 files changed, 96 insertions, 0 deletions
diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml
index 46b77a89a..3151ac563 100644
--- a/.github/workflows/build-macos.yml
+++ b/.github/workflows/build-macos.yml
@@ -87,6 +87,8 @@ jobs:
- name: Build wasi-libc
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc
+ - name: make gen-device
+ run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index b2a3be139..fd46e8d87 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -97,6 +97,8 @@ jobs:
- name: Install wasmtime
run: |
scoop install wasmtime
+ - name: make gen-device
+ run: make -j3 gen-device
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-short"
diff --git a/builder/sizes_test.go b/builder/sizes_test.go
new file mode 100644
index 000000000..98f01184b
--- /dev/null
+++ b/builder/sizes_test.go
@@ -0,0 +1,92 @@
+package builder
+
+import (
+ "runtime"
+ "testing"
+ "time"
+
+ "github.com/tinygo-org/tinygo/compileopts"
+)
+
+var sema = make(chan struct{}, runtime.NumCPU())
+
+type sizeTest struct {
+ target string
+ path string
+ codeSize uint64
+ rodataSize uint64
+ dataSize uint64
+ bssSize uint64
+}
+
+// Test whether code and data size is as expected for the given targets.
+// This tests both the logic of loadProgramSize and checks that code size
+// doesn't change unintentionally.
+//
+// If you find that code or data size is reduced, then great! You can reduce the
+// number in this test.
+// If you find that the code or data size is increased, take a look as to why
+// this is. It could be due to an update (LLVM version, Go version, etc) which
+// is fine, but it could also mean that a recent change introduced this size
+// increase. If so, please consider whether this new feature is indeed worth the
+// size increase for all users.
+func TestBinarySize(t *testing.T) {
+ if runtime.GOOS == "linux" && !hasBuiltinTools {
+ // Debian LLVM packages are modified a bit and tend to produce
+ // different machine code. Ideally we'd fix this (with some attributes
+ // or something?), but for now skip it.
+ t.Skip("Skip: using external LLVM version so binary size might differ")
+ }
+
+ // This is a small number of very diverse targets that we want to test.
+ tests := []sizeTest{
+ // microcontrollers
+ {"hifive1b", "examples/echo", 4556, 272, 0, 2252},
+ {"microbit", "examples/serial", 2680, 380, 8, 2256},
+ {"wioterminal", "examples/pininterrupt", 6109, 1455, 116, 6816},
+
+ // TODO: also check wasm. Right now this is difficult, because
+ // wasm binaries are run through wasm-opt and therefore the
+ // output varies by binaryen version.
+ }
+ for _, tc := range tests {
+ tc := tc
+ t.Run(tc.target+"/"+tc.path, func(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)
+ }
+
+ // Check whether the size of the binary matches the expected size.
+ sizes, err := loadProgramSize(result.Executable, nil)
+ if err != nil {
+ t.Fatal("could not read program size:", err)
+ }
+ if sizes.Code != tc.codeSize || sizes.ROData != tc.rodataSize || sizes.Data != tc.dataSize || sizes.BSS != tc.bssSize {
+ t.Errorf("Unexpected code size when compiling: -target=%s %s", tc.target, tc.path)
+ t.Errorf(" code rodata data bss")
+ t.Errorf("expected: %6d %6d %6d %6d", tc.codeSize, tc.rodataSize, tc.dataSize, tc.bssSize)
+ t.Errorf("actual: %6d %6d %6d %6d", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS)
+ }
+ })
+ }
+}