When should I use __forceinline instead of inline?
Asked Answered
S

13

47

Visual Studio includes support for __forceinline. The Microsoft Visual Studio 2005 documentation states:

The __forceinline keyword overrides the cost/benefit analysis and relies on the judgment of the programmer instead.

This raises the question: When is the compiler's cost/benefit analysis wrong? And, how am I supposed to know that it's wrong?

In what scenario is it assumed that I know better than my compiler on this issue?

Schmitz answered 30/9, 2008 at 5:58 Comment(0)
H
29

The compiler is making its decisions based on static code analysis, whereas if you profile as don says, you are carrying out a dynamic analysis that can be much farther reaching. The number of calls to a specific piece of code is often largely determined by the context in which it is used, e.g. the data. Profiling a typical set of use cases will do this. Personally, I gather this information by enabling profiling on my automated regression tests. In addition to forcing inlines, I have unrolled loops and carried out other manual optimizations on the basis of such data, to good effect. It is also imperative to profile again afterwards, as sometimes your best efforts can actually lead to decreased performance. Again, automation makes this a lot less painful.

More often than not though, in my experience, tweaking alogorithms gives much better results than straight code optimization.

Hoof answered 30/9, 2008 at 6:49 Comment(0)
A
71

You know better than the compiler only when your profiling data tells you so.

Adelinaadelind answered 30/9, 2008 at 6:3 Comment(4)
Should be the top answer ;)Cherin
While this answer has a good point, it does not say anything about inlining.Vodka
@Vodka It directly answers the question posed in the question. It no more says nothing about inlining than "yes" as an answer to "do you like apples" says nothing about apples.Indocile
This is too terse to be a sensible answer. The people who know the value of profiling will agree that the statement is true, but for the people who don't know the value it really needs to be explicitly stated, as @SmacL's answer does.Mikiso
M
37

The one place I am using it is licence verification.

One important factor to protect against easy* cracking is to verify being licenced in multiple places rather than only one, and you don't want these places to be the same function call.


*) Please don't turn this in a discussion that everything can be cracked - I know. Also, this alone does not help much.

Marte answered 26/10, 2008 at 20:56 Comment(4)
I am planning to use __foceinline for the very same reason. Can you be 100% that it will be inlined when using __forceinline. I am in doubt since msdn also says: "You cannot force the compiler to inline a particular function, even with the __forceinline keyword. "Laryngoscope
@Koray: you should check the generated code. In my experience, yes, ti works even for gigantic functions. One exception (IIRC) are functions with variable arguments, and it's likely that the documentation refers to that.Marte
@mentat: You can't be 100% sure, but you can let yourself be warned. Warning C4714 will do so - it is a debug level 4 warning, so depending on your settings needs to be explicitly enabled.Fagen
@Marte another possibility is that the docs are merely accounting for the fact that recursive functions (usually) cannot be completely inlined in themselvesShani
H
29

The compiler is making its decisions based on static code analysis, whereas if you profile as don says, you are carrying out a dynamic analysis that can be much farther reaching. The number of calls to a specific piece of code is often largely determined by the context in which it is used, e.g. the data. Profiling a typical set of use cases will do this. Personally, I gather this information by enabling profiling on my automated regression tests. In addition to forcing inlines, I have unrolled loops and carried out other manual optimizations on the basis of such data, to good effect. It is also imperative to profile again afterwards, as sometimes your best efforts can actually lead to decreased performance. Again, automation makes this a lot less painful.

More often than not though, in my experience, tweaking alogorithms gives much better results than straight code optimization.

Hoof answered 30/9, 2008 at 6:49 Comment(0)
A
12

I've developed software for limited resource devices for 9 years or so and the only time I've ever seen the need to use __forceinline was in a tight loop where a camera driver needed to copy pixel data from a capture buffer to the device screen. There we could clearly see that the cost of a specific function call really hogged the overlay drawing performance.

Amanda answered 2/10, 2008 at 9:17 Comment(0)
T
7

The only way to be sure is to measure performance with and without. Unless you are writing highly performance critical code, this will usually be unnecessary.

Transform answered 30/9, 2008 at 6:2 Comment(0)
G
4

For SIMD code.

SIMD code often uses constants/magic numbers. In a regular function, every const __m128 c = _mm_setr_ps(1,2,3,4); becomes a memory reference.

With __forceinline, compiler can load it once and reuse the value, unless your code exhausts registers (usually 16).

CPU caches are great but registers are still faster.

P.S. Just got 12% performance improvement by __forceinline alone.

Gildagildas answered 7/10, 2018 at 9:39 Comment(2)
Why would inline not be sufficient in these cases?Odyl
@einpoklumn Because inline is mostly used as an linker directive to give a symbol weak linkage. It is also another parameter to the compiler's inlining heuristics (along with a heap of different compiler flags). inline does not inline code it only hints that to the compiler. Only way to actually inline code is to use compiler specific forceinline decoration.Vodka
M
3

The inline directive will be totally of no use when used for functions which are:

recursive, long, composed of loops,

If you want to force this decision using __forceinline

Misusage answered 6/6, 2009 at 18:3 Comment(0)
U
3

Actually, even with the __forceinline keyword. Visual C++ sometimes chooses not to inline the code. (Source: Resulting assembly source code.)

Always look at the resulting assembly code where speed is of importance (such as tight inner loops needed to be run on each frame).

Sometimes using #define instead of inline will do the trick. (of course you loose a lot of checking by using #define, so use it only when and where it really matters).

Uzia answered 1/2, 2013 at 7:12 Comment(1)
Actually, there's no need to check the assembler (not that it hurts much either). VS has a warning for that - C4714.Imposture
F
2

Actually, boost is loaded with it.

For example

 BOOST_CONTAINER_FORCEINLINE flat_tree&  operator=(BOOST_RV_REF(flat_tree) x)
    BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value ||
                        allocator_traits_type::is_always_equal::value) &&
                         boost::container::container_detail::is_nothrow_move_assignable<Compare>::value)
 {  m_data = boost::move(x.m_data); return *this;  }

 BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const
 { return static_cast<const value_compare &>(this->m_data); }

 BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp()
 { return static_cast<value_compare &>(this->m_data); }

 BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const
 { return this->priv_value_comp().get_comp(); }

 BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp()
 { return this->priv_value_comp().get_comp(); }

 public:
 // accessors:
 BOOST_CONTAINER_FORCEINLINE Compare key_comp() const
 { return this->m_data.get_comp(); }

 BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const
 { return this->m_data; }

 BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const
 { return this->m_data.m_vect.get_allocator(); }

 BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const
 {  return this->m_data.m_vect.get_stored_allocator(); }

 BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator()
 {  return this->m_data.m_vect.get_stored_allocator(); }

 BOOST_CONTAINER_FORCEINLINE iterator begin()
 { return this->m_data.m_vect.begin(); }

 BOOST_CONTAINER_FORCEINLINE const_iterator begin() const
 { return this->cbegin(); }

 BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const
 { return this->m_data.m_vect.begin(); }
Fagen answered 18/9, 2017 at 14:33 Comment(0)
L
1

There are several situations where the compiler is not able to determine categorically whether it is appropriate or beneficial to inline a function. Inlining may involve trade-off's that the compiler is unwilling to make, but you are (e.g,, code bloat).

In general, modern compilers are actually pretty good at making this decision.

Linettelineup answered 30/9, 2008 at 6:10 Comment(0)
M
1

When you know that the function is going to be called in one place several times for a complicated calculation, then it is a good idea to use __forceinline. For instance, a matrix multiplication for animation may need to be called so many times that the calls to the function will start to be noticed by your profiler. As said by the others, the compiler can't really know about that, especially in a dynamic situation where the execution of the code is unknown at compile time.

Merrow answered 25/1, 2013 at 18:43 Comment(0)
H
0

wA Case For noinline

I wanted to pitch in with an unusual suggestion and actually vouch for __noinline in MSVC or the noinline attribute/pragma in GCC and ICC as an alternative to try out first over __forceinline and its equivalents when staring at profiler hotspots. YMMV but I've gotten so much more mileage (measured improvements) out of telling the compiler what to never inline than what to always inline. It also tends to be far less invasive and can produce much more predictable and understandable hotspots when profiling the changes.

While it might seem very counter-intuitive and somewhat backward to try to improve performance by telling the compiler what not to inline, I'd claim based on my experience that it's much more harmonious with how optimizing compilers work and far less invasive to their code generation. A detail to keep in mind that's easy to forget is this:

Inlining a callee can often result in the caller, or the caller of the caller, to cease to be inlined.

This is what makes force inlining a rather invasive change to the code generation that can have chaotic results on your profiling sessions. I've even had cases where force inlining a function reused in several places completely reshuffled all top ten hotspots with the highest self-samples all over the place in very confusing ways. Sometimes it got to the point where I felt like I'm fighting with the optimizer making one thing faster here only to exchange a slowdown elsewhere in an equally common use case, especially in tricky cases for optimizers like bytecode interpretation. I've found noinline approaches so much easier to use successfully to eradicate a hotspot without exchanging one for another elsewhere.

It would be possible to inline functions much less invasively if we could inline at the call site instead of determining whether or not every single call to a function should be inlined. Unfortunately, I've not found many compilers supporting such a feature besides ICC. It makes much more sense to me if we are reacting to a hotspot to respond by inlining at the call site instead of making every single call of a particular function forcefully inlined. Lacking this wide support among most compilers, I've gotten far more successful results with noinline.

Optimizing With noinline

So the idea of optimizing with noinline is still with the same goal in mind: to help the optimizer inline our most critical functions. The difference is that instead of trying to tell the compiler what they are by forcefully inlining them, we are doing the opposite and telling the compiler what functions definitely aren't part of the critical execution path by forcefully preventing them from being inlined. We are focusing on identifying the rare-case non-critical paths while leaving the compiler still free to determine what to inline in the critical paths.

Say you have a loop that executes for a million iterations, and there is a function called baz which is only very rarely called in that loop once every few thousand iterations on average in response to very unusual user inputs even though it only has 5 lines of code and no complex expressions. You've already profiled this code and the profiler shows in the disassembly that calling a function foo which then calls baz has the largest number of samples with lots of samples distributed around calling instructions. The natural temptation might be to force inline foo. I would suggest instead to try marking baz as noinline and time the results. I've managed to make certain critical loops execute 3 times faster this way.

Analyzing the resulting assembly, the speedup came from the foo function now being inlined as a result of no longer inlining baz calls into its body.

enter image description here

I've often found in cases like these that marking the analogical baz with noinline produces even bigger improvements than force inlining foo. I'm not a computer architecture wizard to understand precisely why but glancing at the disassembly and the distribution of samples in the profiler in such cases, the result of force inlining foo was that the compiler was still inlining the rarely-executed baz on top of foo, making foo more bloated than necessary by still inlining rare-case function calls. By simply marking baz with noinline, we allow foo to be inlined when it wasn't before without actually also inlining baz. Why the extra code resulting from inlining baz as well slowed down the overall function is still not something I understand precisely; in my experience, jump instructions to more distant paths of code always seemed to take more time than closer jumps, but I'm at a loss as to why (maybe something to do with the jump instructions taking more time with larger operands or something to do with the instruction cache). What I can definitely say for sure is that favoring noinline in such cases offered superior performance to force inlining and also didn't have such disruptive results on the subsequent profiling sessions.

So anyway, I'd suggest to give noinline a try instead and reach for it first before force inlining.

Human vs. Optimizer

In what scenario is it assumed that I know better than my compiler on this issue?

I'd refrain from being so bold as to assume. At least I'm not good enough to do that. If anything, I've learned over the years the humbling fact that my assumptions are often wrong once I check and measure things I try with the profiler. I have gotten past the stage (over a couple of decades of making my profiler my best friend) to avoid completely blind stabs at the dark only to face humbling defeat and revert my changes, but at my best, I'm still making, at most, educated guesses. Still, I've always known better than my compiler, and hopefully, most of us programmers have always known this better than our compilers, how our product is supposed to be designed and how it is is going to most likely be used by our customers. That at least gives us some edge in the understanding of common-case and rare-case branches of code that compilers don't possess (at least without PGO and I've never gotten the best results with PGO). Compilers don't possess this type of runtime information and foresight of common-case user inputs. It is when I combine this user-end knowledge, and with a profiler in hand, that I've found the biggest improvements nudging the optimizer here and there in teaching it things like what to inline or, more commonly in my case, what to never inline.

Hegira answered 28/9, 2020 at 0:50 Comment(0)
B
0

One other possibility that I don't think has been discussed is that you may wish to use __forceinline or __noinline when you want to ensure you have control of the decisions the compiler is making.

Suppose you have a function like _ReturnAddress (or, in Gnuville, __builtin_frame_address) where the result depends on the presence or absence of a stack frame. Instead of telling the compiler, "inline this or not, whatever you decide is fine." you might want to be explicit about how many stack frames get created around that call.

Either mechanic could probably work -- you could write code for either the no-inline case or for the yes-inline case. It's just a matter of choosing the best one.

Bittersweet answered 12/11, 2023 at 18:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.