rpm  5.4.10
rpmsw.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 #include <rpmiotypes.h>
7 #include <rpmsw.h>
8 #include "debug.h"
9 
10 #if defined(__LCLINT__)
11 /*@-exportheader@*/
12 extern int nanosleep(const struct timespec *__requested_time,
13  /*@out@*/ /*@null@*/ struct timespec *__remaining)
14  /*@globals errno @*/
15  /*@modifies *__remaining, errno @*/;
16 /*@=exportheader@*/
17 #endif
18 
19 /*@unchecked@*/
20 int _rpmsw_stats = 0;
21 
22 /*@unchecked@*/
24 
25 /*@unchecked@*/
27 
28 /*@unchecked@*/
29 static int rpmsw_type = 0;
30 
31 /*@unchecked@*/
32 static int rpmsw_initialized = 0;
33 
34 #if defined(__linux__) && defined(__i386__) && !defined(RPM_VENDOR_PLD)
35 /* Swiped from glibc-2.3.2 sysdeps/i386/i686/hp-timing.h */
36 
37 #define HP_TIMING_ZERO(Var) (Var) = (0)
38 #define HP_TIMING_NOW(Var) __asm__ __volatile__ ("rdtsc" : "=A" (Var))
39 
40 /* It's simple arithmetic for us. */
41 #define HP_TIMING_DIFF(Diff, Start, End) (Diff) = ((End) - (Start))
42 
43 /* We have to jump through hoops to get this correctly implemented. */
44 #define HP_TIMING_ACCUM(Sum, Diff) \
45  do { \
46  char __not_done; \
47  hp_timing_t __oldval = (Sum); \
48  hp_timing_t __diff = (Diff) - GL(dl_hp_timing_overhead); \
49  do \
50  { \
51  hp_timing_t __newval = __oldval + __diff; \
52  int __temp0, __temp1; \
53  __asm__ __volatile__ ("xchgl %4, %%ebx\n\t" \
54  "lock; cmpxchg8b %1\n\t" \
55  "sete %0\n\t" \
56  "movl %4, %%ebx" \
57  : "=q" (__not_done), "=m" (Sum), \
58  "=A" (__oldval), "=c" (__temp0), \
59  "=SD" (__temp1) \
60  : "1" (Sum), "2" (__oldval), \
61  "3" (__newval >> 32), \
62  "4" (__newval & 0xffffffff) \
63  : "memory"); \
64  } \
65  while (__not_done); \
66  } while (0)
67 
68 /* No threads, no extra work. */
69 #define HP_TIMING_ACCUM_NT(Sum, Diff) (Sum) += (Diff)
70 
71 /* Print the time value. */
72 #define HP_TIMING_PRINT(Buf, Len, Val) \
73  do { \
74  char __buf[20]; \
75  char *__cp = _itoa (Val, __buf + sizeof (__buf), 10, 0); \
76  int __len = (Len); \
77  char *__dest = (Buf); \
78  while (__len-- > 0 && __cp < __buf + sizeof (__buf)) \
79  *__dest++ = *__cp++; \
80  memcpy (__dest, " clock cycles", MIN (__len, sizeof (" clock cycles"))); \
81  } while (0)
82 #endif /* __i386__ */
83 
85 {
86  if (!rpmsw_initialized)
87  (void) rpmswInit();
88  if (sw == NULL)
89  return NULL;
90  switch (rpmsw_type) {
91  case 0:
92  if (gettimeofday(&sw->u.tv, NULL))
93  return NULL;
94  break;
95 #if defined(HP_TIMING_NOW)
96  case 1:
97  HP_TIMING_NOW(sw->u.ticks);
98  break;
99 #endif
100  }
101  return sw;
102 }
103 
110 static inline
111 rpmtime_t tvsub(/*@null@*/ const struct timeval * etv,
112  /*@null@*/ const struct timeval * btv)
113  /*@*/
114 {
115  time_t secs, usecs;
116  if (etv == NULL || btv == NULL) return 0;
117  secs = etv->tv_sec - btv->tv_sec;
118  for (usecs = etv->tv_usec - btv->tv_usec; usecs < 0; usecs += 1000000)
119  secs--;
120  return (rpmtime_t) ((secs * 1000000) + usecs);
121 }
122 
124 {
125  rpmuint64_t ticks = 0;
126 
127  if (end == NULL || begin == NULL)
128  return 0;
129  switch (rpmsw_type) {
130  default:
131  case 0:
132  ticks = tvsub(&end->u.tv, &begin->u.tv);
133  break;
134 #if defined(HP_TIMING_NOW)
135  case 1:
136  if (end->u.ticks > begin->u.ticks)
137  HP_TIMING_DIFF(ticks, begin->u.ticks, end->u.ticks);
138  break;
139 #endif
140  }
141  if (ticks >= rpmsw_overhead)
142  ticks -= rpmsw_overhead;
143  if (rpmsw_cycles > 1)
144  ticks /= rpmsw_cycles;
145  return (rpmtime_t) ticks;
146 }
147 
148 #if defined(HP_TIMING_NOW)
149 static rpmtime_t rpmswCalibrate(void)
150  /*@globals internalState @*/
151  /*@modifies internalState @*/
152 {
153  struct rpmsw_s begin, end;
155  struct timespec req, rem;
156  int rc;
157  int i;
158 
159 /*@-uniondef@*/
160  (void) rpmswNow(&begin);
161 /*@=uniondef@*/
162  req.tv_sec = 0;
163  req.tv_nsec = 20 * 1000 * 1000;
164  for (i = 0; i < 100; i++) {
165  rc = nanosleep(&req, &rem);
166  if (rc == 0)
167  break;
168  if (rem.tv_sec == 0 && rem.tv_nsec == 0)
169  break;
170  req = rem; /* structure assignment */
171  }
172 /*@-uniondef@*/
173  ticks = rpmswDiff(rpmswNow(&end), &begin);
174 /*@=uniondef@*/
175 
176  return ticks;
177 }
178 #endif
179 
181  /*@globals rpmsw_cycles, rpmsw_initialized, rpmsw_overhead,
182  rpmsw_type @*/
183  /*@modifies rpmsw_cycles, rpmsw_initialized, rpmsw_overhead,
184  rpmsw_type @*/
185 {
186  struct rpmsw_s begin, end;
187  rpmtime_t sum_overhead = 0;
188 #if defined(HP_TIMING_NOW)
189  rpmtime_t cycles;
190  rpmtime_t sum_usecs = 0;
191  rpmuint64_t sum_cycles = 0;
192 #endif
193  int i;
194 
195  rpmsw_initialized = 1;
196 
197  rpmsw_overhead = 0;
198  rpmsw_cycles = 0;
199 
200  /* Convergence for simultaneous cycles and overhead is overkill ... */
201  for (i = 0; i < 3; i++) {
202 #if defined(HP_TIMING_NOW)
203  rpmtime_t save_cycles = rpmsw_cycles;
204 
205  /* We want cycles, not cycles/usec, here. */
206  rpmsw_cycles = 1;
207 
208  /* Start wall clock. */
209  rpmsw_type = 0;
210 /*@-uniondef@*/
211  (void) rpmswNow(&begin);
212 /*@=uniondef@*/
213 
214  /* Get no. of cycles while doing nanosleep. */
215  rpmsw_type = 1;
216  cycles = rpmswCalibrate();
217  if (save_cycles > 0 && rpmsw_overhead > 0)
218  cycles -= (save_cycles * rpmsw_overhead);
219  sum_cycles += cycles;
220 
221  /* Compute wall clock delta in usecs. */
222  rpmsw_type = 0;
223 /*@-uniondef@*/
224  sum_usecs += rpmswDiff(rpmswNow(&end), &begin);
225 /*@=uniondef@*/
226  rpmsw_type = 1;
227 
228  /* Compute cycles/usec */
229  if (sum_usecs > 0) /* XXX insure that time has passed. */
230  rpmsw_cycles = sum_cycles/sum_usecs;
231 #else
232  rpmsw_type = 0;
233 #endif
234 
235  /* Calculate timing overhead in usecs. */
236 /*@-uniondef@*/
237  (void) rpmswNow(&begin);
238  sum_overhead += rpmswDiff(rpmswNow(&end), &begin);
239 /*@=uniondef@*/
240 
241  rpmsw_overhead = sum_overhead/(i+1);
242 
243  }
244 
245  return rpmsw_overhead;
246 }
247 
248 int rpmswEnter(rpmop op, ssize_t rc)
249 {
250  if (op == NULL)
251  return 0;
252 
253  op->count++;
254  if (rc < 0) {
255  op->bytes = 0;
256  op->usecs = 0;
257  }
258 /*@-uniondef@*/
259  (void) rpmswNow(&op->begin);
260 /*@=uniondef@*/
261  return 0;
262 }
263 
264 rpmtime_t rpmswExit(rpmop op, ssize_t rc)
265 {
266  struct rpmsw_s end;
267 
268  if (op == NULL)
269  return 0;
270 
271 /*@-uniondef@*/
272  op->usecs += rpmswDiff(rpmswNow(&end), &op->begin);
273 /*@=uniondef@*/
274  if (rc > 0)
275  op->bytes += rc;
276  op->begin = end; /* structure assignment */
277  return op->usecs;
278 }
279 
281 {
282  rpmtime_t usecs = 0;
283  if (to != NULL && from != NULL) {
284  to->count += from->count;
285  to->bytes += from->bytes;
286  to->usecs += from->usecs;
287  usecs = to->usecs;
288  }
289  return usecs;
290 }
291 
293 {
294  rpmtime_t usecs = 0;
295  if (to != NULL && from != NULL) {
296  to->count -= from->count;
297  to->bytes -= from->bytes;
298  to->usecs -= from->usecs;
299  usecs = to->usecs;
300  }
301  return usecs;
302 }
303 
304 void rpmswPrint(const char * name, rpmop op, FILE * fp)
305 {
306  static unsigned int scale = (1000 * 1000);
307  if (fp == NULL)
308  fp = stderr;
309  if (op != NULL && op->count > 0)
310  fprintf(fp, " %s %8d %6lu.%06lu MB %6lu.%06lu secs\n",
311  name, op->count,
312  (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
313  op->usecs/scale, op->usecs%scale);
314 }
rpmtime_t rpmswExit(rpmop op, ssize_t rc)
Exit timed operation.
Definition: rpmsw.c:264
static rpmtime_t rpmsw_cycles
Definition: rpmsw.c:26
rpmtime_t usecs
Definition: rpmsw.h:37
rpmtime_t rpmswAdd(rpmop to, rpmop from)
Sum statistic counters.
Definition: rpmsw.c:280
rpmtime_t rpmswInit(void)
Return benchmark time stamp overhead.
Definition: rpmsw.c:180
struct timeval tv
Definition: rpmsw.h:24
void rpmswPrint(const char *name, rpmop op, FILE *fp)
Print operation statistics.
Definition: rpmsw.c:304
int count
Definition: rpmsw.h:35
static rpmtime_t tvsub(const struct timeval *etv, const struct timeval *btv)
Return difference of 2 timeval stamps in micro-seconds.
Definition: rpmsw.c:111
rpmtime_t rpmswDiff(rpmsw end, rpmsw begin)
Return benchmark time stamp difference.
Definition: rpmsw.c:123
struct rpmsw_s begin
Definition: rpmsw.h:34
union rpmsw_s::@7 u
unsigned long long rpmuint64_t
Definition: rpmiotypes.h:26
int rpmswEnter(rpmop op, ssize_t rc)
Enter timed operation.
Definition: rpmsw.c:248
static int rpmsw_type
Definition: rpmsw.c:29
Cumulative statistics for an operation.
Definition: rpmsw.h:33
static rpmtime_t rpmsw_overhead
Definition: rpmsw.c:23
Definition: rpmsw.h:22
rpmtime_t rpmswSub(rpmop to, rpmop from)
Subtract statistic counters.
Definition: rpmsw.c:292
unsigned long long int ticks
Definition: rpmsw.h:25
unsigned long long bytes
Definition: rpmsw.h:36
int _rpmsw_stats
Definition: rpmsw.c:20
static const char * name
static int rpmsw_initialized
Definition: rpmsw.c:32
unsigned long int rpmtime_t
Definition: rpmsw.h:10
rpmsw rpmswNow(rpmsw sw)
Return benchmark time stamp.
Definition: rpmsw.c:84