/* * fcyc.c - Estimate the time (in CPU cycles) used by a function f * * Copyright (c) 2002, R. Bryant and D. O'Hallaron, All rights reserved. * May not be used, modified, or copied without permission. * * Uses the cycle timer routines in clock.c to estimate the * the time in CPU cycles for a function f. */ #include #include #include #include "fcyc.h" #include "clock.h" /* Default values */ #define K 3 /* Value of K in K-best scheme */ #define MAXSAMPLES 20 /* Give up after MAXSAMPLES */ #define EPSILON 0.01 /* K samples should be EPSILON of each other*/ #define CLEAR_CACHE 0 /* Clear cache before running test function */ #define CACHE_BYTES (1<<19) /* Max cache size in bytes */ #define CACHE_BLOCK 32 /* Cache block size in bytes */ static int kbest = K; static int maxsamples = MAXSAMPLES; static double epsilon = EPSILON; static int clear_cache = CLEAR_CACHE; static int cache_bytes = CACHE_BYTES; static int cache_block = CACHE_BLOCK; static int* cache_buf = NULL; static double* values = NULL; static int samplecount = 0; /* for debugging only */ #define KEEP_VALS 0 #define KEEP_SAMPLES 0 #if KEEP_SAMPLES static double* samples = NULL; #endif /* * init_sampler - Start new sampling process */ static void init_sampler(void) { if (values) free(values); values = calloc(kbest, sizeof(double)); #if KEEP_SAMPLES if (samples) free(samples); /* Allocate extra for wraparound analysis */ samples = calloc(maxsamples + kbest, sizeof(double)); #endif samplecount = 0; } /* * add_sample - Add new sample */ static void add_sample(double val) { int pos = 0; if (samplecount < kbest) { pos = samplecount; values[pos] = val; } else if (val < values[kbest - 1]) { pos = kbest - 1; values[pos] = val; } #if KEEP_SAMPLES samples[samplecount] = val; #endif samplecount++; /* Insertion sort */ while (pos > 0 && values[pos - 1] > values[pos]) { double temp = values[pos - 1]; values[pos - 1] = values[pos]; values[pos] = temp; pos--; } } /* * has_converged- Have kbest minimum measurements converged within epsilon? */ static int has_converged(void) { return (samplecount >= kbest) && ((1 + epsilon) * values[0] >= values[kbest - 1]); } /* * clear - Code to clear cache */ static volatile int sink = 0; static void clear(void) { int x = sink; int* cptr, * cend; int incr = cache_block / sizeof(int); if (!cache_buf) { cache_buf = malloc(cache_bytes); if (!cache_buf) { printf("[%s]致命错误:当试图清除cache时,malloc返回null\n", __func__); exit(1); } } cptr = (int*)cache_buf; cend = cptr + cache_bytes / sizeof(int); while (cptr < cend) { x += *cptr; cptr += incr; } sink = x; } /* * fcyc - Use K-best scheme to estimate the running time of function f */ double fcyc(test_funct f, void* argp) { double result; init_sampler(); make_CPU_busy(); do { double cyc; if (clear_cache) clear(); start_counter(); f(argp); cyc = get_counter(); add_sample(cyc); } while (!has_converged() && samplecount < maxsamples); #ifdef DEBUG { int i; printf(" %d smallest values: [", kbest); for (i = 0; i < kbest; i++) printf("%.0f%s", values[i], i == kbest - 1 ? "]\n" : ", "); } #endif result = values[0]; #if !KEEP_VALS free(values); values = NULL; #endif return result; } /************************************************************* * Set the various parameters used by the measurement routines ************************************************************/ /* * set_fcyc_clear_cache - When set, will run code to clear cache * before each measurement. * Default = 0 */ void set_fcyc_clear_cache(int clear) { clear_cache = clear; } /* * set_fcyc_cache_size - Set size of cache to use when clearing cache * Default = 1<<19 (512KB) */ void set_fcyc_cache_size(int bytes) { if (bytes != cache_bytes) { cache_bytes = bytes; if (cache_buf) { free(cache_buf); cache_buf = NULL; } } } /* * set_fcyc_cache_block - Set size of cache block * Default = 32 */ void set_fcyc_cache_block(int bytes) { cache_block = bytes; } /* * set_fcyc_k - Value of K in K-best measurement scheme * Default = 3 */ void set_fcyc_k(int k) { kbest = k; } /* * set_fcyc_maxsamples - Maximum number of samples attempting to find * K-best within some tolerance. * When exceeded, just return best sample found. * Default = 20 */ void set_fcyc_maxsamples(int maxsamples_arg) { maxsamples = maxsamples_arg; } /* * set_fcyc_epsilon - Tolerance required for K-best * Default = 0.01 */ void set_fcyc_epsilon(double epsilon_arg) { epsilon = epsilon_arg; }