tinygo-org / tinygo

Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM.
https://tinygo.org
Other
15.43k stars 911 forks source link

[Question] Noticeable performance differences compared to C #3876

Open DrMagPie opened 1 year ago

DrMagPie commented 1 year ago

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.

deadprogram commented 1 year ago

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.

DrMagPie commented 1 year ago

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.

soypat commented 1 year ago

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

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

Gustavomurta commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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