summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-09-17 03:18:51 +0000
committerTavian Barnes <tavianator@gmail.com>2009-09-17 03:18:51 +0000
commit66084b816dd25a41f774240328a31d57efd276e4 (patch)
treeacd22d0e3eb5f5608184fc18479e8890906cbe7f /src
parentf46ea7eb1b6f55036f10b6ae919c1785cb72c836 (diff)
downloadlibsandglass-66084b816dd25a41f774240328a31d57efd276e4.tar.xz
Begin libsandglass implementation.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/sandglass.c249
-rw-r--r--src/sandglass.h13
-rw-r--r--src/sandglass_impl.h39
-rw-r--r--src/tsc.c39
-rw-r--r--src/x86/tsc-x86.s17
-rw-r--r--src/x86_64/tsc-x86_64.s17
7 files changed, 368 insertions, 10 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4fc85ab..476c855 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,7 +21,7 @@ lib_LTLIBRARIES = libsandglass.la
nobase_include_HEADERS = sandglass.h
-libsandglass_la_SOURCES = sandglass.h sandglass.c
+libsandglass_la_SOURCES = sandglass.h sandglass_impl.h sandglass.c tsc.c
if X86
libsandglass_la_SOURCES += x86/tsc-x86.s
@@ -30,3 +30,5 @@ endif
if X86_64
libsandglass_la_SOURCES += x86_64/tsc-x86_64.s
endif
+
+libsandglass_la_LIBADD = -lrt
diff --git a/src/sandglass.c b/src/sandglass.c
index 4acf983..57729f9 100644
--- a/src/sandglass.c
+++ b/src/sandglass.c
@@ -18,4 +18,253 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
+#include "sandglass_impl.h"
#include "sandglass.h"
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+
+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_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)
+ {
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ /* 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;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+sandglass_real_create(sandglass_t *sandglass,
+ const sandglass_attributes_t *attr)
+{
+ switch (attr->incrementation) {
+ case SANDGLASS_MONOTONIC:
+ switch (attr->resolution) {
+ case SANDGLASS_REALTICKS:
+#ifdef SANDGLASS_TSC
+ sandglass->resolution = sandglass_tsc_resolution();
+ sandglass->loops = sandglass_tsc_loops();
+ break;
+#else
+ return -1;
+#endif
+
+ case SANDGLASS_CPUTIME:
+#ifdef SANDGLASS_TSC
+ sandglass->resolution = sandglass_tsc_resolution();
+ sandglass->loops = 1;
+ break;
+#else
+ return -1;
+#endif
+
+ case SANDGLASS_SYSTEM:
+ sandglass->resolution = 1e9;
+ sandglass->loops = 1;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case SANDGLASS_INTROSPECTIVE:
+ switch (attr->resolution) {
+ case SANDGLASS_REALTICKS:
+ /* No such thing as an introspective raw TSC */
+ return -1;
+
+ 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;
+ }
+
+ sandglass->attributes = *attr;
+ return 0;
+}
+
+/* Store a timer value in sandglass->grains */
+static int sandglass_real_gettime(sandglass_t *sandglass);
+
+/* Start timing */
+int
+sandglass_begin(sandglass_t *sandglass)
+{
+ return sandglass_real_gettime(sandglass);
+}
+
+/* Finish timing */
+int
+sandglass_elapse(sandglass_t *sandglass)
+{
+ long oldgrains = sandglass->grains;
+
+ if (sandglass_real_gettime(sandglass) != 0)
+ return -1;
+
+ sandglass->grains -= oldgrains;
+ sandglass->grains /= sandglass->loops;
+
+ return 0;
+}
+
+/* Store a timer value in sandglass->grains */
+static int
+sandglass_real_gettime(sandglass_t *sandglass)
+{
+ struct timespec ts;
+ clock_t clock_ticks;
+
+ switch (sandglass->attributes.incrementation) {
+ case SANDGLASS_MONOTONIC:
+ switch (sandglass->attributes.resolution) {
+ case SANDGLASS_REALTICKS:
+#ifdef SANDGLASS_TSC
+ sandglass->grains = sandglass_get_tsc();
+ break;
+#else
+ return -1;
+#endif
+
+ case SANDGLASS_CPUTIME:
+#ifdef SANDGLASS_TSC
+ sandglass->grains = sandglass_get_tsc();
+ break;
+#else
+ return -1;
+#endif
+
+ case SANDGLASS_SYSTEM:
+ 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;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case SANDGLASS_INTROSPECTIVE:
+ switch (sandglass->attributes.resolution) {
+ case SANDGLASS_REALTICKS:
+ /* No such thing as an introspective raw TSC */
+ return -1;
+
+ case SANDGLASS_CPUTIME:
+ 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;
+ break;
+
+ case SANDGLASS_SYSTEM:
+ if ((clock_ticks = clock()) == -1)
+ return -1;
+ sandglass->grains = clock();
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/sandglass.h b/src/sandglass.h
index a9e99e5..3cd14ba 100644
--- a/src/sandglass.h
+++ b/src/sandglass.h
@@ -93,7 +93,7 @@ struct sandglass_t
long grains;
/* grains/resolution should give elapsed time in seconds */
- long resolution;
+ double resolution;
/*
* Internal fields
@@ -140,20 +140,15 @@ int sandglass_elapse(sandglass_t *sandglass);
do { \
routine; \
sandglass_begin(sandglass); \
- for ((sandglass)->i = 0; (sandglass)->i < (sandglass)->loops; ++i) { \
+ for ((sandglass)->i = 0; \
+ (sandglass)->i < (sandglass)->loops; \
+ ++(sandglass)->i) { \
SANDGLASS_NO_UNROLL(); \
routine; \
} \
sandglass_elapse(sandglass); \
} while (0)
-/*
- * Low-level API
- */
-
-/* Read the time stamp counter */
-long sandglass_get_tsc();
-
#ifdef __cplusplus
}
#endif
diff --git a/src/sandglass_impl.h b/src/sandglass_impl.h
new file mode 100644
index 0000000..5a3650e
--- /dev/null
+++ b/src/sandglass_impl.h
@@ -0,0 +1,39 @@
+/*************************************************************************
+ * 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/>. *
+ *************************************************************************/
+
+/*
+ * Internal libsandglass API
+ */
+
+#ifndef SANDGLASS_IMPL_H_INCLUDED
+#define SANDGLASS_IMPL_H_INCLUDED
+
+#include "sandglass.h"
+
+#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 */
+unsigned int sandglass_tsc_loops();
+#endif
+
+#endif /* SANDGLASS_IMPL_H_INCLUDED */ \ No newline at end of file
diff --git a/src/tsc.c b/src/tsc.c
new file mode 100644
index 0000000..64fe1b1
--- /dev/null
+++ b/src/tsc.c
@@ -0,0 +1,39 @@
+/*************************************************************************
+ * 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>
+
+/* 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 };
+
+ if (tsc == 0) {
+ tsc = sandglass_get_tsc();
+ while (nanosleep(&ts, &ts) != 0);
+ tsc = sandglass_get_tsc() - tsc;
+ }
+
+ return tsc*10.0;
+}
diff --git a/src/x86/tsc-x86.s b/src/x86/tsc-x86.s
index 570b8af..46013bb 100644
--- a/src/x86/tsc-x86.s
+++ b/src/x86/tsc-x86.s
@@ -38,3 +38,20 @@ sandglass_get_tsc:
popl %ebx
ret
.size sandglass_get_tsc, .-sandglass_get_tsc
+
+/*
+ * Return the granularity of the TSC
+ */
+
+/* unsigned int sandglass_tsc_loops(); */
+.globl sandglass_tsc_loops
+ .type sandglass_tsc_loops, @function
+sandglass_tsc_loops:
+ rdtsc /* Read time stamp counter */
+ movl %eax, %ecx
+.Lrdtsc:
+ rdtsc /* Read counter again */
+ subl %ecx, %eax
+ jz .Lrdtsc /* If we got the same value, try again */
+ ret
+ .size sandglass_tsc_loops, .-sandglass_tsc_loops
diff --git a/src/x86_64/tsc-x86_64.s b/src/x86_64/tsc-x86_64.s
index c585719..52f02c2 100644
--- a/src/x86_64/tsc-x86_64.s
+++ b/src/x86_64/tsc-x86_64.s
@@ -38,3 +38,20 @@ sandglass_get_tsc:
movq %rdi, %rbx
ret
.size sandglass_get_tsc, .-sandglass_get_tsc
+
+/*
+ * Return the granularity of the TSC
+ */
+
+/* unsigned int sandglass_tsc_loops(); */
+.globl sandglass_tsc_loops
+ .type sandglass_tsc_loops, @function
+sandglass_tsc_loops:
+ rdtsc /* Read time stamp counter */
+ movl %eax, %ecx
+.Lrdtsc:
+ rdtsc /* Read counter again */
+ subl %ecx, %eax
+ jz .Lrdtsc /* If we got the same value, try again */
+ ret
+ .size sandglass_tsc_loops, .-sandglass_tsc_loops