From 9a358c3cdf8eb34754cc5544e2a5e0f67c022f8d Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 17 Sep 2009 13:33:06 +0000 Subject: Improve sandglass_tsc_resolution(), and fix timespec-based grains counts. --- src/Makefile.am | 6 +++++- src/sandglass.c | 9 +++++---- src/sandglass_impl.h | 3 +++ src/timespec.c | 30 ++++++++++++++++++++++++++++++ src/tsc.c | 35 +++++++++++++++++++++++++++++++---- 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 src/timespec.c diff --git a/src/Makefile.am b/src/Makefile.am index 476c855..519e0ea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,11 @@ lib_LTLIBRARIES = libsandglass.la nobase_include_HEADERS = sandglass.h -libsandglass_la_SOURCES = sandglass.h sandglass_impl.h sandglass.c tsc.c +libsandglass_la_SOURCES = sandglass.h \ + sandglass_impl.h \ + sandglass.c \ + timespec.c \ + tsc.c if X86 libsandglass_la_SOURCES += x86/tsc-x86.s diff --git a/src/sandglass.c b/src/sandglass.c index 57729f9..3399b73 100644 --- a/src/sandglass.c +++ b/src/sandglass.c @@ -184,6 +184,9 @@ sandglass_elapse(sandglass_t *sandglass) return -1; sandglass->grains -= oldgrains; + /* Magical correction for timespec-based grains */ + if (sandglass->grains < 0) + sandglass->grains += 2000000000L; sandglass->grains /= sandglass->loops; return 0; @@ -219,12 +222,11 @@ sandglass_real_gettime(sandglass_t *sandglass) if (sysconf(_SC_MONOTONIC_CLOCK) > 0) { if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return -1; - sandglass->grains = ts.tv_nsec; } else { if (clock_gettime(CLOCK_REALTIME, &ts) != 0) return -1; - sandglass->grains = ts.tv_nsec; } + sandglass->grains = sandglass_timespec_grains(&ts); break; default: @@ -242,13 +244,12 @@ sandglass_real_gettime(sandglass_t *sandglass) if (sysconf(_SC_THREAD_CPUTIME) > 0) { if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) return -1; - sandglass->grains = ts.tv_nsec; } else if (sysconf(_SC_CPUTIME) > 0) { if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) != 0) return -1; - sandglass->grains = ts.tv_nsec; } else return -1; + sandglass->grains = sandglass_timespec_grains(&ts); break; case SANDGLASS_SYSTEM: diff --git a/src/sandglass_impl.h b/src/sandglass_impl.h index 5a3650e..b618a93 100644 --- a/src/sandglass_impl.h +++ b/src/sandglass_impl.h @@ -26,6 +26,7 @@ #define SANDGLASS_IMPL_H_INCLUDED #include "sandglass.h" +#include #ifdef SANDGLASS_TSC /* Read the time stamp counter */ @@ -36,4 +37,6 @@ double sandglass_tsc_resolution(); unsigned int sandglass_tsc_loops(); #endif +long sandglass_timespec_grains(const 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..81a5815 --- /dev/null +++ b/src/timespec.c @@ -0,0 +1,30 @@ +/************************************************************************* + * Copyright (C) 2008 Tavian Barnes * + * * + * 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 * + * . * + *************************************************************************/ + +#include "sandglass_impl.h" +#include "sandglass.h" +#include + +/* Convert a timespec to grains */ +long +sandglass_timespec_grains(const struct timespec *ts) +{ + return (ts->tv_sec%2L)*1000000000L + ts->tv_nsec; +} \ No newline at end of file diff --git a/src/tsc.c b/src/tsc.c index 64fe1b1..8038c0e 100644 --- a/src/tsc.c +++ b/src/tsc.c @@ -21,19 +21,46 @@ #include "sandglass_impl.h" #include "sandglass.h" #include +#include /* Gets the number of clock ticks per second */ double sandglass_tsc_resolution() { - static long tsc = 0; - struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + static long tsc = 0, grains1, grains2; + + int monotonic; + struct timespec ts; 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(); - while (nanosleep(&ts, &ts) != 0); + grains1 = sandglass_timespec_grains(&ts); + grains2 = grains1; + + while (((grains2 >= grains1) ? grains2 - grains1 + : 2000000000L + (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 = sandglass_timespec_grains(&ts); + } + tsc = sandglass_get_tsc() - tsc; } - return tsc*10.0; + return tsc*1.0e9/(grains2 - grains1); } -- cgit v1.2.3