Server response time

I am trying to measure the roundtrip time of:
‘message to server - getting message back from server’.

So first question, is this a meaningful way of measuring the roundtrip?

(
s.waitForBoot{
	SynthDef(\test, { SendReply.kr(\trig.tr(0)) }).add;
	s.sync;
	~synth = Synth(\test);
	~osc.free;
	~osc = OSCFunc({ ("roundtrip in ms: " + (Main.elapsedTime - ~time * 1000)).postln }, '/reply');
}
)

( // Run several times. On my macBook M1 I get everything from 0.5 - 10 ms)
~time = Main.elapsedTime;
~synth.set(\trig, 1)
)

// cleanup
(
~synth.free;
~osc.free;
)

And assuming this is a valid way of meassuring, why are the response times so inconsistent (0.5 - 10 ms on osx, M1)?

What I am really interested in is the oneway trip sclang - server. How long does it take to trigger a sound with 0 attack and how jittery is the timing? I can’t think of any way of measuring the oneway trip.

The round-trip is something like:

  1. time to transmit
  2. time until next audio wake-up (<= buffer duration)
  3. time to process buffer (<= buffer duration)
  4. time to transmit

The thing you probably really care about is #1 and #2 - I’m guessing the 0.5-1 ms is fully explained by #2 and #3. 0.5 ms is probably a buffer size of 256, so a 0.5ms - 1ms makes perfect sense for a 256 or 512 buffer sizes. I can ALMOST promise that the time to transmit to a local, in-process server is much less than the buffer size - any latency from this will be dwarfed by just waiting for the next audio block to process. I would venture to guess that the transmission time for a local server is small enough that you wouldn’t be able to hear the difference in onset times at ALL unless you had e.g. another event to compare to.

At the end of the day, you probably have a worst case latency of your buffer duration, and a best case of the time to transmit, which is likely to be microsecond range or less.

1 Like

@scztt - thanks a lot. Just to clarify, when you say ‘buffer duration’ is that blocksize/samplerate?

  1. time to transmit
  2. time until next audio wake-up (<= buffer duration)
  3. time to process buffer (<= buffer duration)
  4. time to transmit

One missing factor is language jitter!

I can ALMOST promise that the time to transmit to a local, in-process server is much less than the buffer size

Yes, sending UDP packets over localhost is a matter of microseconds.

Running sclang in both sc-ide and vscode:

vscode side (immediate fire-back):

n = NetAddr("127.0.0.1", 57120);

OSCdef(\x, { |msg| n.sendBundle(nil, msg) }, '/ping');

SC-IDE side:

n = NetAddr("127.0.0.1", 57121);

(
var now;

OSCFunc({
	(Main.elapsedTime - now).postln;
}, '/ping').oneShot;

now = Main.elapsedTime;
n.sendMsg(\ping);
)

Answer hovers around 0.0004 sec – network transmission time on localhost is negligible.

scztt is correct that the main factor is the hardware block size. Scsynth will receive the message essentially instantaneously, but it can’t perform the message until the next hardware block boundary.

It is not the control block size. When scsynth responds to an audio callback, it performs enough control blocks to fill up the hardware buffer, as fast as possible. It’s a common misconception that control blocks are performed monotonically:

HW buffer
1                       2

block -- note, this is NOT what happens
1  2  3  4  5  6  7  8  9  10 11 12...

It’s more like (if HW block = 512 and control block = 64):

HW buffer
1                       2

block
12345678                910111213141516

If a message arrives after control block 1 above has started processing, the earliest opportunity to respond is control block 9.

We get sub-control-block hardware-buffer timing by timestamping messages to be performed sometime after the next control block boundary (and for audio output, sub-control-block with a timestamp and OffsetOut).

hjh

1 Like

Yes, sorry, I meant the duration of the audio hardware buffer - this is listed as driver's block size = XXX when you boot the server. James’s is a much more detailed explanation here :slight_smile:

1 Like

Thank you all for taking the time to explain. After testing with the default hardware buffer size of 512 I tested with a hardware buffer size of 64 and indeed got roundtrip response time in the 0.5 - 1.5 ms range as expected. Really nice to know that the communication between sclang and server does not contribute to overall latency in any significant way.