1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 11:42:21 +00:00

Millisecond precision for 'times' builtin (re: 65d363fd, 5c677a4c)

Now that we have an iffe feature test for getrusage(3), introduced
in 70fc1da7, the millisecond-precision 'times' command from the
last version of ksh2020 can easily be backported.

src/cmd/ksh93/bltins/misc.c:
- Incorporate ksh2020 'times' command, with a couple of tweaks:
  * Use locale's radix point instead of '.'.
  * Pad seconds with initial zero if < 10.

src/cmd/ksh93/data/builtins.c:
- Update version date for 'times --man'.

src/cmd/ksh93/tests/builtins.sh:
- Update 'times' test for 3 digits after radix point.
This commit is contained in:
Martijn Dekker 2020-07-15 04:11:33 +01:00
parent c5820aabc9
commit b1a4131123
4 changed files with 59 additions and 13 deletions

3
NEWS
View file

@ -7,6 +7,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
- Fixed a bug that caused 'set -b' to have no effect. - Fixed a bug that caused 'set -b' to have no effect.
- Following the 'time' keyword, the 'times' builtin command now also
supports millisecond precision.
2020-07-13: 2020-07-13:
- Fixed a fork bomb that could occur when the vi editor was sent SIGTSTP - Fixed a fork bomb that could occur when the vi editor was sent SIGTSTP

View file

@ -47,7 +47,13 @@
#include "jobs.h" #include "jobs.h"
#include <math.h> #include <math.h>
#include "FEATURE/locale"
#include "FEATURE/time"
#if _lib_getrusage
#include <sys/resource.h>
#else
#include <times.h> #include <times.h>
#endif
#define DOTMAX MAXDEPTH /* maximum level of . nesting */ #define DOTMAX MAXDEPTH /* maximum level of . nesting */
@ -464,17 +470,57 @@ int b_jobs(register int n,char *argv[],Shbltin_t *context)
/* /*
* times command * times command
*/ */
static void print_times(clock_t uticks, clock_t sticks, Shbltin_t *context) static void print_times(struct timeval utime, struct timeval stime)
{ {
int clk_tck = context->shp->gd->lim.clk_tck; int ut_min = utime.tv_sec / 60;
double utime = (double)uticks / clk_tck, stime = (double)sticks / clk_tck; int ut_sec = utime.tv_sec % 60;
sfprintf(sfstdout, "%dm%05.2fs %dm%05.2fs\n", int ut_ms = utime.tv_usec / 1000;
(int)floor(utime / 60), fmod(utime, 60), int st_min = stime.tv_sec / 60;
(int)floor(stime / 60), fmod(stime, 60)); int st_sec = stime.tv_sec % 60;
int st_ms = stime.tv_usec / 1000;
char radix = GETDECIMAL(0);
sfprintf(sfstdout, "%dm%02d%c%03ds %dm%02d%c%03ds\n", ut_min, ut_sec, radix, ut_ms, st_min, st_sec, radix, st_ms);
} }
#if _lib_getrusage
static void print_cpu_times()
{
struct rusage usage;
/* Print the time (user & system) consumed by the shell. */
getrusage(RUSAGE_SELF, &usage);
print_times(usage.ru_utime, usage.ru_stime);
/* Print the time (user & system) consumed by the child processes of the shell. */
getrusage(RUSAGE_CHILDREN, &usage);
print_times(usage.ru_utime, usage.ru_stime);
}
#else /* _lib_getrusage */
static void print_cpu_times()
{
struct timeval utime, stime;
double dtime;
int clk_tck = shgd->lim.clk_tck;
struct tms cpu_times;
times(&cpu_times);
/* Print the time (user & system) consumed by the shell. */
dtime = (double)cpu_times.tms_utime / clk_tck;
utime.tv_sec = dtime / 60;
utime.tv_usec = 1000000 * (dtime - utime.tv_sec);
dtime = (double)cpu_times.tms_stime / clk_tck;
stime.tv_sec = dtime / 60;
stime.tv_usec = 1000000 * (dtime - utime.tv_sec);
print_times(utime, stime);
/* Print the time (user & system) consumed by the child processes of the shell. */
dtime = (double)cpu_times.tms_cutime / clk_tck;
utime.tv_sec = dtime / 60;
utime.tv_usec = 1000000 * (dtime - utime.tv_sec);
dtime = (double)cpu_times.tms_cstime / clk_tck;
stime.tv_sec = dtime / 60;
stime.tv_usec = 1000000 * (dtime - utime.tv_sec);
print_times(utime, stime);
}
#endif /* _lib_getrusage */
int b_times(int argc, char *argv[], Shbltin_t *context) int b_times(int argc, char *argv[], Shbltin_t *context)
{ {
struct tms cpu_times; NOT_USED(context);
/* No options or operands are supported, except --man, etc. */ /* No options or operands are supported, except --man, etc. */
if (argc = optget(argv, sh_opttimes)) switch (argc) if (argc = optget(argv, sh_opttimes)) switch (argc)
{ {
@ -488,10 +534,7 @@ int b_times(int argc, char *argv[], Shbltin_t *context)
if (argv[opt_info.index]) if (argv[opt_info.index])
errormsg(SH_DICT, ERROR_exit(2), e_toomanyops); errormsg(SH_DICT, ERROR_exit(2), e_toomanyops);
/* Get & print the times */ /* Get & print the times */
if (times(&cpu_times) == (clock_t)-1) print_cpu_times();
errormsg(SH_DICT, ERROR_exit(1), "times(3) failed: %s", strerror(errno));
print_times(cpu_times.tms_utime, cpu_times.tms_stime, context);
print_times(cpu_times.tms_cutime, cpu_times.tms_cstime, context);
return(0); return(0);
} }

View file

@ -1906,7 +1906,7 @@ USAGE_LICENSE
; ;
const char sh_opttimes[] = const char sh_opttimes[] =
"[-1c?@(#)$Id: times (ksh93) 2020-06-24 $\n]" "[-1c?@(#)$Id: times (ksh93) 2020-07-14 $\n]"
"[+NAME?times - display CPU usage by the shell and child processes]" "[+NAME?times - display CPU usage by the shell and child processes]"
"[+DESCRIPTION?\btimes\b displays the accumulated user and system CPU times, " "[+DESCRIPTION?\btimes\b displays the accumulated user and system CPU times, "
"one line with the times used by the shell and another with those used by " "one line with the times used by the shell and another with those used by "

View file

@ -700,7 +700,7 @@ fi
# ====== # ======
# 'times' builtin # 'times' builtin
expect=$'0m00.0[0-9]s 0m00.0[0-9]s\n0m00.00s 0m00.00s' expect=$'0m00.0[0-9][0-9]s 0m00.0[0-9][0-9]s\n0m00.000s 0m00.000s'
actual=$("$SHELL" -c times) actual=$("$SHELL" -c times)
[[ $actual == $expect ]] || err_exit "times output: expected $(printf %q "$expect"), got $(printf %q "$actual"))" [[ $actual == $expect ]] || err_exit "times output: expected $(printf %q "$expect"), got $(printf %q "$actual"))"