diff options
Diffstat (limited to 'miscutils/time.c')
| -rw-r--r-- | miscutils/time.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/miscutils/time.c b/miscutils/time.c index 77d35a832..9a1039be9 100644 --- a/miscutils/time.c +++ b/miscutils/time.c | |||
| @@ -22,10 +22,17 @@ | |||
| 22 | //kbuild:lib-$(CONFIG_TIME) += time.o | 22 | //kbuild:lib-$(CONFIG_TIME) += time.o |
| 23 | 23 | ||
| 24 | //usage:#define time_trivial_usage | 24 | //usage:#define time_trivial_usage |
| 25 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
| 25 | //usage: "[-vpa] [-o FILE] PROG ARGS" | 26 | //usage: "[-vpa] [-o FILE] PROG ARGS" |
| 27 | //usage: ) | ||
| 28 | //usage: IF_PLATFORM_MINGW32( | ||
| 29 | //usage: "[-pa] [-f FMT] [-o FILE] PROG ARGS" | ||
| 30 | //usage: ) | ||
| 26 | //usage:#define time_full_usage "\n\n" | 31 | //usage:#define time_full_usage "\n\n" |
| 27 | //usage: "Run PROG, display resource usage when it exits\n" | 32 | //usage: "Run PROG, display resource usage when it exits\n" |
| 33 | //usage: IF_NOT_PLATFORM_MINGW32( | ||
| 28 | //usage: "\n -v Verbose" | 34 | //usage: "\n -v Verbose" |
| 35 | //usage: ) | ||
| 29 | //usage: "\n -p POSIX output format" | 36 | //usage: "\n -p POSIX output format" |
| 30 | //usage: "\n -f FMT Custom format" | 37 | //usage: "\n -f FMT Custom format" |
| 31 | //usage: "\n -o FILE Write result to FILE" | 38 | //usage: "\n -o FILE Write result to FILE" |
| @@ -57,6 +64,7 @@ static const char default_format[] ALIGN1 = "real\t%E\nuser\t%u\nsys\t%T"; | |||
| 57 | /* The output format for the -p option .*/ | 64 | /* The output format for the -p option .*/ |
| 58 | static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; | 65 | static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; |
| 59 | 66 | ||
| 67 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 60 | /* Format string for printing all statistics verbosely. | 68 | /* Format string for printing all statistics verbosely. |
| 61 | Keep this output to 24 lines so users on terminals can see it all.*/ | 69 | Keep this output to 24 lines so users on terminals can see it all.*/ |
| 62 | static const char long_format[] ALIGN1 = | 70 | static const char long_format[] ALIGN1 = |
| @@ -83,6 +91,7 @@ static const char long_format[] ALIGN1 = | |||
| 83 | "\tSignals delivered: %k\n" | 91 | "\tSignals delivered: %k\n" |
| 84 | "\tPage size (bytes): %Z\n" | 92 | "\tPage size (bytes): %Z\n" |
| 85 | "\tExit status: %x"; | 93 | "\tExit status: %x"; |
| 94 | #endif | ||
| 86 | 95 | ||
| 87 | /* Wait for and fill in data on child process PID. | 96 | /* Wait for and fill in data on child process PID. |
| 88 | Return 0 on error, 1 if ok. */ | 97 | Return 0 on error, 1 if ok. */ |
| @@ -93,7 +102,11 @@ static void resuse_end(pid_t pid, resource_t *resp) | |||
| 93 | 102 | ||
| 94 | /* Ignore signals, but don't ignore the children. When wait3 | 103 | /* Ignore signals, but don't ignore the children. When wait3 |
| 95 | * returns the child process, set the time the command finished. */ | 104 | * returns the child process, set the time the command finished. */ |
| 105 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 96 | while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { | 106 | while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { |
| 107 | #else | ||
| 108 | while ((caught=mingw_wait3(pid, &resp->waitstatus, 0, &resp->ru)) != pid) { | ||
| 109 | #endif | ||
| 97 | if (caught == -1 && errno != EINTR) { | 110 | if (caught == -1 && errno != EINTR) { |
| 98 | bb_simple_perror_msg("wait"); | 111 | bb_simple_perror_msg("wait"); |
| 99 | return; | 112 | return; |
| @@ -189,9 +202,11 @@ static unsigned long ptok(const unsigned pagesize, const unsigned long pages) | |||
| 189 | 202 | ||
| 190 | static void summarize(const char *fmt, char **command, resource_t *resp) | 203 | static void summarize(const char *fmt, char **command, resource_t *resp) |
| 191 | { | 204 | { |
| 205 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 192 | unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ | 206 | unsigned vv_ms; /* Elapsed virtual (CPU) milliseconds */ |
| 193 | unsigned cpu_ticks; /* Same, in "CPU ticks" */ | 207 | unsigned cpu_ticks; /* Same, in "CPU ticks" */ |
| 194 | unsigned pagesize = bb_getpagesize(); | 208 | unsigned pagesize = bb_getpagesize(); |
| 209 | #endif | ||
| 195 | 210 | ||
| 196 | /* Impossible: we do not use WUNTRACED flag in wait()... | 211 | /* Impossible: we do not use WUNTRACED flag in wait()... |
| 197 | if (WIFSTOPPED(resp->waitstatus)) | 212 | if (WIFSTOPPED(resp->waitstatus)) |
| @@ -205,6 +220,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 205 | printf("Command exited with non-zero status %u\n", | 220 | printf("Command exited with non-zero status %u\n", |
| 206 | WEXITSTATUS(resp->waitstatus)); | 221 | WEXITSTATUS(resp->waitstatus)); |
| 207 | 222 | ||
| 223 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 208 | vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 | 224 | vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000 |
| 209 | + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; | 225 | + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000; |
| 210 | 226 | ||
| @@ -215,6 +231,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 215 | cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; | 231 | cpu_ticks = vv_ms * (unsigned long long)TICKS_PER_SEC / 1000; |
| 216 | #endif | 232 | #endif |
| 217 | if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ | 233 | if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */ |
| 234 | #endif | ||
| 218 | 235 | ||
| 219 | while (*fmt) { | 236 | while (*fmt) { |
| 220 | /* Handle leading literal part */ | 237 | /* Handle leading literal part */ |
| @@ -242,6 +259,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 242 | case 'C': /* The command that got timed. */ | 259 | case 'C': /* The command that got timed. */ |
| 243 | printargv(command); | 260 | printargv(command); |
| 244 | break; | 261 | break; |
| 262 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 245 | case 'D': /* Average unshared data size. */ | 263 | case 'D': /* Average unshared data size. */ |
| 246 | /* (linux kernel sets ru_idrss/isrss/ixrss to 0, | 264 | /* (linux kernel sets ru_idrss/isrss/ixrss to 0, |
| 247 | * docs say the value is in kbytes, so ptok() is wrong) */ | 265 | * docs say the value is in kbytes, so ptok() is wrong) */ |
| @@ -251,6 +269,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 251 | ) / cpu_ticks | 269 | ) / cpu_ticks |
| 252 | ); | 270 | ); |
| 253 | break; | 271 | break; |
| 272 | #endif | ||
| 254 | case 'E': { /* Elapsed real (wall clock) time. */ | 273 | case 'E': { /* Elapsed real (wall clock) time. */ |
| 255 | unsigned seconds = resp->elapsed_ms / 1000; | 274 | unsigned seconds = resp->elapsed_ms / 1000; |
| 256 | if (seconds >= 3600) /* One hour -> h:m:s. */ | 275 | if (seconds >= 3600) /* One hour -> h:m:s. */ |
| @@ -265,6 +284,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 265 | (unsigned)(resp->elapsed_ms / 10) % 100); | 284 | (unsigned)(resp->elapsed_ms / 10) % 100); |
| 266 | break; | 285 | break; |
| 267 | } | 286 | } |
| 287 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 268 | case 'F': /* Major page faults. */ | 288 | case 'F': /* Major page faults. */ |
| 269 | printf("%lu", resp->ru.ru_majflt); | 289 | printf("%lu", resp->ru.ru_majflt); |
| 270 | break; | 290 | break; |
| @@ -297,6 +317,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 297 | case 'R': /* Minor page faults (reclaims). */ | 317 | case 'R': /* Minor page faults (reclaims). */ |
| 298 | printf("%lu", resp->ru.ru_minflt); | 318 | printf("%lu", resp->ru.ru_minflt); |
| 299 | break; | 319 | break; |
| 320 | #endif | ||
| 300 | case 'S': /* System time. */ | 321 | case 'S': /* System time. */ |
| 301 | printf("%u.%02u", | 322 | printf("%u.%02u", |
| 302 | (unsigned)resp->ru.ru_stime.tv_sec, | 323 | (unsigned)resp->ru.ru_stime.tv_sec, |
| @@ -331,6 +352,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 331 | (unsigned)(resp->ru.ru_utime.tv_sec % 60), | 352 | (unsigned)(resp->ru.ru_utime.tv_sec % 60), |
| 332 | (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); | 353 | (unsigned)(resp->ru.ru_utime.tv_usec / 10000)); |
| 333 | break; | 354 | break; |
| 355 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 334 | case 'W': /* Times swapped out. */ | 356 | case 'W': /* Times swapped out. */ |
| 335 | printf("%lu", resp->ru.ru_nswap); | 357 | printf("%lu", resp->ru.ru_nswap); |
| 336 | break; | 358 | break; |
| @@ -343,11 +365,13 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 343 | case 'c': /* Involuntary context switches. */ | 365 | case 'c': /* Involuntary context switches. */ |
| 344 | printf("%lu", resp->ru.ru_nivcsw); | 366 | printf("%lu", resp->ru.ru_nivcsw); |
| 345 | break; | 367 | break; |
| 368 | #endif | ||
| 346 | case 'e': /* Elapsed real time in seconds. */ | 369 | case 'e': /* Elapsed real time in seconds. */ |
| 347 | printf("%u.%02u", | 370 | printf("%u.%02u", |
| 348 | (unsigned)resp->elapsed_ms / 1000, | 371 | (unsigned)resp->elapsed_ms / 1000, |
| 349 | (unsigned)(resp->elapsed_ms / 10) % 100); | 372 | (unsigned)(resp->elapsed_ms / 10) % 100); |
| 350 | break; | 373 | break; |
| 374 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 351 | case 'k': /* Signals delivered. */ | 375 | case 'k': /* Signals delivered. */ |
| 352 | printf("%lu", resp->ru.ru_nsignals); | 376 | printf("%lu", resp->ru.ru_nsignals); |
| 353 | break; | 377 | break; |
| @@ -366,6 +390,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 366 | case 'w': /* Voluntary context switches. */ | 390 | case 'w': /* Voluntary context switches. */ |
| 367 | printf("%lu", resp->ru.ru_nvcsw); | 391 | printf("%lu", resp->ru.ru_nvcsw); |
| 368 | break; | 392 | break; |
| 393 | #endif | ||
| 369 | case 'x': /* Exit status. */ | 394 | case 'x': /* Exit status. */ |
| 370 | printf("%u", WEXITSTATUS(resp->waitstatus)); | 395 | printf("%u", WEXITSTATUS(resp->waitstatus)); |
| 371 | break; | 396 | break; |
| @@ -409,6 +434,7 @@ static void summarize(const char *fmt, char **command, resource_t *resp) | |||
| 409 | static void run_command(char *const *cmd, resource_t *resp) | 434 | static void run_command(char *const *cmd, resource_t *resp) |
| 410 | { | 435 | { |
| 411 | pid_t pid; | 436 | pid_t pid; |
| 437 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 412 | void (*interrupt_signal)(int); | 438 | void (*interrupt_signal)(int); |
| 413 | void (*quit_signal)(int); | 439 | void (*quit_signal)(int); |
| 414 | 440 | ||
| @@ -429,6 +455,13 @@ static void run_command(char *const *cmd, resource_t *resp) | |||
| 429 | /* Re-enable signals. */ | 455 | /* Re-enable signals. */ |
| 430 | signal(SIGINT, interrupt_signal); | 456 | signal(SIGINT, interrupt_signal); |
| 431 | signal(SIGQUIT, quit_signal); | 457 | signal(SIGQUIT, quit_signal); |
| 458 | #else | ||
| 459 | resp->elapsed_ms = monotonic_ms(); | ||
| 460 | if ((pid=spawn((char **)cmd)) == -1) | ||
| 461 | bb_perror_msg_and_die("can't execute %s", cmd[0]); | ||
| 462 | |||
| 463 | resuse_end(pid, resp); | ||
| 464 | #endif | ||
| 432 | } | 465 | } |
| 433 | 466 | ||
| 434 | int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 467 | int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| @@ -442,20 +475,35 @@ int time_main(int argc UNUSED_PARAM, char **argv) | |||
| 442 | int opt; | 475 | int opt; |
| 443 | int ex; | 476 | int ex; |
| 444 | enum { | 477 | enum { |
| 478 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 445 | OPT_v = (1 << 0), | 479 | OPT_v = (1 << 0), |
| 446 | OPT_p = (1 << 1), | 480 | OPT_p = (1 << 1), |
| 447 | OPT_a = (1 << 2), | 481 | OPT_a = (1 << 2), |
| 448 | OPT_o = (1 << 3), | 482 | OPT_o = (1 << 3), |
| 449 | OPT_f = (1 << 4), | 483 | OPT_f = (1 << 4), |
| 484 | #else | ||
| 485 | OPT_p = (1 << 0), | ||
| 486 | OPT_a = (1 << 1), | ||
| 487 | OPT_o = (1 << 2), | ||
| 488 | OPT_f = (1 << 3), | ||
| 489 | #endif | ||
| 450 | }; | 490 | }; |
| 451 | 491 | ||
| 452 | /* "+": stop on first non-option */ | 492 | /* "+": stop on first non-option */ |
| 493 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 453 | opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, | 494 | opt = getopt32(argv, "^+" "vpao:f:" "\0" "-1"/*at least one arg*/, |
| 454 | &output_filename, &output_format | 495 | &output_filename, &output_format |
| 455 | ); | 496 | ); |
| 497 | #else | ||
| 498 | opt = getopt32(argv, "^+" "pao:f:" "\0" "-1"/*at least one arg*/, | ||
| 499 | &output_filename, &output_format | ||
| 500 | ); | ||
| 501 | #endif | ||
| 456 | argv += optind; | 502 | argv += optind; |
| 503 | #if !ENABLE_PLATFORM_MINGW32 | ||
| 457 | if (opt & OPT_v) | 504 | if (opt & OPT_v) |
| 458 | output_format = long_format; | 505 | output_format = long_format; |
| 506 | #endif | ||
| 459 | if (opt & OPT_p) | 507 | if (opt & OPT_p) |
| 460 | output_format = posix_format; | 508 | output_format = posix_format; |
| 461 | output_fd = STDERR_FILENO; | 509 | output_fd = STDERR_FILENO; |
| @@ -476,6 +524,9 @@ int time_main(int argc UNUSED_PARAM, char **argv) | |||
| 476 | 524 | ||
| 477 | /* Cheat. printf's are shorter :) */ | 525 | /* Cheat. printf's are shorter :) */ |
| 478 | xdup2(output_fd, STDOUT_FILENO); | 526 | xdup2(output_fd, STDOUT_FILENO); |
| 527 | #if ENABLE_PLATFORM_MINGW32 | ||
| 528 | setvbuf(stdout, NULL, _IOFBF, 256); | ||
| 529 | #endif | ||
| 479 | summarize(output_format, argv, &res); | 530 | summarize(output_format, argv, &res); |
| 480 | 531 | ||
| 481 | ex = WEXITSTATUS(res.waitstatus); | 532 | ex = WEXITSTATUS(res.waitstatus); |
