mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 10:37:46 +00:00
78914382c3
Account for the sleep queue base time in the computation of the wakeup
time.
Tested with the following program on pico2.
func main() {
go func() {
for i := range 60 {
const delay = 20 * time.Millisecond
before := time.Now()
time.Sleep(delay)
if d := time.Since(before); true || d < delay {
log.Println(i, "actual", d, "delay", delay)
}
}
}()
time.Sleep(500 * time.Millisecond)
log.Println("******** done sleeping ********")
select {}
}
Without this change, the program would print lines such as:
17 actual 15.494ms delay 20ms
18 actual 15.49ms delay 20ms
19 actual 15.585ms delay 20ms
20 actual 15.493ms delay 20ms
21 actual 15.494ms delay 20ms
22 actual 15.487ms delay 20ms
23 actual 15.498ms delay 20ms
******** done sleeping ********
24 actual 15.548ms delay 20ms
25 actual 20.011ms delay 20ms
26 actual 20.01ms delay 20ms
27 actual 20.011ms delay 20ms
28 actual 20.015ms delay 20ms
Note that while more than one sleeping goroutine is in the timer queue,
the sleep duration is 5ms short.
141 lines
4.2 KiB
Go
141 lines
4.2 KiB
Go
package builder
|
|
|
|
import (
|
|
"regexp"
|
|
"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", 4580, 280, 0, 2264},
|
|
{"microbit", "examples/serial", 2928, 388, 8, 2272},
|
|
{"wioterminal", "examples/pininterrupt", 7387, 1489, 116, 6912},
|
|
|
|
// 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.
|
|
result := buildBinary(t, tc.target, tc.path)
|
|
|
|
// 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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|