ws2811/2812 Programs very slow

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: ws2811/2812 Programs very slow

Post by kevinkk525 » Tue Sep 25, 2018 5:17 pm

You could try using a bytearray to store all the values. That's faster and saves RAM as the bytearray is not changed in size after creation.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 5:21 pm

kevinkk525 wrote:You could try using a bytearray to store all the values. That's faster and saves RAM as the bytearray is not changed in size after creation.

But tuples are immutable and he has tuple of ints which are completely immutable.

Why isn’t the same tuple being used for all array entries?


Sent from my iPhone using Tapatalk Pro

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: ws2811/2812 Programs very slow

Post by kevinkk525 » Tue Sep 25, 2018 5:53 pm

jickster wrote:
Tue Sep 25, 2018 5:21 pm
kevinkk525 wrote:You could try using a bytearray to store all the values. That's faster and saves RAM as the bytearray is not changed in size after creation.

But tuples are immutable and he has tuple of ints which are completely immutable.

Why isn’t the same tuple being used for all array entries?


Sent from my iPhone using Tapatalk Pro
True but he recreates those tuples in every iteration of the while loop. So instead of using a list of size n with each slot containing a tuple of size 3 (each slot being an integer), it would be better to use a bytearray size n*3 (also saving a lot of RAM as each "slot" would be a byte, not an integer). Would improve the performance as well.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 6:00 pm

kevinkk525 wrote:
jickster wrote:
Tue Sep 25, 2018 5:21 pm
kevinkk525 wrote:You could try using a bytearray to store all the values. That's faster and saves RAM as the bytearray is not changed in size after creation.

But tuples are immutable and he has tuple of ints which are completely immutable.

Why isn’t the same tuple being used for all array entries?


Sent from my iPhone using Tapatalk Pro
True but he recreates those tuples in every iteration of the while loop. So instead of using a list of size n with each slot containing a tuple of size 3 (each slot being an integer), it would be better to use a bytearray size n*3 (also saving a lot of RAM as each "slot" would be a byte, not an integer). Would improve the performance as well.
Where does he re-create the tuples?

They’re created when they’re first used unless I don’t understand the immutability of tuples.


Sent from my iPhone using Tapatalk Pro

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: ws2811/2812 Programs very slow

Post by kevinkk525 » Tue Sep 25, 2018 6:02 pm

jickster wrote:
Tue Sep 25, 2018 6:00 pm
kevinkk525 wrote:
jickster wrote:
Tue Sep 25, 2018 5:21 pm



But tuples are immutable and he has tuple of ints which are completely immutable.

Why isn’t the same tuple being used for all array entries?


Sent from my iPhone using Tapatalk Pro
True but he recreates those tuples in every iteration of the while loop. So instead of using a list of size n with each slot containing a tuple of size 3 (each slot being an integer), it would be better to use a bytearray size n*3 (also saving a lot of RAM as each "slot" would be a byte, not an integer). Would improve the performance as well.
Where does he re-create the tuples?

They’re created when they’re first used unless I don’t understand the immutability of tuples.


Sent from my iPhone using Tapatalk Pro
He has an unconditional while loop and in there a for loop that recreates all the tuples in the array on each iteration of the while loop.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 6:06 pm

kevinkk525 wrote:
jickster wrote:
Tue Sep 25, 2018 6:00 pm
kevinkk525 wrote: True but he recreates those tuples in every iteration of the while loop. So instead of using a list of size n with each slot containing a tuple of size 3 (each slot being an integer), it would be better to use a bytearray size n*3 (also saving a lot of RAM as each "slot" would be a byte, not an integer). Would improve the performance as well.
Where does he re-create the tuples?

They’re created when they’re first used unless I don’t understand the immutability of tuples.


Sent from my iPhone using Tapatalk Pro
He has an unconditional while loop and in there a for loop that recreates all the tuples in the array on each iteration of the while loop.
I see the loop but tuples are immutable like ints.

If I say
a = 555555555555555555555555
b = 555555555555555555555555

Shouldn’t “b” point to the same int object in memory?

Same principle
c = (255,0,0)
d = (255,0,0)

Maybe my understanding is wrong. Idk. Send me a link to read if I’m wrong.


Sent from my iPhone using Tapatalk Pro

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: ws2811/2812 Programs very slow

Post by kevinkk525 » Tue Sep 25, 2018 6:20 pm

jickster wrote:
Tue Sep 25, 2018 6:06 pm
kevinkk525 wrote:
jickster wrote:
Tue Sep 25, 2018 6:00 pm


Where does he re-create the tuples?

They’re created when they’re first used unless I don’t understand the immutability of tuples.


Sent from my iPhone using Tapatalk Pro
He has an unconditional while loop and in there a for loop that recreates all the tuples in the array on each iteration of the while loop.
I see the loop but tuples are immutable like ints.

If I say
a = 555555555555555555555555
b = 555555555555555555555555

Shouldn’t “b” point to the same int object in memory?

Same principle
c = (255,0,0)
d = (255,0,0)

Maybe my understanding is wrong. Idk. Send me a link to read if I’m wrong.


Sent from my iPhone using Tapatalk Pro
Hmm I don't have anything to read about that.
But a definitely has not the same memory as b. Easy to test because if you add 1 to a, b would be 1 bigger as well, which of course does not happen (if micropython separetes the memory only when one of the objects get modified then idk about that).
As for tuples they are immutable once created but I don't know if all tuples with equal values have the same memory.
But even then he stores first tuples (0,0,0) in every slot in the list and then iterates over the list changing some slots to (255,0,0).
Maybe the performance problem and the neccessity for gc.collect() comes from the recreation of tuples.

But I did not intend to turn a question about basic micropython stuff into a discussion on "developer level", having to look at the internals of micropython (because I have no knowledge of that anyways). I just thought he'd be better off using bytearrays which could solve his RAM and performance problems.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

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

You could try this

Post by pythoncoder » Tue Sep 25, 2018 7:00 pm

@ARTaylor Firstly I'm surprised that your code is slowing down so very much. Normally garbage collection occurs in a very few milliseconds.

However I can see ways to improve things. Firstly, as others have suggested, create a bytearray and re-use it. This avoids allocation. Secondly I think your code can be made quicker by not zeroing every LED on every pass. Can you not do something like this?

Code: Select all

from time import sleep
pixelcount = 50
np = NeoPixel(Pin(19), pixelcount)
buf = bytearray(3)
while True:    # Green chaser
    for i in range(pixelcount):
        buf[0] = 255
        np[i] = buf
        np.write()
        buf[0] = 0  # Blank the LED you've just written
        np[i] = buf  # this will take effect on the next pass
        sleep(0.01)
Apologies if I've missed something here - I haven't got the hardware to hand to test this.
Peter Hinch
Index to my micropython libraries.

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Tue Sep 25, 2018 8:05 pm

Wrap your while True loop in a function and reply with the results on memory usage.

Stackoverflow says tuples allocated inside a function are cached.


Sent from my iPhone using Tapatalk Pro

jickster
Posts: 629
Joined: Thu Sep 07, 2017 8:57 pm

Re: ws2811/2812 Programs very slow

Post by jickster » Wed Sep 26, 2018 6:47 pm

ARTaylor wrote:
Tue Sep 25, 2018 4:41 pm
Writing the tuple is the problem:

Code: Select all

np = (n,n,n)
for example, commenting that out fixes the issue. I guess the value for every LED is being stored, and 50+ is excessive
It's far more than 50.

The statement (255, 0, 0) is creating a new tuple every single time. I thought there'd be caching but guess not.
To fix it, all you have to do is create dummy vars to hold (255, 0, 0) and (0, 0, 0) initially and then assign it to np as needed.

Code: Select all

from machine import Pin
from neopixel import NeoPixel
from time import sleep
import gc

pixelcount = 50
np = NeoPixel(Pin(19), pixelcount)

led_on = (255, 0, 0)
led_off = (0, 0, 0)


for n in range(pixelcount):
    np[n] = led_off
while True:
    # Green
    # Reset all LEDs
    for i in range(pixelcount):        
        np[i] = led_on
        np.write()
        np[i] = led_off
        sleep(0.01)
If np.write() doesn't do anything that requires memory allocation, you don't even need to do gc.collect().
If this is your entire program, you don't EVER have to do gc.collect().

Post Reply