github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/builder/sizes_test.go (about) 1 package builder 2 3 import ( 4 "runtime" 5 "testing" 6 "time" 7 8 "github.com/tinygo-org/tinygo/compileopts" 9 ) 10 11 var sema = make(chan struct{}, runtime.NumCPU()) 12 13 type sizeTest struct { 14 target string 15 path string 16 codeSize uint64 17 rodataSize uint64 18 dataSize uint64 19 bssSize uint64 20 } 21 22 // Test whether code and data size is as expected for the given targets. 23 // This tests both the logic of loadProgramSize and checks that code size 24 // doesn't change unintentionally. 25 // 26 // If you find that code or data size is reduced, then great! You can reduce the 27 // number in this test. 28 // If you find that the code or data size is increased, take a look as to why 29 // this is. It could be due to an update (LLVM version, Go version, etc) which 30 // is fine, but it could also mean that a recent change introduced this size 31 // increase. If so, please consider whether this new feature is indeed worth the 32 // size increase for all users. 33 func TestBinarySize(t *testing.T) { 34 if runtime.GOOS == "linux" && !hasBuiltinTools { 35 // Debian LLVM packages are modified a bit and tend to produce 36 // different machine code. Ideally we'd fix this (with some attributes 37 // or something?), but for now skip it. 38 t.Skip("Skip: using external LLVM version so binary size might differ") 39 } 40 41 // This is a small number of very diverse targets that we want to test. 42 tests := []sizeTest{ 43 // microcontrollers 44 {"hifive1b", "examples/echo", 4476, 280, 0, 2252}, 45 {"microbit", "examples/serial", 2724, 388, 8, 2256}, 46 {"wioterminal", "examples/pininterrupt", 5996, 1484, 116, 6816}, 47 48 // TODO: also check wasm. Right now this is difficult, because 49 // wasm binaries are run through wasm-opt and therefore the 50 // output varies by binaryen version. 51 } 52 for _, tc := range tests { 53 tc := tc 54 t.Run(tc.target+"/"+tc.path, func(t *testing.T) { 55 t.Parallel() 56 57 // Build the binary. 58 options := compileopts.Options{ 59 Target: tc.target, 60 Opt: "z", 61 Semaphore: sema, 62 InterpTimeout: 60 * time.Second, 63 Debug: true, 64 VerifyIR: true, 65 } 66 target, err := compileopts.LoadTarget(&options) 67 if err != nil { 68 t.Fatal("could not load target:", err) 69 } 70 config := &compileopts.Config{ 71 Options: &options, 72 Target: target, 73 } 74 result, err := Build(tc.path, "", t.TempDir(), config) 75 if err != nil { 76 t.Fatal("could not build:", err) 77 } 78 79 // Check whether the size of the binary matches the expected size. 80 sizes, err := loadProgramSize(result.Executable, nil) 81 if err != nil { 82 t.Fatal("could not read program size:", err) 83 } 84 if sizes.Code != tc.codeSize || sizes.ROData != tc.rodataSize || sizes.Data != tc.dataSize || sizes.BSS != tc.bssSize { 85 t.Errorf("Unexpected code size when compiling: -target=%s %s", tc.target, tc.path) 86 t.Errorf(" code rodata data bss") 87 t.Errorf("expected: %6d %6d %6d %6d", tc.codeSize, tc.rodataSize, tc.dataSize, tc.bssSize) 88 t.Errorf("actual: %6d %6d %6d %6d", sizes.Code, sizes.ROData, sizes.Data, sizes.BSS) 89 } 90 }) 91 } 92 }