… continuing as normal I guess??
Perhaps this could be its own topic, but I think its deeply connected to what is being discussed, let me know and I’ll move it if needed!
I’ve figured out how the optimisation pass works a little better now and have been able to get it to reduce more additions into Sum3
s and Sum4
s.
It was a simple matter of altering BinaryOpUGen:optimize(Sum3|Sum4|MulAdd...)
to:
- stop checking that there is only one descendant
- stop removing the ‘input’.
- rerun optimizeGraph in SynthDef to retrigger the deadcode elimination.
This runs the risk of creating duplicates, which works well with the rest of @jamshark70’s code!
I think the optimisation passes could be rewritten. Its very odd that the graph (SynthDef) delegates to the nodes (UGen) to do all of the optimisation and mutate the state of the entire graph.
Dead code elimination is one such optimisation that could probably be done at the graph level.
Here are some examples.
A clear win.
SynthDef(\s, {
|a, b, c, d|
var sig = a + b;
Out.kr(1, sig + d);
Out.kr(0, sig + c);
}).dumpUGens
// Old
[0_Control, control, nil]
[1_+, control, [0_Control[0], 0_Control[1]]]
[2_+, control, [1_+, 0_Control[3]]]
[3_Out, control, [1, 2_+]]
[4_+, control, [1_+, 0_Control[2]]]
[5_Out, control, [0, 4_+]]
// New
[0_Control, control, nil]
[1_Sum3, control, [0_Control[3], 0_Control[1], 0_Control[0]]]
[2_Out, control, [1, 1_Sum3]]
[3_Sum3, control, [0_Control[2], 0_Control[1], 0_Control[0]]]
[4_Out, control, [0, 3_Sum3]]
A draw, perhaps?
SynthDef(\s, {
|a, b, c, d|
var sig = a + b;
Out.kr(1, sig + d);
Out.kr(0, sig + c);
Out.kr(4, sig);
}).dumpUGens
// old
[0_Control, control, nil]
[1_+, control, [0_Control[0], 0_Control[1]]]
[2_+, control, [1_+, 0_Control[3]]]
[3_Out, control, [1, 2_+]]
[4_+, control, [1_+, 0_Control[2]]]
[5_Out, control, [0, 4_+]]
[6_Out, control, [4, 1_+]]
// new
[0_Control, control, nil]
[1_+, control, [0_Control[0], 0_Control[1]]]
[2_Out, control, [4, 1_+]]
[3_Sum3, control, [0_Control[3], 0_Control[1], 0_Control[0]]]
[4_Out, control, [1, 3_Sum3]]
[5_Sum3, control, [0_Control[2], 0_Control[1], 0_Control[0]]]
[6_Out, control, [0, 5_Sum3]]
A clear win, but needs @jamshark70 duplicate removable to improve further.
SynthDef(\t, {
|a, b, c, d|
var com = a + b;
Out.kr(0, com + c);
Out.kr(1, com + c);
}).dumpUGens;
// old
[0_Control, control, nil]
[1_+, control, [0_Control[0], 0_Control[1]]]
[2_+, control, [1_+, 0_Control[2]]]
[3_Out, control, [0, 2_+]]
[4_+, control, [1_+, 0_Control[2]]]
[5_Out, control, [1, 4_+]]
// new
[0_Control, control, nil]
[1_Sum3, control, [0_Control[2], 0_Control[1], 0_Control[0]]]
[2_Out, control, [0, 1_Sum3]]
duplicate>> [3_Sum3, control, [0_Control[2], 0_Control[1], 0_Control[0]]]
[4_Out, control, [1, 3_Sum3]]
Again, all this is based on the assumption that Sum3 and Sum4 are cheap and that UGen calls are expensive.