Created
June 4, 2012 15:18
-
-
Save aprell/2869011 to your computer and use it in GitHub Desktop.
Reading the Time Stamp Counter (x86)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
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
Hello good job but....
#define timer_reset(t, f) timer_new(t, f)....where do input parameters t and f come from?