StackThreads/MP: version 0.77 User's Guide
We must make sure that a procedure call expression that appears in
ST_THREAD_CREATE
is not inline-expanded. For example, when you write
ST_THREAD_CREATE(f(x))
, you must make sure procedure call f(x)
is not inlined by gcc
. When this condition holds, separate stack
frames are allocated for f and the caller of f. StackThreads/MP
runtime can then execute f and the caller in parallel by executing
the two frames on different processors. This is impossible if
f(...)
is inlined, because their stack frames are
merged. stgcc
command automatically disables inlining by giving
gcc
suitable options (-fno-inline-functions
for normal functions
and -fno-default-inline
for C++ member functions defined in a class
definition). This is safe, but sometimes results in a noticeable
slowdown compared to gcc
, particularly for C++ programs.
Giving -fno-inline-functions
and -fno-default-inline
are very
pessimistic, because we only have to make sure that inlining won't occur
on parallel calls (ST_THREAD_CREATE
). Inlining normal procedure
calls are no problem, but the problem is we have no way to prohibit
inlining of designated call sites. Here are a couple of suggestions to
enable inlining sequential calls.
inline
keyword for functions that
are called only sequentially. These functions are subject of inlining
even when -fno-inline-functions
and -fno-default-inline
are
given.
inline
keyword is onerous (as is typically
the case in C++ programs), and if you are sure that procedures called
with ST_THREAD_CREATE
are never inlined somehow, you can supply
--inline_functions_is_ok
and --default_inline_is_ok
to
stgcc
. This enables inlining by stgcc
. The remaining problem is
how do you make sure that procedure calls in ST_THREAD_CREATE
are
never inline-expanded.
In practice, GCC/G++ never inline-expands procedure calls whose function
part is not a simple function name. For example, in the following
example, procedure call f(x)
is likely to be expanded.
int f(int x) { return x + 1; } g(int x) { return 2 * f(x); }
On the other hand, the following procedure call is, in practice, never inline-expanded. Therefore you can always make sure that inlining won't occur by calling a function through a function pointer.
@ int f(int x) { return x + 1; } @ @ g(int x) @ { @ int (*pf)(int) = f; @ return 2 * pf(x); @ }
In this way, for all procedures whose definitions are visible in the
same compilation unit, you can make the call performed through a
function pointer. The above code does not compile if the declaration of
f
were not given, but in this case the gcc
does not
inline-expand the call either.
To summarize, if the called function is not a simple function name, the
procedure call won't be inlined. If the called function is a simple
function name and its definition is not known in the compilation unit,
again gcc
does not inline it. Finally, if the definition is known,
you can obscure the called function by transforming the function call in
the way described above.