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

/* I wanted to know how fast the TSC on my laptop increments.  It's a
 * 700MHz PIII, and /proc/cpuinfo says it's "697.007" MHz, so I
 * expected it would increment at 697.007 million counts per second,
 * more or less.  So I wrote this program to find out.
 *
 * Much to my surprise, when the laptop is mostly idle, the number
 * varies wildly, usually staying between 300 million and 500 million
 * per second, but occasionally going above or below this range; and
 * when the laptop is loaded, it stays between 547.5 and 547.7 million
 * per second.  When I run it on Panacea, which has a 1.8GHz dual-core
 * Opteron, it's consistently between 1799 and 1801 million ticks per
 * second.
 *
 * The Intel manual (Intel document 253669) section 18.10 ("Time-stamp
 * counter") explains that on old CPUs, the TSC doesn't increase at a
 * constant rate, but rather varies with the clock speed.  I don't
 * understand what is going on with my laptop; apparently it's
 * actually running at 550MHz rather than 700, and maybe the TSC
 * doesn't increment while the CPU is halted?
 *
 * ...after further testing, it seems to sometimes be 700 million
 * ticks per second, and sometimes 550.
 */


double now() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec + tv.tv_usec / 1000000.0;
}

unsigned rdtsc() {
  register unsigned rv asm ("%eax");
  /* If we don't specify "volatile", GCC may optimize away the asm
   * expression or the call to rdtsc() */
  asm volatile ("rdtsc" : "=r" (rv) : : "edx");
  return rv;
}

int main(int argc, char **argv) {
  unsigned start, end;
  double starttime_inner, starttime_outer, endtime_inner, endtime_outer;

  starttime_outer = now();
  start = rdtsc();
  starttime_inner = now();

  usleep(50000);               /* 50ms should be plenty long enough */

  endtime_inner = now();
  end = rdtsc();
  endtime_outer = now();

  printf("Got %d RDTSC ticks in %.3f-%.3f ms, ",
         end - start,
         (endtime_inner - starttime_inner) * 1000,
         (endtime_outer - starttime_outer) * 1000);
  printf("for %.3f-%.3f million ticks per second.\n",
         (end - start) / (endtime_outer - starttime_outer) / 1000 / 1000,
         (end - start) / (endtime_inner - starttime_inner) / 1000 / 1000);
  
  return 0;
}

Reply via email to