From d9082d59db90a4373ec52d932b87234e3c39b21b Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Wed, 6 Sep 2006 01:37:13 -0700 Subject: [PATCH] Prefer CPU performance counters (if available) over gettimeofday. I've seen this improve the std. deviation often by a factor of 2 and occasionally up to a factor of 10. It is sometimes not much better, but never seems to be appreciably worse compared to using gettimeofday. Thanks to David A. Schleef and his liboil for the implementation. --- perf/cairo-perf-posix.c | 124 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 8 deletions(-) diff --git a/perf/cairo-perf-posix.c b/perf/cairo-perf-posix.c index 452f05822..2105f9c97 100644 --- a/perf/cairo-perf-posix.c +++ b/perf/cairo-perf-posix.c @@ -25,6 +25,34 @@ * Carl Worth */ +/* Portions of this file come from liboil: + * + * LIBOIL - Library of Optimized Inner Loops + * Copyright (c) 2003,2004 David A. Schleef + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + #include #include #include @@ -36,37 +64,117 @@ /* timers */ +#if defined(__i386__) || defined(__amd64__) +static inline unsigned long +oil_profile_stamp_rdtsc (void) +{ + unsigned long ts; + __asm__ __volatile__("rdtsc\n" : "=a" (ts) : : "edx"); + return ts; +} +#define OIL_STAMP oil_profile_stamp_rdtsc +#endif + +#if defined(__powerpc__) || defined(__PPC__) || defined(__ppc__) +static inline cairo_perf_ticks_t +oil_profile_stamp_tb(void) +{ + unsigned long ts; + __asm__ __volatile__("mftb %0\n" : "=r" (ts)); + return ts; +} +#define OIL_STAMP oil_profile_stamp_tb +#endif + +#if defined(__alpha__) +static inline cairo_perf_ticks_t +oil_profile_stamp_alpha(void) +{ + unsigned int ts; + __asm__ __volatile__ ("rpcc %0\n" : "=r"(ts)); + return ts; +} +#define OIL_STAMP oil_profile_stamp_alpha +#endif + +#if defined(__s390__) +static cairo_perf_ticks_t +oil_profile_stamp_s390(void) +{ + uint64_t ts; + __asm__ __volatile__ ("STCK %0\n" : : "m" (ts)); + return ts; +} +#define OIL_STAMP oil_profile_stamp_s390 +#endif + typedef struct _cairo_perf_timer { - struct timeval start; - struct timeval stop; +#ifdef OIL_STAMP + cairo_perf_ticks_t start; + cairo_perf_ticks_t stop; +#else + struct timeval tv_start; + struct timeval tv_stop; +#endif } cairo_perf_timer_t; static cairo_perf_timer_t timer; void cairo_perf_timer_start (void) { - gettimeofday (&timer.start, NULL); +#ifdef OIL_STAMP + timer.start = OIL_STAMP (); +#else + gettimeofday (&timer.tv_start, NULL); +#endif } void cairo_perf_timer_stop (void) { - gettimeofday (&timer.stop, NULL); +#ifdef OIL_STAMP + timer.stop = OIL_STAMP (); +#else + gettimeofday (&timer.tv_stop, NULL); +#endif } cairo_perf_ticks_t cairo_perf_timer_elapsed (void) { - cairo_perf_ticks_t usec; + cairo_perf_ticks_t ticks; - usec = (timer.stop.tv_sec - timer.start.tv_sec) * 1000000; - usec += (timer.stop.tv_usec - timer.start.tv_usec); +#ifdef OIL_STAMP + ticks = (timer.stop - timer.start); +#else + ticks = (timer.tv_stop.tv_sec - timer.tv_start.tv_sec) * 1000000; + ticks += (timer.tv_stop.tv_usec - timer.tv_start.tv_usec); +#endif - return usec; + return ticks; } cairo_perf_ticks_t cairo_perf_ticks_per_second (void) { +#ifdef OIL_STAMP + static cairo_perf_ticks_t tps = 0; + /* XXX: This is obviously not stable in light of changing CPU speed. */ + if (tps == 0) { + struct timeval tv_start, tv_stop; + double tv_elapsed; + cairo_perf_timer_start (); + gettimeofday (&tv_start, NULL); + sleep (1); + cairo_perf_timer_stop (); + gettimeofday (&tv_stop, NULL); + tv_elapsed = ((tv_stop.tv_sec - tv_start.tv_sec) + + + (tv_stop.tv_usec - tv_start.tv_usec) / 1000000.0); + tps = round (cairo_perf_timer_elapsed () / tv_elapsed); + } + return tps; +#else + /* For gettimeofday the units are micro-seconds */ return 1000000; +#endif } /* yield */