rpm
5.2.1
|
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 }