From the original SynthMaker forum (2004–2014), with its members’ names and dates.
treacherousumbrella ·
Currently working on quite a CPU intensive audio effect, I'm aware of the usual CPU savings to be had by doing as many calculations as possible in green, reducing graphics refresh rates and stream lining ASM but could do with making savings wherever possible to cut down the CPU use.
Is there any benefit to be had from using the non packed opcodes such as fadd, fmul etc instead of the packed stream opcodes?
How do you convert from the packed stream into mono stream values?
Any other optimisation tips you find useful?
If anyone has a simple example in ASM it would be much appreciated. Thanks 🙂
trogluddite ·
Hi there,
If your code is working well using the packed SSE opcodes then switching to the FPU (unpacked) opcodes is unlikely to make your code any faster - even for mono signals where only one channel needs processing. If you are using more than one channel (mono4), it will make things much less efficient, as the processing has to then be done deparately for each stream - requiring a much longer code.
If you have sections of code that are already FPU based (e.g. array access, some maths functions), then you can make some savings by deleting the FPU instructions for any unpacked channels that you aren't using.
The unpacked channels are denoted by numbers in square brackets: [0], [1], [2], [3] - the individual channel numbers can only be used with variables, not the xmm registers.
As an example, say you have only two mono signals (e.g. left and right). Seems wasteful to pack and unpack all four values - but assembly can be used to pack and unpack just those two channels...
The CPU saving here is very small compared to just using the regular pack and unpack - but I have made good savings with this technique when; (a) there is lots of packing, and (b) values don't change often, so the packing can be hopped.
Mostly it is just an example to show how the channel numbers are used - if the main body of the code used any FPU opcodes already, then any instructions using channel {2} or [3] would be fair game for deleting.
Hopefully, it also shows why using the FPU is a bad idea when it isn't really needed - as well as all the extra instructions, it always involves a lot of temporary variables. Using the minimum number of variables is always a good idea, as accessing memory (even the cache), costs a lot more CPU cycles than register-only operations - plus extra variables increase the chances of cahe pollution, leading to even slower memory access.
treacherousumbrella ·
Thanks, that's some really useful information and good example code.
Discovered your post on shufps which has helped cut down on a lot of packing/unpacking and also selectors with the jz code.
This post on the wiki seems to suggest that packed calculations are more efficient in almost every circumstance: [old link]
Managed to shave an extra few percent off so thanks again 🙂
trogluddite ·
No problem. 🙂
BTW) One important point for anyone considering editing any FPU instructions - e.g. to remove unused channels.
The FPU uses a stack to pass parameters in and out, for example...
fld X[0]; //Pushes a value onto the stack
fld Y[0];
fadd; //pops the top two values, adds them, and pushes the result.
fstp Sum[0]; //Pops a value off the stack (result of X+Y)
This makes it very easy to crash SM if the number of values pushed isn't the same as the number popped - so take care out there!!
Wrote something here? To have a post removed or your name hidden, write to [email protected].