Skip to content

Boehm GC support #4385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 18, 2025
Merged

Boehm GC support #4385

merged 2 commits into from
Mar 18, 2025

Conversation

aykevl
Copy link
Member

@aykevl aykevl commented Aug 5, 2024

This adds support for the well-known Boehm GC. It's significantly faster than our own naive GC and could be used as an alternative on bigger systems.

In the future, this GC might also be supported on WebAssembly with some extra work. Right now it's Linux only (though Windows/MacOS shouldn't be too difficult to add).


Still a draft because it depends on #4101 and I might improve the PR a little bit more.

Copy link

github-actions bot commented Aug 5, 2024

Size difference with the dev branch:

Binary size difference
not the same command!
    tinygo build -size short -o ./build/test.hex -target=pico ./examples/tmc5160/main.go
    go: downloading golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
not the same command!
    tinygo build -size short -o ./build/test.hex -target=nano-rp2040 -stack-size 8kb ./examples/net/websocket/dial/
    go: downloading golang.org/x/net v0.33.0
not the same command!
    tinygo build -size short -o ./build/test.hex -target=nano-rp2040 -stack-size 8kb ./examples/net/mqttclient/natiu/
    go: downloading github.com/soypat/natiu-mqtt v0.5.1
not the same command!
    tinygo build -size short -o ./build/test.hex -target=wioterminal -stack-size 8kb ./examples/net/mqttclient/paho/
    go: downloading github.com/eclipse/paho.mqtt.golang v1.2.0
 flash                          ram
 before   after   diff          before   after   diff
  16760   16760      0   0.00%    4180    4180      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/adafruit4650
  61472   61472      0   0.00%    6188    6188      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adt7410/main.go
   9604    9604      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/adxl345/main.go
  13716   13716      0   0.00%    6796    6796      0   0.00% tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/amg88xx
   9104    9104      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
  11848   11848      0   0.00%    6580    6580      0   0.00% tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/apds9960/proximity/main.go
   9920    9920      0   0.00%    4760    4760      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
   8376    8376      0   0.00%    2320    2320      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
   8164    8164      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bh1750/main.go
   7468    7468      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/blinkm/main.go
  70692   70692      0   0.00%    3656    3656      0   0.00% tinygo build -size short -o ./build/test.hex -target=pinetime     ./examples/bma42x/main.go
  64340   64340      0   0.00%    6204    6204      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmi160/main.go
  27804   27804      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp180/main.go
  64048   64048      0   0.00%    6228    6228      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/bmp280/main.go
  12248   12248      0   0.00%    4812    4812      0   0.00% tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bmp388/main.go
   8364    8364      0   0.00%    3352    3352      0   0.00% tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/sram/main.go
  22300   22300      0   0.00%    3556    3556      0   0.00% tinygo build -size short -o ./build/test.hex -target=bluepill ./examples/ds1307/time/main.go
  69720   69720      0   0.00%    6376    6376      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/ds3231/main.go
   4628    4628      0   0.00%    2280    2280      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/easystepper/main.go
  69980   69980      0   0.00%    6980    6980      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/flash/console/spi
  66724   66724      0   0.00%    9020    9020      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/flash/console/qspi
   7308    7308      0   0.00%    2284    2284      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/gc9a01/main.go
  67668   67668      0   0.00%    6360    6360      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/gps/i2c/main.go
  68220   68220      0   0.00%    6504    6504      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/gps/uart/main.go
   8012    8012      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/hcsr04/main.go
   5840    5840      0   0.00%    2280    2280      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hd44780/customchar/main.go
   5792    5792      0   0.00%    2280    2280      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hd44780/text/main.go
  10568   10568      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/hd44780i2c/main.go
  14748   14748      0   0.00%    6580    6580      0   0.00% tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/hts221/main.go
  16216   16216      0   0.00%    2364    2364      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/hub75/main.go
  10276   10276      0   0.00%    6924    6924      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/basic
  11180   11180      0   0.00%    4884    4884      0   0.00% tinygo build -size short -o ./build/test.hex -target=xiao ./examples/ili9341/basic
  29644   29644      0   0.00%   38084   38084      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/pyportal_boing
  10300   10300      0   0.00%    6916    6916      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/scroll
  11264   11264      0   0.00%    4876    4876      0   0.00% tinygo build -size short -o ./build/test.hex -target=xiao ./examples/ili9341/scroll
 263492  263492      0   0.00%   46752   46752      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/ili9341/slideshow
  11772   11772      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis3dh/main.go
  14112   14112      0   0.00%    6580    6580      0   0.00% tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/lps22hb/main.go
  26500   26500      0   0.00%    2328    2328      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/lsm303agr/main.go
  12484   12484      0   0.00%    4788    4788      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/lsm6ds3/main.go
  10760   10760      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mag3110/main.go
   9940    9940      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017/main.go
  10380   10380      0   0.00%    4788    4788      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp23017-multiple/main.go
  10276   10276      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp3008/main.go
  68952   68952      0   0.00%    6204    6204      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mcp2515/main.go
  27152   27152      0   0.00%    3640    3640      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/microbitmatrix/main.go
  27016   27016      0   0.00%    5620    5620      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit-v2 ./examples/microbitmatrix/main.go
   8276    8276      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mma8653/main.go
   8184    8184      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/mpu6050/main.go
  75644   75644      0   0.00%    7452    7452      0   0.00% tinygo build -size short -o ./build/test.hex -target=p1am-100 ./examples/p1am/main.go
  12352   12352      0   0.00%    3360    3360      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/pca9685/main.go
   6268    6268      0   0.00%    3292    3292      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setbuffer/main.go
   5296    5296      0   0.00%    2284    2284      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/pcd8544/setpixel/main.go
  10640   10640      0   0.00%    3336    3336      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/seesaw
   2841    2841      0   0.00%     558     558      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino ./examples/servo
  13888   13888      0   0.00%    3408    3408      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico     ./examples/sgp30
   8212    8212      0   0.00%    6788    6788      0   0.00% tinygo build -size short -o ./build/test.hex -target=pybadge ./examples/shifter/main.go
  57480   57480      0   0.00%    3688    3688      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht3x/main.go
  57448   57448      0   0.00%    3696    3696      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/sht4x/main.go
  57444   57444      0   0.00%    3688    3688      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/shtc3/main.go
   6704    6704      0   0.00%    2288    2288      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/i2c_128x32/main.go
   6216    6216      0   0.00%    2284    2284      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1306/spi_128x64/main.go
   5912    5912      0   0.00%    2284    2284      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ssd1331/main.go
   6848    6848      0   0.00%    2284    2284      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7735/main.go
   6776    6776      0   0.00%    2284    2284      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/st7789/main.go
  17544   17544      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/thermistor/main.go
  10712   10712      0   0.00%    4540    4540      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-bluefruit ./examples/tone
  10208   10208      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/tm1637/main.go
  10916   10916      0   0.00%    3348    3348      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/touch/capacitive
   9648    9648      0   0.00%    6788    6788      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/fourwire/main.go
  12548   12548      0   0.00%    6984    6984      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal ./examples/touch/resistive/pyportal_touchpaint/main.go
  15372   15372      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/vl53l1x/main.go
  13852   13852      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/vl6180x/main.go
  24796   24796      0   0.00%   13728   13728      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-nrf52840-sense ./examples/waveshare-epd/epd1in54/main.go
   6520    6520      0   0.00%    2324    2324      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13/main.go
   6188    6188      0   0.00%    2316    2316      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd2in13x/main.go
   6440    6440      0   0.00%    2324    2324      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/waveshare-epd/epd4in2/main.go
  26216   26216      0   0.00%   16420   16420      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/waveshare-epd/epd2in66b/main.go
   6988    6988      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/ws2812
   5768    5768      0   0.00%    9522    9522      0   0.00% '-xesppie' is not a recognized feature for this target (ignoring feature)
  62744   62744      0   0.00%    5948    5948      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-nrf52840 ./examples/is31fl3731/main.go
   1581    1581      0   0.00%     598     598      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino   ./examples/ws2812
   1056    1056      0   0.00%     180     180      0   0.00% tinygo build -size short -o ./build/test.hex -target=digispark ./examples/ws2812
  32256   32256      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/bme280/main.go
  17104   17104      0   0.00%    4732    4732      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/microphone/main.go
  11640   11640      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/buzzer/main.go
  12820   12820      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=trinket-m0 ./examples/veml6070/main.go
   6904    6904      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l293x/simple/main.go
   8804    8804      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l293x/speed/main.go
   6872    6872      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/simple/main.go
   9316    9316      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/l9110x/speed/main.go
   7404    7404      0   0.00%    3324    3324      0   0.00% tinygo build -size short -o ./build/test.hex -target=nucleo-f103rb ./examples/shiftregister/main.go
   6996    6996      0   0.00%    2272    2272      0   0.00% '-xesppie' is not a recognized feature for this target (ignoring feature)
  13372   13372      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=circuitplay-express ./examples/lis2mdl/main.go
   9920    9920      0   0.00%    4764    4764      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/max72xx/main.go
  77244   77244      0   0.00%    6344    6344      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/dht/main.go
  36600   36600      0   0.00%    3988    3988      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/pcf8523/
  71408   71408      0   0.00%    6352    6352      0   0.00% tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/alarm/
   7316    7316      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/clkout/
  70936   70936      0   0.00%    6348    6348      0   0.00% tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/time/
  71312   71312      0   0.00%    6352    6352      0   0.00% tinygo build -size short -o ./build/test.hex -target=xiao ./examples/pcf8563/timer/
  12296   12296      0   0.00%    3312    3312      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/qmi8658c/main.go
  10916   10916      0   0.00%    3296    3296      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-rp2040 ./examples/pcf8591/
   8788    8788      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina260/main.go
  13228   13228      0   0.00%    4780    4780      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m0 ./examples/ina219/main.go
   9392    9392      0   0.00%    5248    5248      0   0.00% tinygo build -size short -o ./build/test.hex -target=nucleo-l432kc ./examples/aht20/main.go
  73932   73932      0   0.00%   10764   10764      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/sdcard/console/
  61748   61748      0   0.00%    8236    8236      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/
  10416   10416      0   0.00%    6788    6788      0   0.00% tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/
   9124    9124      0   0.00%    3284    3284      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/xpt2046/main.go
  13260   13260      0   0.00%    4936    4936      0   0.00% tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/sx126x/lora_rxtx/
  31372   31372      0   0.00%    4552    4552      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/ssd1289/main.go
  11304   11304      0   0.00%    4260    4260      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/irremote/main.go
  12188   12188      0   0.00%    3332    3332      0   0.00% tinygo build -size short -o ./build/test.hex -target=badger2040 ./examples/uc8151/main.go
  10540   10540      0   0.00%    3364    3364      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/scd4x/main.go
   8700    8700      0   0.00%    4748    4748      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=circuitplay-express ./examples/makeybutton/main.go
   9708    9708      0   0.00%    4764    4764      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ds18b20/main.go
  82636   82636      0   0.00%    6592    6592      0   0.00% tinygo build -size short -o ./build/test.hex -target=nucleo-wl55jc ./examples/lora/lorawan/atcmd/
  15928   15928      0   0.00%    4876    4876      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/as560x/main.go
   9984    9984      0   0.00%    3304    3304      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu6886/main.go
   7948    7948      0   0.00%    4740    4740      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ttp229/main.go
  66872   66872      0   0.00%    4816    4816      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/ndir/main_ndir.go
  62240   62240      0   0.00%    3784    3784      0   0.00% tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ndir/main_ndir.go
  65308   65308      0   0.00%    6260    6260      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ndir/main_ndir.go
   9416    9416      0   0.00%    3296    3296      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/main.go
  11676   11676      0   0.00%    3332    3332      0   0.00% tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/sh1106/macropad_spi
   8532    8532      0   0.00%    3760    3760      0   0.00% tinygo build -size short -o ./build/test.hex -target=macropad-rp2040 ./examples/encoders/quadrature-interrupt
  66272   66272      0   0.00%    4784    4784      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mcp9808/main.go
  29900   29900      0   0.00%    3680    3680      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/tmc2209/main.go
  13348   13348      0   0.00%    3292    3292      0   0.00% tinygo build -size short -o ./build/test.hex -target=pico ./examples/tmc5160/main.go
  12500   12500      0   0.00%    4552    4552      0   0.00% tinygo build -size short -o ./build/test.uf2 -target=nicenano ./examples/sharpmem/main.go
  60324   60324      0   0.00%    5968    5968      0   0.00% tinygo build -size short -o ./build/test.hex -target=feather-nrf52840 ./examples/max6675/main.go
  86404   86404      0   0.00%    5148    5148      0   0.00% tinygo build -size short -o ./build/test.hex -target=challenger-rp2040 ./examples/net/ntpclient/
 298396  298396      0   0.00%   15908   15908      0   0.00% tinygo build -size short -o ./build/test.hex -target=pyportal -stack-size 8kb ./examples/net/http-get/
 119272  119272      0   0.00%    7848    7848      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-nano33 -stack-size 8kb ./examples/net/tcpclient/
 251160  251160      0   0.00%   12868   12868      0   0.00% tinygo build -size short -o ./build/test.hex -target=nano-rp2040 -stack-size 8kb ./examples/net/websocket/dial/
 102872  102872      0   0.00%    9816    9816      0   0.00% tinygo build -size short -o ./build/test.hex -target=metro-m4-airlift -stack-size 8kb ./examples/net/socket/
 339048  339048      0   0.00%   16512   16512      0   0.00% tinygo build -size short -o ./build/test.hex -target=matrixportal-m4 -stack-size 8kb ./examples/net/webstatic/
 111232  111232      0   0.00%    7784    7784      0   0.00% tinygo build -size short -o ./build/test.hex -target=arduino-mkrwifi1010 -stack-size 8kb ./examples/net/tlsclient/
 154040  154040      0   0.00%    6548    6548      0   0.00% tinygo build -size short -o ./build/test.hex -target=nano-rp2040 -stack-size 8kb ./examples/net/mqttclient/natiu/
 116280  116280      0   0.00%   13124   13124      0   0.00% tinygo build -size short -o ./build/test.hex -target=wioterminal -stack-size 8kb ./examples/net/webclient/
 287288  287288      0   0.00%   19564   19564      0   0.00% tinygo build -size short -o ./build/test.hex -target=wioterminal -stack-size 8kb ./examples/net/webserver/
 290824  290824      0   0.00%   20872   20872      0   0.00% tinygo build -size short -o ./build/test.hex -target=wioterminal -stack-size 8kb ./examples/net/mqttclient/paho/
 118156  118156      0   0.00%    9504    9504      0   0.00% tinygo build -size short -o ./build/test.hex -target=elecrow-rp2040 -stack-size 8kb ./examples/net/tlsclient/
 117972  117972      0   0.00%    9564    9564      0   0.00% tinygo build -size short -o ./build/test.hex -target=elecrow-rp2350 -stack-size 8kb ./examples/net/ntpclient/
5713642 5713642      0   0.00%  857586  857586      0   0.00%

@pulsejet
Copy link

Is it currently planned to finish this work? We're using tinygo for wasm because using asyncify is a huge win for optimization and binary size, but the gc bottleneck makes it unusable (pauses are ~400ms vs ~20ms for gc)

For example, with -gc=none and -gc=leaking, no heap needs to be
allocated when initializing the runtime. And some GCs (like -gc=custom)
are responsible for allocating the heap themselves.
@aykevl
Copy link
Member Author

aykevl commented Mar 14, 2025

Updated the PR, I think it's still valuable to have.

@deadprogram
Copy link
Member

Updated the PR, I think it's still valuable to have.

Yes, please!

In the future, this GC might also be supported on WebAssembly with some extra work.

IMO this is a very important feature to add.

@aykevl
Copy link
Member Author

aykevl commented Mar 14, 2025

Here is a comparison benchmarking the html package:

$ benchstat html-precise.txt html-boehm.txt
               │ html-precise.txt │            html-boehm.txt             │
               │      sec/op      │    sec/op     vs base                 │
Escape               23.68µ ± ∞ ¹   16.52µ ± ∞ ¹        ~ (p=1.000 n=1) ²
EscapeNone           9.007µ ± ∞ ¹   8.990µ ± ∞ ¹        ~ (p=1.000 n=1) ²
Unescape             41.26µ ± ∞ ¹   27.56µ ± ∞ ¹        ~ (p=1.000 n=1) ²
UnescapeNone         1.885µ ± ∞ ¹   1.946µ ± ∞ ¹        ~ (p=1.000 n=1) ²
UnescapeSparse      10.465µ ± ∞ ¹   6.265µ ± ∞ ¹        ~ (p=1.000 n=1) ²
UnescapeDense        35.62µ ± ∞ ¹   25.57µ ± ∞ ¹        ~ (p=1.000 n=1) ²
geomean              13.55µ         10.41µ        -23.13%
¹ need >= 6 samples for confidence interval at level 0.95
² need >= 4 samples to detect a difference at alpha level 0.05

If I read this correctly, it's 23% faster.

And for go/format, with -gc=boehm:

BenchmarkFormat/array1-10000                 402          14963832 ns/op           4.33 MB/s     7324959 B/op          0 allocs/op

-gc=precise:

BenchmarkFormat/array1-10000                 144          63817734 ns/op           1.01 MB/s     8169418 B/op     204348 allocs/op

(The 0 allocs/op are likely incorrect, but the ns/op is massively faster).

These were just the first two packages I found with benchmarks included that I thought would hit the GC hard, other packages probably have a different result.

@aykevl
Copy link
Member Author

aykevl commented Mar 14, 2025

Ran a few more benchmarks, this time with the -count parameter so benchstat can actually run some statistics on the numbers.

go/format benchmark, which seems to be 321% faster (or take 76% less time):

$ benchstat go-format-precise.txt go-format-boehm.txt
                    │ go-format-precise.txt │         go-format-boehm.txt         │
                    │        sec/op         │   sec/op     vs base                │
Format/array1-10000            63.53m ± 43%   15.06m ± 1%  -76.30% (p=0.000 n=10)

                    │ go-format-precise.txt │          go-format-boehm.txt           │
                    │          B/s          │      B/s       vs base                 │
Format/array1-10000           996.1Ki ± 31%   4199.2Ki ± 1%  +321.57% (p=0.000 n=10)

                    │ go-format-precise.txt │         go-format-boehm.txt          │
                    │         B/op          │     B/op      vs base                │
Format/array1-10000            7.790Mi ± 0%   6.980Mi ± 0%  -10.40% (p=0.000 n=10)

html benchmark, which seems to take 21% less time:

$ benchstat html-precise.txt html-boehm.txt
               │ html-precise.txt │           html-boehm.txt            │
               │      sec/op      │   sec/op     vs base                │
Escape                24.39µ ± 0%   17.78µ ± 2%  -27.08% (p=0.000 n=10)
EscapeNone            9.370µ ± 1%   9.329µ ± 2%        ~ (p=0.172 n=10)
Unescape              42.21µ ± 1%   29.53µ ± 1%  -30.03% (p=0.000 n=10)
UnescapeNone          1.922µ ± 2%   1.968µ ± 1%   +2.42% (p=0.000 n=10)
UnescapeSparse       10.489µ ± 3%   6.529µ ± 0%  -37.75% (p=0.000 n=10)
UnescapeDense         36.62µ ± 1%   26.69µ ± 2%  -27.10% (p=0.000 n=10)
geomean               13.87µ        10.90µ       -21.38%

crypto/sha1 might be a little bit slower (not sure why):

$ benchstat sha1-precise.txt sha1-boehm.txt
                 │ sha1-precise.txt │           sha1-boehm.txt           │
                 │      sec/op      │   sec/op     vs base               │
Hash8Bytes/New          178.3n ± 1%   180.2n ± 1%  +1.09% (p=0.019 n=10)
Hash8Bytes/Sum          170.0n ± 1%   171.6n ± 1%  +0.91% (p=0.005 n=10)
Hash320Bytes/New        949.8n ± 1%   947.8n ± 2%       ~ (p=0.796 n=10)
Hash320Bytes/Sum        944.3n ± 1%   947.4n ± 2%       ~ (p=0.247 n=10)
Hash1K/New              2.679µ ± 1%   2.682µ ± 1%       ~ (p=0.286 n=10)
Hash1K/Sum              2.673µ ± 1%   2.694µ ± 1%  +0.77% (p=0.015 n=10)
Hash8K/New              19.96µ ± 1%   20.29µ ± 1%  +1.65% (p=0.000 n=10)
Hash8K/Sum              20.08µ ± 1%   20.34µ ± 1%  +1.32% (p=0.007 n=10)
geomean                 1.724µ        1.737µ       +0.75%

                 │ sha1-precise.txt │           sha1-boehm.txt            │
                 │       B/s        │     B/s       vs base               │
Hash8Bytes/New         42.79Mi ± 1%   42.33Mi ± 1%  -1.06% (p=0.022 n=10)
Hash8Bytes/Sum         44.88Mi ± 1%   44.47Mi ± 1%  -0.89% (p=0.007 n=10)
Hash320Bytes/New       321.3Mi ± 1%   322.0Mi ± 2%       ~ (p=0.796 n=10)
Hash320Bytes/Sum       323.2Mi ± 1%   322.1Mi ± 2%       ~ (p=0.247 n=10)
Hash1K/New             364.6Mi ± 1%   364.1Mi ± 1%       ~ (p=0.280 n=10)
Hash1K/Sum             365.3Mi ± 1%   362.6Mi ± 1%  -0.75% (p=0.015 n=10)
Hash8K/New             391.4Mi ± 1%   385.0Mi ± 1%  -1.63% (p=0.000 n=10)
Hash8K/Sum             389.1Mi ± 1%   384.0Mi ± 1%  -1.31% (p=0.007 n=10)
geomean                211.8Mi        210.2Mi       -0.74%

encoding/hex is a lot faster in some benchmarks:

$ benchstat hex-precise.txt hex-boehm.txt 
                   │ hex-precise.txt │            hex-boehm.txt            │
                   │     sec/op      │    sec/op     vs base               │
Encode/256              202.3n ± ∞ ¹   204.0n ± ∞ ¹        ~ (p=0.257 n=4)
Encode/1024             782.2n ± ∞ ¹   794.3n ± ∞ ¹   +1.55% (p=0.029 n=4)
Encode/4096             3.171µ ± ∞ ¹   3.184µ ± ∞ ¹        ~ (p=0.686 n=4)
Encode/16384            12.51µ ± ∞ ¹   12.79µ ± ∞ ¹   +2.25% (p=0.029 n=4)
Decode/256              136.5n ± ∞ ¹   138.6n ± ∞ ¹        ~ (p=0.114 n=4)
Decode/1024             520.8n ± ∞ ¹   528.8n ± ∞ ¹        ~ (p=0.200 n=4)
Decode/4096             2.081µ ± ∞ ¹   2.102µ ± ∞ ¹        ~ (p=0.343 n=4)
Decode/16384            8.354µ ± ∞ ¹   8.443µ ± ∞ ¹   +1.07% (p=0.029 n=4)
DecodeString/256        243.2n ± ∞ ¹   187.1n ± ∞ ¹  -23.07% (p=0.029 n=4)
DecodeString/1024       918.4n ± ∞ ¹   692.4n ± ∞ ¹  -24.61% (p=0.029 n=4)
DecodeString/4096       3.826µ ± ∞ ¹   3.181µ ± ∞ ¹  -16.85% (p=0.029 n=4)
DecodeString/16384      20.77µ ± ∞ ¹   11.84µ ± ∞ ¹  -43.00% (p=0.029 n=4)
Dump/256                5.910µ ± ∞ ¹   5.799µ ± ∞ ¹   -1.89% (p=0.029 n=4)
Dump/1024               25.18µ ± ∞ ¹   21.27µ ± ∞ ¹  -15.54% (p=0.029 n=4)
Dump/4096              102.51µ ± ∞ ¹   91.09µ ± ∞ ¹  -11.14% (p=0.029 n=4)
Dump/16384              397.1µ ± ∞ ¹   334.5µ ± ∞ ¹  -15.77% (p=0.029 n=4)
geomean                 3.611µ         3.253µ         -9.90%
¹ need >= 6 samples for confidence interval at level 0.95

                   │ hex-precise.txt │             hex-boehm.txt             │
                   │       B/s       │      B/s        vs base               │
Encode/256             1.179Gi ± ∞ ¹    1.169Gi ± ∞ ¹        ~ (p=0.200 n=4)
Encode/1024            1.219Gi ± ∞ ¹    1.201Gi ± ∞ ¹   -1.53% (p=0.029 n=4)
Encode/4096            1.203Gi ± ∞ ¹    1.198Gi ± ∞ ¹        ~ (p=0.686 n=4)
Encode/16384           1.220Gi ± ∞ ¹    1.193Gi ± ∞ ¹   -2.20% (p=0.029 n=4)
Decode/256             1.746Gi ± ∞ ¹    1.720Gi ± ∞ ¹        ~ (p=0.114 n=4)
Decode/1024            1.831Gi ± ∞ ¹    1.804Gi ± ∞ ¹        ~ (p=0.200 n=4)
Decode/4096            1.833Gi ± ∞ ¹    1.815Gi ± ∞ ¹        ~ (p=0.343 n=4)
Decode/16384           1.827Gi ± ∞ ¹    1.807Gi ± ∞ ¹   -1.05% (p=0.029 n=4)
DecodeString/256      1003.9Mi ± ∞ ¹   1304.9Mi ± ∞ ¹  +29.98% (p=0.029 n=4)
DecodeString/1024      1.038Gi ± ∞ ¹    1.377Gi ± ∞ ¹  +32.64% (p=0.029 n=4)
DecodeString/4096     1021.1Mi ± ∞ ¹   1227.9Mi ± ∞ ¹  +20.26% (p=0.029 n=4)
DecodeString/16384     753.5Mi ± ∞ ¹   1319.5Mi ± ∞ ¹  +75.11% (p=0.029 n=4)
Dump/256               41.31Mi ± ∞ ¹    42.10Mi ± ∞ ¹   +1.93% (p=0.029 n=4)
Dump/1024              38.79Mi ± ∞ ¹    45.92Mi ± ∞ ¹  +18.40% (p=0.029 n=4)
Dump/4096              38.11Mi ± ∞ ¹    42.88Mi ± ∞ ¹  +12.53% (p=0.029 n=4)
Dump/16384             39.34Mi ± ∞ ¹    46.71Mi ± ∞ ¹  +18.73% (p=0.029 n=4)
geomean                541.0Mi          600.4Mi        +10.98%
¹ need >= 6 samples for confidence interval at level 0.95

@aykevl
Copy link
Member Author

aykevl commented Mar 14, 2025

In the future, this GC might also be supported on WebAssembly with some extra work.

IMO this is a very important feature to add.

I don't think it will take a lot of work (or at least I hope so), but I prefer doing that in a separate PR after this one is merged. WebAssembly and GC is always a bit messy.

@pulsejet
Copy link

This is looking great, thank you for continuing on this! FYI, Microsoft is porting the Typescript compiler to Go and they've explicitly said they might consider tinygo for the wasm build (microsoft/typescript-go#458 (reply in thread)), hopefully this means more resources for the project! (I consider this PR as a step towards that since the current GC is not exactly usable on heavy apps, at least in wasm)

@aykevl aykevl force-pushed the bdwgc branch 2 times, most recently from 2c6bf79 to 8fcbbc1 Compare March 17, 2025 08:21
@aykevl
Copy link
Member Author

aykevl commented Mar 17, 2025

@pulsejet

We're using tinygo for wasm because using asyncify is a huge win for optimization and binary size, but the gc bottleneck makes it unusable (pauses are ~400ms vs ~20ms for gc)

To clarify: maybe asyncify has an effect, but there are other reasons why TinyGo produces binaries that are so much smaller. For example, they're also a lot smaller on Linux which doesn't need something like Asyncify. Using Asyncify in the standard Go compiler won't get you to binary sizes like in TinyGo (though it might help a little).

@aykevl
Copy link
Member Author

aykevl commented Mar 17, 2025

I did a quick-and-dirty port to wasip1, benchmarked the html package, and got the following result:

$ benchstat html-precise.txt html-boehm.txt
               │ html-precise.txt │           html-boehm.txt           │
               │      sec/op      │   sec/op     vs base               │
Escape               110.29µ ± 0%   73.62µ ± 3%  -33.25% (p=0.002 n=6)
EscapeNone            48.37µ ± 0%   49.15µ ± 1%   +1.62% (p=0.002 n=6)
Unescape             192.31µ ± 5%   84.53µ ± 3%  -56.04% (p=0.002 n=6)
UnescapeNone          2.638µ ± 1%   2.559µ ± 4%        ~ (p=0.132 n=6)
UnescapeSparse        45.44µ ± 2%   18.55µ ± 1%  -59.17% (p=0.002 n=6)
UnescapeDense        182.55µ ± 1%   79.63µ ± 1%  -56.38% (p=0.002 n=6)
geomean               53.11µ        32.40µ       -39.00%

A geomean of -39% is very significant! It's also a much bigger difference than the difference on Linux.
(GC pauses are probably also reduced, but I didn't check those).

I also tried benchmarking go/format on wasip1 and while that one did pass with -gc=boehm, it actually crashed with -gc=precise (out of memory). So -gc=boehm is an improvement there as well. It also seemed to improve performance a lot.

@aykevl aykevl mentioned this pull request Mar 17, 2025
2 tasks
This adds support for the well-known Boehm GC. It's significantly faster
than our own naive GC and could be used as an alternative on bigger
systems.

In the future, this GC might also be supported on WebAssembly with some
extra work. Right now it's Linux only (though Windows/MacOS shouldn't be
too difficult to add).
@pulsejet
Copy link

@pulsejet

We're using tinygo for wasm because using asyncify is a huge win for optimization and binary size, but the gc bottleneck makes it unusable (pauses are ~400ms vs ~20ms for gc)

To clarify: maybe asyncify has an effect, but there are other reasons why TinyGo produces binaries that are so much smaller. For example, they're also a lot smaller on Linux which doesn't need something like Asyncify. Using Asyncify in the standard Go compiler won't get you to binary sizes like in TinyGo (though it might help a little).

Yes, absolutely 👍🏻

It's just that for wasm specifically, the gc compiler emits a branch for every single function call, including inside tight loops that never actually (need to) yield. This likely is the reason why the wasm size explodes out of control very fast (the size problem is way worse than other platforms) and performance is terrible due to the large branch tables (many of them in the standard library)

@deadprogram
Copy link
Member

This is very exciting work @aykevl thank you for putting in the time! Also thanks @pulsejet for the feedback.

Now merging.

@deadprogram deadprogram merged commit 3a7c25f into dev Mar 18, 2025
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants