9 #if defined(__LCLINT__)
11 extern int nanosleep(const struct timespec *__requested_time,
12 /*@out@*/ /*@null@*/ struct timespec *__remaining)
14 /*@modifies *__remaining, errno @*/;
19 static rpmtime_t rpmsw_overhead = 0;
22 static rpmtime_t rpmsw_cycles = 1;
25 static int rpmsw_type = 0;
28 static int rpmsw_initialized = 0;
31 /* Swiped from glibc-2.3.2 sysdeps/i386/i686/hp-timing.h */
33 #define HP_TIMING_ZERO(Var) (Var) = (0)
34 #define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var))
36 /* It's simple arithmetic for us. */
37 #define HP_TIMING_DIFF(Diff, Start, End) (Diff) = ((End) - (Start))
39 /* We have to jump through hoops to get this correctly implemented. */
40 #define HP_TIMING_ACCUM(Sum, Diff) \
43 hp_timing_t __oldval = (Sum); \
44 hp_timing_t __diff = (Diff) - GL(dl_hp_timing_overhead); \
47 hp_timing_t __newval = __oldval + __diff; \
48 int __temp0, __temp1; \
49 __asm__ __volatile__ ("xchgl %4, %%ebx\n\t" \
50 "lock; cmpxchg8b %1\n\t" \
53 : "=q" (__not_done), "=m" (Sum), \
54 "=A" (__oldval), "=c" (__temp0), \
56 : "1" (Sum), "2" (__oldval), \
57 "3" (__newval >> 32), \
58 "4" (__newval & 0xffffffff) \
64 /* No threads, no extra work. */
65 #define HP_TIMING_ACCUM_NT(Sum, Diff) (Sum) += (Diff)
67 /* Print the time value. */
68 #define HP_TIMING_PRINT(Buf, Len, Val) \
71 char *__cp = _itoa (Val, __buf + sizeof (__buf), 10, 0); \
73 char *__dest = (Buf); \
74 while (__len-- > 0 && __cp < __buf + sizeof (__buf)) \
75 *__dest++ = *__cp++; \
76 memcpy (__dest, " clock cycles", MIN (__len, sizeof (" clock cycles"))); \
80 rpmsw rpmswNow(rpmsw sw)
83 if (!rpmsw_initialized)
90 if (gettimeofday(&sw->u.tv, NULL))
93 #if defined(HP_TIMING_NOW)
95 HP_TIMING_NOW(sw->u.ticks);
103 * Return difference of 2 timeval stamps in micro-seconds.
104 * @param *etv end timeval
105 * @param *btv begin timeval
106 * @return difference in milli-seconds
109 rpmtime_t tvsub(/*@null@*/ const struct timeval * etv,
110 /*@null@*/ const struct timeval * btv)
114 if (etv == NULL || btv == NULL) return 0;
115 secs = etv->tv_sec - btv->tv_sec;
116 for (usecs = etv->tv_usec - btv->tv_usec; usecs < 0; usecs += 1000000)
118 return ((secs * 1000000) + usecs);
121 rpmtime_t rpmswDiff(rpmsw end, rpmsw begin)
123 unsigned long long ticks = 0;
125 if (end == NULL || begin == NULL)
127 switch (rpmsw_type) {
130 ticks = tvsub(&end->u.tv, &begin->u.tv);
132 #if defined(HP_TIMING_NOW)
134 if (end->u.ticks > begin->u.ticks)
135 HP_TIMING_DIFF(ticks, begin->u.ticks, end->u.ticks);
139 if (ticks >= rpmsw_overhead)
140 ticks -= rpmsw_overhead;
141 if (rpmsw_cycles > 1)
142 ticks /= rpmsw_cycles;
146 #if defined(HP_TIMING_NOW)
148 static rpmtime_t rpmswCalibrate(void)
149 /*@globals internalState @*/
150 /*@modifies internalState @*/
152 struct rpmsw_s begin, end;
154 struct timespec req, rem;
159 (void) rpmswNow(&begin);
162 req.tv_nsec = 20 * 1000 * 1000;
163 for (i = 0; i < 100; i++) {
165 rc = nanosleep(&req, &rem);
169 if (rem.tv_sec == 0 && rem.tv_nsec == 0)
171 req = rem; /* structure assignment */
174 ticks = rpmswDiff(rpmswNow(&end), &begin);
183 rpmtime_t rpmswInit(void)
184 /*@globals rpmsw_cycles, rpmsw_initialized, rpmsw_overhead,
186 /*@modifies rpmsw_cycles, rpmsw_initialized, rpmsw_overhead,
189 struct rpmsw_s begin, end;
190 unsigned long long sum_cycles = 0;
191 rpmtime_t sum_usecs = 0;
192 rpmtime_t sum_overhead = 0;
196 rpmsw_initialized = 1;
201 /* Convergence for simultaneous cycles and overhead is overkill ... */
202 for (i = 0; i < 3; i++) {
203 #if defined(HP_TIMING_NOW)
204 rpmtime_t save_cycles = rpmsw_cycles;
206 /* We want cycles, not cycles/usec, here. */
209 /* Start wall clock. */
212 (void) rpmswNow(&begin);
215 /* Get no. of cycles while doing nanosleep. */
217 cycles = rpmswCalibrate();
218 if (save_cycles > 0 && rpmsw_overhead > 0)
219 cycles -= (save_cycles * rpmsw_overhead);
220 sum_cycles += cycles;
222 /* Compute wall clock delta in usecs. */
225 sum_usecs += rpmswDiff(rpmswNow(&end), &begin);
229 /* Compute cycles/usec */
230 rpmsw_cycles = sum_cycles/sum_usecs;
233 /* Calculate timing overhead in usecs. */
235 (void) rpmswNow(&begin);
236 sum_overhead += rpmswDiff(rpmswNow(&end), &begin);
239 rpmsw_overhead = sum_overhead/(i+1);
243 return rpmsw_overhead;
248 int rpmswEnter(rpmop op, ssize_t rc)
256 (void) rpmswNow(&op->begin);
261 rpmtime_t rpmswExit(rpmop op, ssize_t rc)
266 op->usecs += rpmswDiff(rpmswNow(&end), &op->begin);
270 op->begin = end; /* structure assignment */
274 rpmtime_t rpmswAdd(rpmop to, rpmop from)
276 if (to != NULL && from != NULL) {
277 to->count += from->count;
278 to->bytes += from->bytes;
279 to->usecs += from->usecs;
284 rpmtime_t rpmswSub(rpmop to, rpmop from)
286 if (to != NULL && from != NULL) {
287 to->count -= from->count;
288 to->bytes -= from->bytes;
289 to->usecs -= from->usecs;