? vs ??: The final showdown
[email protected] Wed, 16 May 2018 08:54:49 +0800
| Newsgroups | gmane.comp.audio.supercollider.devel |
|---|---|
| Message-ID | <[email protected]> |
In a github issue just now, the assertion came up again that "x ? y" might be faster than "x ?? { y }" -- which, based on my understanding of the interpreter, shouldn't be the case. So, let's run some tests.
(
var x = #[nil, 1].choose;
"\n\n? variant".postln;
{ x ? inf }.def.dumpByteCodes;
"\n\n?? variant".postln;
{ x ?? { inf } }.def.dumpByteCodes;
)
? variant
BYTECODES: (6)
0 21 00 PushTempVar 'x'
2 6F PushSpecialValue 'end'
3 8F 16 ControlOpcode
5 F2 BlockReturn
^^ Here, no matter which branch is taken, two values are pushed to the stack and a control opcode executed.
?? variant
BYTECODES: (8)
0 21 00 PushTempVar 'x'
2 8F 17 00 01 ControlOpcode 1 (6)
6 6F PushSpecialValue 'end'
7 F2 BlockReturn
^^ Here, no matter which branch, *one* value is pushed and a control opcode executed, and *maybe* another value is pushed. So, for ??, if the first operand is not nil, then we skip the second push. This should be faster.
Benchmarks: It is not reliable to run a single benchmark and assume correctness. You have to do multiple trials and checked some simple steps to have even a vague idea of the margin of error.
Initially, I tested a random distribution using wchoose -- but it turns out that wchoose itself performs differently depending on how many weights it has to skip over. That's significant enough to affect the results. So I'll do two tests for each operator: nil only, and non-nil only.
nil, ?: mean, median, min, max: [ 0.0089033373999769, 0.0089324304998399, 0.0081120800000463, 0.0098123490001853 ]
nil, ??: mean, median, min, max: [ 0.0087776425999891, 0.0088757224999654, 0.0078802929999711, 0.0097283939999215 ]
^^ In the best case for '?' (where we have to replace nil, forcing '??' to do the second push), '??' is still very slightly faster on average, though possibly within the margin of error.
1, ?: mean, median, min, max: [ 0.0091182382000056, 0.0091062014998897, 0.0079923820001113, 0.010048374000007 ]
1, ??: mean, median, min, max: [ 0.0084886964500129, 0.0083961775000034, 0.0076925020000544, 0.0095530910000434 ]
^^ When '??' can skip the second push, it's noticeably faster (as expected, considering the work that the interpreter is really doing).
So, let's please put this one to bed. 'x ?? { y }' is faster.
hjh
_______________________________________________
sc-dev mailing list
info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/