Home > OS >  Is there any point in using __attribute__((noinline)) in a source file (not header file)?
Is there any point in using __attribute__((noinline)) in a source file (not header file)?

Time:10-12

Some programmers at my company have started sprinkling __attribute__((noinline)) in methods all over our code, in both header and source files. We do not use whole-program optimization. And in the vast majority of the cases I'm seeing, these methods are not calling other methods in the same source file ("translation unit"); the only callers of these "noinline" methods are (in most cases) methods in other source files.

I want to make a point that these __attribute__((noinline)) attribute markers are not doing anything and only clutter our code, but before I do that I just want to verify that I'm right:

Is there any benefit to marking a method "noinline" if its definition (code body) is...

  • in a source (.c or .cpp) file
  • not called by any other methods in that source file
  • and whole program optimization is not being used

...?

I.e., in the absence of whole-program optimization, could a compiler linker even inline a method defined as such (above bullet points) anyway?

CodePudding user response:

Is there any benefit to marking a method "noinline" if its definition (code body) is...

  • in a source (.c or .cpp) file
  • not called by any other methods in that source file
  • and whole program optimization is not being used

...?

The position of the attribute on the function / method definition instead of on a non-definition declaration is not necessarily relevant in the particular case of a noinline attribute, because in order for inlining to be performed, some form of the function's definition (which bears the attribute) must be available.

Certainly the function won't be inlined into any other functions in the same translation unit if no other functions in that unit call it in the first place, directly or indirectly.

The "whole program optimization is not being used" seems to be an attempt to stipulate that the function in question cannot be inlined into any other functions, either. In that case, the noinline attribute is, by assumption, unnecessary to prevent inlining of that function.

I.e., in the absence of whole-program optimization, could a compiler linker even inline a method defined as such (above bullet points) anyway?

This seems to be a question of semantics. I would categorize any optimization that crosses translation-unit boundaries as a "whole-program optimization". In that sense, then, no, a build process that does not perform any whole-program optimization will not perform the specific whole-program optimization of inlining a function from one TU into a function from a different TU.

Since you have not specified any details of your compilation procedure, we cannot speak to whether it is really true in your particular case that whole program optimzation is not being used, in the sense described above.


However, whether the attribute is necessary to prevent inlining of functions in your current code base is not the only consideration relevant to the "Is there any benefit?" question. Consider:

  • Whether the attribute is necessary to prevent inlining or not, it is effective at communicating the intent that the function should not be inlined.

  • In the event that your analysis of the code is wrong, or the code changes so that it no longer applies, the noinline attributes will provide for the desired inlining-suppression behavior.

Both of these are reminiscent of the nature and (proper) usage of assertions. If an assertion in my program ever triggers then that means a situation has arisen that I believed could not happen and assumed would not happen. Are assertions then just wasteful code? No, certainly not. They serve a documentary purpose (often supplemented with explanatory code comments), an error detection purpose, and often a failsafe purpose. Similar can be said of use of noinline under the circumstances you describe.

CodePudding user response:

Inlining can still happen within a source file. If a function is called after its definition, the compiler could inline it. So the attribute would prevent that.

Therefore, this attribute can still have useful effects in source files, to the extent that you need to turn off inlining.

CodePudding user response:

Regardless of the merits (of using noinline or not), I would use macros rather than peppering __attribute__((noinline)) everywhere.

And, the compiler can disable inlining via the command line (see below).


In my code, I sometimes want a function [usually defined in a .h file] that will always be inlined:

static inline __attribute__((always_inline))

That's relatively verbose [and error prone], so I define:

#define inline_always static inline __attribute__((always_inline))

I'm not a fan of the compiler deciding the inlining of a function for me, so I disable it from the command line:

-fno-inline-small-functions -fno-inline-functions-called-once -fno-inline-functions

That might be a safer/better alternative than changing function prototypes.


There is some merit to not inlining functions that have not been explicitly marked as inline.

For debugging and breakpoints.

The compiler's heuristic fails to produce the best code:

  1. It inlines something that provides little benefit from the inlining vs. the function call overhead.
  2. The inlining seems good to the compiler but the calling function's code is sub-optimal because it causes additional register pressure requiring that the registers be spilled [to the stack] more often.

For debug, we can compile with -O0 to disable compiler inlining of functions.

But, sometimes, we need to be able to put a [gdb] breakpoint on a function in code that has been compiled with optimization. If the function has been [auto] inlined, this won't work [too well].

So, either use -fno-inline et. al. or apply the macro to key functions as in:

#ifdef DEBUG_NOINLINE
#define noinline_debug      __attribute__((noinline))
#else
#define noinline_debug      /**/
#endif

Note that the Linux kernel uses such macros:

#define noinline __attribute__((noinline))
#define __always_inline inline __attribute__((__always_inline__))

This is useful in case a given compiler does not support a particular attribute:

#if __has_attribute(__nonstring__)
# define __nonstring                    __attribute__((__nonstring__))
#else
# define __nonstring
#endif

  •  Tags:  
  • c c
  • Related