Back to index

glibc  2.9
hp-timing.h
Go to the documentation of this file.
00001 /* High precision, low overhead timing functions.  IA-64 version.
00002    Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@cygnus.com>, 2001.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #ifndef _HP_TIMING_H
00022 #define _HP_TIMING_H 1
00023 
00024 #include <string.h>
00025 #include <sys/param.h>
00026 #include <stdio-common/_itoa.h>
00027 #include <ia64intrin.h>
00028 
00029 /* The macros defined here use the timestamp counter in IA-64.  They
00030    provide a very accurate way to measure the time with very little
00031    overhead.  The time values themself have no real meaning, only
00032    differences are interesting.
00033 
00034    The list of macros we need includes the following:
00035 
00036    - HP_TIMING_AVAIL: test for availability.
00037 
00038    - HP_TIMING_INLINE: this macro is non-zero if the functionality is not
00039      implemented using function calls but instead uses some inlined code
00040      which might simply consist of a few assembler instructions.  We have to
00041      know this since we might want to use the macros here in places where we
00042      cannot make function calls.
00043 
00044    - hp_timing_t: This is the type for variables used to store the time
00045      values.
00046 
00047    - HP_TIMING_ZERO: clear `hp_timing_t' object.
00048 
00049    - HP_TIMING_NOW: place timestamp for current time in variable given as
00050      parameter.
00051 
00052    - HP_TIMING_DIFF_INIT: do whatever is necessary to be able to use the
00053      HP_TIMING_DIFF macro.
00054 
00055    - HP_TIMING_DIFF: compute difference between two times and store it
00056      in a third.  Source and destination might overlap.
00057 
00058    - HP_TIMING_ACCUM: add time difference to another variable.  This might
00059      be a bit more complicated to implement for some platforms as the
00060      operation should be thread-safe and 64bit arithmetic on 32bit platforms
00061      is not.
00062 
00063    - HP_TIMING_ACCUM_NT: this is the variant for situations where we know
00064      there are no threads involved.
00065 
00066    - HP_TIMING_PRINT: write decimal representation of the timing value into
00067      the given string.  This operation need not be inline even though
00068      HP_TIMING_INLINE is specified.
00069 
00070 */
00071 
00072 /* We always assume having the timestamp register.  */
00073 #define HP_TIMING_AVAIL            (1)
00074 
00075 /* We indeed have inlined functions.  */
00076 #define HP_TIMING_INLINE    (1)
00077 
00078 /* We use 64bit values for the times.  */
00079 typedef unsigned long int hp_timing_t;
00080 
00081 /* Set timestamp value to zero.  */
00082 #define HP_TIMING_ZERO(Var) (Var) = (0)
00083 
00084 
00085 /* The Itanium/Merced has a bug where the ar.itc register value read
00086    is not correct in some situations.  The solution is to read again.
00087    For now we always do this until we know how to recognize a fixed
00088    processor implementation.  */
00089 #define REPEAT_READ(val) __builtin_expect ((long int) val == -1, 0)
00090 
00091 /* That's quite simple.  Use the `ar.itc' instruction.  */
00092 #define HP_TIMING_NOW(Var) \
00093   ({ unsigned long int __itc;                                               \
00094      do                                                                     \
00095        asm volatile ("mov %0=ar.itc" : "=r" (__itc) : : "memory");          \
00096      while (REPEAT_READ (__itc));                                    \
00097      Var = __itc; })
00098 
00099 /* Use two 'ar.itc' instructions in a row to find out how long it takes.  */
00100 #define HP_TIMING_DIFF_INIT() \
00101   do {                                                               \
00102     int __cnt = 5;                                                   \
00103     GLRO(dl_hp_timing_overhead) = ~0ul;                                     \
00104     do                                                               \
00105       {                                                                     \
00106        hp_timing_t __t1, __t2;                                              \
00107        HP_TIMING_NOW (__t1);                                                \
00108        HP_TIMING_NOW (__t2);                                                \
00109        if (__t2 - __t1 < GLRO(dl_hp_timing_overhead))                       \
00110          GLRO(dl_hp_timing_overhead) = __t2 - __t1;                         \
00111       }                                                                     \
00112     while (--__cnt > 0);                                             \
00113   } while (0)
00114 
00115 /* It's simple arithmetic for us.  */
00116 #define HP_TIMING_DIFF(Diff, Start, End)  (Diff) = ((End) - (Start))
00117 
00118 /* We have to jump through hoops to get this correctly implemented.  */
00119 #define HP_TIMING_ACCUM(Sum, Diff) \
00120   do {                                                               \
00121     hp_timing_t __oldval;                                            \
00122     hp_timing_t __diff = (Diff) - GLRO(dl_hp_timing_overhead);              \
00123     hp_timing_t __newval;                                            \
00124     do                                                               \
00125       {                                                                     \
00126        __oldval = (Sum);                                             \
00127        __newval = __oldval + __diff;                                        \
00128       }                                                                     \
00129     while (! __sync_bool_compare_and_swap (&Sum, __oldvar, __newval));             \
00130   } while (0)
00131 
00132 /* No threads, no extra work.  */
00133 #define HP_TIMING_ACCUM_NT(Sum, Diff)     (Sum) += (Diff)
00134 
00135 /* Print the time value.  */
00136 #define HP_TIMING_PRINT(Buf, Len, Val) \
00137   do {                                                               \
00138     char __buf[20];                                                  \
00139     char *__cp = _itoa_word (Val, __buf + sizeof (__buf), 10, 0);           \
00140     int __len = (Len);                                                      \
00141     char *__dest = (Buf);                                            \
00142     while (__len-- > 0 && __cp < __buf + sizeof (__buf))                    \
00143       *__dest++ = *__cp++;                                           \
00144     memcpy (__dest, " clock cycles", MIN (__len,                     \
00145                                      (int) sizeof (" clock cycles")));   \
00146   } while (0)
00147 
00148 #endif /* hp-timing.h */