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

251 lines
5.3 KiB

пре 2 година
  1. /*
  2. * fcyc.c - Estimate the time (in CPU cycles) used by a function f
  3. *
  4. * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved.
  5. * May not be used, modified, or copied without permission.
  6. *
  7. * Uses the cycle timer routines in clock.c to estimate the
  8. * the time in CPU cycles for a function f.
  9. */
  10. #include <stdlib.h>
  11. #include <sys/times.h>
  12. #include <stdio.h>
  13. #include "fcyc.h"
  14. #include "clock.h"
  15. /* Default values */
  16. #define K 3 /* Value of K in K-best scheme */
  17. #define MAXSAMPLES 20 /* Give up after MAXSAMPLES */
  18. #define EPSILON 0.01 /* K samples should be EPSILON of each other*/
  19. #define COMPENSATE 0 /* 1-> try to compensate for clock ticks */
  20. #define CLEAR_CACHE 0 /* Clear cache before running test function */
  21. #define CACHE_BYTES (1<<19) /* Max cache size in bytes */
  22. #define CACHE_BLOCK 32 /* Cache block size in bytes */
  23. static int kbest = K;
  24. static int maxsamples = MAXSAMPLES;
  25. static double epsilon = EPSILON;
  26. static int compensate = COMPENSATE;
  27. static int clear_cache = CLEAR_CACHE;
  28. static int cache_bytes = CACHE_BYTES;
  29. static int cache_block = CACHE_BLOCK;
  30. static int *cache_buf = NULL;
  31. static double *values = NULL;
  32. static int samplecount = 0;
  33. /* for debugging only */
  34. #define KEEP_VALS 0
  35. #define KEEP_SAMPLES 0
  36. #if KEEP_SAMPLES
  37. static double *samples = NULL;
  38. #endif
  39. /*
  40. * init_sampler - Start new sampling process
  41. */
  42. static void init_sampler()
  43. {
  44. if (values)
  45. free(values);
  46. values = calloc(kbest, sizeof(double));
  47. #if KEEP_SAMPLES
  48. if (samples)
  49. free(samples);
  50. /* Allocate extra for wraparound analysis */
  51. samples = calloc(maxsamples+kbest, sizeof(double));
  52. #endif
  53. samplecount = 0;
  54. }
  55. /*
  56. * add_sample - Add new sample
  57. */
  58. static void add_sample(double val)
  59. {
  60. int pos = 0;
  61. if (samplecount < kbest) {
  62. pos = samplecount;
  63. values[pos] = val;
  64. } else if (val < values[kbest-1]) {
  65. pos = kbest-1;
  66. values[pos] = val;
  67. }
  68. #if KEEP_SAMPLES
  69. samples[samplecount] = val;
  70. #endif
  71. samplecount++;
  72. /* Insertion sort */
  73. while (pos > 0 && values[pos-1] > values[pos]) {
  74. double temp = values[pos-1];
  75. values[pos-1] = values[pos];
  76. values[pos] = temp;
  77. pos--;
  78. }
  79. }
  80. /*
  81. * has_converged- Have kbest minimum measurements converged within epsilon?
  82. */
  83. static int has_converged()
  84. {
  85. return
  86. (samplecount >= kbest) &&
  87. ((1 + epsilon)*values[0] >= values[kbest-1]);
  88. }
  89. /*
  90. * clear - Code to clear cache
  91. */
  92. static volatile int sink = 0;
  93. static void clear()
  94. {
  95. int x = sink;
  96. int *cptr, *cend;
  97. int incr = cache_block/sizeof(int);
  98. if (!cache_buf) {
  99. cache_buf = malloc(cache_bytes);
  100. if (!cache_buf) {
  101. fprintf(stderr, "Fatal error. Malloc returned null when trying to clear cache\n");
  102. exit(1);
  103. }
  104. }
  105. cptr = (int *) cache_buf;
  106. cend = cptr + cache_bytes/sizeof(int);
  107. while (cptr < cend) {
  108. x += *cptr;
  109. cptr += incr;
  110. }
  111. sink = x;
  112. }
  113. /*
  114. * fcyc - Use K-best scheme to estimate the running time of function f
  115. */
  116. double fcyc(test_funct f, void *argp)
  117. {
  118. double result;
  119. init_sampler();
  120. if (compensate) {
  121. do {
  122. double cyc;
  123. if (clear_cache)
  124. clear();
  125. start_comp_counter();
  126. f(argp);
  127. cyc = get_comp_counter();
  128. add_sample(cyc);
  129. } while (!has_converged() && samplecount < maxsamples);
  130. } else {
  131. do {
  132. double cyc;
  133. if (clear_cache)
  134. clear();
  135. start_counter();
  136. f(argp);
  137. cyc = get_counter();
  138. add_sample(cyc);
  139. } while (!has_converged() && samplecount < maxsamples);
  140. }
  141. #ifdef DEBUG
  142. {
  143. int i;
  144. printf(" %d smallest values: [", kbest);
  145. for (i = 0; i < kbest; i++)
  146. printf("%.0f%s", values[i], i==kbest-1 ? "]\n" : ", ");
  147. }
  148. #endif
  149. result = values[0];
  150. #if !KEEP_VALS
  151. free(values);
  152. values = NULL;
  153. #endif
  154. return result;
  155. }
  156. /*************************************************************
  157. * Set the various parameters used by the measurement routines
  158. ************************************************************/
  159. /*
  160. * set_fcyc_clear_cache - When set, will run code to clear cache
  161. * before each measurement.
  162. * Default = 0
  163. */
  164. void set_fcyc_clear_cache(int clear)
  165. {
  166. clear_cache = clear;
  167. }
  168. /*
  169. * set_fcyc_cache_size - Set size of cache to use when clearing cache
  170. * Default = 1<<19 (512KB)
  171. */
  172. void set_fcyc_cache_size(int bytes)
  173. {
  174. if (bytes != cache_bytes) {
  175. cache_bytes = bytes;
  176. if (cache_buf) {
  177. free(cache_buf);
  178. cache_buf = NULL;
  179. }
  180. }
  181. }
  182. /*
  183. * set_fcyc_cache_block - Set size of cache block
  184. * Default = 32
  185. */
  186. void set_fcyc_cache_block(int bytes) {
  187. cache_block = bytes;
  188. }
  189. /*
  190. * set_fcyc_compensate- When set, will attempt to compensate for
  191. * timer interrupt overhead
  192. * Default = 0
  193. */
  194. void set_fcyc_compensate(int compensate_arg)
  195. {
  196. compensate = compensate_arg;
  197. }
  198. /*
  199. * set_fcyc_k - Value of K in K-best measurement scheme
  200. * Default = 3
  201. */
  202. void set_fcyc_k(int k)
  203. {
  204. kbest = k;
  205. }
  206. /*
  207. * set_fcyc_maxsamples - Maximum number of samples attempting to find
  208. * K-best within some tolerance.
  209. * When exceeded, just return best sample found.
  210. * Default = 20
  211. */
  212. void set_fcyc_maxsamples(int maxsamples_arg)
  213. {
  214. maxsamples = maxsamples_arg;
  215. }
  216. /*
  217. * set_fcyc_epsilon - Tolerance required for K-best
  218. * Default = 0.01
  219. */
  220. void set_fcyc_epsilon(double epsilon_arg)
  221. {
  222. epsilon = epsilon_arg;
  223. }