cortex.c 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. /*
  2. cpucycles/cortex.c version 20101203
  3. D. J. Bernstein
  4. Public domain.
  5. */
  6. #define SCALE 1
  7. #include <time.h>
  8. #include <unistd.h>
  9. #include <sys/time.h>
  10. static int enabled = 0;
  11. static int prev[3];
  12. static unsigned long long prevcycles = 0;
  13. static int now[3];
  14. static long long cyclespersec = 0;
  15. static void readticks(unsigned int *result)
  16. {
  17. struct timeval t;
  18. unsigned int cc;
  19. if (!enabled) {
  20. asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r"(17));
  21. asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(0x8000000f));
  22. asm volatile("mcr p15, 0, %0, c9, c12, 3" :: "r"(0x8000000f));
  23. enabled = 1;
  24. }
  25. asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(cc));
  26. gettimeofday(&t,(struct timezone *) 0);
  27. result[0] = cc;
  28. result[1] = t.tv_usec;
  29. result[2] = t.tv_sec;
  30. }
  31. long long cpucycles_cortex(void)
  32. {
  33. unsigned long long delta4;
  34. int deltan;
  35. int deltas;
  36. unsigned long long guesscycles;
  37. readticks(now);
  38. delta4 = (unsigned int) (now[0] - prev[0]); /* unsigned change in number of cycles mod 2^32 */
  39. deltan = now[1] - prev[1]; /* signed change in number of nanoseconds mod 10^9 */
  40. deltas = now[2] - prev[2]; /* signed change in number of seconds */
  41. if ((deltas == 0 && deltan < 200000) || (deltas == 1 && deltan < -800000))
  42. return (prevcycles + delta4) * SCALE;
  43. prev[0] = now[0];
  44. prev[1] = now[1];
  45. prev[2] = now[2];
  46. if ((deltas == 0 && deltan < 300000) || (deltas == 1 && deltan < -700000)) {
  47. // actual number of cycles cannot have increased by 2^32 in <0.3ms
  48. cyclespersec = 1000000 * (unsigned long long) delta4;
  49. cyclespersec /= deltan + 1000000 * (long long) deltas;
  50. } else {
  51. guesscycles = deltas * cyclespersec;
  52. guesscycles += (deltan * cyclespersec) / 1000000;
  53. while (delta4 + 2147483648ULL < guesscycles) delta4 += 4294967296ULL;
  54. /* XXX: could do longer-term extrapolation here */
  55. }
  56. prevcycles += delta4;
  57. return prevcycles * SCALE;
  58. }
  59. long long cpucycles_cortex_persecond(void)
  60. {
  61. while (!cyclespersec) cpucycles_cortex();
  62. return cyclespersec * SCALE;
  63. }