Hi,

I want to call CTest's StaticMethod via a function pointer from Class CCaller. I noticed that StaticMethod is not inlined and the call takes much more time compared to calling the function directly. When calling directly the function gets inlined - even without the inline keyword.
Can't the function pointer call be optimized by the compiler? Are there additional keywords necessary for telling it to do so?

class CTest
{
  public:
    inline static void StaticMethod(void)
    {
      //Do something  
    }
};

typedef void (*tPtr)(void);

static tPtr fPointer = &CTest::StaticMethod;


class CCaller 
{
  public:
    static void CallMethod(void)
    {
       //either or:

       //this is pretty fast
       CTest::StaticMethod();
       
       //this is very slow
       //fPointer();
     }
};

Thanks in advance,
Mirco

Well, in order to inline a function pointed to by a function pointer, the compiler must know
(at compile time) which function the pointer points at when it's used. The compiler doesn't know that.

Therefore, this code...

#include <cstdio>

class CTest
{
  public:
    inline static void StaticMethod(void)
    {
        printf("lalalalalalala\n");
    }
};

typedef void (*tPtr)(void);

static tPtr fPointer = &CTest::StaticMethod;

class CCaller
{
  public:
    static void CallMethod(void)
    {
       //this is pretty fast
       CTest::StaticMethod();

       //this is very slow
       fPointer();
     }
};

int main()
{
    CCaller::CallMethod();

    return 0;
}

Generates something like this...

.file	"main.cpp"
	.section .rdata,"dr"
LC0:
	.ascii "lalalalalalala\0"
	.section	.text$_ZN5CTest12StaticMethodEv,"x"
	.linkonce discard
	.p2align 2,,3
.globl __ZN5CTest12StaticMethodEv
	.def	__ZN5CTest12StaticMethodEv;	.scl	2;	.type	32;	.endef
__ZN5CTest12StaticMethodEv:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$24, %esp
	movl	$LC0, (%esp)
	call	_puts
	leave
	ret
	.def	___main;	.scl	2;	.type	32;	.endef
	.text
	.p2align 2,,3
.globl _main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$16, %esp
	call	___main
	movl	$LC0, (%esp)                 
	call	_puts                       // <- inlining
	call	__ZN5CTest12StaticMethodEv  // <- call
	xorl	%eax, %eax
	leave
	ret
	.def	_puts;	.scl	2;	.type	32;	.endef

However, if you tell the compiler he can be sure that the pointer always points to that specific function...

#include <cstdio>

class CTest
{
  public:
    inline static void StaticMethod(void)
    {
        printf("lalalalalalala\n");
    }
};

typedef void (*tPtr)(void);

static const tPtr fPointer = &CTest::StaticMethod;

class CCaller
{
  public:
    static void CallMethod(void)
    {
       //this is pretty fast
       CTest::StaticMethod();

       //this is very slow
       fPointer();
     }
};

int main()
{
    CCaller::CallMethod();

    return 0;
}

It will gladly make the optimization...

.file	"main.cpp"
	.def	___main;	.scl	2;	.type	32;	.endef
	.section .rdata,"dr"
LC0:
	.ascii "lalalalalalala\0"
	.text
	.p2align 2,,3
.globl _main
	.def	_main;	.scl	2;	.type	32;	.endef
_main:
	pushl	%ebp
	movl	%esp, %ebp
	andl	$-16, %esp
	subl	$16, %esp
	call	___main
	movl	$LC0, (%esp)  
	call	_puts         // <- inlining
	movl	$LC0, (%esp)
	call	_puts         // <- inlining
	xorl	%eax, %eax
	leave
	ret
	.def	_puts;	.scl	2;	.type	32;	.endef

Though, having a const function pointer kind of defeats the point of having a function pointer...

Edited 5 Years Ago by m4ster_r0shi: n/a

Thanks for the reply. When I make the function pointer const it gets faster only a bit.
I made some measurements which show that...

In the StaticMethod I set and reset a bit in an volatile register of the uC.

  • When I call CallMethod in a loop 0xAA times the direct pure call of the static function takes 0us - So I see it's inlined.
  • The call via the non-const function pointer takes 210us
  • and the call via the const one as you described takes 195us.

So there is an improvement but I guess in my case unfortunately the function does not get inlined.

It is not a problem having const function pointers. I'd like to register Callbacks at compile time for implementing ISRs...

When I make the function pointer const it gets faster only a bit. [...] So there is an improvement but I guess in my case unfortunately the function does not get inlined.

Do you use the best speed optimization option when you compile? (I compiled both my examples with g++ using -O3)

Edited 5 Years Ago by m4ster_r0shi: n/a

Yes, I use the Arm C Compiler armcc with -O3 and optimization for time -Otime

The problem here is with the use of the function pointer. Whether it is const or not is neither here nor there. From what I can remember about inline functions; virtual functions and functions pointed to by function pointers cannot be inlined. At least, that's what I was always told!

However, seeing Roshi's post. Perhaps the optimisation settings of the compiler might be able to circumvent the function pointer rule. Assuming that the optimising compiler is intelligent enough to realise that the function pointed to by the pointer can be inlined. And I suppose if the function pointer is const and is pointing to an inline function, that might be all the indication that is needed. Compiler optimisation has come a long way over the last decade or so. However, implementation of this could vary from compiler to compiler, so it might not guarantee that the function will always be inlined!
So this may work with gcc. But VS, Borland, ARM or other compilers might not support it.

Either way optimisations aside; typically inline functions are not inlined when called via a function pointer!

Edited 5 Years Ago by JasonHippy: n/a

This article has been dead for over six months. Start a new discussion instead.