• 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 }

Generated on Fri Dec 3 2010 20:54:40 for rpm by  doxygen 1.7.2