[SOLVED] How to do MCU utilization measurements

Hi,

in my current project I’m getting some weird noise when I start up an additional LFO. So I wonder if I have hit the roof, performance wise.

How can I measure this? I guess it is a matter of detecting whether the audio callback takes too long?

I saw @antisvin’s reply (The Daisy Roadmap) to the Road map, but I don’t understand it. I’m running C++ with libdaisy and DaisySP.

Many thanks in advance!

Staffan

What exactly is not clear? You have:

  • known value of MCU cycles per second 400’000’000 (ncpu)
  • known sample buffer size (48 by default) (bs)
  • know number of samples per second (48000) (sr)
  • a register that counts how many MCU cycles passed

So you can count number of cycles that would be available for processing each buffer (total = ncpu * bs / sr). With default settings you should be able to use up to 400k cycles.

I’ve left some code for accessing DWT register on MCU that you’ve seen. You must unlock its debug mode to enable cycles measurement when when your patch starts. Then you’ll have to write 0 to the counter field when your audio callback starts and read new value from it just before exiting audio callback. This would give you the actual number of cycles spent processing audio which you can divide by total cycles to get CPU utilization ratio.

DWT register definition is in “core_cm7.h” header from CMSIS, it’s present in libDaisy.

1 Like

Thank you @antisvin, worked like a charm! Very helpful!

(I understood the calculations, but not the technique, as I haven’t dived this deep into the MCU before.)

This is what I did in case anyone else need this.

Include

#include "core_cm7.h"

In main(), before starting the audio callback:

// setup measurement
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->LAR = 0xC5ACCE55;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

// Start calling the audio callback
hardware.StartAudio(AudioCallback);

Then at the very top of my audio callback:

void AudioCallback(float* in, float* out, size_t size)
{
	// variable declarations here -- removed

	// measure - start
	DWT->CYCCNT = 0;

And right before exiting the audio callback I check the value and turn on the LED if I’m near the limit:

// measure - stop
if (DWT->CYCCNT > 390000)
	hardware.SetLed(true);

This corresponded with me getting audio artefacts (noise). The value (390 000) should be computed according to @antisvin’s clear listing. Right now I only wanted to know if I was maxing out the processor.

Once again, thanks!

1 Like

Good to know that you’ve got it working!

I would say that maxing out processor is not necessary the reason - it can be caused by too much SDRAM access, for instance. This happens frequently for certain DSP code (reverbs, phys. modeling).

1 Like

Yeah, I have some delaylines in SDRAM…I will look into that. But I broke the 390K barrier by starting up a bunch of LFOs. I am using the Oscillator class for that, maybe I can use something smarter. Or rather, maybe call my lfo[].Process()'s less often, say every 10th CB?

You can use the same approach to measure various sections of your code to nail down what exactly is using the most time.

The Oscillator class still uses the math.h sin function instead of some fast-approximation which could be pretty limiting depending on how-many you’re using and what waveform. You could sanity check that by switching them all to the naive square waveform and seeing if you’re still close. And you could run the LFOs at once per callback instead of once per sample, but then you’ll still have to filter or interpolate it to get smooth changes on most parameters.

And if you haven’t you could can always boost the CPU to 480MHz for a bit of cpu headroom.

1 Like

That is good advice! I could probably do with a triangle wave for LFO.

But I am still amazed by the Daisy Seed performance. Right now I’ve got:

7 x synth tracks with filters, adsr, delay, lfo (filter cutoff), reverb send

1 x drum track with 2 osc’s doing pitch and amp envelopes, 4 noise gen’s running filter and adsr, reverb send

1 x mixer that pans and “gains” all tracks AND sends an adjustable amount to a global reverb

all controlled by a sequencer controlled by the Metro class.

Awesome!!!

1 Like

Right now I am running them every 10th sample, it made a difference.

Or someone could can give everyone a free CPU upgrade finally :wink: No problems noticed while running on stock frequency for last few months on OWL.