Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

How to enforce inlining ?

FlyingHermes
New Contributor I
2,173 Views

Hi,

My code involves a derived-type variable (denoted 'Object' hereafter) holding another derived-type variable as a component (denoted 'SubObject').

The SubObject has a type-bound procedure for computing some quantity, let say Q.

The Object also has a procedure for computing Q, but the actual computation is delegated to the SubObject component.

Here is simple example:

Module SubObject_Module
  implicit none
  private
  public        ::      SubObject_Type
  Type          ::      SubObject_Type
  contains
    procedure   ::      Compute => Compute_SubObj
  End Type
  contains
Pure Subroutine Compute_SubObj( This, Inp, Out )
  class(SubObject_Type)         ,intent(in)     ::      This
  integer                       ,intent(in)     ::      Inp
  integer                       ,intent(out)    ::      Out
  Out = Inp * 2
End Subroutine
End Module

Module Object_Module
  use SubObject_Module  ,only:  SubObject_Type
  implicit none
  private
  public        ::      Object_Type
  Type  ::      Object_Type
    private
    type(SubObject_Type) ::      Sub
  contains
    procedure   ::      Compute => Compute_Obj
  End Type
  contains
Pure Subroutine Compute_Obj( This, Inp, Out )
  class(Object_Type)            ,intent(in)     ::      This
  integer                       ,intent(in)     ::      Inp
  integer                       ,intent(out)    ::      Out
  call This%Sub%Compute( Inp, Out )
End Subroutine
End Module

Program Main
  use Object_Module ,only: Object_Type
  implicit none
  type(Object_Type)             ::      Object
  integer                       ::      Inp = 5, Out
  call Object%Compute( Inp, Out )
End Program

As you can see, in the main program I'm calling the TBP from the Object variable using "call Object%Compute(...)" (line 43).

The only task of this TBP is to call the TBP from the SubObject component, using "call This%Sub%Compute(...)" (line 34)

My real code heavily uses this delegation approach, which leads to lots of TBP being actually only wrappers to components' TBP calls.

Now, I want to avoid the extra cost of calling all those "useless" TBP (Compute_Obj) by forcing inlining of the call to the component's TBP (Compute_SubObj).

How should I do so ?

For now, I'm adding the "!DEC$ ATTRIBUTES FORCEINLINE :: Compute_SubObj" line before the "Compute_SubObj" procedure:

!DEC$ ATTRIBUTES FORCEINLINE :: Compute_SubObj
Pure Subroutine Compute_SubObj( This, Inp, Out )
  class(SubObject_Type)         ,intent(in)     ::      This
  integer                       ,intent(in)     ::      Inp
  integer                       ,intent(out)    ::      Out
  Out = Inp * 2
End Subroutine

Is it the correct way to enforce  inlining?

I know that inlining can also be changed using the following compiler options:

  -inline-factor
  -inline-min-size
  -inline-max-size
  -inline-max-total-size
  -inline-max-per-routine
  -inline-max-per-compile

but with no guarantee that the inlining is actually going to happen.

Am I right ?

Thank for yous enlightenment.

0 Kudos
6 Replies
FortranFan
Honored Contributor III
2,173 Views

flying_hermes wrote:

Hi,

My code involves a derived-type variable (denoted 'Object' hereafter) holding another derived-type variable as a component (denoted 'SubObject').

The SubObject has a type-bound procedure for computing some quantity, let say Q.

The Object also has a procedure for computing Q, but the actual computation is delegated to the SubObject component.

 ...

As you can see, in the main program I'm calling the TBP from the Object variable using "call Object%Compute(...)" (line 43).

The only task of this TBP is to call the TBP from the SubObject component, using "call This%Sub%Compute(...)" (line 34)

My real code heavily uses this delegation approach, which leads to lots of TBP being actually only wrappers to components' TBP calls.

Now, I want to avoid the extra cost of calling all those "useless" TBP (Compute_Obj) by forcing inlining of the call to the component's TBP (Compute_SubObj).

How should I do so ?

...

Have you investigated extended derived types and checked whether your code design can be modified to make to use of them?  

0 Kudos
FlyingHermes
New Contributor I
2,173 Views

Actually, in the real code, the Object derived-type contains several sub-objects and wraps all there TBP in its own TBP.

Since multiple inheritance is not supported in Fortran, type extension will not help here.

Thanks anyway for the suggestion.

0 Kudos
FortranFan
Honored Contributor III
2,173 Views

flying_hermes wrote:

Actually, in the real code, the Object derived-type contains several sub-objects and wraps all there TBP in its own TBP.

Since multiple inheritance is not supported in Fortran, type extension will not help here.

Thanks anyway for the suggestion.

Oh well, if you can't make use of the right combination of inheritance and aggregation in code design (something that many OOP experts recommend over multiple inheritance), then the complex and limiting world of compiler-specific options and optimizations beckons you..

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,173 Views

While I am not too up on OOP programming in Fortran, I am assuming that you will be having multiple SubObject types. In OOP programming the methods are contained within the object, therefore if the subobject cannot be determined at compile time there is no way other than pointer to function. What you could do is to have the main object explicitly contain a pointer to method and where this pointer is defined when the subobject is bound to the object. This will remove one level of indirection, but it will not yield inlining.

What you might consider looking at is: http://sourceforge.net/projects/blockit/

Blockit can be used as a preprocessor to provide templates to Fortran. Therefore, if the subobjects are determinable at compile time, the compiler should be able to inline the method.

Jim Dempsey

0 Kudos
FlyingHermes
New Contributor I
2,173 Views

I found several, possibly contradictory, descriptions of the -inline-forceinline option.

The first description is the following:

Instructs the compiler to force inlining of functions suggested for inlining whenever the compiler is capable doing so. Typically, the compiler targets functions that have been marked for inlining based on the presence of directives, like DEC$ ATTRIBUTES FORCEINLINE, in the source code; however, all such directives in the source code are treated only as suggestions for inlining. The option instructs the compiler to view the inlining suggestion as mandatory and inline the marked function if it can be done legally.

However, I'm not sure if this documentation refers to the version latest versions of ifort or an old one.

The second description is taken from https://software.intel.com/en-us/compiler_15.0_ug_f :

This option instructs the compiler to force inlining of functions suggested for inlining whenever the compiler is capable doing so.

Without this option, the compiler treats functions declared with an INLINE attribute as merely being recommended for inlining. When this option is used, it is as if they were declared with the directive !DIR$ ATTRIBUTES FORCEINLINE.

In the fist case, it is explicitly said that "functions are marked for inlining based on the presence of directives, like DEC$ ATTRIBUTES FORCEINLINE", while in the second case, it say that "it is as if [functions] were declared with the directive !DIR$ ATTRIBUTES FORCEINLINE"

BTW, are subroutines also inlined ?

 

0 Kudos
Steven_L_Intel1
Employee
2,173 Views

FORCEINLINE basically tells the compiler to disregard its opinion as to whether inlining is worthwhile. Yes, subroutines can be inlined - the wording is sort of C-centric where everything is a function.

0 Kudos
Reply