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