这是一个本人学习 csapp 的 learning 库

188 строки
3.9 KiB

2 лет назад
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/times.h>
  5. #include <string.h>
  6. #include "clock.h"
  7. /* Keep track of most recent reading of cycle counter */
  8. static unsigned cyc_hi = 0;
  9. static unsigned cyc_lo = 0;
  10. void access_counter(unsigned *hi, unsigned *lo)
  11. {
  12. /* Get cycle counter */
  13. asm("rdtsc; movl %%edx,%0; movl %%eax,%1"
  14. : "=r" (*hi), "=r" (*lo)
  15. : /* No input */
  16. : "%edx", "%eax");
  17. }
  18. void start_counter()
  19. {
  20. access_counter(&cyc_hi, &cyc_lo);
  21. }
  22. double get_counter()
  23. {
  24. unsigned ncyc_hi, ncyc_lo;
  25. unsigned hi, lo, borrow;
  26. double result;
  27. /* Get cycle counter */
  28. access_counter(&ncyc_hi, &ncyc_lo);
  29. /* Do double precision subtraction */
  30. lo = ncyc_lo - cyc_lo;
  31. borrow = lo > ncyc_lo;
  32. hi = ncyc_hi - cyc_hi - borrow;
  33. result = (double) hi * (1 << 30) * 4 + lo;
  34. if (result < 0) {
  35. fprintf(stderr, "Error: Cycle counter returning negative value: %.0f\n", result);
  36. }
  37. return result;
  38. }
  39. double ovhd()
  40. {
  41. /* Do it twice to eliminate cache effects */
  42. int i;
  43. double result;
  44. for (i = 0; i < 2; i++) {
  45. start_counter();
  46. result = get_counter();
  47. }
  48. return result;
  49. }
  50. /* Keep track of clock speed */
  51. double cpu_ghz = 0.0;
  52. /* Get megahertz from /etc/proc */
  53. #define MAXBUF 512
  54. double core_mhz(int verbose) {
  55. static char buf[MAXBUF];
  56. FILE *fp = fopen("/proc/cpuinfo", "r");
  57. cpu_ghz = 0.0;
  58. if (!fp) {
  59. fprintf(stderr, "Can't open /proc/cpuinfo to get clock information\n");
  60. cpu_ghz = 1.0;
  61. return cpu_ghz * 1000.0;
  62. }
  63. while (fgets(buf, MAXBUF, fp)) {
  64. if (strstr(buf, "cpu MHz")) {
  65. double cpu_mhz = 0.0;
  66. sscanf(buf, "cpu MHz\t: %lf", &cpu_mhz);
  67. cpu_ghz = cpu_mhz / 1000.0;
  68. break;
  69. }
  70. }
  71. fclose(fp);
  72. if (cpu_ghz == 0.0) {
  73. fprintf(stderr, "Can't open /proc/cpuinfo to get clock information\n");
  74. cpu_ghz = 1.0;
  75. return cpu_ghz * 1000.0;
  76. }
  77. if (verbose) {
  78. printf("Processor Clock Rate ~= %.4f GHz (extracted from file)\n", cpu_ghz);
  79. }
  80. return cpu_ghz * 1000;
  81. }
  82. double mhz(int verbose) {
  83. double val = core_mhz(verbose);
  84. return val;
  85. }
  86. /* Determine clock rate by measuring cycles
  87. elapsed while sleeping for sleeptime seconds */
  88. double mhz_full(int verbose, int sleeptime)
  89. {
  90. double rate;
  91. start_counter();
  92. sleep(sleeptime);
  93. rate = get_counter()/(1e6*sleeptime);
  94. if (verbose)
  95. printf("Processor Clock Rate ~= %.1f MHz\n", rate);
  96. return rate;
  97. }
  98. ///* Version using a default sleeptime */
  99. //double mhz(int verbose)
  100. //{
  101. // return mhz_full(verbose, 2);
  102. //}
  103. /** Special counters that compensate for timer interrupt overhead */
  104. static double cyc_per_tick = 0.0;
  105. #define NEVENT 100
  106. #define THRESHOLD 1000
  107. #define RECORDTHRESH 3000
  108. /* Attempt to see how much time is used by timer interrupt */
  109. static void callibrate(int verbose)
  110. {
  111. double oldt;
  112. struct tms t;
  113. clock_t oldc;
  114. int e = 0;
  115. times(&t);
  116. oldc = t.tms_utime;
  117. start_counter();
  118. oldt = get_counter();
  119. while (e <NEVENT) {
  120. double newt = get_counter();
  121. if (newt-oldt >= THRESHOLD) {
  122. clock_t newc;
  123. times(&t);
  124. newc = t.tms_utime;
  125. if (newc > oldc) {
  126. double cpt = (newt-oldt)/(newc-oldc);
  127. if ((cyc_per_tick == 0.0 || cyc_per_tick > cpt) && cpt > RECORDTHRESH)
  128. cyc_per_tick = cpt;
  129. /*
  130. if (verbose)
  131. printf("Saw event lasting %.0f cycles and %d ticks. Ratio = %f\n",
  132. newt-oldt, (int) (newc-oldc), cpt);
  133. */
  134. e++;
  135. oldc = newc;
  136. }
  137. oldt = newt;
  138. }
  139. }
  140. if (verbose)
  141. printf("Setting cyc_per_tick to %f\n", cyc_per_tick);
  142. }
  143. static clock_t start_tick = 0;
  144. void start_comp_counter() {
  145. struct tms t;
  146. if (cyc_per_tick == 0.0)
  147. callibrate(1);
  148. times(&t);
  149. start_tick = t.tms_utime;
  150. start_counter();
  151. }
  152. double get_comp_counter() {
  153. double time = get_counter();
  154. double ctime;
  155. struct tms t;
  156. clock_t ticks;
  157. times(&t);
  158. ticks = t.tms_utime - start_tick;
  159. ctime = time - ticks*cyc_per_tick;
  160. /*
  161. printf("Measured %.0f cycles. Ticks = %d. Corrected %.0f cycles\n",
  162. time, (int) ticks, ctime);
  163. */
  164. return ctime;
  165. }