467,169 Members | 1,004 Online
Bytes | Developer Community
Ask Question

Home New Posts Topics Members FAQ

Post your question to a community of 467,169 developers. It's quick & easy.

Inlined functions in mixed mode C++

Hi,

We've found some pretty serious performance hits that we didn't expect in a
mixed mode C++ application. The number crunching bits of our algorithms are
compiled with #pragma unmanaged. They call a number of inline functions
elsewhere, and from the documentation my understanding was that inlined
function calls are supposed to be effectively replaced by their
implementation at compile time. This would mean that inline functions used
in a #pragma unmanaged function would also be compiled unmanaged.

However, having written a short test, this appears not to be the case -
putting #pragmas in the header affects how the inlined functions are
compiled (and affects running time enormously).

So given the code at the bottom of this post, my understanding would be the
following:
- Calling from a managed function, the first function should be as quick as
NumberCrunching_InlineFunction_InNoGCClass_Managed , which is compiled as
managed.
- Calling from an unmanaged function, the first should be as fast as
NumberCrunching_InlineFunction_InNoGCClass_Unmanag ed, which is specified to
be unmanaged.

Given that it is apparently possible to influence how inlined functions are
compiled in the header, and that our inlined functions may be called from
both managed and unmanaged functions, what are we supposed to do? And
equally, how does all this apply to templated functions (which should be
compiled as they're used)? We're pretty sure that instead of the inlining
giving us good performance, it's causing masses of transitions between
managed / unmanaged processes. Any help would really be appreciated, as
would any links to info.

Thanks!

Steve

### CODE ###

__nogc class UnmanagedClass
{
public:
// This function isn't specified how to compile
__forceinline void
NumberCrunching_InlineFunction_InNoGCClass_LeftToI tsOwnDevices()
{
for ( int i = 0 ; i < 1000000 ; i++ )
{
double d = sqrt( 69765.43556 ) * log( 9032425.543535 ) / sqrt( log
( exp( 3.65464 ) ) );
}
}

#pragma unmanaged
__forceinline void NumberCrunching_InlineFunction_InNoGCClass_Unmanag ed()
{
for ( int i = 0 ; i < 1000000 ; i++ )
{
double d = sqrt( 69765.43556 ) * log( 9032425.543535 ) / sqrt( log
( exp( 3.65464 ) ) );
}
}

#pragma managed
__forceinline void NumberCrunching_InlineFunction_InNoGCClass_Managed ()
{
for ( int i = 0 ; i < 1000000 ; i++ )
{
double d = sqrt( 69765.43556 ) * log( 9032425.543535 ) / sqrt( log
( exp( 3.65464 ) ) );
}
}
};
Nov 17 '05 #1
  • viewed: 1118
Share:
2 Replies
Steve McLellan wrote:
Hi,

We've found some pretty serious performance hits that we didn't
expect in a mixed mode C++ application. The number crunching bits of
our algorithms are compiled with #pragma unmanaged. They call a
number of inline functions elsewhere, and from the documentation my
understanding was that inlined function calls are supposed to be
effectively replaced by their implementation at compile time. This
would mean that inline functions used in a #pragma unmanaged function
would also be compiled unmanaged.

However, having written a short test, this appears not to be the case
- putting #pragmas in the header affects how the inlined functions are
compiled (and affects running time enormously).

So given the code at the bottom of this post, my understanding would
be the following:
- Calling from a managed function, the first function should be as
quick as NumberCrunching_InlineFunction_InNoGCClass_Managed , which is
compiled as managed.
- Calling from an unmanaged function, the first should be as fast as
NumberCrunching_InlineFunction_InNoGCClass_Unmanag ed, which is
specified to be unmanaged.

Given that it is apparently possible to influence how inlined
functions are compiled in the header, and that our inlined functions
may be called from both managed and unmanaged functions, what are we
supposed to do? And equally, how does all this apply to templated
functions (which should be compiled as they're used)? We're pretty
sure that instead of the inlining giving us good performance, it's
causing masses of transitions between managed / unmanaged processes.
Any help would really be appreciated, as would any links to info.


Separate your code into pure-native and pure-managed compilation units and
never use #pragma {un}managed. That should result in inlined IL versions of
your functions in the managed module(s) and inlined native versions in the
native modules. Templates should work out the same.

-cd
Nov 17 '05 #2
> Steve McLellan wrote:
Hi,

We've found some pretty serious performance hits that we didn't
expect in a mixed mode C++ application. The number crunching bits of
our algorithms are compiled with #pragma unmanaged. They call a
number of inline functions elsewhere, and from the documentation my
understanding was that inlined function calls are supposed to be
effectively replaced by their implementation at compile time. This
would mean that inline functions used in a #pragma unmanaged function
would also be compiled unmanaged.

However, having written a short test, this appears not to be the case
- putting #pragmas in the header affects how the inlined functions are
compiled (and affects running time enormously).

So given the code at the bottom of this post, my understanding would
be the following:
- Calling from a managed function, the first function should be as
quick as NumberCrunching_InlineFunction_InNoGCClass_Managed , which is
compiled as managed.
- Calling from an unmanaged function, the first should be as fast as
NumberCrunching_InlineFunction_InNoGCClass_Unmanag ed, which is
specified to be unmanaged.

Given that it is apparently possible to influence how inlined
functions are compiled in the header, and that our inlined functions
may be called from both managed and unmanaged functions, what are we
supposed to do? And equally, how does all this apply to templated
functions (which should be compiled as they're used)? We're pretty
sure that instead of the inlining giving us good performance, it's
causing masses of transitions between managed / unmanaged processes.
Any help would really be appreciated, as would any links to info.
Separate your code into pure-native and pure-managed compilation units and
never use #pragma {un}managed. That should result in inlined IL versions

of your functions in the managed module(s) and inlined native versions in the
native modules. Templates should work out the same.


Hi Daniel,

Thanks - that's what we figured. Just what you need to realise a few weeks
before the project's meant to be completed :-)

Is this behaviour what you'd expect - i.e. is it what would happen with any
C++ compiler with regard to inlined functions? Or did the compiler team make
the decision to aim for easy portability at the expense of performance in
this case? IJW - but not fast :-)

Presumably it's still possible to link against a static LIB when building an
..NET assembly if I stick the unmanaged stuff in one?

Thanks again,

Steve
Nov 17 '05 #3

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

15 posts views Thread by Steven T. Hatton | last post: by
8 posts views Thread by Bern McCarty | last post: by
1 post views Thread by Jacobo Rodriguez Villar | last post: by
8 posts views Thread by Nadav | last post: by
8 posts views Thread by Edward Diener | last post: by
9 posts views Thread by Amit Dedhia | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.