From 35a1d0d051546f0bbaae9338aa3fed4d04a9a92e Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 23 Oct 2009 18:14:55 +0000 Subject: New sandglass_bench_* macros, remove SANDGLASS_REALTICKS. sandglass_bench_fine() replaces SANDGLASS_REALTICKS; use SANDGLASS_CPUTIME instead. Also, sandglass_bench_noprecache() for when the expression to be timed has side-effects and should be executed only once. --- src/sandglass.c | 20 +----- src/sandglass.h | 68 ++++++++++++++++---- tests/monotonic-realticks.c | 4 +- tests/simple-test | 148 -------------------------------------------- 4 files changed, 59 insertions(+), 181 deletions(-) delete mode 100755 tests/simple-test diff --git a/src/sandglass.c b/src/sandglass.c index 6db28a3..f97b9c1 100644 --- a/src/sandglass.c +++ b/src/sandglass.c @@ -104,19 +104,10 @@ sandglass_real_create(sandglass_t *sandglass, 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; + sandglass->loops = sandglass_tsc_loops(); break; #else return -1; @@ -134,10 +125,6 @@ sandglass_real_create(sandglass_t *sandglass, 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; @@ -202,7 +189,6 @@ sandglass_real_gettime(sandglass_t *sandglass) switch (sandglass->attributes.incrementation) { case SANDGLASS_MONOTONIC: switch (sandglass->attributes.resolution) { - case SANDGLASS_REALTICKS: case SANDGLASS_CPUTIME: #ifdef SANDGLASS_TSC sandglass->grains = sandglass_get_tsc(); @@ -230,10 +216,6 @@ sandglass_real_gettime(sandglass_t *sandglass) 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) diff --git a/src/sandglass.h b/src/sandglass.h index 0d5e5e5..34461ba 100644 --- a/src/sandglass.h +++ b/src/sandglass.h @@ -26,6 +26,8 @@ #ifndef SANDGLASS_H_INCLUDED #define SANDGLASS_H_INCLUDED +#include + #ifdef __cplusplus /* We've been included from a C++ file; mark everything here as extern "C" */ extern "C" { @@ -65,14 +67,7 @@ enum sandglass_resolution_t * portable. Uses the CLOCK_THREAD_CPUTIME_ID clock for * SANDGLASS_INTROSPECTIVE mode, and the raw TSC for SANDGLASS_MONOTONIC. */ - SANDGLASS_CPUTIME, - - /* - * Get timing information accurate to within one CPU clock cycle - requires - * some looping and other trickery to account for TSCs which are not accurate - * to within one clock cycle. Not valid with SANDGLASS_INTROSPECTIVE. - */ - SANDGLASS_REALTICKS + SANDGLASS_CPUTIME }; typedef enum sandglass_resolution_t sandglass_resolution_t; @@ -134,16 +129,18 @@ int sandglass_elapse(sandglass_t *sandglass); #define SANDGLASS_NO_UNROLL() __asm__ __volatile__ ("") /* - * Macro to facilitate correct benchmarking of blocks of code. May be called + * Macros to facilitate correct benchmarking of blocks of code. May be called * like so: - * sandglass_bench(&sandglass, f(x)) + * sandglass_bench*(&sandglass, f(x)) * or like so: - * sandglass_bench(&sandglass, { + * sandglass_bench*(&sandglass, { * f(x); * g(x); * }); */ -#define sandglass_bench(sandglass, routine) \ + +/* Provides single clock cycle resolution in some cases */ +#define sandglass_bench_fine(sandglass, routine) \ do { \ /* Warm up the cache for these functions */ \ sandglass_begin(sandglass); \ @@ -161,6 +158,7 @@ int sandglass_elapse(sandglass_t *sandglass); \ /* Warm up the cache for our routine */ \ routine; \ + \ /* Time our routine in a loop */ \ sandglass_begin(sandglass); \ for ((sandglass)->i = 0; \ @@ -168,6 +166,7 @@ int sandglass_elapse(sandglass_t *sandglass); ++(sandglass)->i) { \ SANDGLASS_NO_UNROLL(); \ routine; \ + SANDGLASS_NO_UNROLL(); \ } \ sandglass_elapse(sandglass); \ \ @@ -176,6 +175,51 @@ int sandglass_elapse(sandglass_t *sandglass); (sandglass)->grains /= (sandglass)->loops; \ } while (0) +/* General high resolution timer */ +#define sandglass_bench(sandglass, routine) \ + do { \ + /* Warm up the cache for these functions */ \ + sandglass_begin(sandglass); \ + sandglass_elapse(sandglass); \ + \ + /* Time an empty routine for our baseline */ \ + sandglass_begin(sandglass); \ + sandglass_elapse(sandglass); \ + (sandglass)->baseline = (sandglass)->grains; \ + \ + /* Warm up the cache for our routine */ \ + routine; \ + \ + /* Time the routine */ \ + sandglass_begin(sandglass); \ + routine; \ + sandglass_elapse(sandglass); \ + \ + /* Subtract the baseline */ \ + (sandglass)->grains -= (sandglass)->baseline; \ + } while (0) + +/* Only executes routine once - useful if routine has side-effects */ +#define sandglass_bench_noprecache(sandglass, routine) \ + do { \ + /* Warm up the cache for these functions */ \ + sandglass_begin(sandglass); \ + sandglass_elapse(sandglass); \ + \ + /* Time an empty loop for our baseline */ \ + sandglass_begin(sandglass); \ + sandglass_elapse(sandglass); \ + (sandglass)->baseline = (sandglass)->grains; \ + \ + /* Time the routine */ \ + sandglass_begin(sandglass); \ + routine; \ + sandglass_elapse(sandglass); \ + \ + /* Subtract the baseline */ \ + (sandglass)->grains -= (sandglass)->baseline; \ + } while (0) + #ifdef __cplusplus } #endif diff --git a/tests/monotonic-realticks.c b/tests/monotonic-realticks.c index 9b5daff..51404f5 100644 --- a/tests/monotonic-realticks.c +++ b/tests/monotonic-realticks.c @@ -30,14 +30,14 @@ int main() { sandglass_t sandglass; - sandglass_attributes_t attr = { SANDGLASS_MONOTONIC, SANDGLASS_REALTICKS }; + sandglass_attributes_t attr = { SANDGLASS_MONOTONIC, SANDGLASS_CPUTIME }; if (sandglass_create(&sandglass, &attr, &attr) != 0) { perror("sandglass_create()"); return EXIT_FAILURE; } - sandglass_bench(&sandglass, sandglass_get_tsc()); + sandglass_bench_fine(&sandglass, sandglass_get_tsc()); printf("%ld\n", sandglass.grains); diff --git a/tests/simple-test b/tests/simple-test deleted file mode 100755 index 8fbcf16..0000000 --- a/tests/simple-test +++ /dev/null @@ -1,148 +0,0 @@ -#! /bin/sh - -# simple-test - temporary wrapper script for .libs/simple-test -# Generated by ltmain.sh (GNU libtool) 2.2.6 -# -# The simple-test program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed='/bin/sed -e 1s/^X//' -sed_quote_subst='s/\([`"$\\]\)/\\\1/g' - -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command="(cd /home/tavianator/libsandglass/tests; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; { test -z \"\${LD_LIBRARY_PATH+set}\" || unset LD_LIBRARY_PATH || { LD_LIBRARY_PATH=; export LD_LIBRARY_PATH; }; }; PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/java/bin:/opt/java/jre/bin:/home/tavianator/bin:/usr/bin/perlbin/site:/usr/bin/perlbin/vendor:/usr/bin/perlbin/core:/opt/qt/bin; export PATH; gcc -g -Wall -o \$progdir/\$file simple.o ../src/.libs/libsandglass.so -lrt -Wl,-rpath -Wl,/home/tavianator/libsandglass/src/.libs)" - -# This environment variable determines our operation mode. -if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then - # install mode needs the following variables: - generated_by_libtool_version='2.2.6' - notinst_deplibs=' ../src/libsandglass.la' -else - # When we are sourced in execute mode, $file and $ECHO are already set. - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - ECHO="echo" - file="$0" - # Make sure echo works. - if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then - # Yippee, $ECHO works! - : - else - # Restart under the correct shell, and then maybe $ECHO will work. - exec /bin/sh "$0" --no-reexec ${1+"$@"} - fi - fi - - # Find the directory that this script lives in. - thisdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` - test "x$thisdir" = "x$file" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'` - while test -n "$file"; do - destdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'` - - # If there was a directory component, then change thisdir. - if test "x$destdir" != "x$file"; then - case "$destdir" in - [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;; - *) thisdir="$thisdir/$destdir" ;; - esac - fi - - file=`$ECHO "X$file" | $Xsed -e 's%^.*/%%'` - file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'` - done - - - # Usually 'no', except on cygwin/mingw when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no - if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then - # special case for '.' - if test "$thisdir" = "."; then - thisdir=`pwd` - fi - # remove .libs from thisdir - case "$thisdir" in - *[\\/].libs ) thisdir=`$ECHO "X$thisdir" | $Xsed -e 's%[\\/][^\\/]*$%%'` ;; - .libs ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=`cd "$thisdir" && pwd` - test -n "$absdir" && thisdir="$absdir" - - program=lt-'simple-test' - progdir="$thisdir/.libs" - - if test ! -f "$progdir/$program" || - { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \ - test "X$file" != "X$progdir/$program"; }; then - - file="$$-$program" - - if test ! -d "$progdir"; then - mkdir "$progdir" - else - rm -f "$progdir/$file" - fi - - # relink executable if necessary - if test -n "$relink_command"; then - if relink_command_output=`eval $relink_command 2>&1`; then : - else - echo "$relink_command_output" >&2 - rm -f "$progdir/$file" - exit 1 - fi - fi - - mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null || - { rm -f "$progdir/$program"; - mv -f "$progdir/$file" "$progdir/$program"; } - rm -f "$progdir/$file" - fi - - if test -f "$progdir/$program"; then - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - # Run the actual program with our arguments. - - exec "$progdir/$program" ${1+"$@"} - - $ECHO "$0: cannot exec $program $*" 1>&2 - exit 1 - fi - else - # The program doesn't exist. - $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2 - $ECHO "This script is just a wrapper for $program." 1>&2 - echo "See the libtool documentation for more information." 1>&2 - exit 1 - fi -fi -- cgit v1.2.3