tags:

views:

216

answers:

7
+1  Q: 

Scope Guard in C

I would like to use scope guard in C in order to do profiling.

I would like to know how much time I spend in a function. Here is what I do:

int function() {

  tic();

  ... do stuff ...
  if (something)
  {
    toc();
    return 0;
   }

  toc();
  return 1;
}

I need to place a toc statement each time I exit the function. I would like to do that without having to copy paste toc everywhere. Is there a generic way to do that, using a macro or something ? Also I don't want to change the way the function is called, as there are many functions I have to profile.

Thanks

+3  A: 

You could define a macro like:

#define TOC_RETURN(x) \
    do { \
    toc(); \
    return x; \
    } while(0)

which should work anywhere you put it. Then you can automate replacing return *; with TOC_RETURN(*).

ezod
A: 

Hmm, maybe wrap the function call in a macro (family of macros, really)? Here is one which takes no arguments and returns Retval:

// define the wrapper for name
#define DEFTIMECALL0(Retval,name) \
    Retval timed##name() \
    { \
        Retval ret;
        tic(); \
        ret = name(); \
        toc(); \
        return ret; \
    }

You'll need macros for every arity of function calls you make, with a Retval and void returning version.

Edit Maybe there isn't even a point in defining the wrapper function, and better to just have a family of macros (again, for each arity and return type/void versions) which wrap a function call in a tic/toc directly at the callsites

Don't be afraid of instrumenting profilers, which essentially do this for you.

Terry Mahaffey
+1  A: 

I wouldn't recommend a macro for this. You profile the code just once in a while, and replacing 'return' with some special macro just for that purpose makes code less readable.

Isn't it better to do as follows?

tic();
call_function();
toc();

This automatically handles "all exit points" from the function.

P.S. Why don't you use a profiler?

Eli Bendersky
+1  A: 

A real profiler doesn't need you to modify the code, just to compile it with profiling enabled.

P-Nuts
+3  A: 

Why not use an actual profiling tool, like gprof?

jamessan
gprof is not part of the C standard ;-)
Steve Jessop
Changed the wording to avoid any potential confusion. :)
jamessan
+1  A: 

You could just "redefine" return via a macro: (please see Disclaimer)

#include <iostream>

void tic() { std::cout << "tic" << std::endl; }
void tac() { std::cout << "tac" << std::endl; }

#define return tac(); return
int foo() {
    tic();

    return 0;
}
#undef return

int main() {
    foo();
    return 0;
}

Disclaimer: This can be considered ugly and hacky because:

  • It won't work for void functions unless you use return;-statements.
  • It might not be portable/standard, even though it works on MSVC8.
  • One shouldn't define keywords.
abenthy
+4  A: 

This doesn't change the way the function is called. Probably not much use if you want to be able to profile every single function, though.

static inline int real_function() {
    // previous contents of function(), with no tic or toc
}

int function() {
    tic();
    int r = real_function();
    toc();
    return r;
}

As everyone else says: use a profiler, it will save you a lot of effort in the long run. As they don't say: if your platform has one.

If it doesn't, then the easiest might be to say (as a coding rule) that functions must have only one exit point, and that exit point must be via your macro. Then you can manually instrument all your functions with code at entry and exit. Legacy functions with multiple returns can be wrapped up as above.

Also, bear in mind when you're doing anything like this that your compiler can mess you up. You might write this:

tic();
do_something();
int i = something_else();
toc();
return i;

If the compiler determines that something_else has no side-effects, then even though something_else takes significant time, it might turn the code into this:

tic();
do_something();
toc();
return something_else();

And your profile data will under-estimate the time spent in your function. Another reason it's so good to have a real profiler - it can co-operate with the compiler.

Steve Jessop