Performance of double precision math lazarus / 62-General ---------------------------------------------------------------------- EdwinV · 2016-05-18 15:25 I'm using a numerical simulation program written in Pascal and originally compiled with GPC. Since GPC appears to be a dead end, I've been looking at other compilers to take over. My first attempt was the Delphi XE2 compiler that I'm still using for other things. It took a few days to get it to build, but got everything to work properly. Then it was time for a performance test. A representative test case run with the 2004 GPC (bases on GCC 3.2.3) ran in 7.3 seconds. The Delphi version required over 14 seconds. Scratch Delphi. Now I turned to FPC with its many options for code generation for modern CPU. I did a fair amount of trials and the biggest gain was turning SSE 4.2 on. Eventually I used these options: -O4 -CfSSE42 -OpCOREAVX -OoFASTMATH End result: a rather unimpressive 8.3 seconds. So how is it possible that a supposedly modern compiler with loads of optimisation features and support for modern instruction sets can't manage to beat a 2004 compiler? Am I missing something or is it just a testament to the quality of the code generated by GPC/GCC? If you have any tips or insights I'd be happy to hear them! ---------------------------------------------------------------------- marcov · 2016-05-18 15:45 Look at the generated assembler. Maybe GPC vectorizes. Actually coming that close is not bad, usually FPC comes in behind Delphi. Is the benchmarked code simple or relatively complex? ---------------------------------------------------------------------- EdwinV · 2016-05-18 16:10 Pretty complex (total thing is about 7 MB of code). A lot of it is matrix factorization, which in addition to calculations also does a lot of memory reads/writes. I could look at the asm if I have time. But knowing how it does it doesn't really help me. Then I may as well keep building it with GPC for as long as it will run. ---------------------------------------------------------------------- Jonas Maebe · 2016-05-18 17:15 Quote from: EdwinV on May 18, 2016, 06:10:59 pmI could look at the asm if I have time. But knowing how it does it doesn't really help me. Then I may as well keep building it with GPC for as long as it will run. It may help you if it results in FPC generating equally performant code by the time GPC doesn't run anymore... ---------------------------------------------------------------------- EdwinV · 2016-05-19 11:41 Good point. I'll have to see if I can profile the two first. Otherwise it will be a needle in a haystack. ---------------------------------------------------------------------- Thaddy · 2016-05-19 12:22 You specify a AVX cpu, yet you specify SSE4.2 as fpu? Why not specify AVX or AVX2 as fpu? That should be considerably more performant. More specifically alignment issues are no longer an issue.... e.g.: Supported FPU instruction sets:   SSE64,SSE3,SSSE3,SSE41,SSE42,AVX,AVX2 Supported FPU instruction sets:   X87,SSE,SSE2,SSE3,SSSE3,SSE41,SSE42,AVX,AVX2 ---------------------------------------------------------------------- EdwinV · 2016-05-19 13:43 AVX2 restricts the allowable CPUs too much. AVX would have been acceptable, but wouldn't compile. I'll make a bug report when I have time to investigate. It shouldn't be too hard because it was an error from the assembler. ---------------------------------------------------------------------- Thaddy · 2016-05-19 14:54 I never have trouble with AVX. I DO often have trouble with alignment issues due to the moronic memory manager (You should always check alignment by hand, otherwise you'll end up with a cache stall more often than not). For AVX(+) that does not matter. The default memory manager is moronic because it aligns the allocated memory including the lead-in "administrative" part and forgets that it should align the payload...  Oh, well, I get angry every time. So you will almost never end up with the alignment you want and have to force it for MMX and SS(X). Worse, the compiler itself is completely unaware of this crippling issue..... and happily generates mmx or sse+ code when asked... at the wrong alignment... That's sick. That's also a big part of FPC loosing out in compiler shootouts. Replace the damn thing with something more performant. ---------------------------------------------------------------------- EdwinV · 2016-05-20 10:13 I did another try. With AVX2 I get the following error: Error: Asm: [vsqrtsd xmmreg,xmmreg,mem128] invalid combination of opcode and operands The code on the line in question is just "n:=sqrt(n);", where n is of type real. To try and get some more info on context I added "-a" to the command line. However, no error this time and a working executable was produced. The asm line in question was now compiled as: vsqrtsd   16(%esp),%xmm0,%xmm0 All in all, it didn't help for performance though, 8.2 seconds. I suppose this means that alignment problems are not to blame here. ---------------------------------------------------------------------- Thaddy · 2016-05-20 10:27 No, in the case of AVX that should not matter too much, since microcode should take care of alignment issues. But: Try cmem as the memory manager. That will align properly at the cost of more memory use. Add it as the first unit in your project file. This will perform. ( I am a heretic, but it is simply true) Plz report back... Note this one should not happen: Error: Asm: [vsqrtsd xmmreg,xmmreg,mem128] invalid combination of opcode and operands I can't reproduce that with trunk x86_64-win64 ---------------------------------------------------------------------- Jonas Maebe · 2016-05-20 10:31 Quote from: Thaddy on May 20, 2016, 12:27:40 pmTry cmem as the memory manager. That will align properly at the cost of more memory use. No, it won't. In fact, using cmem may well decrease the memory alignment due to the way cmem is implemented and the requirement to support memsize(). ---------------------------------------------------------------------- Thaddy · 2016-05-20 10:36 Quote from: Jonas Maebe on May 20, 2016, 12:31:25 pmQuote from: Thaddy on May 20, 2016, 12:27:40 pmTry cmem as the memory manager. That will align properly at the cost of more memory use. No, it won't. In fact, using cmem may well decrease the memory alignment due to the way cmem is implemented and the requirement to support memsize(). Ok I'll setup some tests over the weekend. And see if I can come up with a properly aligning memory manager. Which means the payload should be aligned. Which it isn't at the moment. But for AVX(+) that should not matter. ---------------------------------------------------------------------- MathMan · 2016-05-20 11:22 Quote from: Thaddy on May 20, 2016, 12:36:02 pmQuote from: Jonas Maebe on May 20, 2016, 12:31:25 pmQuote from: Thaddy on May 20, 2016, 12:27:40 pmTry cmem as the memory manager. That will align properly at the cost of more memory use. No, it won't. In fact, using cmem may well decrease the memory alignment due to the way cmem is implemented and the requirement to support memsize(). Ok I'll setup some tests over the weekend. And see if I can come up with a properly aligning memory manager. Which means the payload should be aligned. Which it isn't at the moment. But for AVX(+) that should not matter. Thaddy - if you're going at it anyway. Would you consider looking at a memory manager that aligns the payload to 64 bytes? 32 byte alignment will be sufficient for AVX/AVX2 but the upcoming AVX512 will need 64 byte alignment of payload. Beside that alignment has a hughe impact on performance. Up to the most recent incarnation of Core I (Skylake) the non-aligned operations (e.g. movdqu vs. movdqa) could incure penalties of several clock cycles (for each operation). It has been lessend with Skylake but I do see (in my benchmarks) differences of up to 50%. Regards, MathMan ---------------------------------------------------------------------- Thaddy · 2016-05-21 09:32 That's exactly what I plan to do: arbitrary alignment ON THE PAYLOAD. Finally. Takes some time but I have already started and memory managers are definitely not new to me. But plz note that on Skylake (as per its specifications) there should not be ( or a small) performance penalty, because the processor takes care of proper alignment anyway. Just MMX and SSE(x) are really affected by alignment issues. ---------------------------------------------------------------------- MathMan · 2016-05-23 09:30 Quote from: Thaddy on May 21, 2016, 11:32:38 amThat's exactly what I plan to do: arbitrary alignment ON THE PAYLOAD. Finally. Takes some time but I have already started and memory managers are definitely not new to me. But plz note that on Skylake (as per its specifications) there should not be ( or a small) performance penalty, because the processor takes care of proper alignment anyway. Just MMX and SSE(x) are really affected by alignment issues. Good to hear - let me know if I can be of assistance (e.g. porting to assembler or such). Regarding the other point - maybe we are talking cross-purposes here. If you like we can take this offline and I'll explain in detail. Kind regards, MathMan ---------------------------------------------------------------------- marcov · 2016-05-23 09:48 (if your main buffers are allocated through a routine, e.g. newvector() or something like that, adapting that routine to get a slightly larger block and then aligning the pointer manually might help. Of course you need to revert that again for the freemem. I do this for my own image type) ---------------------------------------------------------------------- Thaddy · 2016-05-23 10:08 Yes, I use a similar scheme. But this can be transferred to the memory manager by a slightly modified maintenance record at a negative offset (that is ideally also modulo alignment = 0 or respects default alignment). Problem is: it is a global setting that needs to be respected. I haven't quite decided on which approach is best. In both cases the negative offset can be calculated from the payload. ---------------------------------------------------------------------- FPK · 2016-06-01 20:57 Quote from: EdwinV on May 20, 2016, 12:13:00 pmI did another try. With AVX2 I get the following error: Error: Asm: [vsqrtsd xmmreg,xmmreg,mem128] invalid combination of opcode and operands I hope rev. 33877 fixes this.