stagehacks / Cue-View

A dashboard for everything in your show.
57 stars 6 forks source link

Performance #261

Open tm1000 opened 1 day ago

tm1000 commented 1 day ago

I've built this project on a raspberry-pi 4 with 8GB of ram. Loading a QLab file with 7 cue lists and 100 cues in each list it takes a long time to load.

Initially it seems to load the cues very quickly but then the styling of the cue "groups" seems to drag on for 20-30 minutes and the cpu spikes to 120%. I don't really expect amazing performance out of a raspi. However once this loading is complete cueview only takes about 10-20% of cpu. So the majority of the performance issues seem to be in the rendering portion of the QLab plugin

Have you given any thought to this project use vue or react. Perhaps this is just something that needs to be refined in the plugin itself

You also don't build for arm64-Linux but you have a build step for it in package so I suspect you were on the path of doing this

I think (my opinion) the raspi is a perfectly capable system to run this tool and something that could be the easiest way to utilize this for just "cue viewing"

jwetzell commented 1 day ago

It's unlikely that any sort of UI framework/library will be put into place here. I think exploring how to draw and render the cues in a more efficient would be best. For most of the plugins is what done in the easiest way to get it working which is not always optimal at scale. I can try and setup a QLab workspace that will cause it to choke and see what can be done about improving the speed of that.

Good note on the arm64 build as well, I will also look into how much of a lift that would be to add to list of releases.

tm1000 commented 1 day ago

Hey @jwetzell

I can provide you this crazy workspace over Dropbox if you'd like. It's just a dance show so nothing copyrighted

As for the gui portion. All good. If/when I can contribute it's good to know what the vision/goal of the project is. In the end I doubt react/vue would make the execution any faster than native

Also when I get a few more cycles today I want to load the same show on my M3 Mac as I suspect it'll load much quicker.

I suppose after discussing this you'd say the goal would be to have it perform better on raspi systems if possible?

Of note. I did try to cross compile the Linux arm version on my Mac and it did not run correctly on the pi. So I had to just build it there. I don't know if you'd run into the same issue on GitHub's runners (also not sure if they have an arm64-Linux runner but I'd have to check)

jwetzell commented 1 day ago

I've got a workspace setup that seems to generally reproduce this. This probably is not unique to the QLab plugin so finding a good way to improve it would be beneficial across the board. The issue is usually with integrations where data is populated over time and not all at once (it takes multiple calls to populate all the data needed) for QLab the amount of message is at a minimum the number of cues and then add on a few more for other bits of data. Our general problem is that when data changes it usually means we need to redraw, but for plugins like this data can change fast when the connection is initially setup so device.draw() gets called a lot.

For a more intricate fix I think exploring some sort of virtual DOM concept might be more in line with what this really calls for as right now device.draw() is a generate body and replace what is there which is not exactly efficient to do really fast.

tm1000 commented 1 day ago

@jwetzell heh "virtual dom"? So like react or vue

I kid

Kinda ;-)

In a case like this perhaps it is suited to at least try react/vuejs or something similar with the virtual dom concept.

Unless you want to write something from scratch yourself (https://medium.com/@deathmood/how-to-write-your-own-virtual-dom-ee74acc13060)

But if react and vuejs (+others) have already done the years of work to get theirs right...

Whatever it is it should be you deciding first. As for me an outside contributor/developer I'll go the direction of the project. :-)

sparks-alec commented 1 day ago

To me, the major challenge here is how QLab informs clients of changes. If a root cue is moved, QLab tells you (via OSC) to fetch all the cues at root again. And to get all those cues, you need their children. Etc. You wind up having to re-draw the whole dang cue list pretty frequently.

I am not sure how much heuristics can be done to improve that without changes in QLab's OSC responses. The QLab remote app also struggles with very large cue lists.

I can ask the QLab folks to sit down with us and walk through exactly how they recommend an app like ours would communicate- I'd be curious to learn.

sparks-alec commented 1 day ago

Also, as a person who primarily works in C++ and likes to do everything myself, I am pretty allergic to react and its relatives. I think they have made the web worse.

tm1000 commented 1 day ago

The primary goal of react and others is the virtual dom. You could write your own here if so desired.

I think this could be tightened up to not call draw on every OSC change. Especially when you know you are getting the default list.

The issue here is truly that the browser is constantly rerendering its entire dom when only a single row is changing

To be fair this is already using a framework. That's electron. It's also using lodash as the template engine. Has another template engine been evaluated?

The most optimal format would be c++/rust/swift etc but you'd lose a lot of traction.

jwetzell commented 1 day ago

Currently, the draw function seems to just set the innerHTML of the body with the result of the template engine (not great..). The line that sets innerHTML makes up over 90% of the time spent in device.draw() (from the small testing I did).

When I've got some time I'll probably look into some libraries that might handle this DOM manipulation in a better way it doesn't even need to be virtual 🙃. I've explored swapping templating libraries just for the heck of it, there isn't much of anything crazy in these templates. But if it's just pure template -> HTML string not sure that helps anything (other than I don't like this templating language syntax).

jwetzell commented 1 day ago

I have started a branch qlab-fast-redraw-fix to explore some solutions that don't require changing up things a whole lot. Just basically avoid device.draw() as much as possible. If a new update comes in it basically postpones the draw which results in less overall draws (about two per cue list instead of one per cue list + one for every group cue in the workspace)