|
3 | 3 | //
|
4 | 4 | #include "config_ast.h" // IWYU pragma: keep
|
5 | 5 |
|
6 |
| -#include <errno.h> |
7 |
| -#include <math.h> |
8 | 6 | #include <string.h>
|
9 |
| -#include <sys/times.h> |
| 7 | +#include <sys/time.h> |
10 | 8 |
|
11 | 9 | #include "builtins.h"
|
12 | 10 | #include "defs.h"
|
|
15 | 13 | #include "sfio.h"
|
16 | 14 | #include "shcmd.h"
|
17 | 15 |
|
| 16 | +// Print user and system mode CPU times. |
| 17 | +static_fn void print_times(struct timeval utime, struct timeval stime) { |
| 18 | + int ut_min = utime.tv_sec / 60; |
| 19 | + int ut_sec = utime.tv_sec % 60; |
| 20 | + int ut_ms = utime.tv_usec / 1000; |
| 21 | + int st_min = stime.tv_sec / 60; |
| 22 | + int st_sec = stime.tv_sec % 60; |
| 23 | + int st_ms = stime.tv_usec / 1000; |
| 24 | + sfprintf(sfstdout, "%dm%d.%03ds %dm%d.%03ds\n", ut_min, ut_sec, ut_ms, st_min, st_sec, st_ms); |
| 25 | +} |
| 26 | + |
| 27 | +#if _lib_getrusage |
| 28 | + |
| 29 | +// Use getrusage() rather than times() since the former typically has higher resolution. |
| 30 | +#include <sys/resource.h> |
| 31 | + |
| 32 | +// Print user and system mode CPU times for both the shell and its child processes. |
| 33 | +static_fn void print_cpu_times(Shell_t *shp) { |
| 34 | + UNUSED(shp); |
| 35 | + struct rusage usage; |
| 36 | + |
| 37 | + // Print the time (user & system) consumed by the shell. |
| 38 | + getrusage(RUSAGE_SELF, &usage); |
| 39 | + print_times(usage.ru_utime, usage.ru_stime); |
| 40 | + // Print the time (user & system) consumed by the child processes of the shell. |
| 41 | + getrusage(RUSAGE_CHILDREN, &usage); |
| 42 | + print_times(usage.ru_utime, usage.ru_stime); |
| 43 | +} |
| 44 | + |
| 45 | +#else // _lib_getrusage |
| 46 | + |
| 47 | +// Use times() since getrusage() isn't available. Note that it typically has a lower resolution |
| 48 | +// which is why we prefer getrusage(). |
| 49 | +#include <sys/times.h> |
| 50 | + |
| 51 | +// Print user and system mode CPU times for both the shell and its child processes. |
| 52 | +static_fn void print_cpu_times(Shell_t *shp) { |
| 53 | + struct tms cpu_times; |
| 54 | + struct timeval utime, stime; |
| 55 | + double dtime; |
| 56 | + |
| 57 | + times(&cpu_times); |
| 58 | + |
| 59 | + // Print the time (user & system) consumed by the shell. |
| 60 | + dtime = (double)cpu_times.tms_utime / shp->gd->lim.clk_tck; |
| 61 | + utime.tv_sec = dtime / 60; |
| 62 | + utime.tv_usec = 1000000 * (dtime - utime.tv_sec); |
| 63 | + dtime = (double)cpu_times.tms_stime / shp->gd->lim.clk_tck; |
| 64 | + stime.tv_sec = dtime / 60; |
| 65 | + stime.tv_usec = 1000000 * (dtime - utime.tv_sec); |
| 66 | + print_times(utime, stime); |
| 67 | + |
| 68 | + // Print the time (user & system) consumed by the child processes of the shell. |
| 69 | + dtime = (double)cpu_times.tms_cutime / shp->gd->lim.clk_tck; |
| 70 | + utime.tv_sec = dtime / 60; |
| 71 | + utime.tv_usec = 1000000 * (dtime - utime.tv_sec); |
| 72 | + dtime = (double)cpu_times.tms_cstime / shp->gd->lim.clk_tck; |
| 73 | + stime.tv_sec = dtime / 60; |
| 74 | + stime.tv_usec = 1000000 * (dtime - utime.tv_sec); |
| 75 | + print_times(utime, stime); |
| 76 | +} |
| 77 | + |
| 78 | +#endif // _lib_getrusage |
| 79 | + |
18 | 80 | int b_times(int argc, char *argv[], Shbltin_t *context) {
|
19 |
| - Shell_t *shp = context->shp; |
20 | 81 | const char *cmd = argv[0];
|
21 | 82 |
|
22 | 83 | while ((argc = optget(argv, sh_opttimes))) {
|
@@ -44,31 +105,6 @@ int b_times(int argc, char *argv[], Shbltin_t *context) {
|
44 | 105 | __builtin_unreachable();
|
45 | 106 | }
|
46 | 107 |
|
47 |
| - struct tms cpu_times; |
48 |
| - clock_t rv = times(&cpu_times); |
49 |
| - if (rv == (clock_t)-1) { |
50 |
| - errormsg(SH_DICT, ERROR_usage(2), "times() function unexpectedly failed: errno %d %s", |
51 |
| - errno, strerror(errno)); |
52 |
| - __builtin_unreachable(); |
53 |
| - } |
54 |
| - |
55 |
| - double utime, stime, utime_min, utime_sec, stime_min, stime_sec; |
56 |
| - |
57 |
| - utime = (double)cpu_times.tms_utime / shp->gd->lim.clk_tck; |
58 |
| - utime_min = floor(utime / 60); |
59 |
| - utime_sec = utime - utime_min; |
60 |
| - stime = (double)cpu_times.tms_stime / shp->gd->lim.clk_tck; |
61 |
| - stime_min = floor(stime / 60); |
62 |
| - stime_sec = stime - stime_min; |
63 |
| - sfprintf(sfstdout, "%dm%.2fs %dm%.2fs\n", (int)utime_min, utime_sec, (int)stime_min, stime_sec); |
64 |
| - |
65 |
| - utime = (double)cpu_times.tms_cutime / shp->gd->lim.clk_tck; |
66 |
| - utime_min = floor(utime / 60); |
67 |
| - utime_sec = utime - utime_min; |
68 |
| - stime = (double)cpu_times.tms_cstime / shp->gd->lim.clk_tck; |
69 |
| - stime_min = floor(stime / 60); |
70 |
| - stime_sec = stime - stime_min; |
71 |
| - sfprintf(sfstdout, "%dm%.2fs %dm%.2fs\n", (int)utime_min, utime_sec, (int)stime_min, stime_sec); |
72 |
| - |
| 108 | + print_cpu_times(context->shp); |
73 | 109 | return 0;
|
74 | 110 | }
|
0 commit comments