CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Jan 2009
    Posts
    1,689

    Which offers the best performance?

    I have a library that I am trying to clean up (it's got way too much preprocessor in it.) I wanted to ask here to be sure that the replacements I'm making will not show any performance problems.

    Preprocessor
    Code:
    #define AMOUNT 5
    #define INC
    
    int foo(int i){
       #ifdef INC
          return i + AMOUNT;
       #else
          return i - AMOUNT;
       #endif
    }
    Consts
    Code:
    const int AMOUNT = 5;
    const bool INC = true;
    
    int foo(int i){
       if (INC){
          return i + AMOUNT;
       }
       return i - AMOUNT;  //not in an else to prevent compiler warnings about reaching end of non-void method
    }
    Templates
    Code:
    template <bool INC, int AMOUNT>
    int foo(int i){
       if (INC){
          return i + AMOUNT;
       }
       return i - AMOUNT;  //not in an else to prevent compiler warnings about reaching end of non-void method
    }
    Each of these approaches should end up producing the same instructions correct? All of the decisions end up being made at compile time and the compiler will remove the compiled code that is inaccessible. I will end up using a mix of const and templates depending on the circumstances of the change, but since it's a time critical library, I want to make sure there is no performance degradation.
    Last edited by ninja9578; March 28th, 2012 at 11:53 AM.

  2. #2
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    Re: Which offers the best performance?

    I think I would use a template for the INC, at least. There is probably no benefit to doing so for AMOUNT.

  3. #3
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Which offers the best performance?

    AFAIK, you should get the same results in a release build.

    In debug though, your code is compiled literally, so you'll have to pay to evaluate the if. Not true with the pre-proc approach.

    The cleanest approach might be to use a compile time trait, something akin to how "distance" forwards to 1 of 2 possible calls?

    The problem with your template signature is that your template parameters are not the global mainspace variables, so your callers will have to literally write foo<INC, AMOUNT>(some_number). Unless you are using C++11, where template functions are allowed default template function parameters.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  4. #4
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Which offers the best performance?

    Quote Originally Posted by ninja9578 View Post
    ...Each of these approaches should end up producing the same instructions correct?
    If it's true that each approach ends up with the same instructions (and as pointed out by monarch_dodra, it might be true for a release build although it's probably not true for a debug build), then there is absolutely no difference in performance, and you should choose the one that's clearest to you under the circumstances.

    Mike

  5. #5
    Join Date
    May 2009
    Posts
    2,413

    Re: Which offers the best performance?

    There's another option I would prefer:

    Code:
    #define INC
    
    const int AMOUNT = 5
    
    #ifdef INC
    
    int foo(int i){
          return i + AMOUNT;
    }
    
    #else
    
    int foo(int i){
          return i - AMOUNT;
    }
    
    #endif
    Here the preprocessor is kept for conditional compilation of system parts but otherwise replaced with C++ constructs.

    Also when you do this code reorganization anyway maybe you could take the opportunity and introduce a version control system.
    Last edited by nuzzle; March 29th, 2012 at 12:52 AM.

  6. #6
    Join Date
    Jan 2009
    Posts
    1,689

    Re: Which offers the best performance?

    Thanks, I only care about the performance of the release version, while debugging it can be a little slower. nuzzle, I know, I'm creating a svn repo for it too.

  7. #7
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: Which offers the best performance?

    Quote Originally Posted by ninja9578 View Post
    I have a library that I am trying to clean up (it's got way too much preprocessor in it.)
    If you primary goal is to “clean up” – I would stay away from the template approach.
    As was stated, any decent compiler will optimize your first and second fragments to the same code.
    But I question that premise (that you use a decent compiler) based on your comment:
    Code:
    //not in an else to prevent compiler warnings about reaching end of non-void method
    I don’t see any warnings in VS 2010 with /W4. What warning should I get?

    Also, the major difference between using #define and global const (at least, to me) is that you only change build parameters to create different configurations in the first case, but you have to change the source code in the second.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  8. #8
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: Which offers the best performance?

    VladimirF makes a good point about templates, although, I guess it depends on what is meant by "clean up".

    #define's affect every file in the compilation and do not obey scope. Global variables are slightly better but affect every translation unit in which they are included, and in addition are not good practice - at the very least, you would be better encapsulating them into a namespace.

    Template's on the other hand can provide a good solution (just as long as by 'clean up' you are not meaning that you want to make things clearer for the average maintainer).

    Ninja, you may get a warning with your version of the template, since INC is a compile-time constant. A better template solution that does not rely on #define's would be something along the lines of:

    Code:
    #include <iostream>
    
    namespace myns
    {
      enum e_modification_values
      {
        e_increment = true,
        e_amount    = 5
      };
    
      template <bool Increment, int Amount>
      struct mod
      {
        inline static int result(int value)
        {
          return value + Amount;
        }
      };
    
      //Template specialisation of the above
      template <int Amount>
      struct mod<false, Amount>
      {
        inline static int result(int value)
        {
          return value - Amount;
        }
      };
    }
    
    int foo(int value)
    {
      typedef myns::mod<myns::e_increment, myns::e_amount> modifier;
    
      return modifier::result(value);
    }
    
    int main()
    {
      std::cout << foo(20) << std::endl;
    }
    From a performance point of view, the above doesn't depend on your compilers ability to optimise. From a code contamination point of view, the above works very well, but at the same time, it is hardly clear as to what is going on to someone that may have little knowledge of how templates work.

    To some degree it's swings and roundabouts - the compiler should make a good optimisation of any of the alternate solutions and therefore, it could be argued that the solution that I am providing is possibly pointless for something as trivial as this.

    Perhaps a question you should be asking is, how many times will foo() be called?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured