COCKOS
CONFEDERATED FORUMS
Cockos : REAPER : NINJAM : Forums
Forum Home : Register : FAQ : Members List : Search :
Old 08-28-2018, 01:20 AM   #1
hannesmenzel
Human being with feelings
 
Join Date: Jul 2018
Posts: 24
Default Strange cpu consumption issue

Hey there,

I noticed some strange behaviour of my "learning c++ testthing"-plugin. Since the last edits, which are mostly namespaces in my filter classes, the plugins processor consumption rises AFTER stopping playback. During playback it uses the usual ~2%, but about 5 seconds after stopping playback, it slowly rises to around 10%.

I don't want to spam the forum with my code until I got myself into this Git thing. Do you have any idea what could cause things like this? I don't know where to start.

EDIT: The rise of cpu consumption not only occurs when stopped, but also while playback silence. So obviously my plugin doesn't like zeros(?)

Last edited by hannesmenzel; 08-28-2018 at 01:42 AM.
hannesmenzel is offline   Reply With Quote
Old 08-28-2018, 02:53 AM   #2
hannesmenzel
Human being with feelings
 
Join Date: Jul 2018
Posts: 24
Default

I solved it in a somehow dirty way by adding 0.0000000001 to the signal at the beginning of the DoubleReplacing process and subtracting it again at the end. So, there must be something in it, that doesn't like zeros.

The two strange things are, that

1. I'm almost sure that it occured lately and was ok before.
2. Each of my effects/filters only engage when a specific knob is moved (for example the equalizers filters only engage if the gain knob is != 0.), so I was able to figure out that every single effect uses about 3X more cpu when engaged and silence occurs... (eq, comp, limiter, clipper, sat, even input and output gain)
hannesmenzel is offline   Reply With Quote
Old 08-28-2018, 12:04 PM   #3
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 8,062
Default

You will want to disable/filter out denormal numbers on the CPU. The WDL library (which is included with IPlug) has the denormal.h header that contains various macros/functions for that purpose. I don't know which one is the best to use, though...(Why are there so many anyway...?)
__________________
I am no longer part of the REAPER community. Please don't contact me with any REAPER-related issues.
Xenakios is offline   Reply With Quote
Old 08-29-2018, 07:00 AM   #4
hannesmenzel
Human being with feelings
 
Join Date: Jul 2018
Posts: 24
Default

Since my programming knowledge is also in range for denormalization, I would be greatful if you could give an example for one strategy. Seems like it works similar?
hannesmenzel is offline   Reply With Quote
Old 08-29-2018, 12:48 PM   #5
earlevel
Human being with feelings
 
Join Date: Dec 2015
Posts: 331
Default

You're on the right track. A little explanation first, if you don't already know (or for the benefit of future thread readers).

Floating point processors try to keep number in a normalized state, which means everything is of of the form of signed 1.xxxxx times 2^n, to take full advantage of the mantissa bits (and 1 is discarded to gain a bit). Even through that allows for tiny numbers, processors go a step further and allow numbers to be de-normallized. So if the smallest normalized number is 1.00000 x 2^-127, denormalization allows 0.00001 x 2^-127. This trick allows greater precision for values close to zero. But there's a hug performance penalty. modern processors have means of flushing to zero or treating denormals as zero, another topic.

In plugins, you may have a recursive lowpass filter. Everything's fine while you're putting audio through it, but maybe when you stop playback, the host continues to send you empty buffers. So, you have zero into the filter, and decaying what's in the filter memory—eventually into denormals, which in turn propagate to your next DSP elements.

But again you were on the right track. Another way to get rid of denormals is to add a small DC offset to the signal. 1E-15 is a nice number, because it's -300 dB—even with substantial gain, it will never get close to your 24-bit DAC output, or 32-bit float files. Yet, it's relatively large compared to denormals (hundreds of dB for float, thousands for double)—even if your DSP chain reduced it by a high margin, it's still big enough to wipe denormals. A highpass filter in the chain could take it out, but you can either re-add it after such key points in your chain, better yet just alternate it plus and minus periodically (like, reverse it each time you get a buffer to process).

If you are truly paranoid about adding values hundreds of dB down, you can add the small value then subtract it. The nature of floating point is that adding very small numbers to relative large number results in no change to the large number. So, adding 1E-15 to 1.2345E-3 results in 1.2345E-3—no change. And if you subtract 1E-15 from that, you still end up with 1.2345E-3—again no change. But adding 1E-15 to denormalized 0.0001E-127 yields 1E-15. Then if you subtract 1E-15 from that you get 0.0000—you just flushed any denormalized number to zero, while having no effect at all on larger numbers. But practically, just adding the tiny value does the trick.
earlevel is offline   Reply With Quote
Old 08-29-2018, 01:04 PM   #6
earlevel
Human being with feelings
 
Join Date: Dec 2015
Posts: 331
Default

I'm not fond of the direct methods of testing for denormals, like in denormals.h. Testing and branching, but more importantly you might have to repeat the process after the very next math operation. Denormals only occur below the smallest normal number. That's thousands of dB down when using doubles. Just ensure you never get that small by offsetting the stream by a value too tiny to matter.
earlevel is offline   Reply With Quote
Old 09-05-2018, 08:12 AM   #7
hannesmenzel
Human being with feelings
 
Join Date: Jul 2018
Posts: 24
Default

Thanks a lot. I will examine your answer slowly. Btw, what a pleasure that you answering is the one who lead me onto the first steps of audio programming (biquad soruce). I'm trying to get into it since a couple of weeks (including learning c++). My testplugin is a channelstrip using some open source algorithms (chunkware's dynamics, your biquads, enhanced with some other filters from Will Pirkles book, soft saturation algo from musicdsp.org). What is actually my testbed is this:
Attached Images
File Type: jpg Channel.jpg (60.7 KB, 163 views)

Last edited by hannesmenzel; 09-05-2018 at 08:21 AM.
hannesmenzel is offline   Reply With Quote
Old 09-13-2018, 05:05 PM   #8
earlevel
Human being with feelings
 
Join Date: Dec 2015
Posts: 331
Default

Great!

The first time I hit denormals was maybe 15 years ago. I was moving from DSP chips programming to native for the first time, for serious "real time" processing anyway. My code ran fine on my early PowerMac, but when I moved to PC, it just completely locked up the computer. Fortunately, I had read about denormals, but I was surprised at the hit (Pentiums took a much larger denormal hit than PowerPC architecture).

Coincidently, I'm finishing up a new plugin, and was leaving denormals for last (the hit is not so great these days). In the DAW, the plugin's CPU monitor was reasonable and fairly steady, but after stopping playback (which feeds a steady stream of zeros to the plugin), the CPU hit would jumps to 3 or 4 times that level. After posting above, I decided it was time to take care of it.

The plugin has many processing stages, a number of FIRs, nonlinear processing with sample rate conversion, etc. But you mainly need to be concerned with lowpass IIR filters (output decays towards zero, exponentially). Adding a tiny offset will kill the denormals, but the offset will get wiped out by a DC block/highpass filter (which I also have). I initialized a member variable to 1e-18, and flipp the sign once per buffer (start of ProcessDoubleReplacing). I usually use 1e-15 (-300dB), but chose to drop a few decimal places (at -20 dB per)—this plugin happens to have a huge gain stage for the non-linear processing.

So, I just added that value in one place, right after an initial noise gate, ahead of the next component which happens to be a DC blocker. Now the CPU hit remains the same whether audio is going through, or zeros. Super simple.
earlevel is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 02:17 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.