0

I have some code in a header, which is a library shared between multiple projects. The code is templated, so it cannot be moved to a separate source file. As this project is for a small embedded microcontroller, code size is important. As it happens, in one of the projects, a certain function gets inlined many times over, wasting a lot of code space since in this case speed isn't really important.

I can solve this problem immediately by prefixing the function in question with __attribute__ ((noinline)) in the library. However, this then prevents inlining in all the other projects too.

Question: what's the most elegant way to prevent inlining in one project only? The only thought I have now is with macros that need to be defined before including the file, which is possible but a bit messy.

Timo
  • 739
  • 1
  • 6
  • 13
  • 1
    [Explicit instantiation](https://stackoverflow.com/questions/2351148/explicit-template-instantiation-when-is-it-used) might help. – Jarod42 Mar 09 '21 at 12:57
  • I think if you want the *same* code to compile differently in *different* projects, then you'll have to use some sort of macro (or related pre-processor tricks) - but that could be defined (or not) on the command line (for each project), rather than using conditional `#ifdef...` blocks. – Adrian Mole Mar 09 '21 at 13:22
  • You should probably optimize for size `-Os` and not for speed. In this case, the compiler should only inline functions if that saves code size. – prapin Mar 09 '21 at 14:31
  • @prapin speed is only unimportant for this specific function in this specific case: it initiates I/O, which is then waited for, i.e. we block right after the call anyway. Elsewhere in the same project speed is quite important. – Timo Mar 09 '21 at 16:10
  • @Timo Performance difference between code optimized for speed and for size is not big: most code optimizations techniques (except of course inlining) do decrease simultaneously code size and CPU time. On the embedded system I worked in my previous job (a MIPS processor with only 4 kiB of cache), it happened that code optimized for size was actually _faster_ than that optimized for speed! Because the cache was so small, decreasing code fetch was a more significant boost than the number of instructions executed. – prapin Mar 09 '21 at 19:09
  • @prapin sure, but since this is a small part (essentially a production test) of a larger project which has already been tested quite thoroughly, I'd rather not change the optimization settings projectwide, since then we'd need to check again that the performance is adequate everywhere. Though that does lead me to think of changing the optimization for the production test code only... – Timo Mar 10 '21 at 08:18

1 Answers1

0

__attribute__ ((noinline)) is part of the application source code. Differences in source code for different platforms are solved using

  • preprocessor macros
  • code generation tools
  • different source files for different platforms

For example, you can define a macro PREFER_SMALL_CODE_SIZE and then

#ifdef PREFER_SMALL_CODE_SIZE
#  define COND_INLINE __attribute__ ((noinline))
#else
#  define COND_INLINE
#endif

class MyClass {
  COND_INLINE void my_func() { /* ... */ }
};

Now when compiled with -DPREFER_SMALL_CODE_SIZE, the code should be smaller.

It may be "messy", but IMHO there is no other way.

Another option is to compile with -fno-inline-small-functions. But it's probably too inflexible.

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • I believe this is the "macros that need to be defined before including the file" solution the author identified as messy and was looking for alternatives. – L. Scott Johnson Mar 09 '21 at 13:31
  • You could simplify this using `#ifndef COND_INLINE ... #define COND_INLINE...` and then use a `/DCOND_INLINE="__attribute__ ((noinline))"` (or equivalent) switch on the command line for project needing the attribute. (Though that may not be considered 'simplifying' by some!) – Adrian Mole Mar 09 '21 at 13:34