Thread: Performance and footprint of virtual function

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    1,579

    Performance and footprint of virtual function

    Hello everyone,


    I want to know why virtual function's footprint and performance is compared with normal function call.

    Here is my analysis, please review whether I am correct. Thanks.

    1. foorprint

    Code:
    class Foo
    {
    protected:
    		char * pName;
    		int nSize;
    		virtual void copyName(char* pN) {return;}
    		void virFunc() {return;}
    };
    Class Foo instance will consume 12 bytes other than 8 bytes to hold an additonal __vfptr pointing to the entry address of virtual function table. If we remove virtual keyword, the footprint of class Foo instance will consume only 8 bytes.

    2. performance

    2.1 Virtual function call's performance is worse than normal function call is because it needs to use __vfptr to find the virtual function table, then invokes the function. Here using __vfptr brings one more level of indirection compared with normal function call, which is the most important reason making the performance worse.

    2.2 Are there anything else matters performance?
    2.3 How to find normal function call address can be determined during compile time and virtual function call address can only be determined during runtime?

    Please comment whether my understanding of 1 and 2 are correct or not?


    thanks in advance,
    George

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by George2 View Post
    Hello everyone,


    I want to know why virtual function's footprint and performance is compared with normal function call.

    Here is my analysis, please review whether I am correct. Thanks.

    1. foorprint

    Code:
    class Foo
    {
    protected:
    		char * pName;
    		int nSize;
    		virtual void copyName(char* pN) {return;}
    		void virFunc() {return;}
    };
    Class Foo instance will consume 12 bytes other than 8 bytes to hold an additonal __vfptr pointing to the entry address of virtual function table. If we remove virtual keyword, the footprint of class Foo instance will consume only 8 bytes.
    Yes, on a 32-bit pointer architecture, it will consume 4 bytes for the vtable.

    2. performance

    2.1 Virtual function call's performance is worse than normal function call is because it needs to use __vfptr to find the virtual function table, then invokes the function. Here using __vfptr brings one more level of indirection compared with normal function call, which is the most important reason making the performance worse.
    Correct - however, if you really want to achieve this sort of thing, you will end up with some sort of indirection whatever solution you choose, so it's no worse than any other solution of the same problem. [Assuming of course that you NEED to use virtual functions].

    The overhead is most noticeable on functions that do very little [e.g. getters & setters].

    And it's worth noting that the overhead is most likely less than an if-statement, so if you end up with code that does:
    Code:
       if (isSometype)
           // do something
       else
           // do else
    in the non-virtual function, to avoid having a virtual function, then you are probably not gaining anything from the non-virtual solution.

    2.2 Are there anything else matters performance?
    not that I'm aware of - of course, the extra indirection causes a memory read which in turn touches the cache, so cache hit ratio will be marginally impacted.
    2.3 How to find normal function call address can be determined during compile time and virtual function call address can only be determined during runtime?
    if the compiler knows the full type of the object - e.g. it's not a pointer, then the function address can be found directly.

    Please comment whether my understanding of 1 and 2 are correct or not?


    thanks in advance,
    George
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks matsp,


    1.

    For virtual function, the address of called function is retrieved from runtime and for normal function call, the address of called function is retrieved from compile time?

    2.

    If a class has both virtual and non-virtual functions, only virtual functions' address are stored in the table of __vfptr. Right?

    (I should debug this, but I found the value pointed by __vfptr are not readable -- binary values.)

    Quote Originally Posted by matsp View Post
    Yes, on a 32-bit pointer architecture, it will consume 4 bytes for the vtable.

    Correct - however, if you really want to achieve this sort of thing, you will end up with some sort of indirection whatever solution you choose, so it's no worse than any other solution of the same problem. [Assuming of course that you NEED to use virtual functions].

    The overhead is most noticeable on functions that do very little [e.g. getters & setters].

    And it's worth noting that the overhead is most likely less than an if-statement, so if you end up with code that does:
    Code:
       if (isSometype)
           // do something
       else
           // do else
    in the non-virtual function, to avoid having a virtual function, then you are probably not gaining anything from the non-virtual solution.

    not that I'm aware of - of course, the extra indirection causes a memory read which in turn touches the cache, so cache hit ratio will be marginally impacted.

    if the compiler knows the full type of the object - e.g. it's not a pointer, then the function address can be found directly.

    regards,
    George

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by George2 View Post
    Thanks matsp,


    1.

    For virtual function, the address of called function is retrieved from runtime and for normal function call, the address of called function is retrieved from compile time?
    Yes, the vtable contains only virtual functions (what you call __vfptr in MS VC++, but the name is implementation dependent).

    Note that the table itself is not part of the object - only a pointer to it. So there is only ONE table per class-type, whilst there may be many instances of that class.

    2.

    If a class has both virtual and non-virtual functions, only virtual functions' address are stored in the table of __vfptr. Right?
    As above.

    (I should debug this, but I found the value pointed by __vfptr are not readable -- binary values.)
    Yes, it's the addresses of the functions.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    My question is almost answered. From your points, I think there are two factors which degrade the performance of virtual function call,

    1. one more level of indirection through __vfptr;

    2. runtime function call address resolving other than compile time.

    Quote Originally Posted by matsp View Post
    Yes, the vtable contains only virtual functions (what you call __vfptr in MS VC++, but the name is implementation dependent).

    Note that the table itself is not part of the object - only a pointer to it. So there is only ONE table per class-type, whilst there may be many instances of that class.

    As above.

    Yes, it's the addresses of the functions.

    --
    Mats

    regards,
    George

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, although 1 & 2 are the same thing - the runtime resolution of the function call is through the vtable.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    My question is answered.

    Quote Originally Posted by matsp View Post
    Yes, although 1 & 2 are the same thing - the runtime resolution of the function call is through the vtable.

    --
    Mats

    regards,
    George

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    There's no guarantee that virtual functions are implemented through a vtable. It's proven to be the simplest and fastest implementation, so everyone uses it, but there's no requirement, and the details still differ between implementations.


    Also, the main performance problem is not actually the cost of indirection itself. This cost is very small, and on most functions completely drowned out by the function body.
    The real cost is in functions where the indirection overhead is noticeable: very small functions. These functions should be inlined - but the runtime resolution of the actual call prevents this. That's where the real cost of virtual functions lies. Functions that are so large that they wouldn't profit from being inline are big enough that the overhead doesn't matter.
    (If it weren't so, languages where every function is virtual unless static or explicitly marked final/sealed - like Java and C# - would have horrible a performance overhead. Now, these two have some pretty bad overheads, but they don't stem from function calls.)
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  9. #9
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks CornedBee,


    I also agree that invocation of virtual function is not quite time consuming and could be the most important reason to degrade performance, as found also from,

    http://www.parashift.com/c++-faq-lit...functions.html

    Quote Originally Posted by CornedBee View Post
    There's no guarantee that virtual functions are implemented through a vtable. It's proven to be the simplest and fastest implementation, so everyone uses it, but there's no requirement, and the details still differ between implementations.


    Also, the main performance problem is not actually the cost of indirection itself. This cost is very small, and on most functions completely drowned out by the function body.
    The real cost is in functions where the indirection overhead is noticeable: very small functions. These functions should be inlined - but the runtime resolution of the actual call prevents this. That's where the real cost of virtual functions lies. Functions that are so large that they wouldn't profit from being inline are big enough that the overhead doesn't matter.
    (If it weren't so, languages where every function is virtual unless static or explicitly marked final/sealed - like Java and C# - would have horrible a performance overhead. Now, these two have some pretty bad overheads, but they don't stem from function calls.)

    regards,
    George

Popular pages Recent additions subscribe to a feed