Cabbage Logo
Back to Cabbage Site

Possible SVG bug/CPU Spikes

Not sure if this is a bug or not… when iterating a bunch (64) of SVGs to draw, there’s a significant CPU spike in Live. If I change the SVG attribute text to a simple string (e.g. “hello”) there is no spike.

Here is a signed VST (OSX) to try in Live:

It generates 64 random SVGs on the button click. Note that I don’t think it’s the actual drawing of the SVGs causing the spike b/c it still happens when the cabbageSet opcode is commented out.

I’ll take a look when i get a chance. Generating 64 SVGs might be a little sluggish? I never thought someone would go that far down the rabbit hole :laughing:

So, you’re not generating 64 different SVGs, but just a single SVGs, with 64 different vertical lines. It looks like it’s not the drawing of the SVG data, but the call to sprintf? When you replace the sprintfk for a const string it works without any spikes. Well, it doesn’t draw, but it doesn’t cause any spike either. This would also seem to confirm your assessment that it’s not the call to cabbageSet :thinking:

I wonder if there is a better way of generating the SVG text. Strings in Csound have never been the most robust of constructs. Also, I wonder if using a band of 64 image widgets would be so terrible. I can have a go at this tomorrow. It shouldn’t be much work to update from your example. The advantage is that you would only ever have to update the bands that change rather than the entire SVG. And you would not need to use sprintf to generate those long strings.

I’ve been thinking about this and if the issue is indeed with Csound’s string performance, then I could write a set of opcodes for generating the SVGs on the Cabbage side, which would be much faster. Something like:

while iCnt < 64 do
    addRect "image1", kX, iY, iWidth, iHeight, kColour  
    kX += iWidth
    iCnt += 1

This would be much faster than messing around with sprintf. At the same time, it also adds more moving parts. And more code to maintain.

I think I’ve identified the major bottleneck here, line 45:

if chnget:k("Random") > 0 then

You should do something like this instead:

if changed(chnget:k("Random")) == 0 then

Or use the cabbageGet opcodes with the trigger value output. In your code you draw the table more times then needed. Even though the button is not latched, it will be 1 for as long as someone is holding it. When I remove this I get much better performance, although I haven’t tried it in a plugin yet.

Yes! that was it. Thanks Rory!

What do you use to monitor these spikes? I can’t see them in activity monitor - only in Live’s cpu monitor.

I usually use Reaper performance meter as a rough guide, if I really want to dig in I have to use Xcode’s profiler. But in this case I finally worked it out based on what I was seen on the screen in terms of redrawing.

1 Like

Also getting these same CPU spikes in Live when generating a table from within an instrument
iL ftgen 0, 0, 0, 1, gSFile, 0, 0, 1

I know it’s recommended to populate the table on init but in this case the instrument allows the user to load a sample and then creates the table.

I’m not really sure how to avoid those. You’re loading sound files right? I assume the bigger they are the more the spike. Are you loading them up in a different instrument to the one calling them?

No it’s the same instrument… I mean I have it set so that it loads when the file name changes… full version attached

if ki2 > 0 && changed(gSFile) > 0 then; if instr 2 is running and stop mode is activated, turnoff 2
    turnoff2 2, 0, 0

if strlenk(gSFile) > 1 && changed(gSFile) > 0 then ;if a file is loaded and play mode is activated
    event "i", 2, 0, 500000     


instr 2
iNChns  filenchnls  gSFile
    if iNChns==2 then
        iL ftgen 0, 0, 0, 1, gSFile, 0, 0, 1
		iR ftgen 0, 0, 0, 1, gSFile, 0, 0, 2
        iL ftgen 0, 0, 0, 1, gSFile, 0, 0, 1
		iR ftgen 0, 0, 0, 1, gSFile, 0, 0, 1

TestFileLoad.csd (1.2 KB)

Yeah, I’m not sure how best to avoid this - if you have to use tables. have you tried adding the --realtime flag? This offloads the loading of sound files, and init-pass processing, to a separate thread. I’ve never used it, but it’s definitely worth giving it a go.