Giter VIP home page Giter VIP logo

Comments (12)

ambv avatar ambv commented on July 20, 2024 1

If you really don't want to make aiosc support numpy, you could make it support Python's built-in array.array instead. Compared to numpy we lose:

  • multidimensionality, moving those calculations to Python loses efficiency; and
  • the ability to zero the array efficiently.

We'd still maintain:

  • memory locality; and
  • ability to serialize quickly in C with arr.tobytes() (although OSC is big-endian so we'd have to first call arr.byteswap() so that's slower than numpy's version)

I think allowing numpy arrays would be better because numpy's it's the fastest option and it's got a lot of mindshare in Python. The changes to aiosc are all in the original message above (no import numpy) and the changes to monome.py is just two new methods.

Making Buffer instances work with array.array internally would also be an efficiency win, although a more modest one.

Making Buffer instances use single-dimensional list objects won't be very effective because those are still arrays of pointers to PyObjects.


Here's my testing code:
https://gist.github.com/ambv/e422fc092d3ac3e79e8b53f8efcb3108

The latest revision uses numpy. The previous revision uses pure Python data routines that created buffers with every frame. The numpy version is butter smooth on Python 3.11.1. The previous revision has occasional stutters of a few frames.

I can't see it on the Grid, but it's more obvious to me on the Arc because the pixels are much closer together and so smooth movement look like solid motion while stuttery movement breaks the illusion.

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

Hey @ambv, thanks for the suggestion. For pymonome and especially aiosc I would rather avoid having heavyweight external dependencies though.

Does it not work for you if you initialize GridBuffer once (e.g. in on_grid_ready callback)?

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

Oh, I see. You problem is allocating the OSC message itself, sorry. I've never experienced any delays in refreshing grid at 30 fps myself (I have a 256), could you share the sample code that exposes the issue?

from pymonome.

ambv avatar ambv commented on July 20, 2024

For pymonome and especially aiosc I would rather avoid having heavyweight external dependencies though.

I understand you don't want to add numpy to your requirements, and you don't have to. As you can see above, I'm specifically checking for an numpy.ndarray type without ever importing numpy. You don't have to have numpy as a runtime dependency to support this.

Does it not work for you if you initialize GridBuffer once (e.g. in on_grid_ready callback)?

Not really because the .levels property on the buffer can only be cleared by a Python-level quadratic loop (led_level_all). Plus .levels is written in terms of regular lists of lists, which are rather poor for cache locality. Numpy arrays are faster in those two cases, but also in turning the array into a bytestream (that bit happens in aiosc).

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

Not really because the .levels property on the buffer can only be cleared by a Python-level quadratic loop (led_level_all). Plus .levels is written in terms of regular lists of lists, which are rather poor for cache locality. Numpy arrays are faster in those two cases, but also in turning the array into a bytestream (that bit happens in aiosc).

If the buffer would be a 1-dimensional list would that improve performance without introducing an optional numpy dependency?

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

Yep, array.array is a cool idea. I'd happily pull the change to the repo. As for numpy arrays - is it a viable option for for your use-case to convert numpy array to bytes at the application level?

from pymonome.

ambv avatar ambv commented on July 20, 2024

Yes, if you supported passing bytes directly to aiosc, that would be fine by me, then I'd do the entire numpy dance on my end.

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

bytes class is currently mapped to OSC blob type in aiosc, however passing bytes to send with an asterisk should repack them as integers one by one - is the resulting performance good enough to have it this way?

from pymonome.

ambv avatar ambv commented on July 20, 2024

I haven't tested that. It just seems wasteful to me because I'd be unpacking the bytes unnecessarily on one end only to repack them again one-by-one on the other end.

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

Right, but also bytes->blob is a pretty straightforward type mapping in the current send calling convention and having it any other way (bytes -> integer array) feels a bit less intuitive.

arrays (numpy or lists) can be converted to OSC in more than one way on the other hand, and your initial proposal is about having send convert a specific type in a specific way. Would that require a different conversion logic for any other case? I think a good candidate for resolving this would rather be the application (or at least the pymonome) layer, but happy to stand corrected in case i'm missing something obvious (it's past midnight here, sorry :))

It should be also possible to work around the conversion entirely by generating raw OSC completely in your drawing methods and using grid.transport.sendto to send it to the grid in case you need extreme optimization.

from pymonome.

ambv avatar ambv commented on July 20, 2024

There is no hurry in developing the API well here. I personally care about making things efficient by default so that pymonome code can be used for tricky use cases as well. In my case, I'm doing MIDI and even realtime audio processing and the Grid + Arc are controllers. I'd rather only spend as little CPU time on that task as possible.

from pymonome.

artfwo avatar artfwo commented on July 20, 2024

Sure thing, I care about efficiency as well. But I'd argue that pymonome is quite efficient for practical usage already :) My live setup is also a grid + arc (sometimes 2 grids + arc) with a lot of bidirectional OSC traffic going between serialosc, the controller/sequencer scripts and the audio engine. There's a lot of grid redrawing going on constantly with several off-screen (off-grid) buffers. Not so much animations on the arc, but the rings react very well to user input.

There's a noticeable CPU overhead in the entire controller app since I've switched to asyncio, likely related to a lot of i/o polling happening under the hood, but I'm getting it with or without rendering. I also rarely (if ever) do zeroing of the LED buffers. Instead, the rendering loop body typically fills the entire buffer in most of my scripts.

That said, extra optimization would never hurt. With the solution above I have some doubts though - it's a bit hackish, and it's a really neat hack! But it caters to a rather specific way of concatenating a numpy array to the rest of the arguments (breaking the consistency of 1:1 mapping of send arguments to OSC arguments) and it adds a dependency on numpy to function properly in the client code, despite not requiring the module. Is this where practicality beats purity? Being a numpy user myself, i'm not 100% sure :)

I'm glad to discuss this or other approaches further to solve the original issue of course.

FWIW, here's the output of your test script I'm getting with regular Python lists and uvloop, visibly things are smooth:

FPS: computation=95.20 (min=85.60) rendering=31.80
FPS: computation=95.14 (min=84.15) rendering=31.82
FPS: computation=95.01 (min=89.94) rendering=31.73
FPS: computation=95.14 (min=84.85) rendering=31.64
FPS: computation=94.72 (min=84.60) rendering=31.87
FPS: computation=95.41 (min=85.74) rendering=31.83
FPS: computation=95.30 (min=88.92) rendering=31.78

from pymonome.

Related Issues (3)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.