rpmio/rpmsw.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 #include <rpmsw.h>
00007 #include "debug.h"
00008 
00009 #if defined(__LCLINT__)
00010 /*@-exportheader@*/
00011 extern int nanosleep(const struct timespec *__requested_time,
00012                 /*@out@*/ /*@null@*/ struct timespec *__remaining)
00013         /*@globals errno @*/
00014         /*@modifies *__remaining, errno @*/;
00015 /*@=exportheader@*/
00016 #endif
00017 
00018 /*@unchecked@*/
00019 static rpmtime_t rpmsw_overhead = 0;
00020 
00021 /*@unchecked@*/
00022 static rpmtime_t rpmsw_cycles = 1;
00023 
00024 /*@unchecked@*/
00025 static int rpmsw_type = 0;
00026 
00027 /*@unchecked@*/
00028 static int rpmsw_initialized = 0;
00029 
00030 #if defined(__i386__)
00031 /* Swiped from glibc-2.3.2 sysdeps/i386/i686/hp-timing.h */
00032 
00033 #define HP_TIMING_ZERO(Var)     (Var) = (0)
00034 #define HP_TIMING_NOW(Var)      __asm__ __volatile__ ("rdtsc" : "=A" (Var))
00035 
00036 /* It's simple arithmetic for us.  */
00037 #define HP_TIMING_DIFF(Diff, Start, End)        (Diff) = ((End) - (Start))
00038 
00039 /* We have to jump through hoops to get this correctly implemented.  */
00040 #define HP_TIMING_ACCUM(Sum, Diff) \
00041   do {                                                                        \
00042     char __not_done;                                                          \
00043     hp_timing_t __oldval = (Sum);                                             \
00044     hp_timing_t __diff = (Diff) - GL(dl_hp_timing_overhead);                  \
00045     do                                                                        \
00046       {                                                                       \
00047         hp_timing_t __newval = __oldval + __diff;                             \
00048         int __temp0, __temp1;                                                 \
00049         __asm__ __volatile__ ("xchgl %4, %%ebx\n\t"                           \
00050                               "lock; cmpxchg8b %1\n\t"                        \
00051                               "sete %0\n\t"                                   \
00052                               "movl %4, %%ebx"                                \
00053                               : "=q" (__not_done), "=m" (Sum),                \
00054                                 "=A" (__oldval), "=c" (__temp0),              \
00055                                 "=SD" (__temp1)                               \
00056                               : "1" (Sum), "2" (__oldval),                    \
00057                                 "3" (__newval >> 32),                         \
00058                                 "4" (__newval & 0xffffffff)                   \
00059                               : "memory");                                    \
00060       }                                                                       \
00061     while (__not_done);                                                       \
00062   } while (0)
00063 
00064 /* No threads, no extra work.  */
00065 #define HP_TIMING_ACCUM_NT(Sum, Diff)   (Sum) += (Diff)
00066 
00067 /* Print the time value.  */
00068 #define HP_TIMING_PRINT(Buf, Len, Val) \
00069   do {                                                                        \
00070     char __buf[20];                                                           \
00071     char *__cp = _itoa (Val, __buf + sizeof (__buf), 10, 0);                  \
00072     int __len = (Len);                                                        \
00073     char *__dest = (Buf);                                                     \
00074     while (__len-- > 0 && __cp < __buf + sizeof (__buf))                      \
00075       *__dest++ = *__cp++;                                                    \
00076     memcpy (__dest, " clock cycles", MIN (__len, sizeof (" clock cycles")));  \
00077   } while (0)
00078 #endif  /* __i386__ */
00079 
00080 rpmsw rpmswNow(rpmsw sw)
00081 {
00082     if (!rpmsw_initialized)
00083         (void) rpmswInit();
00084     if (sw == NULL)
00085         return NULL;
00086     switch (rpmsw_type) {
00087     case 0:
00088         if (gettimeofday(&sw->u.tv, NULL))
00089             return NULL;
00090         break;
00091 #if defined(HP_TIMING_NOW)
00092     case 1:
00093         HP_TIMING_NOW(sw->u.ticks);
00094         break;
00095 #endif
00096     }
00097     return sw;
00098 }
00099 
00106 static inline
00107 rpmtime_t tvsub(/*@null@*/ const struct timeval * etv,
00108                 /*@null@*/ const struct timeval * btv)
00109         /*@*/
00110 {
00111     time_t secs, usecs;
00112     if (etv == NULL  || btv == NULL) return 0;
00113     secs = etv->tv_sec - btv->tv_sec;
00114     for (usecs = etv->tv_usec - btv->tv_usec; usecs < 0; usecs += 1000000)
00115         secs--;
00116     return ((secs * 1000000) + usecs);
00117 }
00118 
00119 rpmtime_t rpmswDiff(rpmsw end, rpmsw begin)
00120 {
00121     unsigned long long ticks = 0;
00122 
00123     if (end == NULL || begin == NULL)
00124         return 0;
00125     switch (rpmsw_type) {
00126     default:
00127     case 0:
00128         ticks = tvsub(&end->u.tv, &begin->u.tv);
00129         break;
00130 #if defined(HP_TIMING_NOW)
00131     case 1:
00132         if (end->u.ticks > begin->u.ticks)
00133             HP_TIMING_DIFF(ticks, begin->u.ticks, end->u.ticks);
00134         break;
00135 #endif
00136     }
00137     if (ticks >= rpmsw_overhead)
00138         ticks -= rpmsw_overhead;
00139     if (rpmsw_cycles > 1)
00140         ticks /= rpmsw_cycles;
00141     return ticks;
00142 }
00143 
00144 #if defined(HP_TIMING_NOW)
00145 static rpmtime_t rpmswCalibrate(void)
00146         /*@globals internalState @*/
00147         /*@modifies internalState @*/
00148 {
00149     struct rpmsw_s begin, end;
00150     rpmtime_t ticks;
00151     struct timespec req, rem;
00152     int rc;
00153     int i;
00154 
00155 /*@-uniondef@*/
00156     (void) rpmswNow(&begin);
00157 /*@=uniondef@*/
00158     req.tv_sec = 0;
00159     req.tv_nsec = 20 * 1000 * 1000;
00160     for (i = 0; i < 100; i++) {
00161         rc = nanosleep(&req, &rem);
00162         if (rc == 0)
00163             break;
00164         if (rem.tv_sec == 0 && rem.tv_nsec == 0)
00165             break;
00166         req = rem;      /* structure assignment */
00167     }
00168 /*@-uniondef@*/
00169     ticks = rpmswDiff(rpmswNow(&end), &begin);
00170 /*@=uniondef@*/
00171 
00172     return ticks;
00173 }
00174 #endif
00175 
00176 rpmtime_t rpmswInit(void)
00177         /*@globals rpmsw_cycles, rpmsw_initialized, rpmsw_overhead,
00178                 rpmsw_type @*/
00179         /*@modifies rpmsw_cycles, rpmsw_initialized, rpmsw_overhead,
00180                 rpmsw_type @*/
00181 {
00182     struct rpmsw_s begin, end;
00183     unsigned long long sum_cycles = 0;
00184     rpmtime_t sum_usecs = 0;
00185     rpmtime_t sum_overhead = 0;
00186     rpmtime_t cycles;
00187     int i;
00188 
00189     rpmsw_initialized = 1;
00190 
00191     rpmsw_overhead = 0;
00192     rpmsw_cycles = 0;
00193 
00194     /* Convergence for simultaneous cycles and overhead is overkill ... */
00195     for (i = 0; i < 3; i++) {
00196 #if defined(HP_TIMING_NOW)
00197         rpmtime_t save_cycles = rpmsw_cycles;
00198 
00199         /* We want cycles, not cycles/usec, here. */
00200         rpmsw_cycles = 1;
00201 
00202         /* Start wall clock. */
00203         rpmsw_type = 0;
00204 /*@-uniondef@*/
00205         (void) rpmswNow(&begin);
00206 /*@=uniondef@*/
00207 
00208         /* Get no. of cycles while doing nanosleep. */
00209         rpmsw_type = 1;
00210         cycles = rpmswCalibrate();
00211         if (save_cycles > 0 && rpmsw_overhead > 0)
00212             cycles -= (save_cycles * rpmsw_overhead);
00213         sum_cycles += cycles;
00214 
00215         /* Compute wall clock delta in usecs. */
00216         rpmsw_type = 0;
00217 /*@-uniondef@*/
00218         sum_usecs += rpmswDiff(rpmswNow(&end), &begin);
00219 /*@=uniondef@*/
00220         rpmsw_type = 1;
00221 
00222         /* Compute cycles/usec */
00223         rpmsw_cycles = sum_cycles/sum_usecs;
00224 #else
00225         rpmsw_type = 0;
00226 #endif
00227 
00228         /* Calculate timing overhead in usecs. */
00229 /*@-uniondef@*/
00230         (void) rpmswNow(&begin);
00231         sum_overhead += rpmswDiff(rpmswNow(&end), &begin);
00232 /*@=uniondef@*/
00233 
00234         rpmsw_overhead = sum_overhead/(i+1);
00235 
00236     }
00237 
00238     return rpmsw_overhead;
00239 }
00240 
00241 int rpmswEnter(rpmop op, ssize_t rc)
00242 {
00243     if (op == NULL)
00244         return 0;
00245 
00246     op->count++;
00247     if (rc < 0) {
00248         op->bytes = 0;
00249         op->usecs = 0;
00250     }
00251 /*@-uniondef@*/
00252     (void) rpmswNow(&op->begin);
00253 /*@=uniondef@*/
00254     return 0;
00255 }
00256 
00257 rpmtime_t rpmswExit(rpmop op, ssize_t rc)
00258 {
00259     struct rpmsw_s end;
00260 
00261     if (op == NULL)
00262         return 0;
00263 
00264 /*@-uniondef@*/
00265     op->usecs += rpmswDiff(rpmswNow(&end), &op->begin);
00266 /*@=uniondef@*/
00267     if (rc > 0)
00268         op->bytes += rc;
00269     op->begin = end;    /* structure assignment */
00270     return op->usecs;
00271 }
00272 
00273 rpmtime_t rpmswAdd(rpmop to, rpmop from)
00274 {
00275     rpmtime_t usecs = 0;
00276     if (to != NULL && from != NULL) {
00277         to->count += from->count;
00278         to->bytes += from->bytes;
00279         to->usecs += from->usecs;
00280         usecs = to->usecs;
00281     }
00282     return usecs;
00283 }
00284 
00285 rpmtime_t rpmswSub(rpmop to, rpmop from)
00286 {
00287     rpmtime_t usecs = 0;
00288     if (to != NULL && from != NULL) {
00289         to->count -= from->count;
00290         to->bytes -= from->bytes;
00291         to->usecs -= from->usecs;
00292         usecs = to->usecs;
00293     }
00294     return usecs;
00295 }

Generated on Fri Oct 12 08:44:55 2007 for rpm by  doxygen 1.5.2