rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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@*/
23 static rpmtime_t rpmsw_overhead = 0;
24
25 /*@unchecked@*/
26 static rpmtime_t rpmsw_cycles = 1;
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
84 rpmsw rpmswNow(rpmsw sw)
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
123 rpmtime_t rpmswDiff(rpmsw end, rpmsw begin)
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;
154 rpmtime_t ticks;
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
180 rpmtime_t rpmswInit(void)
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
280 rpmtime_t rpmswAdd(rpmop to, rpmop from)
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
292 rpmtime_t rpmswSub(rpmop to, rpmop from)
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, /*@null@*/ rpmop op)
305 /*@globals fileSystem @*/
306 /*@modifies fileSystem @*/
307 {
308 static unsigned int scale = (1000 * 1000);
309 if (op != NULL && op->count > 0)
310 fprintf(stderr, " %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 }