From 79d0dd0f54d459467dfe88fba68d4b64a461c187 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 3 Mar 2010 23:35:31 -0500 Subject: Make the API not suck. Seriously, not sure what I was thinking with the attributes type. --- src/sandglass.c | 159 +++++++++++++----------------------------- src/sandglass.h | 80 ++++++++------------- src/sandglass_impl.h | 8 +-- src/tsc.c | 2 +- tests/introspective-cputime.c | 5 +- tests/introspective-system.c | 5 +- tests/monotonic-cputime.c | 5 +- tests/monotonic-realticks.c | 3 +- tests/monotonic-system.c | 5 +- tests/noprecache.c | 5 +- 10 files changed, 94 insertions(+), 183 deletions(-) diff --git a/src/sandglass.c b/src/sandglass.c index 6a492c3..7ffe511 100644 --- a/src/sandglass.c +++ b/src/sandglass.c @@ -24,130 +24,61 @@ #include #include -static int sandglass_real_create(sandglass_t *sandglass, - const sandglass_attributes_t *attr); - -/* Create a timer */ int -sandglass_create(sandglass_t *sandglass, - const sandglass_attributes_t *min, - const sandglass_attributes_t *max) +sandglass_init_introspective(sandglass_t *sandglass, sandglass_resolution_t res) { - sandglass_attributes_t realmin, realmax; - - /* Get our real min and max values */ - - if (min) - realmin = *min; - else { - /* min defaults to { SANDGLASS_INTROSPECTIVE, SANDGLASS_SYSTEM } */ - realmin.incrementation = SANDGLASS_INTROSPECTIVE; - realmin.resolution = SANDGLASS_SYSTEM; - } - - if (max) - realmax = *max; - else { - /* max defaults to the greater of min and { SANDGLASS_INTROSPECTIVE, - SANDGLASS_CPUTIME } */ - if (realmin.incrementation > SANDGLASS_INTROSPECTIVE - || (realmin.incrementation == SANDGLASS_INTROSPECTIVE - && realmin.resolution > SANDGLASS_CPUTIME)) - realmax = realmin; - else { - realmax.incrementation = SANDGLASS_INTROSPECTIVE; - realmax.resolution = SANDGLASS_CPUTIME; - } - } - - /* Ensure max >= min */ - if (realmax.incrementation < realmin.incrementation - || (realmax.incrementation == realmin.incrementation - && realmax.resolution < realmin.resolution)) - { - errno = EINVAL; - return -1; - } - - /* Now search for available timers, starting from max */ - - while (sandglass_real_create(sandglass, &realmax) != 0) { - /* Once we reach the minimum attributes, bail out */ - if (realmax.incrementation == realmin.incrementation - && realmax.resolution == realmin.resolution) - { + switch (res) { + case SANDGLASS_CPUTIME: + if (sysconf(_SC_THREAD_CPUTIME) > 0 || sysconf(_SC_CPUTIME) > 0) { + sandglass->freq = 1e9; + sandglass->loops = 1; + } else { errno = ENOTSUP; return -1; } + break; - /* Try the next lowest allowable settings */ - if (realmax.resolution) - --realmax.resolution; - else { - if (realmax.incrementation) { - --realmax.incrementation; - realmax.resolution = SANDGLASS_CPUTIME; - } else { - errno = ENOTSUP; - return -1; - } - } + case SANDGLASS_SYSTEM: + sandglass->freq = CLOCKS_PER_SEC; + sandglass->loops = 1; + break; + + default: + errno = EINVAL; + return -1; } + sandglass->incrementation = SANDGLASS_INTROSPECTIVE; + sandglass->resolution = res; return 0; } -static int -sandglass_real_create(sandglass_t *sandglass, - const sandglass_attributes_t *attr) +int +sandglass_init_monotonic(sandglass_t *sandglass, sandglass_resolution_t res) { - switch (attr->incrementation) { - case SANDGLASS_MONOTONIC: - switch (attr->resolution) { - case SANDGLASS_CPUTIME: + switch (res) { + case SANDGLASS_CPUTIME: #ifdef SANDGLASS_TSC - sandglass->resolution = sandglass_tsc_resolution(); - sandglass->loops = sandglass_tsc_loops(); - break; + sandglass->freq = sandglass_tsc_freq(); + sandglass->loops = sandglass_tsc_loops(); + break; #else - return -1; + errno = ENOTSUP; + return -1; #endif - case SANDGLASS_SYSTEM: - sandglass->resolution = 1e9; - sandglass->loops = 1; - break; + case SANDGLASS_SYSTEM: + sandglass->freq = 1e9; + sandglass->loops = 1; + break; - default: - return -1; - } - break; - - case SANDGLASS_INTROSPECTIVE: - switch (attr->resolution) { - case SANDGLASS_CPUTIME: - if (sysconf(_SC_THREAD_CPUTIME) > 0 || sysconf(_SC_CPUTIME) > 0) { - sandglass->resolution = 1e9; - sandglass->loops = 1; - } else - return -1; - break; - - case SANDGLASS_SYSTEM: - sandglass->resolution = CLOCKS_PER_SEC; - sandglass->loops = 1; - break; - - default: - return -1; - } - break; - - default: - return -1; + default: + errno = EINVAL; + return -1; } - sandglass->attributes = *attr; + sandglass->incrementation = SANDGLASS_MONOTONIC; + sandglass->resolution = res; return 0; } @@ -167,7 +98,7 @@ sandglass_elapse(sandglass_t *sandglass) { long oldgrains = sandglass->grains; - if (sandglass_real_gettime(sandglass) != 0) + if (sandglass_real_gettime(sandglass)) return -1; sandglass->grains -= oldgrains; @@ -185,14 +116,15 @@ sandglass_real_gettime(sandglass_t *sandglass) struct timespec ts; clock_t clock_ticks; - switch (sandglass->attributes.incrementation) { + switch (sandglass->incrementation) { case SANDGLASS_MONOTONIC: - switch (sandglass->attributes.resolution) { + switch (sandglass->resolution) { case SANDGLASS_CPUTIME: #ifdef SANDGLASS_TSC sandglass->grains = sandglass_get_tsc(); break; #else + errno = ENOTSUP; return -1; #endif @@ -209,12 +141,13 @@ sandglass_real_gettime(sandglass_t *sandglass) break; default: + errno = EINVAL; return -1; } break; case SANDGLASS_INTROSPECTIVE: - switch (sandglass->attributes.resolution) { + switch (sandglass->resolution) { case SANDGLASS_CPUTIME: if (sysconf(_SC_THREAD_CPUTIME) > 0) { if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) @@ -222,8 +155,10 @@ sandglass_real_gettime(sandglass_t *sandglass) } else if (sysconf(_SC_CPUTIME) > 0) { if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) != 0) return -1; - } else + } else { + errno = EINVAL; return -1; + } sandglass->grains = ts.tv_nsec; sandglass->adjustment = 1000000000L; break; @@ -231,15 +166,17 @@ sandglass_real_gettime(sandglass_t *sandglass) case SANDGLASS_SYSTEM: if ((clock_ticks = clock()) == -1) return -1; - sandglass->grains = clock(); + sandglass->grains = clock_ticks; break; default: + errno = EINVAL; return -1; } break; default: + errno = EINVAL; return -1; } diff --git a/src/sandglass.h b/src/sandglass.h index 7b7577b..5456391 100644 --- a/src/sandglass.h +++ b/src/sandglass.h @@ -31,8 +31,24 @@ extern "C" { #endif -/* A type to represent a clock's time measurement attributes */ -enum sandglass_incrementation_t +/* A type to represent a clock's timing resolution */ +typedef enum sandglass_resolution_t +{ + /* + * Rely on the kernel to provide time information; less precise, more + * portable + */ + SANDGLASS_SYSTEM, + + /* + * Get timing information directly from the processor; more precise, less + * portable + */ + SANDGLASS_CPUTIME +} sandglass_resolution_t; + +/* An internal type to represent a clock's time measurement attributes */ +typedef enum sandglass_incrementation_t { /* * A clock which only increments during the current process's execution. Less @@ -48,45 +64,20 @@ enum sandglass_incrementation_t * while being timed. */ SANDGLASS_MONOTONIC -}; -typedef enum sandglass_incrementation_t sandglass_incrementation_t; - -/* A type to represent a clock's timing resolution */ -enum sandglass_resolution_t -{ - /* - * Rely on the kernel to provide time information; less precise, more - * portable. Uses times(). - */ - SANDGLASS_SYSTEM, +} sandglass_incrementation_t; - /* - * Get timing information directly from the processor; more precise, less - * portable. Uses the CLOCK_THREAD_CPUTIME_ID clock for - * SANDGLASS_INTROSPECTIVE mode, and the raw TSC for SANDGLASS_MONOTONIC. - */ - SANDGLASS_CPUTIME -}; -typedef enum sandglass_resolution_t sandglass_resolution_t; - -/* Attributes of a clock */ -struct sandglass_attributes_t +/* An high resolution timer */ +typedef struct sandglass_t { + /* The attributes of the clock */ sandglass_incrementation_t incrementation; sandglass_resolution_t resolution; -}; -typedef struct sandglass_attributes_t sandglass_attributes_t; - -struct sandglass_t -{ - /* The attributes of the clock */ - sandglass_attributes_t attributes; /* Units of time which have passed */ long grains; - /* grains/resolution should give elapsed time in seconds */ - double resolution; + /* grains/freq should give elapsed time in seconds */ + double freq; /* * Internal fields @@ -101,24 +92,13 @@ struct sandglass_t /* A field used by sandglass_bench() to store the overhead of sandglass_begin()/_elapse(), and of looping */ long baseline; -}; -typedef struct sandglass_t sandglass_t; +} sandglass_t; -/* - * Creates a timer with at least the precision of `min', and at most the - * precision of `max'. Precisions are compared first by incrementation type: - * all monotonic timers are considered more precise than introspective timers. - * Then, higher resolution timers take precidence. - * - * If `min' is NULL, it defaults to { SANDGLASS_INTROSPECTIVE, - * SANDGLASS_SYSTEM }. - * - * If `max' is NULL, it defaults to at least `min', but not less than - * { SANDGLASS_INTROSPECTIVE, SANDGLASS_CPUTIME }. - */ -int sandglass_create(sandglass_t *sandglass, - const sandglass_attributes_t *min, - const sandglass_attributes_t *max); +/* Create a timer */ +int sandglass_init_introspective(sandglass_t *sandglass, + sandglass_resolution_t res); +int sandglass_init_monotonic(sandglass_t *sandglass, + sandglass_resolution_t res); int sandglass_begin(sandglass_t *sandglass); int sandglass_elapse(sandglass_t *sandglass); diff --git a/src/sandglass_impl.h b/src/sandglass_impl.h index 689c6bf..accb332 100644 --- a/src/sandglass_impl.h +++ b/src/sandglass_impl.h @@ -31,9 +31,9 @@ #ifdef SANDGLASS_TSC /* Read the time stamp counter */ long sandglass_get_tsc(); -/* Get the timing resolution of the TSC */ -double sandglass_tsc_resolution(); -/* Get the necessary number of loops for SANDGLASS_REALTICKS */ +/* Get the frequency of the TSC */ +double sandglass_tsc_freq(); +/* Get the necessary number of loops for sandglass_bench_fine() */ unsigned int sandglass_tsc_loops(); #endif @@ -43,4 +43,4 @@ void sandglass_timespec_sub(struct timespec *ts, const struct timespec *d); int sandglass_timespec_cmp(const struct timespec *a, const struct timespec *b); void sandglass_spin(const struct timespec *ts); -#endif /* SANDGLASS_IMPL_H_INCLUDED */ \ No newline at end of file +#endif /* SANDGLASS_IMPL_H_INCLUDED */ diff --git a/src/tsc.c b/src/tsc.c index 135cd2a..713008c 100644 --- a/src/tsc.c +++ b/src/tsc.c @@ -25,7 +25,7 @@ /* Gets the number of clock ticks per second */ double -sandglass_tsc_resolution() +sandglass_tsc_freq() { static long tsc = 0; static struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000L }; diff --git a/tests/introspective-cputime.c b/tests/introspective-cputime.c index 7ce9a36..3f4158e 100644 --- a/tests/introspective-cputime.c +++ b/tests/introspective-cputime.c @@ -29,17 +29,16 @@ int main() { sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_INTROSPECTIVE, SANDGLASS_CPUTIME }; struct timespec tosleep = { .tv_sec = 0, .tv_nsec = 111111111L }; - if (sandglass_create(&sandglass, &attr, &attr) != 0) { + if (sandglass_init_introspective(&sandglass, SANDGLASS_CPUTIME) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } sandglass_bench(&sandglass, sandglass_spin(&tosleep)); - printf("%.15g\n", sandglass.grains/sandglass.resolution); + printf("%.15g\n", sandglass.grains/sandglass.freq); return EXIT_SUCCESS; } diff --git a/tests/introspective-system.c b/tests/introspective-system.c index 81e3397..5dee23a 100644 --- a/tests/introspective-system.c +++ b/tests/introspective-system.c @@ -29,17 +29,16 @@ int main() { sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_INTROSPECTIVE, SANDGLASS_SYSTEM }; struct timespec tosleep = { .tv_sec = 0, .tv_nsec = 111111111L }; - if (sandglass_create(&sandglass, &attr, &attr) != 0) { + if (sandglass_init_introspective(&sandglass, SANDGLASS_SYSTEM) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } sandglass_bench(&sandglass, sandglass_spin(&tosleep)); - printf("%.15g\n", sandglass.grains/sandglass.resolution); + printf("%.15g\n", sandglass.grains/sandglass.freq); return EXIT_SUCCESS; } diff --git a/tests/monotonic-cputime.c b/tests/monotonic-cputime.c index d0a7de1..f034df3 100644 --- a/tests/monotonic-cputime.c +++ b/tests/monotonic-cputime.c @@ -29,17 +29,16 @@ int main() { sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_MONOTONIC, SANDGLASS_CPUTIME }; struct timespec tosleep = { .tv_sec = 0, .tv_nsec = 111111111L }; - if (sandglass_create(&sandglass, &attr, &attr) != 0) { + if (sandglass_init_monotonic(&sandglass, SANDGLASS_CPUTIME) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } sandglass_bench(&sandglass, sandglass_spin(&tosleep)); - printf("%.15g\n", sandglass.grains/sandglass.resolution); + printf("%.15g\n", sandglass.grains/sandglass.freq); return EXIT_SUCCESS; } diff --git a/tests/monotonic-realticks.c b/tests/monotonic-realticks.c index 51404f5..5fff86e 100644 --- a/tests/monotonic-realticks.c +++ b/tests/monotonic-realticks.c @@ -30,9 +30,8 @@ int main() { sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_MONOTONIC, SANDGLASS_CPUTIME }; - if (sandglass_create(&sandglass, &attr, &attr) != 0) { + if (sandglass_init_monotonic(&sandglass, SANDGLASS_CPUTIME) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } diff --git a/tests/monotonic-system.c b/tests/monotonic-system.c index 0774908..d8ffba9 100644 --- a/tests/monotonic-system.c +++ b/tests/monotonic-system.c @@ -29,17 +29,16 @@ int main() { sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_MONOTONIC, SANDGLASS_SYSTEM }; struct timespec tosleep = { .tv_sec = 0, .tv_nsec = 111111111L }; - if (sandglass_create(&sandglass, &attr, &attr) != 0) { + if (sandglass_init_monotonic(&sandglass, SANDGLASS_SYSTEM) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } sandglass_bench(&sandglass, sandglass_spin(&tosleep)); - printf("%.15g\n", sandglass.grains/sandglass.resolution); + printf("%.15g\n", sandglass.grains/sandglass.freq); return EXIT_SUCCESS; } diff --git a/tests/noprecache.c b/tests/noprecache.c index 071920d..e48929d 100644 --- a/tests/noprecache.c +++ b/tests/noprecache.c @@ -31,10 +31,9 @@ main() { int i = 0; sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_MONOTONIC, SANDGLASS_CPUTIME }; struct timespec tosleep = { .tv_sec = 0, .tv_nsec = 111111111L }; - if (sandglass_create(&sandglass, &attr, &attr) != 0) { + if (sandglass_init_monotonic(&sandglass, SANDGLASS_SYSTEM) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } @@ -49,7 +48,7 @@ main() "sandglass_bench_noprecache() evaluated routine %d times!\n", i); } - printf("%.15g\n", sandglass.grains/sandglass.resolution); + printf("%.15g\n", sandglass.grains/sandglass.freq); return EXIT_SUCCESS; } -- cgit v1.2.3