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