Pin Toggle Frequency Contest against C. Please Help! :)

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
User avatar
pythoncoder
Posts: 3717
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by pythoncoder » Thu Feb 04, 2016 6:20 pm

@Damien I recently started drafting a contribution to the docs on the subject of MicroPython speed optimisation, including the use of Viper. Should I hold fire on this for now if Viper semantics are still fluid?
Peter Hinch

Damien
Site Admin
Posts: 623
Joined: Mon Dec 09, 2013 5:02 pm

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by Damien » Thu Feb 04, 2016 6:31 pm

Docs sound great! Especial needed for viper and "how to do things fast". Feel free to document viper, but just start with the basics of using the decorator and specifying types to args. Enough to bit bang on IO.

mad474
Posts: 60
Joined: Sun Dec 29, 2013 7:48 pm

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by mad474 » Fri Feb 05, 2016 9:15 pm

Docs concerning viper code would be great, even if rudimentary. Thanks!

Apropos: If nobody precedes (Roberthh?) or strangles me I'd push the latest viper code to the german forum tomorrow, just for the snake of informativity and transparency. Maybe we can eventually lure that 21MHz guy from ambush :D

chuckbook
Posts: 107
Joined: Fri Oct 30, 2015 11:55 pm

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by chuckbook » Sat Feb 06, 2016 10:35 am

I had a closer look at this. Brief results are:
  • - The 21MHz toggle frequency is feasible (given C-code) but only if code is executed from flash.
    - 84MHz toggling is also possible (with loop unroll) when executing from flash, 42Mhz executing from RAM.
    - Having the cbxx opcodes in @micropython.asm_thumb would be a good thing for us bit-bangers.

User avatar
pythoncoder
Posts: 3717
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by pythoncoder » Sat Feb 06, 2016 11:05 am

chuckbook wrote:...Having the cbxx opcodes in @micropython.asm_thumb would be a good thing for us bit-bangers.
You've got to be pushing assembler to its limits to need them as far as I can see. It only takes one instruction to set the condition codes, when you can use a conditional branch or an it/ite. As always there's a tradeoff between adding opcodes and keeping it 'micro'.
Peter Hinch

mad474
Posts: 60
Joined: Sun Dec 29, 2013 7:48 pm

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by mad474 » Sat Feb 06, 2016 12:55 pm

@chuckbook
Thanks alot for investigating (and for joining the game and sorry for potential intrusiveness)!

User avatar
pythoncoder
Posts: 3717
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by pythoncoder » Mon Feb 08, 2016 3:36 pm

Damien wrote:...

Code: Select all

@micropython.viper
def togglePerformance3b():
    count = 0 
    stop = int(pyb.millis()) + 1000
    millis = pyb.millis
    odr = ptr16(stm.GPIOA + stm.GPIO_ODR)
    while int(millis()) < stop:
        odr[0] ^= 1 << 13 # PA13 = LED_RED
        count += 1
    print('Counted: {:10,} (viper2)'.format(count))
...
Coming rather late to this party I find that this won't work here. I suspect the issue is with the ptr16 declaration as I've used this successfully where the argument is a buffer - here it is an address. Using today's firmware I'm seeing:

Code: Select all

/mnt/qnap2/data/Projects/MicroPython> repl
Entering REPL. Use Control-X to exit.
>
MicroPython v1.6-19-g8140772 on 2016-02-08; PYBv1.0 with STM32F405RG
Type "help()" for more information.
>>> 
>>> 
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== @micropython.viper
=== def togglePerformance3b():
===     count = 0
===     stop = int(pyb.millis()) + 1000
===     millis = pyb.millis
===     odr = ptr16(stm.GPIOA + stm.GPIO_ODR)
===     while int(millis()) < stop:
===         odr[0] ^= 1 << 13 # PA13 = LED_RED
===         count += 1
===     print('Counted: {:10,} (viper2)'.format(count))
>>> togglePerformance3b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object with buffer protocol required
>>> 
Peter Hinch

User avatar
Roberthh
Posts: 1744
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by Roberthh » Mon Feb 08, 2016 4:03 pm

I have a piece of code that works, submitted to the other forum under a different nickname.

Code: Select all

import pyb, stm

@micropython.viper
def toggleViper(cnt: int):
    bsrr = ptr16(stm.GPIOA + stm.GPIO_BSRRL)
    while cnt:
        bsrr[0] = 1
        bsrr[1] = 1
        cnt -= 1

@micropython.asm_thumb
def toggleASM(r0):    # r0 has loop count
    movwt(r1, stm.GPIOA)    # Use A0
    movw(r2, 1)       # r2 has mask for setting A0
# loop
    label(loopstart)
    strh(r2, [r1, stm.GPIO_BSRRL])  # output high
    strh(r2, [r1, stm.GPIO_BSRRH])  # output low
    sub(r0, 1)  # r0 -= 1
    bpl(loopstart)
# endloop

def main(no = 1000000):
    x1_pin = pyb.Pin('X1', pyb.Pin.OUT_PP)
    start = pyb.millis()
    toggleASM(no)
    timeA = pyb.elapsed_millis(start)
    start = pyb.millis()
    toggleViper(no)
    timeV = pyb.elapsed_millis(start)
    count = round((no * 1000) / timeV) # 2 toggles per iteration
    print('Viper: {:,} toggles/s, {:6.3} MHz, {} Clock Cycles/iter'.format(count * 2, count/1e6, round(pyb.freq()[0]/count)))
    count = round((no * 1000) / timeA) # 2 toggles per iteration
    print('ASM:   {:,} toggles/s, {:6.3} MHz, {} Clock Cycles/iter'.format(count * 2, count/1e6, round(pyb.freq()[0]/count)))
With 100 Mio. cycles, the result is:
Viper: 18,618,506 toggles/s, 9.31 MHz, 18 Clock Cycles/iter
ASM: 27,929,060 toggles/s, 14 MHz, 12 Clock Cycles/iter
Since USB and SYSTICK are still enabled, the numbers are about 0.25% too low. At the moment I am chewing a little bit on the impression, that the ASM version could be 2 clocks faster.

chuckbook
Posts: 107
Joined: Fri Oct 30, 2015 11:55 pm

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by chuckbook » Tue Feb 09, 2016 10:27 am

@pythoncoder the API changed recently. Try this:

Code: Select all

odr = ptr16(bytearray_at(GPIOA + GPIO_ODR,0x100))
@Roberthh don't waste your time, searching for lost cycles. On F405 there exists a memory bottleneck when executing from SRAM (which is the case for MPY). That's where the cycles get lost.

User avatar
Roberthh
Posts: 1744
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: Pin Toggle Frequency Contest against C. Please Help! :)

Post by Roberthh » Tue Feb 09, 2016 10:49 am

@chuckbook: Thanks. That's what I understood from your previous post about the strh instructions. What I was wondering about is, that he unconditional branch takes 2 cycles, opposed to the conditional which seems to take 4 cycles. That looks like accessing the flags adds another timing penatly. It does not worry me at all, it's just for interest in stuff that most likely never will be important.

Post Reply