8 ms·
Interestingly, Casey Muratori accidentally demonstrates during one of his Handmade Hero sessions that the compiler won't always be able to optimize certain bits
by lj3 10y ago
Interestingly, Casey Muratori accidentally demonstrates during one of his Handmade Hero sessions that the compiler won't always be able to optimize certain bits of code that are put in a function as opposed to being inline.
In the video, he inlines a very simple function and his game gets twice as fast for no apparent reason. It's instructive to watch him dive into the generated assembly to figure out why.
https://www.youtube.com/watch?v=B2BFbs0DJzw https://www.youtube.com/watch?v=B2BFbs0DJzw
- sitkack 10y agoTIL, another reason to perform 'defactor inline-method' (with directed feedback of course).
- Longwelwind 10y agoI'm not sure it should be considered as a reason for anything. The most important point of the article, imo, is: If a function is only called from a single place, consider inlining it. You should consider inlining your function, not always do it. Recently, I made a mod for a game and I had to draw an UI by code, and there, it made sens to use one-time function because it made the code easier to read (super-expressive functions like DrawLeftPane() or DrawHeader(), and next to no ties between functions). Most of the time, code readability should be prioritized over performance.
- sitkack 10y agoTotally agree, but in perf critical inner loops, it might be interesting to speculatively inline different functions and measure perf. Overly factored code inside an inner loop has been shown in the video to cause compiler confusion.
- sqeaky 10y agoPeople write perf intensive inner loops so infrequently that this really ought to be discounted as an argument. I work in two performance sensitive projects, both C++, and this has yet to be a reason to inline code. Algorithm choice is optimization of choice first and so far finally.
- jackmott 10y agoAnother example to set aside for the next "So you think you are smarter than the compiler" person.
- Pfhreak 10y agoIs that a helpful response to that person? Isn't that person (despite sounding like an ass) more or less right at any given time? Excepting environments where performance is critical (games comes to mind), shouldn't we bias toward improving the code for human readability?
- AstralStorm 10y agoTechnically, you could have some stronger keyword than inline in future C and C++ standards, akin to constexpr. For hard inlining always. For now, there are macros if an inline function does not work properly. Attributes to force inlining exist in some compilers, at least GCC and clang support those. Additionally marking the function as pure if applicable can help optimisers as well.
- AndrewGaspar 10y ago__forceinline in MSVC.
- niedzielski 10y agoThis is still a suggestion https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
- AstralStorm 10y agoThat usually works, with caveats as mentioned on page. (Security attributes and recursive calls that may remain recursive calls instead of stack utilising loops.) GCC and clang variants do not have this issue. MSVC is generally not really known for high performance of generated code, which is partly why newest versions support a clang backend.
- imtringued 10y agoThe compiler probably turned for(int I = 0; I < 4; ++I) { real32 PixelPx = (real32)(XI + I); real32 PixelPy = (real32)Y; real32 dx = PixelPx - Origin.x; real32 dy = PixelPy - Origin.y; real32 U = dx*nXAxis.x + dy*nXAxis.y; real32 V = dx*nYAxis.x + dy*nYAxis.y; //rest of the loop } into something like real32 PixelPy = (real32)Y; real32 dy = PixelPy - Origin.y; real32 PixelPx = (real32)(XI); real32 dx = PixelPx - Origin.x; real32 U = dx*nXAxis.x + dy*nXAxis.y; real32 V = dx*nYAxis.x + dy*nYAxis.y; for(int I = 0; I < 4; ++I) { U += nXAxis.x; V += nYAxis.x; //rest of the loop } PixelPy and dy are not affected by the counter in the loop which means they can safely moved outside the loop. This also results in the subexpression dynXAxis.y and dynYAxis.y being lifted outside the loop. Now we've moved half of the code outside the loop but we aren't done yet. The same can be done with PixelPx and dx, the trick is to then replace dxnXAxis.x with (dx + I)*nXAxis.x Expanding (dx + I)*nXAxis.x yields dx*nXAxis.x + I*nXAxis.x We can now lift the subexpression dx*nXAxis.x out of the loop. The only thing that is now done in the loop is I*nXAxis.x which can be further simplified to U += nXAxis.x The same happens with nYAxis.x. EDIT: Sorry for the bad formatting. The markdown parser ate my asterisks so I put things into code blocks which requires a new line each time.
- Lerc 10y agoEffectively this means the speedup comes from optimizations that assume the code in question is only ever run in that context. When the code is inline this is an easy call to make. For a function it's trickier. I would hope some compilers make a function to handle arbitrary contexts but try inlining on individual cases to see if significant gains such as this can be made. It's another hurdle for the sufficiently smart compiler though. You need to know how the program will be run to know which is the better form. Once you get into making code-size Vs speed things get murky with instruction caches etc.
- Manozco 10y agohaving const parameters in the function V2i might have helped the compiler I think