Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/miscutils/time.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/miscutils/time.c
r1765 r2725 1 1 /* vi: set sw=4 ts=4: */ 2 /* `time' utility to display resource usage of processes.2 /* 'time' utility to display resource usage of processes. 3 3 Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc. 4 4 5 Licensed under GPL version 2, see file LICENSE in this tarball for details.5 Licensed under GPLv2, see file LICENSE in this source tree. 6 6 */ 7 7 /* Originally written by David Keppel <pardo@cs.washington.edu>. … … 28 28 /* The output format for the -p option .*/ 29 29 static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; 30 31 30 32 31 /* Format string for printing all statistics verbosely. … … 57 56 "\tExit status: %x"; 58 57 59 60 58 /* Wait for and fill in data on child process PID. 61 59 Return 0 on error, 1 if ok. */ 62 63 60 /* pid_t is short on BSDI, so don't try to promote it. */ 64 static int resuse_end(pid_t pid, resource_t * resp) 65 { 66 int status; 61 static void resuse_end(pid_t pid, resource_t *resp) 62 { 67 63 pid_t caught; 68 64 69 65 /* Ignore signals, but don't ignore the children. When wait3 70 66 returns the child process, set the time the command finished. */ 71 while ((caught = wait3(&status, 0, &resp->ru)) != pid) { 72 if (caught == -1) 73 return 0; 67 while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { 68 if (caught == -1 && errno != EINTR) { 69 bb_perror_msg("wait"); 70 return; 71 } 74 72 } 75 resp->elapsed_ms = (monotonic_us() / 1000) - resp->elapsed_ms; 76 resp->waitstatus = status; 77 return 1; 78 } 79 80 /* Print ARGV, with each entry in ARGV separated by FILLER. */ 81 static void printargv(char *const *argv, const char *filler) 82 { 83 fputs(*argv, stdout); 84 while (*++argv) { 85 fputs(filler, stdout); 86 fputs(*argv, stdout); 87 } 73 resp->elapsed_ms = monotonic_ms() - resp->elapsed_ms; 74 } 75 76 static void printargv(char *const *argv) 77 { 78 const char *fmt = " %s" + 1; 79 do { 80 printf(fmt, *argv); 81 fmt = " %s"; 82 } while (*++argv); 88 83 } 89 84 … … 95 90 Note: Some machines express getrusage statistics in terms of K, 96 91 others in terms of pages. */ 97 98 static unsigned long ptok(unsigned long pages) 99 { 100 static unsigned long ps; 92 static unsigned long ptok(const unsigned pagesize, const unsigned long pages) 93 { 101 94 unsigned long tmp; 102 95 103 /* Initialization. */104 if (ps == 0)105 ps = getpagesize();106 107 96 /* Conversion. */ 108 if (pages > (LONG_MAX / p s)) {/* Could overflow. */109 tmp = pages / 1024; 110 return tmp * p s;/* then larger. */97 if (pages > (LONG_MAX / pagesize)) { /* Could overflow. */ 98 tmp = pages / 1024; /* Smaller first, */ 99 return tmp * pagesize; /* then larger. */ 111 100 } 112 101 /* Could underflow. */ 113 tmp = pages * p s;/* Larger first, */114 return tmp / 1024; 102 tmp = pages * pagesize; /* Larger first, */ 103 return tmp / 1024; /* then smaller. */ 115 104 } 116 105 … … 163 152 #endif 164 153 165 static void summarize(const char *fmt, char **command, resource_t * 154 static void summarize(const char *fmt, char **command, resource_t *resp) 166 155 { 167 156 unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ 168 157 unsigned cpu_ticks; /* Same, in "CPU ticks" */ 169 158 unsigned pagesize = getpagesize(); 159 160 /* Impossible: we do not use WUNTRACED flag in wait()... 170 161 if (WIFSTOPPED(resp->waitstatus)) 171 162 printf("Command stopped by signal %u\n", 172 163 WSTOPSIG(resp->waitstatus)); 173 else if (WIFSIGNALED(resp->waitstatus)) 164 else */ 165 if (WIFSIGNALED(resp->waitstatus)) 174 166 printf("Command terminated by signal %u\n", 175 167 WTERMSIG(resp->waitstatus)); … … 182 174 183 175 #if (1000 / TICKS_PER_SEC) * TICKS_PER_SEC == 1000 184 /* 1000 is exactly divisible by TICKS_PER_SEC */176 /* 1000 is exactly divisible by TICKS_PER_SEC (typical) */ 185 177 cpu_ticks = vv_ms / (1000 / TICKS_PER_SEC); 186 178 #else … … 188 180 #endif 189 181 if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ 190 191 /* putchar() != putc(stdout) in glibc! */192 182 193 183 while (*fmt) { … … 206 196 * for everything. With this we do a lot of 1-byte writes */ 207 197 default: 208 putc(*fmt, stdout);198 bb_putchar(*fmt); 209 199 break; 210 200 #endif … … 216 206 /* and we do not take format str from user */ 217 207 default: 218 putc('%', stdout);208 bb_putchar('%'); 219 209 /*FALLTHROUGH*/ 220 210 case '%': 221 211 if (!*fmt) goto ret; 222 putc(*fmt, stdout);212 bb_putchar(*fmt); 223 213 break; 224 214 #endif 225 215 case 'C': /* The command that got timed. */ 226 printargv(command , " ");216 printargv(command); 227 217 break; 228 218 case 'D': /* Average unshared data size. */ 229 219 printf("%lu", 230 ptok((UL) resp->ru.ru_idrss) / cpu_ticks+231 ptok((UL) resp->ru.ru_isrss) / cpu_ticks);220 (ptok(pagesize, (UL) resp->ru.ru_idrss) + 221 ptok(pagesize, (UL) resp->ru.ru_isrss)) / cpu_ticks); 232 222 break; 233 223 case 'E': { /* Elapsed real (wall clock) time. */ … … 253 243 case 'K': /* Average mem usage == data+stack+text. */ 254 244 printf("%lu", 255 ptok((UL) resp->ru.ru_idrss) / cpu_ticks+256 ptok((UL) resp->ru.ru_isrss) / cpu_ticks+257 ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);245 (ptok(pagesize, (UL) resp->ru.ru_idrss) + 246 ptok(pagesize, (UL) resp->ru.ru_isrss) + 247 ptok(pagesize, (UL) resp->ru.ru_ixrss)) / cpu_ticks); 258 248 break; 259 249 case 'M': /* Maximum resident set size. */ 260 printf("%lu", ptok( (UL) resp->ru.ru_maxrss));250 printf("%lu", ptok(pagesize, (UL) resp->ru.ru_maxrss)); 261 251 break; 262 252 case 'O': /* Outputs. */ … … 311 301 break; 312 302 case 'X': /* Average shared text size. */ 313 printf("%lu", ptok( (UL) resp->ru.ru_ixrss) / cpu_ticks);303 printf("%lu", ptok(pagesize, (UL) resp->ru.ru_ixrss) / cpu_ticks); 314 304 break; 315 305 case 'Z': /* Page size. */ 316 printf("%u", getpagesize());306 printf("%u", pagesize); 317 307 break; 318 308 case 'c': /* Involuntary context switches. */ … … 328 318 break; 329 319 case 'p': /* Average stack segment. */ 330 printf("%lu", ptok( (UL) resp->ru.ru_isrss) / cpu_ticks);320 printf("%lu", ptok(pagesize, (UL) resp->ru.ru_isrss) / cpu_ticks); 331 321 break; 332 322 case 'r': /* Incoming socket messages received. */ … … 337 327 break; 338 328 case 't': /* Average resident set size. */ 339 printf("%lu", ptok( (UL) resp->ru.ru_idrss) / cpu_ticks);329 printf("%lu", ptok(pagesize, (UL) resp->ru.ru_idrss) / cpu_ticks); 340 330 break; 341 331 case 'w': /* Voluntary context switches. */ … … 352 342 switch (*++fmt) { 353 343 default: 354 putc('\\', stdout);344 bb_putchar('\\'); 355 345 /*FALLTHROUGH*/ 356 346 case '\\': 357 347 if (!*fmt) goto ret; 358 putc(*fmt, stdout);348 bb_putchar(*fmt); 359 349 break; 360 350 case 't': 361 putc('\t', stdout);351 bb_putchar('\t'); 362 352 break; 363 353 case 'n': 364 putc('\n', stdout);354 bb_putchar('\n'); 365 355 break; 366 356 } … … 371 361 } 372 362 /* ret: */ 373 putc('\n', stdout);363 bb_putchar('\n'); 374 364 } 375 365 376 366 /* Run command CMD and return statistics on it. 377 367 Put the statistics in *RESP. */ 378 static void run_command(char *const *cmd, resource_t * resp) 379 { 380 pid_t pid; /* Pid of child. */ 381 __sighandler_t interrupt_signal, quit_signal; 382 383 resp->elapsed_ms = monotonic_us() / 1000; 384 pid = vfork(); /* Run CMD as child process. */ 385 if (pid < 0) 386 bb_error_msg_and_die("cannot fork"); 387 else if (pid == 0) { /* If child. */ 388 /* Don't cast execvp arguments; that causes errors on some systems, 389 versus merely warnings if the cast is left off. */ 390 BB_EXECVP(cmd[0], cmd); 391 bb_error_msg("cannot run %s", cmd[0]); 392 _exit(errno == ENOENT ? 127 : 126); 368 static void run_command(char *const *cmd, resource_t *resp) 369 { 370 pid_t pid; 371 void (*interrupt_signal)(int); 372 void (*quit_signal)(int); 373 374 resp->elapsed_ms = monotonic_ms(); 375 pid = xvfork(); 376 if (pid == 0) { 377 /* Child */ 378 BB_EXECVP_or_die((char**)cmd); 393 379 } 394 380 395 381 /* Have signals kill the child but not self (if possible). */ 382 //TODO: just block all sigs? and reenable them in the very end in main? 396 383 interrupt_signal = signal(SIGINT, SIG_IGN); 397 384 quit_signal = signal(SIGQUIT, SIG_IGN); 398 385 399 if (resuse_end(pid, resp) == 0) 400 bb_error_msg("error waiting for child process"); 386 resuse_end(pid, resp); 401 387 402 388 /* Re-enable signals. */ … … 405 391 } 406 392 407 int time_main(int argc, char **argv) ;408 int time_main(int argc , char **argv)393 int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 394 int time_main(int argc UNUSED_PARAM, char **argv) 409 395 { 410 396 resource_t res; 411 397 const char *output_format = default_format; 412 char c; 413 414 goto next; 415 /* Parse any options -- don't use getopt() here so we don't 416 * consume the args of our client application... */ 417 while (argc > 0 && argv[0][0] == '-') { 418 while ((c = *++*argv)) { 419 switch (c) { 420 case 'v': 421 output_format = long_format; 422 break; 423 case 'p': 424 output_format = posix_format; 425 break; 426 default: 427 bb_show_usage(); 428 } 429 } 430 next: 431 argv++; 432 argc--; 433 if (!argc) 434 bb_show_usage(); 435 } 398 int opt; 399 400 opt_complementary = "-1"; /* at least one arg */ 401 /* "+": stop on first non-option */ 402 opt = getopt32(argv, "+vp"); 403 argv += optind; 404 if (opt & 1) 405 output_format = long_format; 406 if (opt & 2) 407 output_format = posix_format; 436 408 437 409 run_command(argv, &res); 438 410 439 411 /* Cheat. printf's are shorter :) */ 440 stdout = stderr; 441 dup2(2, 1); /* just in case libc does something silly :( */ 412 xdup2(STDERR_FILENO, STDOUT_FILENO); 442 413 summarize(output_format, argv, &res); 443 414 … … 448 419 if (WIFEXITED(res.waitstatus)) 449 420 return WEXITSTATUS(res.waitstatus); 450 fflush_stdout_and_exit( 0);451 } 421 fflush_stdout_and_exit(EXIT_SUCCESS); 422 }
Note:
See TracChangeset
for help on using the changeset viewer.