diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-06-17 19:09:05 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-06-17 19:09:05 +0000 |
commit | 459be35234cc24b69309eb0ee22600024c73713e (patch) | |
tree | 15ac4122d9c42ec75ba68d342827e37fcb1306ed /miscutils | |
parent | e79dd06782175d50f639180cde5b2c56933aa2ee (diff) | |
download | busybox-w32-459be35234cc24b69309eb0ee22600024c73713e.tar.gz busybox-w32-459be35234cc24b69309eb0ee22600024c73713e.tar.bz2 busybox-w32-459be35234cc24b69309eb0ee22600024c73713e.zip |
hwclock: size optimizations
libbb/time.c: new file, introducing monotonic_us()
pscan, traceroute, arping: use it instead of gettimeofday
ping, zcip: TODO
function old new delta
monotonic_us - 89 +89
find_pair 164 180 +16
.rodata 129747 129763 +16
refresh 1144 1152 +8
............
timeout 8 4 -4
static.start 8 4 -4
last 8 4 -4
parse_conf 1303 1284 -19
time_main 1149 1124 -25
gettimeofday_us 39 - -39
arping_main 2042 1969 -73
hwclock_main 594 501 -93
catcher 485 380 -105
traceroute_main 4300 4117 -183
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 8/11 up/down: 157/-562) Total: -405 bytes
Diffstat (limited to 'miscutils')
-rw-r--r-- | miscutils/time.c | 180 |
1 files changed, 76 insertions, 104 deletions
diff --git a/miscutils/time.c b/miscutils/time.c index 705123c9e..578cb35ff 100644 --- a/miscutils/time.c +++ b/miscutils/time.c | |||
@@ -11,28 +11,16 @@ | |||
11 | 11 | ||
12 | #include "libbb.h" | 12 | #include "libbb.h" |
13 | 13 | ||
14 | #define TV_MSEC tv_usec / 1000 | ||
15 | |||
16 | /* Information on the resources used by a child process. */ | 14 | /* Information on the resources used by a child process. */ |
17 | typedef struct { | 15 | typedef struct { |
18 | int waitstatus; | 16 | int waitstatus; |
19 | struct rusage ru; | 17 | struct rusage ru; |
20 | struct timeval start, elapsed; /* Wallclock time of process. */ | 18 | unsigned elapsed_ms; /* Wallclock time of process. */ |
21 | } resource_t; | 19 | } resource_t; |
22 | 20 | ||
23 | /* msec = milliseconds = 1/1,000 (1*10e-3) second. | 21 | /* msec = milliseconds = 1/1,000 (1*10e-3) second. |
24 | usec = microseconds = 1/1,000,000 (1*10e-6) second. */ | 22 | usec = microseconds = 1/1,000,000 (1*10e-6) second. */ |
25 | 23 | ||
26 | #ifndef TICKS_PER_SEC | ||
27 | #define TICKS_PER_SEC 100 | ||
28 | #endif | ||
29 | |||
30 | /* The number of milliseconds in one `tick' used by the `rusage' structure. */ | ||
31 | #define MSEC_PER_TICK (1000 / TICKS_PER_SEC) | ||
32 | |||
33 | /* Return the number of clock ticks that occur in M milliseconds. */ | ||
34 | #define MSEC_TO_TICKS(m) ((m) / MSEC_PER_TICK) | ||
35 | |||
36 | #define UL unsigned long | 24 | #define UL unsigned long |
37 | 25 | ||
38 | static const char default_format[] = "real\t%E\nuser\t%u\nsys\t%T"; | 26 | static const char default_format[] = "real\t%E\nuser\t%u\nsys\t%T"; |
@@ -76,7 +64,6 @@ static const char long_format[] = | |||
76 | static int resuse_end(pid_t pid, resource_t * resp) | 64 | static int resuse_end(pid_t pid, resource_t * resp) |
77 | { | 65 | { |
78 | int status; | 66 | int status; |
79 | |||
80 | pid_t caught; | 67 | pid_t caught; |
81 | 68 | ||
82 | /* Ignore signals, but don't ignore the children. When wait3 | 69 | /* Ignore signals, but don't ignore the children. When wait3 |
@@ -85,18 +72,8 @@ static int resuse_end(pid_t pid, resource_t * resp) | |||
85 | if (caught == -1) | 72 | if (caught == -1) |
86 | return 0; | 73 | return 0; |
87 | } | 74 | } |
88 | 75 | resp->elapsed_ms = (monotonic_us() / 1000) - resp->elapsed_ms; | |
89 | gettimeofday(&resp->elapsed, (struct timezone *) 0); | ||
90 | resp->elapsed.tv_sec -= resp->start.tv_sec; | ||
91 | if (resp->elapsed.tv_usec < resp->start.tv_usec) { | ||
92 | /* Manually carry a one from the seconds field. */ | ||
93 | resp->elapsed.tv_usec += 1000000; | ||
94 | --resp->elapsed.tv_sec; | ||
95 | } | ||
96 | resp->elapsed.tv_usec -= resp->start.tv_usec; | ||
97 | |||
98 | resp->waitstatus = status; | 76 | resp->waitstatus = status; |
99 | |||
100 | return 1; | 77 | return 1; |
101 | } | 78 | } |
102 | 79 | ||
@@ -181,30 +158,30 @@ static unsigned long ptok(unsigned long pages) | |||
181 | COMMAND is the command and args that are being summarized. | 158 | COMMAND is the command and args that are being summarized. |
182 | RESP is resource information on the command. */ | 159 | RESP is resource information on the command. */ |
183 | 160 | ||
161 | #ifndef TICKS_PER_SEC | ||
162 | #define TICKS_PER_SEC 100 | ||
163 | #endif | ||
164 | |||
184 | static void summarize(const char *fmt, char **command, resource_t * resp) | 165 | static void summarize(const char *fmt, char **command, resource_t * resp) |
185 | { | 166 | { |
186 | unsigned long r; /* Elapsed real milliseconds. */ | 167 | unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ |
187 | unsigned long v; /* Elapsed virtual (CPU) milliseconds. */ | 168 | unsigned cpu_ticks; /* Same, in "CPU ticks" */ |
188 | 169 | ||
189 | if (WIFSTOPPED(resp->waitstatus)) | 170 | if (WIFSTOPPED(resp->waitstatus)) |
190 | printf("Command stopped by signal %d\n", | 171 | printf("Command stopped by signal %u\n", |
191 | WSTOPSIG(resp->waitstatus)); | 172 | WSTOPSIG(resp->waitstatus)); |
192 | else if (WIFSIGNALED(resp->waitstatus)) | 173 | else if (WIFSIGNALED(resp->waitstatus)) |
193 | printf("Command terminated by signal %d\n", | 174 | printf("Command terminated by signal %u\n", |
194 | WTERMSIG(resp->waitstatus)); | 175 | WTERMSIG(resp->waitstatus)); |
195 | else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus)) | 176 | else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus)) |
196 | printf("Command exited with non-zero status %d\n", | 177 | printf("Command exited with non-zero status %u\n", |
197 | WEXITSTATUS(resp->waitstatus)); | 178 | WEXITSTATUS(resp->waitstatus)); |
198 | 179 | ||
199 | /* Convert all times to milliseconds. Occasionally, one of these values | 180 | vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 |
200 | comes out as zero. Dividing by zero causes problems, so we first | 181 | + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; |
201 | check the time value. If it is zero, then we take `evasive action' | ||
202 | instead of calculating a value. */ | ||
203 | 182 | ||
204 | r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000; | 183 | cpu_ticks = vv_ms * TICKS_PER_SEC / 1000; |
205 | 184 | if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ | |
206 | v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC + | ||
207 | resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC; | ||
208 | 185 | ||
209 | /* putchar() != putc(stdout) in glibc! */ | 186 | /* putchar() != putc(stdout) in glibc! */ |
210 | 187 | ||
@@ -245,127 +222,122 @@ static void summarize(const char *fmt, char **command, resource_t * resp) | |||
245 | break; | 222 | break; |
246 | case 'D': /* Average unshared data size. */ | 223 | case 'D': /* Average unshared data size. */ |
247 | printf("%lu", | 224 | printf("%lu", |
248 | MSEC_TO_TICKS(v) == 0 ? 0 : | 225 | ptok((UL) resp->ru.ru_idrss) / cpu_ticks + |
249 | ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) + | 226 | ptok((UL) resp->ru.ru_isrss) / cpu_ticks); |
250 | ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v)); | 227 | break; |
251 | break; | 228 | case 'E': { /* Elapsed real (wall clock) time. */ |
252 | case 'E': /* Elapsed real (wall clock) time. */ | 229 | unsigned seconds = resp->elapsed_ms / 1000; |
253 | if (resp->elapsed.tv_sec >= 3600) /* One hour -> h:m:s. */ | 230 | if (seconds >= 3600) /* One hour -> h:m:s. */ |
254 | printf("%ldh %ldm %02lds", | 231 | printf("%uh %um %02us", |
255 | resp->elapsed.tv_sec / 3600, | 232 | seconds / 3600, |
256 | (resp->elapsed.tv_sec % 3600) / 60, | 233 | (seconds % 3600) / 60, |
257 | resp->elapsed.tv_sec % 60); | 234 | seconds % 60); |
258 | else | 235 | else |
259 | printf("%ldm %ld.%02lds", /* -> m:s. */ | 236 | printf("%um %u.%02us", /* -> m:s. */ |
260 | resp->elapsed.tv_sec / 60, | 237 | seconds / 60, |
261 | resp->elapsed.tv_sec % 60, | 238 | seconds % 60, |
262 | resp->elapsed.tv_usec / 10000); | 239 | (unsigned)(resp->elapsed_ms / 10) % 100); |
263 | break; | 240 | break; |
241 | } | ||
264 | case 'F': /* Major page faults. */ | 242 | case 'F': /* Major page faults. */ |
265 | printf("%ld", resp->ru.ru_majflt); | 243 | printf("%lu", resp->ru.ru_majflt); |
266 | break; | 244 | break; |
267 | case 'I': /* Inputs. */ | 245 | case 'I': /* Inputs. */ |
268 | printf("%ld", resp->ru.ru_inblock); | 246 | printf("%lu", resp->ru.ru_inblock); |
269 | break; | 247 | break; |
270 | case 'K': /* Average mem usage == data+stack+text. */ | 248 | case 'K': /* Average mem usage == data+stack+text. */ |
271 | printf("%lu", | 249 | printf("%lu", |
272 | MSEC_TO_TICKS(v) == 0 ? 0 : | 250 | ptok((UL) resp->ru.ru_idrss) / cpu_ticks + |
273 | ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) + | 251 | ptok((UL) resp->ru.ru_isrss) / cpu_ticks + |
274 | ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v) + | 252 | ptok((UL) resp->ru.ru_ixrss) / cpu_ticks); |
275 | ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v)); | ||
276 | break; | 253 | break; |
277 | case 'M': /* Maximum resident set size. */ | 254 | case 'M': /* Maximum resident set size. */ |
278 | printf("%lu", ptok((UL) resp->ru.ru_maxrss)); | 255 | printf("%lu", ptok((UL) resp->ru.ru_maxrss)); |
279 | break; | 256 | break; |
280 | case 'O': /* Outputs. */ | 257 | case 'O': /* Outputs. */ |
281 | printf("%ld", resp->ru.ru_oublock); | 258 | printf("%lu", resp->ru.ru_oublock); |
282 | break; | 259 | break; |
283 | case 'P': /* Percent of CPU this job got. */ | 260 | case 'P': /* Percent of CPU this job got. */ |
284 | /* % cpu is (total cpu time)/(elapsed time). */ | 261 | /* % cpu is (total cpu time)/(elapsed time). */ |
285 | if (r > 0) | 262 | if (resp->elapsed_ms > 0) |
286 | printf("%lu%%", (v * 100 / r)); | 263 | printf("%u%%", (unsigned)(vv_ms * 100 / resp->elapsed_ms)); |
287 | else | 264 | else |
288 | printf("?%%"); | 265 | printf("?%%"); |
289 | break; | 266 | break; |
290 | case 'R': /* Minor page faults (reclaims). */ | 267 | case 'R': /* Minor page faults (reclaims). */ |
291 | printf("%ld", resp->ru.ru_minflt); | 268 | printf("%lu", resp->ru.ru_minflt); |
292 | break; | 269 | break; |
293 | case 'S': /* System time. */ | 270 | case 'S': /* System time. */ |
294 | printf("%ld.%02ld", | 271 | printf("%u.%02u", |
295 | resp->ru.ru_stime.tv_sec, | 272 | (unsigned)resp->ru.ru_stime.tv_sec, |
296 | resp->ru.ru_stime.TV_MSEC / 10); | 273 | (unsigned)(resp->ru.ru_stime.tv_usec / 10000)); |
297 | break; | 274 | break; |
298 | case 'T': /* System time. */ | 275 | case 'T': /* System time. */ |
299 | if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */ | 276 | if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */ |
300 | printf("%ldh %ldm %02lds", | 277 | printf("%uh %um %02us", |
301 | resp->ru.ru_stime.tv_sec / 3600, | 278 | (unsigned)(resp->ru.ru_stime.tv_sec / 3600), |
302 | (resp->ru.ru_stime.tv_sec % 3600) / 60, | 279 | (unsigned)(resp->ru.ru_stime.tv_sec % 3600) / 60, |
303 | resp->ru.ru_stime.tv_sec % 60); | 280 | (unsigned)(resp->ru.ru_stime.tv_sec % 60)); |
304 | else | 281 | else |
305 | printf("%ldm %ld.%02lds", /* -> m:s. */ | 282 | printf("%um %u.%02us", /* -> m:s. */ |
306 | resp->ru.ru_stime.tv_sec / 60, | 283 | (unsigned)(resp->ru.ru_stime.tv_sec / 60), |
307 | resp->ru.ru_stime.tv_sec % 60, | 284 | (unsigned)(resp->ru.ru_stime.tv_sec % 60), |
308 | resp->ru.ru_stime.tv_usec / 10000); | 285 | (unsigned)(resp->ru.ru_stime.tv_usec / 10000)); |
309 | break; | 286 | break; |
310 | case 'U': /* User time. */ | 287 | case 'U': /* User time. */ |
311 | printf("%ld.%02ld", | 288 | printf("%u.%02u", |
312 | resp->ru.ru_utime.tv_sec, | 289 | (unsigned)resp->ru.ru_utime.tv_sec, |
313 | resp->ru.ru_utime.TV_MSEC / 10); | 290 | (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); |
314 | break; | 291 | break; |
315 | case 'u': /* User time. */ | 292 | case 'u': /* User time. */ |
316 | if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */ | 293 | if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */ |
317 | printf("%ldh %ldm %02lds", | 294 | printf("%uh %um %02us", |
318 | resp->ru.ru_utime.tv_sec / 3600, | 295 | (unsigned)(resp->ru.ru_utime.tv_sec / 3600), |
319 | (resp->ru.ru_utime.tv_sec % 3600) / 60, | 296 | (unsigned)(resp->ru.ru_utime.tv_sec % 3600) / 60, |
320 | resp->ru.ru_utime.tv_sec % 60); | 297 | (unsigned)(resp->ru.ru_utime.tv_sec % 60)); |
321 | else | 298 | else |
322 | printf("%ldm %ld.%02lds", /* -> m:s. */ | 299 | printf("%um %u.%02us", /* -> m:s. */ |
323 | resp->ru.ru_utime.tv_sec / 60, | 300 | (unsigned)(resp->ru.ru_utime.tv_sec / 60), |
324 | resp->ru.ru_utime.tv_sec % 60, | 301 | (unsigned)(resp->ru.ru_utime.tv_sec % 60), |
325 | resp->ru.ru_utime.tv_usec / 10000); | 302 | (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); |
326 | break; | 303 | break; |
327 | case 'W': /* Times swapped out. */ | 304 | case 'W': /* Times swapped out. */ |
328 | printf("%ld", resp->ru.ru_nswap); | 305 | printf("%lu", resp->ru.ru_nswap); |
329 | break; | 306 | break; |
330 | case 'X': /* Average shared text size. */ | 307 | case 'X': /* Average shared text size. */ |
331 | printf("%lu", | 308 | printf("%lu", ptok((UL) resp->ru.ru_ixrss) / cpu_ticks); |
332 | MSEC_TO_TICKS(v) == 0 ? 0 : | ||
333 | ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v)); | ||
334 | break; | 309 | break; |
335 | case 'Z': /* Page size. */ | 310 | case 'Z': /* Page size. */ |
336 | printf("%d", getpagesize()); | 311 | printf("%u", getpagesize()); |
337 | break; | 312 | break; |
338 | case 'c': /* Involuntary context switches. */ | 313 | case 'c': /* Involuntary context switches. */ |
339 | printf("%ld", resp->ru.ru_nivcsw); | 314 | printf("%lu", resp->ru.ru_nivcsw); |
340 | break; | 315 | break; |
341 | case 'e': /* Elapsed real time in seconds. */ | 316 | case 'e': /* Elapsed real time in seconds. */ |
342 | printf("%ld.%02ld", | 317 | printf("%u.%02u", |
343 | resp->elapsed.tv_sec, resp->elapsed.tv_usec / 10000); | 318 | (unsigned)resp->elapsed_ms / 1000, |
319 | (unsigned)(resp->elapsed_ms / 10) % 100); | ||
344 | break; | 320 | break; |
345 | case 'k': /* Signals delivered. */ | 321 | case 'k': /* Signals delivered. */ |
346 | printf("%ld", resp->ru.ru_nsignals); | 322 | printf("%lu", resp->ru.ru_nsignals); |
347 | break; | 323 | break; |
348 | case 'p': /* Average stack segment. */ | 324 | case 'p': /* Average stack segment. */ |
349 | printf("%lu", | 325 | printf("%lu", ptok((UL) resp->ru.ru_isrss) / cpu_ticks); |
350 | MSEC_TO_TICKS(v) == 0 ? 0 : | ||
351 | ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v)); | ||
352 | break; | 326 | break; |
353 | case 'r': /* Incoming socket messages received. */ | 327 | case 'r': /* Incoming socket messages received. */ |
354 | printf("%ld", resp->ru.ru_msgrcv); | 328 | printf("%lu", resp->ru.ru_msgrcv); |
355 | break; | 329 | break; |
356 | case 's': /* Outgoing socket messages sent. */ | 330 | case 's': /* Outgoing socket messages sent. */ |
357 | printf("%ld", resp->ru.ru_msgsnd); | 331 | printf("%lu", resp->ru.ru_msgsnd); |
358 | break; | 332 | break; |
359 | case 't': /* Average resident set size. */ | 333 | case 't': /* Average resident set size. */ |
360 | printf("%lu", | 334 | printf("%lu", ptok((UL) resp->ru.ru_idrss) / cpu_ticks); |
361 | MSEC_TO_TICKS(v) == 0 ? 0 : | ||
362 | ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v)); | ||
363 | break; | 335 | break; |
364 | case 'w': /* Voluntary context switches. */ | 336 | case 'w': /* Voluntary context switches. */ |
365 | printf("%ld", resp->ru.ru_nvcsw); | 337 | printf("%lu", resp->ru.ru_nvcsw); |
366 | break; | 338 | break; |
367 | case 'x': /* Exit status. */ | 339 | case 'x': /* Exit status. */ |
368 | printf("%d", WEXITSTATUS(resp->waitstatus)); | 340 | printf("%u", WEXITSTATUS(resp->waitstatus)); |
369 | break; | 341 | break; |
370 | } | 342 | } |
371 | break; | 343 | break; |
@@ -403,7 +375,7 @@ static void run_command(char *const *cmd, resource_t * resp) | |||
403 | pid_t pid; /* Pid of child. */ | 375 | pid_t pid; /* Pid of child. */ |
404 | __sighandler_t interrupt_signal, quit_signal; | 376 | __sighandler_t interrupt_signal, quit_signal; |
405 | 377 | ||
406 | gettimeofday(&resp->start, (struct timezone *) 0); | 378 | resp->elapsed_ms = monotonic_us() / 1000; |
407 | pid = vfork(); /* Run CMD as child process. */ | 379 | pid = vfork(); /* Run CMD as child process. */ |
408 | if (pid < 0) | 380 | if (pid < 0) |
409 | bb_error_msg_and_die("cannot fork"); | 381 | bb_error_msg_and_die("cannot fork"); |