diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/sandglass_impl.h | 6 | ||||
-rw-r--r-- | src/timespec.c | 109 | ||||
-rw-r--r-- | src/tsc.c | 34 |
4 files changed, 124 insertions, 31 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index d1a0109..a91e2b6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,11 @@ nobase_include_HEADERS = sandglass.h libsandglass_la_SOURCES = sandglass.h \ sandglass_impl.h \ sandglass.c \ - tsc.c + timespec.c + +if TSC + libsandglass_la_SOURCES += tsc.c +endif if X86 libsandglass_la_SOURCES += x86/tsc-x86.s diff --git a/src/sandglass_impl.h b/src/sandglass_impl.h index cea95c3..07a3616 100644 --- a/src/sandglass_impl.h +++ b/src/sandglass_impl.h @@ -37,4 +37,10 @@ double sandglass_tsc_resolution(); unsigned int sandglass_tsc_loops(); #endif +void sandglass_get_currtime(struct timespec *ts); +void sandglass_timespec_add(struct timespec *ts, const struct timespec *d); +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(struct timespec *ts); + #endif /* SANDGLASS_IMPL_H_INCLUDED */
\ No newline at end of file diff --git a/src/timespec.c b/src/timespec.c new file mode 100644 index 0000000..f8ab791 --- /dev/null +++ b/src/timespec.c @@ -0,0 +1,109 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes <tavianator@gmail.com> * + * * + * This file is part of The Sandglass Library. * + * * + * The Sandglass Library is free software; you can redistribute it * + * and/or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Sandglass Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * <http://www.gnu.org/licenses/>. * + *************************************************************************/ + +#include "sandglass_impl.h" +#include "sandglass.h" +#include <time.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +void +sandglass_get_currtime(struct timespec *ts) +{ + static int monotonic = 0; + if (!monotonic) { + monotonic = sysconf(_SC_MONOTONIC_CLOCK); + } + + if (monotonic > 0) { + if (clock_gettime(CLOCK_MONOTONIC, ts) != 0) { + fprintf(stderr, + "libsandglass: couldn't get value of clock CLOCK_MONOTONIC\n"); + exit(EXIT_FAILURE); + } + } else { + if (clock_gettime(CLOCK_REALTIME, ts) != 0) { + fprintf(stderr, + "libsandglass: couldn't get value of clock CLOCK_REALTIME\n"); + exit(EXIT_FAILURE); + } + } +} + +void +sandglass_timespec_add(struct timespec *ts, const struct timespec *d) +{ + if (d->tv_nsec >= 1000000000L - ts->tv_nsec) { + ts->tv_nsec += d->tv_nsec - 1000000000L; + ++ts->tv_sec; + } else { + ts->tv_nsec += d->tv_nsec; + } + ts->tv_sec += d->tv_sec; +} + +void +sandglass_timespec_sub(struct timespec *ts, const struct timespec *d) +{ + if (d->tv_nsec > ts->tv_nsec) { + ts->tv_nsec -= d->tv_nsec - 1000000000L; + --ts->tv_sec; + } else { + ts->tv_nsec -= d->tv_nsec; + } + ts->tv_sec -= d->tv_sec; +} + +int +sandglass_timespec_cmp(const struct timespec *a, const struct timespec *b) +{ + if (a->tv_sec > b->tv_sec) + return 1; + else if (a->tv_sec == b->tv_sec) { + if (a->tv_nsec > b->tv_nsec) + return 1; + else if (a->tv_nsec == b->tv_nsec) + return 0; + else + return -1; + } + else + return -1; +} + +/* Spins for the time interval specified by ts */ +void +sandglass_spin(struct timespec *ts) +{ + struct timespec curr, until; + sandglass_get_currtime(&curr); + until = curr; + sandglass_timespec_add(&until, ts); + + /* Spin */ + do { + sandglass_get_currtime(&curr); + } while (sandglass_timespec_cmp(&curr, &until) < 0); + + /* Adjust ts to the time actually waited */ + sandglass_timespec_sub(&curr, &until); + sandglass_timespec_add(ts, &curr); +} @@ -27,40 +27,14 @@ double sandglass_tsc_resolution() { - static long tsc = 0, grains1, grains2; - - int monotonic; - struct timespec ts; + static long tsc = 0; + static struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000L }; if (tsc == 0) { - monotonic = sysconf(_SC_MONOTONIC_CLOCK) > 0; - if (monotonic) { - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - return 0.0/0.0; - } else { - if (clock_gettime(CLOCK_REALTIME, &ts) != 0) - return 0.0/0.0; - } tsc = sandglass_get_tsc(); - grains1 = sandglass_timespec_grains(&ts); - grains2 = grains1; - - while (((grains2 >= grains1) ? grains2 - grains1 - : 1000000000L + (grains2 - grains1)) - < 10000000L) - { - if (monotonic) { - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - return 0.0/0.0; - } else { - if (clock_gettime(CLOCK_REALTIME, &ts) != 0) - return 0.0/0.0; - } - grains2 = ts.tv_nsec; - } - + sandglass_spin(&ts); tsc = sandglass_get_tsc() - tsc; } - return tsc*1.0e9/(grains2 - grains1); + return tsc*1.0e9/ts.tv_nsec; } |