* Bug: time doesn't work on builtins
@ 2024-08-15 13:15 Mark J. Reed
2024-08-15 18:52 ` Bart Schaefer
0 siblings, 1 reply; 15+ messages in thread
From: Mark J. Reed @ 2024-08-15 13:15 UTC (permalink / raw)
To: Zsh hackers list
[-- Attachment #1: Type: text/plain, Size: 397 bytes --]
This was unexpected:
*zsh%* time read
hello
*zsh%*
Any attempt to *time *a builtin generates no output whatsoever. No timings,
no error message.The timed command executes in the current shell and has
its usual side-effects, but the *time* itself does nothing.
Contrast to bash and ksh, in which time works on builtins the same as on
external commands.
--
Mark J. Reed <markjreed@gmail.com>
[-- Attachment #2: Type: text/html, Size: 925 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-08-15 13:15 Bug: time doesn't work on builtins Mark J. Reed
@ 2024-08-15 18:52 ` Bart Schaefer
2024-08-15 22:08 ` Mark J. Reed
0 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-08-15 18:52 UTC (permalink / raw)
To: Mark J. Reed; +Cc: Zsh hackers list
On Thu, Aug 15, 2024 at 6:15 AM Mark J. Reed <markjreed@gmail.com> wrote:
>
> Any attempt to time a builtin generates no output whatsoever. No timings, no error message.The timed command executes in the current shell and has its usual side-effects, but the time itself does nothing.
This was last discussed in users/28740 and subsequent thread ...
>> The OS facility that reports time statistics only works for a parent
>> process to read the stats of a child. To work on builtins, we'd have
>> to rewrite that internally
That isn't quite accurate ... what we'd have to do is call RUSAGE_SELF
both before and after the builtin and subtract the former from the
latter, there's no (other) facility to get only the internal time
delta.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-08-15 18:52 ` Bart Schaefer
@ 2024-08-15 22:08 ` Mark J. Reed
2024-08-16 19:20 ` Bart Schaefer
0 siblings, 1 reply; 15+ messages in thread
From: Mark J. Reed @ 2024-08-15 22:08 UTC (permalink / raw)
To: Zsh hackers list
[-- Attachment #1: Type: text/plain, Size: 1096 bytes --]
Absent a rewrite of the functionality to actually work on builtins, maybe
it could be modified to output a message about *time* only being supported
for external commands?
On Thu, Aug 15, 2024 at 2:52 PM Bart Schaefer <schaefer@brasslantern.com>
wrote:
> On Thu, Aug 15, 2024 at 6:15 AM Mark J. Reed <markjreed@gmail.com> wrote:
> >
> > Any attempt to time a builtin generates no output whatsoever. No
> timings, no error message.The timed command executes in the current shell
> and has its usual side-effects, but the time itself does nothing.
>
> This was last discussed in users/28740 and subsequent thread ...
>
> >> The OS facility that reports time statistics only works for a parent
> >> process to read the stats of a child. To work on builtins, we'd have
> >> to rewrite that internally
>
> That isn't quite accurate ... what we'd have to do is call RUSAGE_SELF
> both before and after the builtin and subtract the former from the
> latter, there's no (other) facility to get only the internal time
> delta.
>
--
Mark J. Reed <markjreed@gmail.com>
[-- Attachment #2: Type: text/html, Size: 1706 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-08-15 22:08 ` Mark J. Reed
@ 2024-08-16 19:20 ` Bart Schaefer
2024-09-04 0:27 ` Bart Schaefer
0 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-08-16 19:20 UTC (permalink / raw)
To: Zsh hackers list
[-- Attachment #1: Type: text/plain, Size: 169 bytes --]
On Thu, Aug 15, 2024 at 3:08 PM Mark J. Reed <markjreed@gmail.com> wrote:
>
> Absent a rewrite of the functionality to actually work on builtins
Let's try this.
[-- Attachment #2: time-builtins.txt --]
[-- Type: text/plain, Size: 2956 bytes --]
diff --git a/Src/exec.c b/Src/exec.c
index 00278ac50..3c04c5efd 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2938,6 +2938,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
* in order to check for prefix commands.
*/
LinkList preargs;
+ /*
+ * for the "time" builtin
+ */
+ child_times_t shti, chti;
+ struct timeval then;
doneps4 = 0;
@@ -3621,6 +3626,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
/* This is nonzero if the command is a current shell procedure? */
is_cursh = (is_builtin || is_shfunc || nullexec || type >= WC_CURSH);
+ if (is_cursh && (how & Z_TIMED))
+ shelltime(&shti, &chti, &then, 0);
/**************************************************************************
* Do we need to fork? We need to fork if: *
@@ -4377,6 +4384,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
errflag |= ERRFLAG_ERROR;
}
}
+ if (is_cursh && (how & Z_TIMED))
+ shelltime(&shti, is_builtin ? NULL : &chti, &then, 1);
if (newxtrerr) {
int eno = errno;
fil = fileno(newxtrerr);
@@ -5265,7 +5274,7 @@ exectime(Estate state, UNUSED(int do_exec))
jb = thisjob;
if (WC_TIMED_TYPE(state->pc[-1]) == WC_TIMED_EMPTY) {
- shelltime();
+ shelltime(NULL,NULL,NULL,0);
return 0;
}
execpline(state, *state->pc++, Z_TIMED|Z_SYNC, 0);
diff --git a/Src/jobs.c b/Src/jobs.c
index 07facc60b..39c664388 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1894,7 +1894,7 @@ spawnjob(void)
/**/
void
-shelltime(void)
+shelltime(child_times_t *shell, child_times_t *kids, struct timeval *then, int delta)
{
struct timezone dummy_tz;
struct timeval dtimeval, now;
@@ -1913,7 +1913,28 @@ shelltime(void)
ti.ut = buf.tms_utime;
ti.st = buf.tms_stime;
#endif
- printtime(dtime(&dtimeval, &shtimer, &now), &ti, "shell");
+ if (shell) {
+ if (delta) {
+#ifdef HAVE_GETRUSAGE
+ dtime(&ti.ru_utime, &shell->ru_utime, &ti.ru_utime);
+ dtime(&ti.ru_stime, &shell->ru_stime, &ti.ru_stime);
+#else
+ ti.ut -= shell->ut;
+ ti.st -= shell->st;
+#endif
+ } else
+ *shell = ti;
+ }
+ if (delta)
+ dtime(&dtimeval, then, &now);
+ else {
+ if (then)
+ *then = now;
+ dtime(&dtimeval, &shtimer, &now);
+ }
+
+ if (!delta == !shell)
+ printtime(&dtimeval, &ti, "shell");
#ifdef HAVE_GETRUSAGE
getrusage(RUSAGE_CHILDREN, &ti);
@@ -1921,8 +1942,20 @@ shelltime(void)
ti.ut = buf.tms_cutime;
ti.st = buf.tms_cstime;
#endif
- printtime(&dtimeval, &ti, "children");
-
+ if (kids) {
+ if (delta) {
+#ifdef HAVE_GETRUSAGE
+ dtime(&ti.ru_utime, &kids->ru_utime, &ti.ru_utime);
+ dtime(&ti.ru_stime, &kids->ru_stime, &ti.ru_stime);
+#else
+ ti.ut -= shell->ut;
+ ti.st -= shell->st;
+#endif
+ } else
+ *kids = ti;
+ }
+ if (!delta == !kids)
+ printtime(&dtimeval, &ti, "children");
}
/* see if jobs need printing */
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-08-16 19:20 ` Bart Schaefer
@ 2024-09-04 0:27 ` Bart Schaefer
2024-09-04 14:32 ` Jun. T
0 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-09-04 0:27 UTC (permalink / raw)
To: Zsh hackers list
On Fri, Aug 16, 2024 at 12:20 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> Let's try this.
Any comment on the patch?
Where would a test for this go? The other "time" tests are in
A01grammar but only apply to whether it parses and produces TIMEFMT'ed
output correctly. Perhaps A05execution?
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-04 0:27 ` Bart Schaefer
@ 2024-09-04 14:32 ` Jun. T
2024-09-05 17:29 ` Jun. T
2024-09-06 0:10 ` Bart Schaefer
0 siblings, 2 replies; 15+ messages in thread
From: Jun. T @ 2024-09-04 14:32 UTC (permalink / raw)
Cc: zsh-workers
> 2024/09/04 9:27, Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Fri, Aug 16, 2024 at 12:20 PM Bart Schaefer
> <schaefer@brasslantern.com> wrote:
>>
>> Let's try this.
>
> Any comment on the patch?
The followings still give no time statistics:
% time x=1
% time x=$(date)
The following works:
% x=0; time for ((i=1; i<=10000; ++i)); do let 'x+=i'; done; echo $x
shell 0.03s user 0.01s system 99% cpu 0.036 total
children 0.00s user 0.00s system 0% cpu 0.036 total
50005000
But if "let 'x+=i' is replaced by "((x+=i))"
% x=0; time for ((i=1; i<=10000; ++i)); do ((x+=i)); done; echo $x
0
The for loop is not executed, and the time statistics is not output.
This happens also without the patch time-builtins.txt.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-04 14:32 ` Jun. T
@ 2024-09-05 17:29 ` Jun. T
2024-09-05 23:37 ` Bart Schaefer
2024-09-06 0:10 ` Bart Schaefer
1 sibling, 1 reply; 15+ messages in thread
From: Jun. T @ 2024-09-05 17:29 UTC (permalink / raw)
To: zsh-workers
> 2024/09/04 23:32, I wrote:
>
> % x=0; time for ((i=1; i<=10000; ++i)); do ((x+=i)); done; echo $x
> 0
>
> The for loop is not executed, and the time statistics is not output.
The reason that the for loop is skipped may be the following:
When exectime() calls execpline(,slcode=*state->pc++,) (exec.c:5280),
slcode is WC_SUBLIST with WC_SUBLIST_SIMPLE flag, and 'code' (the next
word code) obtained by (exec.c:1677)
wordcode code = *state->pc++;
is just a line number, not WC_PIPE (see parse.c:757). Then the for
loop is skipped by (lines 1680,81)
if (wc_code(code) != WC_PIPE)
return lastval = (slflags & WC_SUBLIST_NOT) != 0;
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-05 17:29 ` Jun. T
@ 2024-09-05 23:37 ` Bart Schaefer
2024-09-06 9:41 ` Jun T
0 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-09-05 23:37 UTC (permalink / raw)
To: Jun. T; +Cc: zsh-workers
On Thu, Sep 5, 2024 at 10:29 AM Jun. T <takimoto-j@kba.biglobe.ne.jp> wrote:
>
> When exectime() calls execpline(,slcode=*state->pc++,) (exec.c:5280),
> slcode is WC_SUBLIST with WC_SUBLIST_SIMPLE flag, and 'code' (the next
> word code) obtained by (exec.c:1677)
> wordcode code = *state->pc++;
> is just a line number, not WC_PIPE (see parse.c:757). Then the for
> loop is skipped by (lines 1680,81)
> if (wc_code(code) != WC_PIPE)
> return lastval = (slflags & WC_SUBLIST_NOT) != 0;
Is this enough? All existing tests still pass, but I wonder if
there's another way to get there.
diff --git a/Src/exec.c b/Src/exec.c
index 00278ac50..057999844 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1677,7 +1677,7 @@ execpline(Estate state, wordcode slcode, int how, int last
1)
wordcode code = *state->pc++;
static int lastwj, lpforked;
- if (wc_code(code) != WC_PIPE)
+ if (wc_code(code) != WC_PIPE && !(how & Z_TIMED))
return lastval = (slflags & WC_SUBLIST_NOT) != 0;
else if (slflags & WC_SUBLIST_NOT)
last1 = 0;
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-04 14:32 ` Jun. T
2024-09-05 17:29 ` Jun. T
@ 2024-09-06 0:10 ` Bart Schaefer
2024-09-06 9:52 ` Jun T
1 sibling, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-09-06 0:10 UTC (permalink / raw)
To: Jun. T; +Cc: zsh-workers
On Wed, Sep 4, 2024 at 7:33 AM Jun. T <takimoto-j@kba.biglobe.ne.jp> wrote:
>
> The followings still give no time statistics:
>
> % time x=1
> % time x=$(date)
Hm, that's because we're taking the code path marked /* Empty command
*/ in execcmd_exec().
I think the only relevant case is around addvars() but can't be sure;
does anyone know a straightforward way to conditionally suppress the
child times in the case where the right-hand-side does not fork?
(Hand-fuzzed patch follows)
diff --git a/Src/exec.c b/Src/exec.c
index 00278ac50..c2f813078 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3381,7 +3386,11 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (varspc) {
/* Make sure $? is still correct for assignment */
lastval = old_lastval;
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 0);
addvars(state, varspc, 0);
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
}
if (errflag)
lastval = 1;
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-05 23:37 ` Bart Schaefer
@ 2024-09-06 9:41 ` Jun T
0 siblings, 0 replies; 15+ messages in thread
From: Jun T @ 2024-09-06 9:41 UTC (permalink / raw)
To: zsh-workers
> 2024/09/06 8:37, Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Thu, Sep 5, 2024 at 10:29 AM Jun. T <takimoto-j@kba.biglobe.ne.jp> wrote:
>>
>> loop is skipped by (lines 1680,81)
>> if (wc_code(code) != WC_PIPE)
>> return lastval = (slflags & WC_SUBLIST_NOT) != 0;
>
> Is this enough? All existing tests still pass, but I wonder if
> there's another way to get there.
Other calls of execpline() are all from execlist(), and it seems
the case with WC_SUBST_SIMPLE is already taken care of (for
example at around line 1492).
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-06 0:10 ` Bart Schaefer
@ 2024-09-06 9:52 ` Jun T
2024-09-06 19:13 ` Bart Schaefer
0 siblings, 1 reply; 15+ messages in thread
From: Jun T @ 2024-09-06 9:52 UTC (permalink / raw)
To: zsh-workers
> 2024/09/06 9:10, Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Wed, Sep 4, 2024 at 7:33 AM Jun. T <takimoto-j@kba.biglobe.ne.jp> wrote:
>>
>> The followings still give no time statistics:
>>
>> % time x=1
>> % time x=$(date)
>
> (Hand-fuzzed patch follows)
The patch works for the above two cases, but I've fond there
are still more problems...
[1] In the patch file "time-builtin.txt":
@@ -4377,6 +4384,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
errflag |= ERRFLAG_ERROR;
}
}
+ if (is_cursh && (how & Z_TIMED))
+ shelltime(&shti, is_builtin ? NULL : &chti, &then, 1);
Due to "is_builtin ? NULL : &chti", child time is not reported for
the cases such as
% time eval 'external command'
% time . ./script # script runs external command
I think it's better to pass &chti always.
[2] Time spent in prefork() is not included in the statistics.
% time echo $(x=0;for ((i=0; i<=100000; ++i)); do ((x+=i)); done; echo $x) 5000050000
shell 0.00s user 0.00s system 100% cpu 0.000 total
% time cat <(time-consuming-command) # cat is not builtin
(the problem existed before applying "time-builtin.txt")
% time echo $(external command)
Even if the problem [1] is fixed (by always passing &chti)
the time reported would not include the time used for
the 'external command'.
Not sure this can be fixed easily.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Bug: time doesn't work on builtins
2024-09-06 9:52 ` Jun T
@ 2024-09-06 19:13 ` Bart Schaefer
2024-09-14 2:10 ` PATCH: " Bart Schaefer
0 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-09-06 19:13 UTC (permalink / raw)
To: Jun T; +Cc: zsh-workers
On Fri, Sep 6, 2024 at 2:52 AM Jun T <takimoto-j@kba.biglobe.ne.jp> wrote:
>
> % time eval 'external command'
> % time . ./script # script runs external command
>
> I think it's better to pass &chti always.
OK.
> [2] Time spent in prefork() is not included in the statistics.
I believe that's fixable by always calling shelltime(...,0) when
Z_TIMED but then only calling shelltime(...,1) when is_cursh is
determined later.
Remaining question is whether stats should be printed on error cases,
e.g., "no such builtin":
time builtin nosuch $(long running command)
That means sticking in a few more calls to shelltime() in front of
early return statements.
^ permalink raw reply [flat|nested] 15+ messages in thread
* PATCH: Re: Bug: time doesn't work on builtins
2024-09-06 19:13 ` Bart Schaefer
@ 2024-09-14 2:10 ` Bart Schaefer
2024-09-20 7:46 ` Oliver Kiddle
0 siblings, 1 reply; 15+ messages in thread
From: Bart Schaefer @ 2024-09-14 2:10 UTC (permalink / raw)
To: Zsh hackers list
[-- Attachment #1: Type: text/plain, Size: 550 bytes --]
On Fri, Sep 6, 2024 at 12:13 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> Remaining question is whether stats should be printed on error cases,
> e.g., "no such builtin":
I've gone ahead with this, it's a bit ugly because of all the early
"return;" but it works.
Tests included, though they only check whether `time' returns
something, not whether that something makes sense in terms of cpu
usage etc. If anyone has any ideas how to make that predictable
enough to pattern-match the output, feel free to update the tests.
[-- Attachment #2: time-builtins2.txt --]
[-- Type: text/plain, Size: 8351 bytes --]
diff --git a/Src/exec.c b/Src/exec.c
index 00278ac50..8aa7466f5 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -881,6 +881,10 @@ execute(LinkList args, int flags, int defpath)
_realexit();
else
zerr("command not found: %s", arg0);
+ /* This is bash behavior, but fails to restore interactive settings etc.
+ lastval = ((eno == EACCES || eno == ENOEXEC) ? 126 : 127);
+ return;
+ */
_exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127);
}
@@ -1677,7 +1681,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
wordcode code = *state->pc++;
static int lastwj, lpforked;
- if (wc_code(code) != WC_PIPE)
+ if (wc_code(code) != WC_PIPE && !(how & Z_TIMED))
return lastval = (slflags & WC_SUBLIST_NOT) != 0;
else if (slflags & WC_SUBLIST_NOT)
last1 = 0;
@@ -2939,6 +2943,14 @@ execcmd_exec(Estate state, Execcmd_params eparams,
*/
LinkList preargs;
+ /*
+ * for the "time" keyword
+ */
+ child_times_t shti, chti;
+ struct timeval then;
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 0);
+
doneps4 = 0;
/*
@@ -3071,6 +3083,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (!(hn = resolvebuiltin(cmdarg, hn))) {
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
if (type != WC_TYPESET)
@@ -3252,6 +3266,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
errflag |= ERRFLAG_ERROR;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
}
@@ -3343,6 +3359,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
errflag |= ERRFLAG_ERROR;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
} else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) {
if (!args)
@@ -3363,6 +3381,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 0;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
} else {
/*
@@ -3375,6 +3395,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
cmdoutval = use_cmdoutval ? lastval : 0;
@@ -3393,6 +3415,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
}
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
} else if (isset(RESTRICTED) && (cflags & BINF_EXEC) && do_exec) {
@@ -3401,6 +3425,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
lastval = 1;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
@@ -3437,6 +3463,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
opts[AUTOCONTINUE] = oautocont;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
break;
@@ -3448,6 +3476,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
if (!(hn = resolvebuiltin(cmdarg, hn))) {
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
break;
@@ -3466,6 +3496,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
opts[AUTOCONTINUE] = oautocont;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
@@ -3545,6 +3577,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
opts[AUTOCONTINUE] = oautocont;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
}
@@ -3575,6 +3609,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
opts[AUTOCONTINUE] = oautocont;
if (forked)
_realexit();
+ if (how & Z_TIMED)
+ shelltime(&shti, &chti, &then, 1);
return;
}
@@ -4377,6 +4413,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
errflag |= ERRFLAG_ERROR;
}
}
+ if ((is_cursh || do_exec) && (how & Z_TIMED))
+ shelltime(&shti, &chti, &then, 1);
if (newxtrerr) {
int eno = errno;
fil = fileno(newxtrerr);
@@ -5265,7 +5303,7 @@ exectime(Estate state, UNUSED(int do_exec))
jb = thisjob;
if (WC_TIMED_TYPE(state->pc[-1]) == WC_TIMED_EMPTY) {
- shelltime();
+ shelltime(NULL,NULL,NULL,0);
return 0;
}
execpline(state, *state->pc++, Z_TIMED|Z_SYNC, 0);
diff --git a/Src/jobs.c b/Src/jobs.c
index 07facc60b..39c664388 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1894,7 +1894,7 @@ spawnjob(void)
/**/
void
-shelltime(void)
+shelltime(child_times_t *shell, child_times_t *kids, struct timeval *then, int delta)
{
struct timezone dummy_tz;
struct timeval dtimeval, now;
@@ -1913,7 +1913,28 @@ shelltime(void)
ti.ut = buf.tms_utime;
ti.st = buf.tms_stime;
#endif
- printtime(dtime(&dtimeval, &shtimer, &now), &ti, "shell");
+ if (shell) {
+ if (delta) {
+#ifdef HAVE_GETRUSAGE
+ dtime(&ti.ru_utime, &shell->ru_utime, &ti.ru_utime);
+ dtime(&ti.ru_stime, &shell->ru_stime, &ti.ru_stime);
+#else
+ ti.ut -= shell->ut;
+ ti.st -= shell->st;
+#endif
+ } else
+ *shell = ti;
+ }
+ if (delta)
+ dtime(&dtimeval, then, &now);
+ else {
+ if (then)
+ *then = now;
+ dtime(&dtimeval, &shtimer, &now);
+ }
+
+ if (!delta == !shell)
+ printtime(&dtimeval, &ti, "shell");
#ifdef HAVE_GETRUSAGE
getrusage(RUSAGE_CHILDREN, &ti);
@@ -1921,8 +1942,20 @@ shelltime(void)
ti.ut = buf.tms_cutime;
ti.st = buf.tms_cstime;
#endif
- printtime(&dtimeval, &ti, "children");
-
+ if (kids) {
+ if (delta) {
+#ifdef HAVE_GETRUSAGE
+ dtime(&ti.ru_utime, &kids->ru_utime, &ti.ru_utime);
+ dtime(&ti.ru_stime, &kids->ru_stime, &ti.ru_stime);
+#else
+ ti.ut -= shell->ut;
+ ti.st -= shell->st;
+#endif
+ } else
+ *kids = ti;
+ }
+ if (!delta == !kids)
+ printtime(&dtimeval, &ti, "children");
}
/* see if jobs need printing */
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index d57085798..660602caf 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -399,13 +399,6 @@
>This is name2
>This is still name2
- (time cat) >&/dev/null
-0:`time' keyword (status only)
-
- TIMEFMT='%E %mE %uE %* %m%mm %u%uu'; time (:)
-0:`time' keyword with custom TIMEFMT
-*?[0-9]##.[0-9](#c2)s [0-9]##ms [0-9]##us %\* %m%mm %u%uu
-
if [[ -f foo && -d . && -n $ZTST_testdir ]]; then
true
else
diff --git a/Test/A08time.ztst b/Test/A08time.ztst
new file mode 100644
index 000000000..9fb1f3ebf
--- /dev/null
+++ b/Test/A08time.ztst
@@ -0,0 +1,64 @@
+#
+# This file contains tests for the "time" reserved word
+#
+
+%prep
+
+ unset TIMEFMT
+
+%test
+
+ (time cat) >&/dev/null
+0:`time' keyword (status only)
+
+ ( TIMEFMT='%E %mE %uE %* %m%mm %u%uu'; time (:) )
+0:`time' keyword with custom TIMEFMT
+*?[0-9]##.[0-9](#c2)s [0-9]##ms [0-9]##us %\* %m%mm %u%uu
+
+ time x=1
+0:`time' simple assignment
+*?shell*
+*?children*
+
+ time x=$(date)
+0:`time' assignment with external command
+*?shell*
+*?children*
+
+ x=0; time for ((i=1; i<=10000; ++i)); do ((x+=i)); done; echo $x
+0:`time' for-loop with arithmetic condition
+>50005000
+*?shell*
+*?children*
+
+ time echo $(x=0;for ((i=0; i<=100000; ++i)); do ((x+=i)); done; echo $x)
+0:`time' of a builtin with argument command substitution
+>5000050000
+*?shell*
+*?children*
+
+ time cat <(x=0;for ((i=0; i<=100000; ++i)); do ((x+=i)); done; echo $x)
+0:`time' of external command with process substitution
+>5000050000
+*?*user*system*cpu*total
+
+ print -u $ZTST_fd 'This test takes 2 seconds'
+ time builtin nonesuch $(sleep 2)
+1:`time' of nonexistent builtin with command substitution
+*?*: no such builtin: nonesuch
+*?shell*
+*?children*
+
+ time /no/such/commmand
+127:`time' of nonexistent external
+*?*no such file or directory: /no/such/commmand
+*?*user*system*cpu*total
+
+ ( setopt errexit; time false; print notreached )
+1:`time' of failed builtin with errexit
+*?shell*
+*?children*
+
+ ( setopt errexit; time =false; print notreached )
+1:`time' of failed external with errexit
+*?*user*system*cpu*total
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: PATCH: Re: Bug: time doesn't work on builtins
2024-09-14 2:10 ` PATCH: " Bart Schaefer
@ 2024-09-20 7:46 ` Oliver Kiddle
2024-09-22 0:59 ` Bart Schaefer
0 siblings, 1 reply; 15+ messages in thread
From: Oliver Kiddle @ 2024-09-20 7:46 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Zsh hackers list
On 13 Sep, Bart Schaefer wrote:
> + ( setopt errexit; time =false; print notreached )
> +1:`time' of failed external with errexit
> +*?*user*system*cpu*total
This test fails on Solaris because the external false returns -1 instead
of 1.
Two alternatives that come to mind would be test which returns false if
given no arguments and expr 0 which has the advantage of not existing as
a builtin so no need for the =. Both of those return 1 on Solaris for
failure.
Oliver
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: PATCH: Re: Bug: time doesn't work on builtins
2024-09-20 7:46 ` Oliver Kiddle
@ 2024-09-22 0:59 ` Bart Schaefer
0 siblings, 0 replies; 15+ messages in thread
From: Bart Schaefer @ 2024-09-22 0:59 UTC (permalink / raw)
To: Zsh hackers list
On Fri, Sep 20, 2024 at 12:46 AM Oliver Kiddle <opk@zsh.org> wrote:
>
> ... expr 0 which has the advantage of not existing as a builtin
I'll go with that.
diff --git a/Test/A08time.ztst b/Test/A08time.ztst
index 9fb1f3ebf..22a460f5e 100644
--- a/Test/A08time.ztst
+++ b/Test/A08time.ztst
@@ -59,6 +59,7 @@
*?shell*
*?children*
- ( setopt errexit; time =false; print notreached )
+ ( setopt errexit; time expr 0; print notreached )
1:`time' of failed external with errexit
+>0
*?*user*system*cpu*total
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2024-09-22 1:00 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-08-15 13:15 Bug: time doesn't work on builtins Mark J. Reed
2024-08-15 18:52 ` Bart Schaefer
2024-08-15 22:08 ` Mark J. Reed
2024-08-16 19:20 ` Bart Schaefer
2024-09-04 0:27 ` Bart Schaefer
2024-09-04 14:32 ` Jun. T
2024-09-05 17:29 ` Jun. T
2024-09-05 23:37 ` Bart Schaefer
2024-09-06 9:41 ` Jun T
2024-09-06 0:10 ` Bart Schaefer
2024-09-06 9:52 ` Jun T
2024-09-06 19:13 ` Bart Schaefer
2024-09-14 2:10 ` PATCH: " Bart Schaefer
2024-09-20 7:46 ` Oliver Kiddle
2024-09-22 0:59 ` Bart Schaefer
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).