rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmio/rpmsw.c
Go to the documentation of this file.

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