aboutsummaryrefslogtreecommitdiff
path: root/miscutils/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'miscutils/time.c')
-rw-r--r--miscutils/time.c51
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 .*/
58static const char posix_format[] ALIGN1 = "real %e\nuser %U\nsys %S"; 65static 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.*/
62static const char long_format[] ALIGN1 = 70static 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
190static void summarize(const char *fmt, char **command, resource_t *resp) 203static 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)
409static void run_command(char *const *cmd, resource_t *resp) 434static 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
434int time_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 467int 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);