Search code examples
cmacrosexecution-time

Measuring the execution time of a function call in C using a function-like macro


Using the standard library function clock() is one of several methods to measure the execution time of a function call in C. So, for example, the comparison of the execution times of two functions (with different prototypes) can be done as follows:

#include <stdio.h>
#include <time.h>

int f(int n) { return n < 3 ? 1 : f(n-1) + f(n-2); }

int g(int n, int a, int b) { return n < 3 ? b : g(n-1, b, a+b); }

int main(void) {
    double start, elapsed1, elapsed2;
    printf("n  f   g\n");
    for(int n = 30; n <= 40; n++) {
        start = (double) clock();
        f(n); 
        elapsed1 = (clock() - start) / CLOCKS_PER_SEC;
        start = (double) clock();
        g(n, 1, 1);
        elapsed2 = ((double) clock() - start) / CLOCKS_PER_SEC;
        printf("%d %.1f %.1f\n", n, elapsed1, elapsed2);
    }
    return 0;
}

To make this code more concise, we could define a function-like macro (since there is no "generic function" pointer in C):

#include <stdio.h>
#include <time.h>

double START, ELAPSED;

#define CPUTIME(FCALL) (START = (double) clock(), FCALL, ELAPSED = ((double) clock() - START) / CLOCKS_PER_SEC)

int f(int n) { return n < 3 ? 1 : f(n-1) + f(n-2); }

int g(int n, int a, int b) { return n < 3 ? b : g(n-1,b,a+b); }

int main(void) {
    printf("n  f   g\n");
    for(int n = 30; n <= 40; n++) 
        printf("%d %.1f %.1f\n", n, CPUTIME(f(n)), CPUTIME(g(n, 1, 1)) );
    return 0;
}

Questions: Is there a way to make variables START and ELAPSED local to the macro definition so that the macro can still be called as a non-void "function"? Is there a better way to make the code more concise, without using a macro definition?


Solution

  • You can use the nonstandard statement-expression C extension (available in at least clang, gcc, and tinycc).

    #include <stdio.h>
    #include <time.h>
    
    #define CPUTIME(FCALL) ({ double START = clock(); FCALL; ((double) clock() - START) / CLOCKS_PER_SEC; })
    
    int f(int n) { return n < 3 ? 1 : f(n-1) + f(n-2); }
    
    int g(int n, int a, int b) { return n < 3 ? b : g(n-1,b,a+b); }
    
    int main(void) {
        printf("n  f   g\n");
        for(int n = 30; n <= 40; n++) 
            printf("%d %.1f %.1f\n", n, CPUTIME(f(n)), CPUTIME(g(n, 1, 1)) );
        return 0;
    }
    

    It's a parenthesized block that's evaluated to what the last statement in it evaluates to.

    I don't think there's a generic solution within standard C that would satisfy your API constraints. If you're after standard-c-only threadsafety and/or slightly better codegen, you could use your original solution and (re)declare the variable(s) locally within the block that calls the macro.