C — How to check how much time a section of code takes to execute.

This requires use of standard C library support for the clock_gettime() function. This returns time as a data-structure (struct timespec) that includes the current time in seconds and nano-seconds. Call this one time before the section of code to evaluate and once after and then take a difference of the end time versus the start time to figure out the time taken in the section of code.

 

struc timespec timespec_diff(struct timespec end, struct timespec start)

{

}

void testThis()

{

int i;

struct timespec start, end, diff;

 

clock_gettime(0, &start);

for (i = 0; i < 100000; i++)

{

x = i * 45;

}

clock_gettime(0, &end);

diff = timespec_diff(end, start);

printf(“Section of code took %u seconds %d nano-seconds\n”, diff.tv_sec, diff.tv_nsec);

}

Share

C — How to check how much time a section of code takes to execute.

This requires use of standard C library support for the clock_gettime() function. This function returns clock time as a data-structure (struct timespec) that includes the the clock time in seconds and nano-seconds.

Call this function one time before the section of code to evaluate and once after and then take a difference of the end time versus the start time to figure out the time taken in the section of code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <time.h> // for the clock_* APIs and struct timespec

struct timespec timespec_diff(struct timespec end, struct timespec start)

{
    timespec temp;


    if ((end.tv_nsec-start.tv_nsec) < 0)
    { // If this is the case, then the seconds values are different by atleast 1.
        temp.tv_sec = end.tv_sec - start.tv_sec - 1; // Borrow one second from the seconds field...
        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; //...and use it in the nano-second field.
    }
    else
    {
        temp.tv_sec = end.tv_sec-start.tv_sec;
        temp.tv_nsec = end.tv_nsec-start.tv_nsec;
    }

    return temp;
}

void testThis()
{
    int i;
    struct timespec start, end, diff;


    clock_gettime(CLOCK_REALTIME, &start);

    for (i = 0; i < 100000; i++)
    {
        x = i * 45;
    }

    clock_gettime(CLOCK_REALTIME, &end);

    diff = timespec_diff(end, start);
    printf("Section of code took %u seconds %d nano-seconds\n", diff.tv_sec, diff.tv_nsec);
}
Share

Async Programming Patterns

Note To Self: In any system where you have multiple processes or tasks handling processing of various events and you provide a mechanism in one process or task for other modules to register a callback, you should also allow for a life-time parameter in the registration that is returned whenever the callback is called. This is so that if callbacks are processed asynchronously by queue-ing messages by the process registering callbacks, there can be stale messages in queue during which time the registration could be deleted and new registrations can happen. So there has to be a mechanism for the callback owner to be able to distinguish the life-time instance of the registration against which the callback was originally made.

Share

Are you unable to use C sizeof operator as expected in pre-processor macros?

If you are trying to use the C programming language’s sizeof operator in a C pre-processor macro and find that you are unable to use it as expected and you see compiler errors (actually C pre-processor (CPP) errors), you are really seeing expected behavior. The sizeof operator works only during compile time and the sizes of structures are only known at compile time and it is not an operator supported by the C pre-processor.

Share

C Optimization Tips – Dealing with Aliasing

Though in general it is true that you should simply leave C code optimization to the compiler, it sometimes is useful to provide hints to the compiler. This is because when optimizing the compiler has to make a few basic global assumptions so as to generate correct code in all situations, but these assumptions may not be true in your specific code.

A case in point is providing aliasing hints through the use of the C99 restrict keyword or the GCC extension __restrict__. See this excellent article with an easy example that will help you understand aliasing and how to deal with it.

Share

C if-else Optimization

When doing some maintenance work on C code (refactoring!), I wondered if I should code C if-else clauses in some particular way to take advantage of modern processor pipelines and caching.

It seems obvious that if you have multiple else-if clauses, then putting the most likely to execute code in the first if clause would be the best (since it avoids subsequent checks most of the time), but what about the case that you only have a two-way if (cond) {…} else {…}  type of code, should you place the code most likely to be executed in the if clause or in the else clause? It would seem that it shouldn’t matter either way since there is only one condition being checked. But…

I did some experimentation on a system at hand (an Intel Pentium system with a small program compiled using gcc) and found that putting the most likely to be executed code as part of the else clause consistently had better timings. Be warned that this was just a simplistic “add-two-values-stored-in-variables-in-one-line” kind of code — definitely not a good test, but sufficient for me to satisfy my curiousity for the time being.

Google searching seemed to indicate that the performance depended on the ‘branch prediction‘ capability of the processor. I also found out that gcc has a compiler directive (__builtin_expect()) that one can use to provide a hint to the compiler so it knows what is the most likely outcome of a if conditional check and generate code suitable for the branch prediction capability of the target processor. The gcc manual recommends against using this directive though! See more details regarding this directive here.

Share