Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Maximum fps when using network sender/receiver?
#1
I'm trying out the network sender and receiver portions of bibliopixel and it appears to be working. However, my initial experiments seem to indicate that running the animation on the same system as the led strips is faster and I was a bit surprised by this (I figured having a beefy system to do the animation calculations would be a good thing).

Has anyone done any experiments with the network sender/receiver mechanism to determine how to maximize frames per second (fps)?

Hardware information:

System controlling the led strip (network receiver):

Approximately 200 led's on an AP102 led strip.
Using a raspberry Pi B (single core) to drive the AP102 strip via SPI.
Using wifi to communicate with the raspberry Pi.
Running Raspian and bibliopixel and python 2.7

System running the animation (network sender):
Standard x86 laptop running linux with multiple cores and lots of memory.

For now, using bibliopixel.strip_animations.Rainbow() as the sample animation that is being used by the sender.


-- charles
#2
Charles,

Performance is going to depend on a lot of things. I agree with your thoughts that running the animation on a system with a lot of power and then displaying it with a lesser system would be better but there is a *huge* caveat to that... it only makes sense if your animation is seriously CPU intensive, because the performance gain by generating frames on the bigger system has to overcome the performance *loss* from then sending those pixels over the network. One great example is a noise animation I tried once with a lot of float-based simplex noise. An RPi just wasn't up to the task.

But let's look at your setup:

APA102 - Awesome. Those are the best in my mind. Super fast. But this means the network performance issue will be seen more as you aren't just waiting for the LEDs to update.

Pi B - Probably what I would choose for this since it doesn't have to be fast, just push the pixels. But maybe you *can* run everything on the Pi with the Pi2?

WiFi - Yeah... WiFi on the Pi works, but it's not great. Being over USB doesn't help that. There's a TON of overhead in this scenario. Ethernet would be way better.

Rainbow Animation - Like mentioned above, you need to overcome the network performance loss. Rainbow is stupidly simple. Even the Pi1 should generate 200 pixels in ~1ms or less.

Are you checking the FPS rate with debug logging? If so, what FPS are you getting? See here: https://github.com/ManiacalLabs/BiblioPixel/wiki/Logging
Do that on both the sender and the receiver and you can see where it's spending all it's time... which should be in Update on the sender end and in Frame on the receiver end.

It's been a while since I performance tested this, but I think I maxed around 30fps for 600 pixels over the network.
#3
Thanks Adam.

I'm trying to do a candle flicker on the leds (and plan on increasing the number of leds to over 500), and the raspberry pi wasn't able to keep up. I used the rainbow animation for testing so that I could focus on the network side of things.

For network performance, using the log.DEBUG, it appears the system can get to about 30-50 fps (messages from network_sender side):

DEBUG - animation - 20ms/50fps / Frame: 0ms / Update: 20ms
DEBUG - animation - 31ms/32fps / Frame: 0ms / Update: 31ms
DEBUG - animation - 28ms/35fps / Frame: 0ms / Update: 28ms
DEBUG - animation - 24ms/41fps / Frame: 0ms / Update: 24ms
DEBUG - animation - 21ms/47fps / Frame: 0ms / Update: 21ms
DEBUG - animation - 24ms/41fps / Frame: 0ms / Update: 24ms

I added the log.DEBUG to the receiver, but didn't see any output.

Using python's cProfile, it looked like a lot of time was spent in the recv for the sender. Specifically, It looks like the sender blocks on the recv() waiting for the RETURN_CODES.SUCCESS from the network_receiver. With a small change to the network receiver driver code, I was able to increase to 55-75 fps with no other changes: 

DEBUG - animation - 17ms/58fps / Frame: 1ms / Update: 16ms
DEBUG - animation - 14ms/71fps / Frame: 0ms / Update: 14ms
DEBUG - animation - 13ms/76fps / Frame: 1ms / Update: 12ms
DEBUG - animation - 14ms/71fps / Frame: 1ms / Update: 13ms
DEBUG - animation - 16ms/62fps / Frame: 0ms / Update: 16ms
DEBUG - animation - 14ms/71fps / Frame: 0ms / Update: 14ms
DEBUG - animation - 13ms/76fps / Frame: 0ms / Update: 13ms

I will post the change at the bottom. Perhaps it can be considered for the bibliopixel library in general.

In the "interesting to know" category, the raspberry pi running the rainbow locally can handle ~50fps (output below):

WARNING - animation - Frame-time of 20ms set, but took 20ms!
WARNING:BiblioPixel:Frame-time of 20ms set, but took 20ms!
WARNING - animation - Frame-time of 20ms set, but took 20ms!
WARNING:BiblioPixel:Frame-time of 20ms set, but took 20ms!

 -- charles

Change to network_receiver.py to speed up network round trips. Basically, send the RETURN_CODES.SUCCESS from the receiver before physically pushing the bytes to the led's.


Code:
$ git diff

diff --git a/bibliopixel/drivers/network_receiver.py b/bibliopixel/drivers/netwo
index b9f1046..879909d 100644
--- a/bibliopixel/drivers/network_receiver.py
+++ b/bibliopixel/drivers/network_receiver.py
@@ -31,15 +31,15 @@ class ThreadedDataHandler(SocketServer.BaseRequestHandler):
                     log.logger.exception("Receieved data size incorrect! Expect
                     return
 
+                packet = bytearray()
+                packet.append(RETURN_CODES.SUCCESS)
+                self.request.sendall(packet)
+
                 self.server.update(data)
                
                 if self.server.hasFrame:
                     while self.server.hasFrame(): pass
 
-                packet = bytearray()
-                packet.append(RETURN_CODES.SUCCESS)
-                self.request.sendall(packet)
-
             elif cmd == CMDTYPE.BRIGHTNESS:
                 res = self.request.recv(1)
                 bright = ord(res)
#4
 
Smile I thought you might try to make that change. Here's the thing... It was done in that order so that the receiver didn't respond until it was *done* outputting the data to the strip. What you've done is bypass that completely. But that means that if it gets a new packet before it's done writing to the strip, that next packet will have to wait. The result of this can be a stutter... the framerate is not consistent.
How about this... revert your change first thought. Then in your LEDStrip class add "threadedUpdate=True" to the parameters. What this will do is basically exactly what you did, but managed correctly. It runs the updates to the strip on a secondary thread so that when you tell it there's new data, you don't have to wait for it to be pushed... AND it keeps the framerate smooth. It's why I added the threadedUpdate option Smile I left it disabled by default so I wasn't making any breaking changes, but with BiblioPixel 2.0 (coming soon) I may force that on by default.
Weird about that warning... my guess is it's a float round error that makes it every so slightly more than 20ms and trigger that warning. I'll take a look. It's not really a big deal if it shows that.

Also, silly me... you didn't get any receiver side output because it doesn't output anything. The FPS output you see is in the animation class. I'll look into adding debug info to NetworkReceiver.
#5
Great sharing information.
Thanks a lot!


Forum Jump:


Users browsing this thread: 1 Guest(s)