00001
00005 #include "system.h"
00006 #include <rpmiotypes.h>
00007 #include <rpmsw.h>
00008 #include "debug.h"
00009
00010 #if defined(__LCLINT__)
00011
00012 extern int nanosleep(const struct timespec *__requested_time,
00013 struct timespec *__remaining)
00014
00015 ;
00016
00017 #endif
00018
00019
00020 int _rpmsw_stats = 0;
00021
00022
00023 static rpmtime_t rpmsw_overhead = 0;
00024
00025
00026 static rpmtime_t rpmsw_cycles = 1;
00027
00028
00029 static int rpmsw_type = 0;
00030
00031
00032 static int rpmsw_initialized = 0;
00033
00034 #if defined(__linux__) && defined(__i386__) && !defined(RPM_VENDOR_PLD)
00035
00036
00037 #define HP_TIMING_ZERO(Var) (Var) = (0)
00038 #define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var))
00039
00040
00041 #define HP_TIMING_DIFF(Diff, Start, End) (Diff) = ((End) - (Start))
00042
00043
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
00069 #define HP_TIMING_ACCUM_NT(Sum, Diff) (Sum) += (Diff)
00070
00071
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
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( const struct timeval * etv,
00112 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
00151
00152 {
00153 struct rpmsw_s begin, end;
00154 rpmtime_t ticks;
00155 struct timespec req, rem;
00156 int rc;
00157 int i;
00158
00159
00160 (void) rpmswNow(&begin);
00161
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;
00171 }
00172
00173 ticks = rpmswDiff(rpmswNow(&end), &begin);
00174
00175
00176 return ticks;
00177 }
00178 #endif
00179
00180 rpmtime_t rpmswInit(void)
00181
00182
00183
00184
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
00201 for (i = 0; i < 3; i++) {
00202 #if defined(HP_TIMING_NOW)
00203 rpmtime_t save_cycles = rpmsw_cycles;
00204
00205
00206 rpmsw_cycles = 1;
00207
00208
00209 rpmsw_type = 0;
00210
00211 (void) rpmswNow(&begin);
00212
00213
00214
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
00222 rpmsw_type = 0;
00223
00224 sum_usecs += rpmswDiff(rpmswNow(&end), &begin);
00225
00226 rpmsw_type = 1;
00227
00228
00229 if (sum_usecs > 0)
00230 rpmsw_cycles = sum_cycles/sum_usecs;
00231 #else
00232 rpmsw_type = 0;
00233 #endif
00234
00235
00236
00237 (void) rpmswNow(&begin);
00238 sum_overhead += rpmswDiff(rpmswNow(&end), &begin);
00239
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
00259 (void) rpmswNow(&op->begin);
00260
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
00272 op->usecs += rpmswDiff(rpmswNow(&end), &op->begin);
00273
00274 if (rc > 0)
00275 op->bytes += rc;
00276 op->begin = end;
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, rpmop op)
00305
00306
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 }