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

# 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(__linux__) && 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 (rpmtime_t) ((secs * 1000000) + usecs);
    00117 }
    00118
    00119 rpmtime_t rpmswDiff(rpmsw end, rpmsw begin)
    00120 {
    00121     uint64_t 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 (rpmtime_t) 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     rpmtime_t sum_overhead = 0;
    00184 #if defined(HP_TIMING_NOW)
    00185     rpmtime_t cycles;
    00186     rpmtime_t sum_usecs = 0;
    00187     uint64_t sum_cycles = 0;
    00188 #endif
    00189     int i;
    00190
    00191     rpmsw_initialized = 1;
    00192
    00193     rpmsw_overhead = 0;
    00194     rpmsw_cycles = 0;
    00195
    00196     /* Convergence for simultaneous cycles and overhead is overkill ... */
    00197     for (i = 0; i < 3; i++) {
    00198 #if defined(HP_TIMING_NOW)
    00199         rpmtime_t save_cycles = rpmsw_cycles;
    00200
    00201         /* We want cycles, not cycles/usec, here. */
    00202         rpmsw_cycles = 1;
    00203
    00204         /* Start wall clock. */
    00205         rpmsw_type = 0;
    00206 /*@-uniondef@*/
    00207         (void) rpmswNow(&begin);
    00208 /*@=uniondef@*/
    00209
    00210         /* Get no. of cycles while doing nanosleep. */
    00211         rpmsw_type = 1;
    00212         cycles = rpmswCalibrate();
    00213         if (save_cycles > 0 && rpmsw_overhead > 0)
    00214             cycles -= (save_cycles * rpmsw_overhead);
    00215         sum_cycles += cycles;
    00216
    00217         /* Compute wall clock delta in usecs. */
    00218         rpmsw_type = 0;
    00219 /*@-uniondef@*/
    00220         sum_usecs += rpmswDiff(rpmswNow(&end), &begin);
    00221 /*@=uniondef@*/
    00222         rpmsw_type = 1;
    00223
    00224         /* Compute cycles/usec */
    00225         rpmsw_cycles = sum_cycles/sum_usecs;
    00226 #else
    00227         rpmsw_type = 0;
    00228 #endif
    00229
    00230         /* Calculate timing overhead in usecs. */
    00231 /*@-uniondef@*/
    00232         (void) rpmswNow(&begin);
    00233         sum_overhead += rpmswDiff(rpmswNow(&end), &begin);
    00234 /*@=uniondef@*/
    00235
    00236         rpmsw_overhead = sum_overhead/(i+1);
    00237
    00238     }
    00239
    00240     return rpmsw_overhead;
    00241 }
    00242
    00243 int rpmswEnter(rpmop op, ssize_t rc)
    00244 {
    00245     if (op == NULL)
    00246         return 0;
    00247
    00248     op->count++;
    00249     if (rc < 0) {
    00250         op->bytes = 0;
    00251         op->usecs = 0;
    00252     }
    00253 /*@-uniondef@*/
    00254     (void) rpmswNow(&op->begin);
    00255 /*@=uniondef@*/
    00256     return 0;
    00257 }
    00258
    00259 rpmtime_t rpmswExit(rpmop op, ssize_t rc)
    00260 {
    00261     struct rpmsw_s end;
    00262
    00263     if (op == NULL)
    00264         return 0;
    00265
    00266 /*@-uniondef@*/
    00267     op->usecs += rpmswDiff(rpmswNow(&end), &op->begin);
    00268 /*@=uniondef@*/
    00269     if (rc > 0)
    00270         op->bytes += rc;
    00271     op->begin = end;    /* structure assignment */
    00272     return op->usecs;
    00273 }
    00274
    00275 rpmtime_t rpmswAdd(rpmop to, rpmop from)
    00276 {
    00277     rpmtime_t usecs = 0;
    00278     if (to != NULL && from != NULL) {
    00279         to->count += from->count;
    00280         to->bytes += from->bytes;
    00281         to->usecs += from->usecs;
    00282         usecs = to->usecs;
    00283     }
    00284     return usecs;
    00285 }
    00286
    00287 rpmtime_t rpmswSub(rpmop to, rpmop from)
    00288 {
    00289     rpmtime_t usecs = 0;
    00290     if (to != NULL && from != NULL) {
    00291         to->count -= from->count;
    00292         to->bytes -= from->bytes;
    00293         to->usecs -= from->usecs;
    00294         usecs = to->usecs;
    00295     }
    00296     return usecs;
    00297 }