Skip to content

Instantly share code, notes, and snippets.

@aprell
Created June 4, 2012 15:18
Show Gist options
  • Save aprell/2869011 to your computer and use it in GitHub Desktop.
Save aprell/2869011 to your computer and use it in GitHub Desktop.
Reading the Time Stamp Counter (x86)
#ifndef TIMER_H
#define TIMER_H
#define CYCLES_PER_SEC(t) ((t) * 1e9)
#define CYCLES_PER_MSEC(t) ((t) * 1e6)
#define CYCLES_PER_USEC(t) ((t) * 1e3)
typedef struct timer {
unsigned long long start, end;
unsigned long long elapsed;
double GHZ;
} mytimer_t;
enum {
timer_us, timer_ms, timer_s
};
static inline unsigned long long getticks(void)
{
unsigned int lo, hi;
// RDTSC copies contents of 64-bit TSC into EDX:EAX
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
return (unsigned long long)hi << 32 | lo;
}
// Resets the timer
static inline void timer_new(mytimer_t *timer, double GHZ)
{
timer->elapsed = 0;
timer->GHZ = GHZ;
}
#define timer_reset(t, f) timer_new(t, f)
static inline void timer_start(mytimer_t *timer)
{
timer->start = getticks();
}
static inline void timer_end(mytimer_t *timer)
{
timer->end = getticks();
timer->elapsed += timer->end - timer->start;
}
// Returns elapsed time in microseconds, milliseconds, or seconds
static inline double timer_elapsed(mytimer_t *timer, int opt)
{
double elapsed = -1.0;
switch (opt) {
case timer_us: // cycles -> microseconds
elapsed = timer->elapsed / CYCLES_PER_USEC(timer->GHZ);
break;
case timer_ms: // cycles -> milliseconds
elapsed = timer->elapsed / CYCLES_PER_MSEC(timer->GHZ);
break;
case timer_s: // cycles -> seconds
elapsed = timer->elapsed / CYCLES_PER_SEC(timer->GHZ);
break;
default:
break;
}
return elapsed;
}
#endif // TIMER_H
@codeslingeroyal
Copy link

Hello good job but....

#define timer_reset(t, f) timer_new(t, f)....where do input parameters t and f come from?

@aprell
Copy link
Author

aprell commented Aug 24, 2019

Sorry, I just came across your comment... timer_reset is an alias for timer_new, so t is a pointer to a mytimer_t and f is the CPU's clock frequency as a double value.

For the record, here's an example of how these functions can be used, assuming a clock frequency of 2.9 GHz:

#include <stdio.h>
#include <stdlib.h>
#include "timer.h"

long fib(int n)
{
    if (n < 2) return n;
    else return fib(n - 1) + fib(n - 2);
}

int main(int argc, char *argv[])
{
    int n = argc > 1 ? atoi(argv[1]) : 40;

    mytimer_t t;
    timer_new(&t, 2.9 /* GHz */);

    timer_start(&t);
    long f = fib(n);
    timer_end(&t);

    printf("fib(%d) = %ld [%.2f ms]\n", n, f, timer_elapsed(&t, timer_ms));

    // Reset the timer's elapsed time to 0
    timer_reset(&t, 2.9 /* GHz */);

    timer_start(&t);
    f = fib(n + 1);
    timer_end(&t);

    printf("fib(%d) = %ld [%.2f ms]\n", n + 1, f, timer_elapsed(&t, timer_ms));

    return 0;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment