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

Generated on Mon Nov 29 2010 05:18:48 for rpm by  doxygen 1.7.2