tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

[Question] Noticeable performance differences compared to C

Open DrMagPie opened this issue 2 years ago • 18 comments

Hi tinyGo team! I'm currently experimenting with tinyGo, and so far I'm loving it, big thank you for that! And to learn tinyGo I am porting simple Arduino Nano + DS3231 (RTC) + hd44780i2c (2004 LCD display) clock. And I noticed that tinyGo takes noticeably more time to update the display. I was expecting some performance differences, but not so big. So my question is, am I doing something wrong? or there really is such a big difference? Have anyone done any benchmarking co compare tinyGo to C/C++?

TinyGo: https://streamable.com/p0983z slow startup, characters appear one by one and dots between numbers appear one after another. C: https://streamable.com/u1zxp1 fast startup, characters appear instantly, dots blink are synchronised.

DrMagPie avatar Aug 19 '23 12:08 DrMagPie

See https://www.mdpi.com/2079-9292/12/1/143 for a research paper on this subject.

The results show that the C/C++ implementations were fastest in most cases, closely followed by TinyGo and Rust...

Must be something much different in your code sample, but I have not had time yet to take a look.

deadprogram avatar Aug 19 '23 18:08 deadprogram

Thank you for sharing this paper, it's an interesting read.

I have uploaded sample code to this repository. (in case you would like to have a closer look, or even run it) I'm using Arduino nano with old bootloader.

Also, please be ware this is a stripped down version of program from videos attached above. But the screen behaves exactly the same way as in the videos.

DrMagPie avatar Aug 19 '23 20:08 DrMagPie

On inspecting the tinygo driver it is clear there is room for improvement:

  • Heap allocation, could be avoided by using struct allocated buffer: https://github.com/tinygo-org/drivers/blob/5e0191655b602ecc49b70aa3c0816834d85c9718/hd44780i2c/hd44780i2c.go#L217
  • Could be global variable: https://github.com/tinygo-org/drivers/blob/5e0191655b602ecc49b70aa3c0816834d85c9718/hd44780i2c/hd44780i2c.go#L124C2-L124C45
  • Also, I'd hope LLVM is optimizing this conversion, which is unecessary

The C version does not heap allocate in the call to expanderWrite

soypat avatar Aug 23 '23 23:08 soypat

My suggestion: If you use a logic analyzer on the I2C bus you will have a clear perception why with TnyGo it is slower. And fix the possible problem.

Cheap logic analyzer SPI i2c UART https://youtu.be/rR5cEFRO9_s?si=bT2rKCLyGnW0LhUO

Gustavomurta avatar Oct 17 '23 13:10 Gustavomurta

DrMagPie, I was unable to test your Tinygo program on my Arduino Nano, as I had already updated the boot loader (new version).

PS C:\Users\jgust\tinygo\programas\arduino\tiny_experiment\tinygo_code> tinygo flash -target=arduino-nano main.go
avrdude.exe: stk500_recv(): programmer is not responding
avrdude.exe: stk500_getsync() attempt 1 of 10: not in sync: resp=0x00
avrdude.exe: stk500_recv(): programmer is not responding

avrdude.exe: stk500_recv(): programmer is not responding
avrdude.exe: stk500_getsync() attempt 10 of 10: not in sync: resp=0x00
avrdude.exe: ser_drain(): read error: Acesso negado.

avrdude.exe: opening programmer "arduino" on port "COM4" failed

avrdude.exe done.  Thank you.

So I tested your program with an Arduino Uno. With Arduino sketch it ran normally. But with Tinygo, it showed the same symptom of slowness.

Checking the I2C bus with Logic Analyzer, I noticed that with TinyGo, the frequency of the I2C interface does not match the configuration.

I tested with this example - https://github.com/tinygo-org/drivers/tree/release/examples/hd44780i2c

With 100 KHz configured - frequency detected: 1.7 KHz approximated With 400 KHz configured - Frequency detected - 10 KHz approximated

machine.I2C0.Configure(machine.I2CConfig{
		Frequency: 400 * machine.KHz,
	})

lcd.Configure(hd44780i2c.Config{
		Width:       20, // required
		Height:      4,  // required
		CursorOn:    true,
		CursorBlink: true,
	})

Tomorrow, I will analyze this problem.

Gustavomurta avatar Oct 18 '23 02:10 Gustavomurta

Today I tested your program with Raspberry Pico and it worked OK! For compatibility of voltage levels I connected resistors of 10K to ground in both lines SDA and SCL Therefore, the voltage levels on the I2C bus are 3.3V (Raspberry Pico level).

https://github.com/DrMagPie/tinyExperiment/tree/main/tinyGo_

I just made this change and the clock frequency was 95 KHz (acceptable), checked with the logic analyzer.

machine.I2C0.Configure(machine.I2CConfig{ Frequency: 100 * machine.KHz, }) // I2C clock frequency 100 KHz

I think there is really something wrong with the hd44780 i2c protocol on the Arduino TinyGo (Atmega328).

Gustavomurta avatar Oct 19 '23 01:10 Gustavomurta

I think i found why I2C clock frequency is wrong using Arduino TinyGo!

Studying source code at: https://github.com/tinygo-org/tinygo/blob/release/src/machine/machine_atmega.go#L35

I think it is wrong - not SetBits, but ClearBits of the TWSR is correct.

image

Comparing with Arduino Source code: https://github.com/arduino/ArduinoCore-avr/blob/master/libraries/Wire/src/utility/twi.c#L91

The two bits of the TWSR are cleared

image

ATMEGA328 Datasheet:

image

image

Gustavomurta avatar Oct 21 '23 03:10 Gustavomurta

DrMagPie, I was unable to test your Tinygo program on my Arduino Nano, as I had already updated the boot loader (new version).

II discovered that there is a version for the new Arduino Nano.

tinygo targets : arduino-nano-new

tinygo build -target=arduino-nano-new main.go

Gustavomurta avatar Oct 21 '23 13:10 Gustavomurta

On the Slack Forum, I received guidance from Kenneth Bell: (Thanks Kenneth) to fix the bug on Github:

"You can simply modify the local copy of the 'machine' package to see if the fix works. Just make a new version of your application.If it works, the instructions for 'building from source' are here: https://tinygo.org/docs/guides/build/ You can fork the tinygo repository, commit your changes and create a PR"

Since I have limited experience with Github, I will try to fix it as soon as possible.

https://tinygo.org/docs/guides/contributing/#how-to-use-our-github-repository

Gustavomurta avatar Oct 22 '23 16:10 Gustavomurta

But, I did a test with success! Clearing TWSR_TWPS bits 0 and 1.

avr.TWSR.ClearBits((avr.TWSR_TWPS0 | avr.TWSR_TWPS1))

Test code: https://github.com/Gustavomurta/tinyGo_my_experiments/blob/main/I2C_clock_test/Arduino_I2C_clock.go

The I2C clock frequency was changed to 100 KHz, using Arduino Uno !

image

Gustavomurta avatar Oct 22 '23 16:10 Gustavomurta