zsh-users
 help / color / mirror / code / Atom feed
* time command with shell builtins
@ 2023-01-23 13:40 Dominik Vogt
  2023-01-23 13:42 ` Roman Perepelitsa
  0 siblings, 1 reply; 26+ messages in thread
From: Dominik Vogt @ 2023-01-23 13:40 UTC (permalink / raw)
  To: Zsh Users

The "time" command does not seem to work with builtin commands:

  $ which time
  time: shell reserved word

  # works
  $ time /bin/echo
  /bin/echo  0.00s user 0.00s system 61% cpu 0.002 total

  # doesn't work
  $ time echo
  # no output

Is it possible to get timing statistics of shell builtins too?
Timing "echo" isn't very interesting, but timing loop constructs
would be:

  $ time while foo; do bar done

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-23 13:40 time command with shell builtins Dominik Vogt
@ 2023-01-23 13:42 ` Roman Perepelitsa
  2023-01-23 14:17   ` zeurkous
  2023-01-23 14:28   ` Dominik Vogt
  0 siblings, 2 replies; 26+ messages in thread
From: Roman Perepelitsa @ 2023-01-23 13:42 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> Is it possible to get timing statistics of shell builtins too?
> Timing "echo" isn't very interesting, but timing loop constructs
> would be:
>
>   $ time while foo; do bar done

This:

    % time ( while foo; do bar; done )

Roman.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: Re: time command with shell builtins
  2023-01-23 13:42 ` Roman Perepelitsa
@ 2023-01-23 14:17   ` zeurkous
  2023-01-23 14:23     ` Roman Perepelitsa
  2023-01-23 14:28   ` Dominik Vogt
  1 sibling, 1 reply; 26+ messages in thread
From: zeurkous @ 2023-01-23 14:17 UTC (permalink / raw)
  To: Roman Perepelitsa, dominik.vogt, Zsh Users

On Mon, 23 Jan 2023 14:42:05 +0100, Roman Perepelitsa <roman.perepelitsa@gmail.com> wrote:
> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>>
>> Is it possible to get timing statistics of shell builtins too?
>> Timing "echo" isn't very interesting, but timing loop constructs
>> would be:
>>
>>   $ time while foo; do bar done
>
> This:
>
>     % time ( while foo; do bar; done )

Doesn't that imply a fork, which will also be timed...?

(Could lead to misleading results, in that case.)

         --zeurkous.

> Roman.

-- 
Friggin' Machines!


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: Re: time command with shell builtins
  2023-01-23 14:17   ` zeurkous
@ 2023-01-23 14:23     ` Roman Perepelitsa
  2023-01-23 14:40       ` zeurkous
  0 siblings, 1 reply; 26+ messages in thread
From: Roman Perepelitsa @ 2023-01-23 14:23 UTC (permalink / raw)
  To: zeurkous; +Cc: dominik.vogt, Zsh Users

On Mon, Jan 23, 2023 at 3:20 PM <zeurkous@blaatscaahp.org> wrote:
>
> On Mon, 23 Jan 2023 14:42:05 +0100, Roman Perepelitsa <roman.perepelitsa@gmail.com> wrote:
> > On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> >>
> >> Is it possible to get timing statistics of shell builtins too?
> >> Timing "echo" isn't very interesting, but timing loop constructs
> >> would be:
> >>
> >>   $ time while foo; do bar done
> >
> > This:
> >
> >     % time ( while foo; do bar; done )
>
> Doesn't that imply a fork, which will also be timed...?

Yes, it does.

> (Could lead to misleading results, in that case.)

Any tool that measures how long a piece of code takes to run gives you
an upper bound, so there is nothing new here. The standard solution is
to ensure that the code under benchmark takes a non-trivial amount of
time to execute. Here's the standard pattern I use:

    time ( repeat 1000 code-under-benchmark )

I tune the loop constant so that the benchmark takes around a second.

Roman.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-23 13:42 ` Roman Perepelitsa
  2023-01-23 14:17   ` zeurkous
@ 2023-01-23 14:28   ` Dominik Vogt
  2023-01-23 14:46     ` zeurkous
                       ` (2 more replies)
  1 sibling, 3 replies; 26+ messages in thread
From: Dominik Vogt @ 2023-01-23 14:28 UTC (permalink / raw)
  To: Zsh Users

On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> >
> > Is it possible to get timing statistics of shell builtins too?
> > Timing "echo" isn't very interesting, but timing loop constructs
> > would be:
> >
> >   $ time while foo; do bar done
>
> This:
>
>     % time ( while foo; do bar; done )

That wasn't really the question.  Of course I can time a loop by
writing a different command, or by putting it in a pipe or file.

  $ time echo foo | true

I just want to get timing statistics of loops either explicitly by
prepending "time" or implicitly with REPORTTIME.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: Re: Re: time command with shell builtins
  2023-01-23 14:23     ` Roman Perepelitsa
@ 2023-01-23 14:40       ` zeurkous
  0 siblings, 0 replies; 26+ messages in thread
From: zeurkous @ 2023-01-23 14:40 UTC (permalink / raw)
  To: Roman Perepelitsa; +Cc: dominik.vogt, Zsh Users

On Mon, 23 Jan 2023 15:23:57 +0100, Roman Perepelitsa <roman.perepelitsa@gmail.com> wrote:
> On Mon, Jan 23, 2023 at 3:20 PM <zeurkous@blaatscaahp.org> wrote:
>>
>> On Mon, 23 Jan 2023 14:42:05 +0100, Roman Perepelitsa <roman.perepelitsa@gmail.com> wrote:
>> > On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>> >>
>> >> Is it possible to get timing statistics of shell builtins too?
>> >> Timing "echo" isn't very interesting, but timing loop constructs
>> >> would be:
>> >>
>> >>   $ time while foo; do bar done
>> >
>> > This:
>> >
>> >     % time ( while foo; do bar; done )
>>
>> Doesn't that imply a fork, which will also be timed...?
>
> Yes, it does.
>
>> (Could lead to misleading results, in that case.)
>
> Any tool that measures how long a piece of code takes to run gives you
> an upper bound, so there is nothing new here.

A fork(2) can be particularly expensive, though, so there's an
opportunity to make things better here.

> The standard solution is
> to ensure that the code under benchmark takes a non-trivial amount of
> time to execute. Here's the standard pattern I use:
>
>     time ( repeat 1000 code-under-benchmark )
>
> I tune the loop constant so that the benchmark takes around a second.

Me's of course aware of such workarounds (they aren't solutions, though
me agrees that a complete solution would be far beyond our scope).

         --zeurkous.

> Roman.

-- 
Friggin' Machines!


^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: Re: time command with shell builtins
  2023-01-23 14:28   ` Dominik Vogt
@ 2023-01-23 14:46     ` zeurkous
  2023-01-23 16:31     ` Bart Schaefer
  2023-01-23 18:31     ` Mikael Magnusson
  2 siblings, 0 replies; 26+ messages in thread
From: zeurkous @ 2023-01-23 14:46 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Mon, 23 Jan 2023 15:28:33 +0100, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
>> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote=
> :
>> >
>> > Is it possible to get timing statistics of shell builtins too?
>> > Timing "echo" isn't very interesting, but timing loop constructs
>> > would be:
>> >
>> >   $ time while foo; do bar done
>>
>> This:
>>
>>     % time ( while foo; do bar; done )
>
> That wasn't really the question.  Of course I can time a loop by
> writing a different command, or by putting it in a pipe or file.
>
>   $ time echo foo | true
>
> I just want to get timing statistics of loops either explicitly by
> prepending "time" or implicitly with REPORTTIME.

That would be useful; me's bumped into this meself a couple of times
before (and applied workarounds like the one suggested by Roman).

> Ciao
>
> Dominik ^_^  ^_^
>
> =2D-
>
> Dominik Vogt

(As an aside, you might want to delimit your signature in plain text.)

         --zeurkous.

-- 
Friggin' Machines!


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-23 14:28   ` Dominik Vogt
  2023-01-23 14:46     ` zeurkous
@ 2023-01-23 16:31     ` Bart Schaefer
  2023-01-23 18:31     ` Mikael Magnusson
  2 siblings, 0 replies; 26+ messages in thread
From: Bart Schaefer @ 2023-01-23 16:31 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Mon, Jan 23, 2023 at 6:28 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> I just want to get timing statistics of loops either explicitly by
> prepending "time" or implicitly with REPORTTIME.

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.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-23 14:28   ` Dominik Vogt
  2023-01-23 14:46     ` zeurkous
  2023-01-23 16:31     ` Bart Schaefer
@ 2023-01-23 18:31     ` Mikael Magnusson
  2023-01-23 18:49       ` Dominik Vogt
  2 siblings, 1 reply; 26+ messages in thread
From: Mikael Magnusson @ 2023-01-23 18:31 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
>> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>> >
>> > Is it possible to get timing statistics of shell builtins too?
>> > Timing "echo" isn't very interesting, but timing loop constructs
>> > would be:
>> >
>> >   $ time while foo; do bar done
>>
>> This:
>>
>>     % time ( while foo; do bar; done )
>
> That wasn't really the question.  Of course I can time a loop by
> writing a different command, or by putting it in a pipe or file.
>
>   $ time echo foo | true
>
> I just want to get timing statistics of loops either explicitly by
> prepending "time" or implicitly with REPORTTIME.

As Bart already mentioned, the answer to your question is "no", but
you can avoid some downsides of the subshell (eg, if your loop has
side effects that are relevant to the rest of the script etc), by
using SECONDS:
% () { typeset -F4 SECONDS=0; sleep 1; () { typeset -F3 SECONDS=0;
sleep 0.43; echo $SECONDS }; sleep 1; echo $SECONDS }
0.431
2.4329
(the downside here is obviously that it doesn't split out cpu/system
time for you, only elapsed time).

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-23 18:31     ` Mikael Magnusson
@ 2023-01-23 18:49       ` Dominik Vogt
  2023-01-24  9:32         ` Mikael Magnusson
  0 siblings, 1 reply; 26+ messages in thread
From: Dominik Vogt @ 2023-01-23 18:49 UTC (permalink / raw)
  To: Zsh Users

On Mon, Jan 23, 2023 at 07:31:12PM +0100, Mikael Magnusson wrote:
> On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
> >> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> >> >
> >> > Is it possible to get timing statistics of shell builtins too?
> >> > Timing "echo" isn't very interesting, but timing loop constructs
> >> > would be:
> >> >
> >> >   $ time while foo; do bar done
> >>
> >> This:
> >>
> >>     % time ( while foo; do bar; done )
> >
> > That wasn't really the question.  Of course I can time a loop by
> > writing a different command, or by putting it in a pipe or file.
> >
> >   $ time echo foo | true
> >
> > I just want to get timing statistics of loops either explicitly by
> > prepending "time" or implicitly with REPORTTIME.
>
> As Bart already mentioned, the answer to your question is "no", but
> you can avoid some downsides of the subshell (eg, if your loop has
> side effects that are relevant to the rest of the script etc), by
> using SECONDS:
> % () { typeset -F4 SECONDS=0; sleep 1; () { typeset -F3 SECONDS=0;
> sleep 0.43; echo $SECONDS }; sleep 1; echo $SECONDS }
> 0.431
> 2.4329
> (the downside here is obviously that it doesn't split out cpu/system
> time for you, only elapsed time).

Well, the worst downside for me is that REPORTTIME does not work.
The use case is "oh, that command ran a long time, I'd really
like to know how long it took".  I see no solution for that if
re-running the command is no optiuon because it takes too long.

At the moment I'm writing some automation scripts that run for
hours and print their progress.  I might want to kill them after a
few hours and see how many seconds they ran and compare it to the
progress output.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-23 18:49       ` Dominik Vogt
@ 2023-01-24  9:32         ` Mikael Magnusson
  2023-01-24 10:48           ` Dominik Vogt
  0 siblings, 1 reply; 26+ messages in thread
From: Mikael Magnusson @ 2023-01-24  9:32 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> On Mon, Jan 23, 2023 at 07:31:12PM +0100, Mikael Magnusson wrote:
>> On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
>> > On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
>> >> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de>
>> >> wrote:
>> >> >
>> >> > Is it possible to get timing statistics of shell builtins too?
>> >> > Timing "echo" isn't very interesting, but timing loop constructs
>> >> > would be:
>> >> >
>> >> >   $ time while foo; do bar done
>> >>
>> >> This:
>> >>
>> >>     % time ( while foo; do bar; done )
>> >
>> > That wasn't really the question.  Of course I can time a loop by
>> > writing a different command, or by putting it in a pipe or file.
>> >
>> >   $ time echo foo | true
>> >
>> > I just want to get timing statistics of loops either explicitly by
>> > prepending "time" or implicitly with REPORTTIME.
>>
>> As Bart already mentioned, the answer to your question is "no", but
>> you can avoid some downsides of the subshell (eg, if your loop has
>> side effects that are relevant to the rest of the script etc), by
>> using SECONDS:
>> % () { typeset -F4 SECONDS=0; sleep 1; () { typeset -F3 SECONDS=0;
>> sleep 0.43; echo $SECONDS }; sleep 1; echo $SECONDS }
>> 0.431
>> 2.4329
>> (the downside here is obviously that it doesn't split out cpu/system
>> time for you, only elapsed time).
>
> Well, the worst downside for me is that REPORTTIME does not work.
> The use case is "oh, that command ran a long time, I'd really
> like to know how long it took".  I see no solution for that if
> re-running the command is no optiuon because it takes too long.
>
> At the moment I'm writing some automation scripts that run for
> hours and print their progress.  I might want to kill them after a
> few hours and see how many seconds they ran and compare it to the
> progress output.

What you can do at the moment is a) put the time in your prompt (and
reset the prompt on accept-line), b) save the current time in preexec
and compare it against the current time in precmd and print it out if
it exceeds some threshold(, c) or both).

a)
  zle -N accept-line _accept_line
  function _accept_line () {
    zle .reset-prompt
  }

b)
  zmodload zsh/datetime
  function precmd_showtime() {
    if ! (( ${+_zsh_time} )); then return 0; fi
    if (( $EPOCHSECONDS - $_zsh_time > 10 )); then
      printf "%i seconds elapsed\n" $(( EPOCHSECONDS - _zsh_time ))
    fi
    unset _zsh_time
  }

  function preexec_recordtime() {
    typeset -g _zsh_time
    _zsh_time=$EPOCHSECONDS
  }

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-24  9:32         ` Mikael Magnusson
@ 2023-01-24 10:48           ` Dominik Vogt
  2023-01-24 23:12             ` Dominik Vogt
  2023-01-24 23:32             ` Bart Schaefer
  0 siblings, 2 replies; 26+ messages in thread
From: Dominik Vogt @ 2023-01-24 10:48 UTC (permalink / raw)
  To: zsh-users

On Tue, Jan 24, 2023 at 10:32:35AM +0100, Mikael Magnusson wrote:
> On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > On Mon, Jan 23, 2023 at 07:31:12PM +0100, Mikael Magnusson wrote:
> >> On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> >> > On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
> >> >> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de>
> >> >> wrote:
> >> >> >
> >> >> > Is it possible to get timing statistics of shell builtins too?
> >> >> > Timing "echo" isn't very interesting, but timing loop constructs
> >> >> > would be:
> >> >> >
> >> >> >   $ time while foo; do bar done
> >> >>
> >> >> This:
> >> >>
> >> >>     % time ( while foo; do bar; done )
> >> >
> >> > That wasn't really the question.  Of course I can time a loop by
> >> > writing a different command, or by putting it in a pipe or file.
> >> >
> >> >   $ time echo foo | true
> >> >
> >> > I just want to get timing statistics of loops either explicitly by
> >> > prepending "time" or implicitly with REPORTTIME.
> >>
> >> As Bart already mentioned, the answer to your question is "no", but
> >> you can avoid some downsides of the subshell (eg, if your loop has
> >> side effects that are relevant to the rest of the script etc), by
> >> using SECONDS:
> >> % () { typeset -F4 SECONDS=0; sleep 1; () { typeset -F3 SECONDS=0;
> >> sleep 0.43; echo $SECONDS }; sleep 1; echo $SECONDS }
> >> 0.431
> >> 2.4329
> >> (the downside here is obviously that it doesn't split out cpu/system
> >> time for you, only elapsed time).
> >
> > Well, the worst downside for me is that REPORTTIME does not work.
> > The use case is "oh, that command ran a long time, I'd really
> > like to know how long it took".  I see no solution for that if
> > re-running the command is no optiuon because it takes too long.
> >
> > At the moment I'm writing some automation scripts that run for
> > hours and print their progress.  I might want to kill them after a
> > few hours and see how many seconds they ran and compare it to the
> > progress output.
>
> What you can do at the moment is a) put the time in your prompt (and
> reset the prompt on accept-line), b) save the current time in preexec
> and compare it against the current time in precmd and print it out if
> it exceeds some threshold(, c) or both).

Good idea.  This is what I use now:

-- snip --
autoload -Uz add-zsh-hook
zmodload zsh/datetime

function preexec_recordtime() {
	typeset -g _zsh_time
	_zsh_time="$EPOCHSECONDS"
}
add-zsh-hook preexec preexec_recordtime

function __prompt_get_displaytime () {
	if ! (( ${+_zsh_time} )); then return 0; fi
	if ! (( ${+REPORTTIME} )); then return 0; fi
	if (( $EPOCHSECONDS - $_zsh_time > $REPORTTIME )); then
		printf " $[EPOCHSECONDS - _zsh_time]s"
	fi
	unset _zsh_time
}

PS1="<...>$(__prompt_get_displaytime)<...>"
-- snip --

The measurement is good enough at the moment.  Putting the result
in the prompt has the advantage of not polluting the terminal.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-24 10:48           ` Dominik Vogt
@ 2023-01-24 23:12             ` Dominik Vogt
  2023-01-24 23:36               ` Bart Schaefer
  2023-01-24 23:32             ` Bart Schaefer
  1 sibling, 1 reply; 26+ messages in thread
From: Dominik Vogt @ 2023-01-24 23:12 UTC (permalink / raw)
  To: zsh-users

On Tue, Jan 24, 2023 at 11:48:39AM +0100, Dominik Vogt wrote:
> On Tue, Jan 24, 2023 at 10:32:35AM +0100, Mikael Magnusson wrote:
> > On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > > On Mon, Jan 23, 2023 at 07:31:12PM +0100, Mikael Magnusson wrote:
> > >> On 1/23/23, Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > >> > On Mon, Jan 23, 2023 at 02:42:05PM +0100, Roman Perepelitsa wrote:
> > >> >> On Mon, Jan 23, 2023 at 2:40 PM Dominik Vogt <dominik.vogt@gmx.de>
> > >> >> wrote:
> > >> >> >
> > >> >> > Is it possible to get timing statistics of shell builtins too?
> > >> >> > Timing "echo" isn't very interesting, but timing loop constructs
> > >> >> > would be:
> > >> >> >
> > >> >> >   $ time while foo; do bar done
> > >> >>
> > >> >> This:
> > >> >>
> > >> >>     % time ( while foo; do bar; done )
> > >> >
> > >> > That wasn't really the question.  Of course I can time a loop by
> > >> > writing a different command, or by putting it in a pipe or file.
> > >> >
> > >> >   $ time echo foo | true
> > >> >
> > >> > I just want to get timing statistics of loops either explicitly by
> > >> > prepending "time" or implicitly with REPORTTIME.
> > >>
> > >> As Bart already mentioned, the answer to your question is "no", but
> > >> you can avoid some downsides of the subshell (eg, if your loop has
> > >> side effects that are relevant to the rest of the script etc), by
> > >> using SECONDS:
> > >> % () { typeset -F4 SECONDS=0; sleep 1; () { typeset -F3 SECONDS=0;
> > >> sleep 0.43; echo $SECONDS }; sleep 1; echo $SECONDS }
> > >> 0.431
> > >> 2.4329
> > >> (the downside here is obviously that it doesn't split out cpu/system
> > >> time for you, only elapsed time).
> > >
> > > Well, the worst downside for me is that REPORTTIME does not work.
> > > The use case is "oh, that command ran a long time, I'd really
> > > like to know how long it took".  I see no solution for that if
> > > re-running the command is no optiuon because it takes too long.
> > >
> > > At the moment I'm writing some automation scripts that run for
> > > hours and print their progress.  I might want to kill them after a
> > > few hours and see how many seconds they ran and compare it to the
> > > progress output.
> >
> > What you can do at the moment is a) put the time in your prompt (and
> > reset the prompt on accept-line), b) save the current time in preexec
> > and compare it against the current time in precmd and print it out if
> > it exceeds some threshold(, c) or both).
>
> Good idea.  This is what I use now:
>
> -- snip --
> autoload -Uz add-zsh-hook
> zmodload zsh/datetime
>
> function preexec_recordtime() {
> 	typeset -g _zsh_time
> 	_zsh_time="$EPOCHSECONDS"
> }
> add-zsh-hook preexec preexec_recordtime
>
> function __prompt_get_displaytime () {
> 	if ! (( ${+_zsh_time} )); then return 0; fi
> 	if ! (( ${+REPORTTIME} )); then return 0; fi
> 	if (( $EPOCHSECONDS - $_zsh_time > $REPORTTIME )); then
> 		printf " $[EPOCHSECONDS - _zsh_time]s"
> 	fi
> 	unset _zsh_time
> }
>
> PS1="<...>$(__prompt_get_displaytime)<...>"
> -- snip --

Hm, any idea how to suppress reporting the run time of interactive
commands like vi, emacs, mutt?  Not very important, but it's a bit
confusing.  As far as I understand there's no reliable access to
which command is being executed in preexec.  I could replace such
commands by functions that erase _zsh_time when they start...

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-24 10:48           ` Dominik Vogt
  2023-01-24 23:12             ` Dominik Vogt
@ 2023-01-24 23:32             ` Bart Schaefer
  2023-01-25  7:43               ` Mikael Magnusson
  1 sibling, 1 reply; 26+ messages in thread
From: Bart Schaefer @ 2023-01-24 23:32 UTC (permalink / raw)
  To: dominik.vogt, zsh-users

On Tue, Jan 24, 2023 at 2:48 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> [...]  This is what I use now:
>
> -- snip --
> autoload -Uz add-zsh-hook
> zmodload zsh/datetime
>
> function preexec_recordtime() {
>         typeset -g _zsh_time
>         _zsh_time="$EPOCHSECONDS"
> }
> add-zsh-hook preexec preexec_recordtime

Unless you're already using psvar for something else, I would suggest

function preexec_recordtime() {
  if [[ -n $REPORTTIME ]]; then
    psvar[1]="$EPOCHSECONDS"
  else
    psvar[1]=''
  fi
}
precmd_reporttime () {
  if [[ -n $REPORTTIME && -n $psvar[1] ]]
  then
    psvar[1]=$(( $EPOCHSECONDS - $psvar[1] ))
    if (( $psvar[1] <= $REPORTTIME ))
    then
      psvar[1]=''
    else
      psvar[1]=" $psvar[1]s "
    fi
  fi
}
add-zsh-hook preexec preexec_recordtime
add-zsh-hook precmd precmd_reporttime

PS1="<...>%1v<...>"

Out of curiosity, why are you doing math on $EPOCHSECONDS rather than
just use $SECONDS?


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-24 23:12             ` Dominik Vogt
@ 2023-01-24 23:36               ` Bart Schaefer
       [not found]                 ` <Y9B7A8dWLiZNXKfW@localhost>
  0 siblings, 1 reply; 26+ messages in thread
From: Bart Schaefer @ 2023-01-24 23:36 UTC (permalink / raw)
  To: dominik.vogt, zsh-users

On Tue, Jan 24, 2023 at 3:14 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> As far as I understand there's no reliable access to
> which command is being executed in preexec.

There's reliable access to what the user typed and to what that
expands to after alias replacement.  What else would you be looking
for?

preexec
     Executed just after a command has been read and is about to be
     executed.  If the history mechanism is active (regardless of
     whether the line was discarded from the history buffer), the string
     that the user typed is passed as the first argument, otherwise it
     is an empty string.  The actual command that will be executed
     (including expanded aliases) is passed in two different forms: the
     second argument is a single-line, size-limited version of the
     command (with things like function bodies elided); the third
     argument contains the full text that is being executed.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-24 23:32             ` Bart Schaefer
@ 2023-01-25  7:43               ` Mikael Magnusson
  2023-01-25 12:58                 ` Dominik Vogt
  0 siblings, 1 reply; 26+ messages in thread
From: Mikael Magnusson @ 2023-01-25  7:43 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: dominik.vogt, zsh-users

On 1/25/23, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Tue, Jan 24, 2023 at 2:48 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>>
>> [...]  This is what I use now:
>>
>> -- snip --
>> autoload -Uz add-zsh-hook
>> zmodload zsh/datetime
>>
>> function preexec_recordtime() {
>>         typeset -g _zsh_time
>>         _zsh_time="$EPOCHSECONDS"
>> }
>> add-zsh-hook preexec preexec_recordtime
>
> Unless you're already using psvar for something else, I would suggest
>
> function preexec_recordtime() {
>   if [[ -n $REPORTTIME ]]; then
>     psvar[1]="$EPOCHSECONDS"
>   else
>     psvar[1]=''
>   fi
> }
> precmd_reporttime () {
>   if [[ -n $REPORTTIME && -n $psvar[1] ]]
>   then
>     psvar[1]=$(( $EPOCHSECONDS - $psvar[1] ))
>     if (( $psvar[1] <= $REPORTTIME ))
>     then
>       psvar[1]=''
>     else
>       psvar[1]=" $psvar[1]s "
>     fi
>   fi
> }
> add-zsh-hook preexec preexec_recordtime
> add-zsh-hook precmd precmd_reporttime
>
> PS1="<...>%1v<...>"
>
> Out of curiosity, why are you doing math on $EPOCHSECONDS rather than
> just use $SECONDS?

I also do this in precmd/exec, so I figured I may as well use the same
thing for all of it, also if I assign to SECONDS interactively maybe
weird things happen wrt float formatting etc,
  function pre{exec,cmd}_datechange() {
    local newdate
    newdate=$(strftime %x $EPOCHSECONDS)
    if [[ $_zsh_date != $newdate ]]; then
      printf "Date changed from %s to %s\n" $_zsh_date $newdate
      _zsh_date=$newdate
    fi
  }


-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-25  7:43               ` Mikael Magnusson
@ 2023-01-25 12:58                 ` Dominik Vogt
  0 siblings, 0 replies; 26+ messages in thread
From: Dominik Vogt @ 2023-01-25 12:58 UTC (permalink / raw)
  To: zsh-users

On Wed, Jan 25, 2023 at 08:43:50AM +0100, Mikael Magnusson wrote:
> On 1/25/23, Bart Schaefer <schaefer@brasslantern.com> wrote:
> > On Tue, Jan 24, 2023 at 2:48 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > Out of curiosity, why are you doing math on $EPOCHSECONDS rather than
> > just use $SECONDS?
>
> I also do this in precmd/exec

Actually, I just copied and modified the code from Mikael without
thinking about SECONDS vs. EPOCHSECONDS.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
       [not found]                 ` <Y9B7A8dWLiZNXKfW@localhost>
@ 2023-01-26 16:23                   ` Dominik Vogt
  2023-01-26 16:56                     ` Bart Schaefer
  2023-02-02 18:10                     ` Dominik Vogt
  0 siblings, 2 replies; 26+ messages in thread
From: Dominik Vogt @ 2023-01-26 16:23 UTC (permalink / raw)
  To: Zsh Users

On Wed, Jan 25, 2023 at 01:42:43AM +0100, Dominik Vogt wrote:
> On Tue, Jan 24, 2023 at 03:36:51PM -0800, Bart Schaefer wrote:
> > On Tue, Jan 24, 2023 at 3:14 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > >
> > > As far as I understand there's no reliable access to
> > > which command is being executed in preexec.
> >
> > There's reliable access to what the user typed and to what that
> > expands to after alias replacement.  What else would you be looking
> > for?
>
> Well, it's more or less "if whatever is being executed is
> interactive, I'm not interested in the time".  This is impossible
> to guess from the command name, except in some manually specified
> cases.  Maye a simple "if command is one of emacs, vi, vim, sleep,
> mutt, visudo, bash, zsh, sh" is good enough.  Or I just get used to
> having unnecessary information in the prompt.

Is there a more elegant way to chek if the command is in a
blacklist than this one?

-- snip --
_zsh_recordtime_skip_list=( emacs vi vim zsh bash sh viduso mutt sleep xemacs )
function preexec_recordtime() {
  if [[ -z "${1:|_zsh_recordtime_skip_list}" ]]; then
    psvar[2]=''
  ...
}
-- snip --

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-26 16:23                   ` Dominik Vogt
@ 2023-01-26 16:56                     ` Bart Schaefer
  2023-01-26 17:26                       ` Dominik Vogt
  2023-02-02 18:10                     ` Dominik Vogt
  1 sibling, 1 reply; 26+ messages in thread
From: Bart Schaefer @ 2023-01-26 16:56 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Thu, Jan 26, 2023 at 8:23 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> Is there a more elegant way to chek if the command is in a
> blacklist than this one?
>
>   if [[ -z "${1:|_zsh_recordtime_skip_list}" ]]; then

Alternate methods, judgement on elegance reserved:

if (( ${_zsh_recordtime_skip_list[(Ie)$1]} )); then

Or maintain _zsh_recordtime_skip_list as an associative array and

if (( ${+_zsh_recordtime_skip_list[$1]} )); then

In that case you could further use patterns as the keys of the array and do

if [[ -z ${_zsh_recordtime_skip_list[(k)$1]} ]]; then

or even use a zsh/db/gdbm ztie'd hash so that new items could be added
to the list and potentially shared among shells.

Note that ${+assocarray[(k)pat]} or [(I)pat] always returns 1 even
when no matching elements exist (that is, the result is empty string
rather than unset).  I'm not sure whether that should be considered a
bug, but it's not explicitly documented.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-26 16:56                     ` Bart Schaefer
@ 2023-01-26 17:26                       ` Dominik Vogt
  2023-01-26 17:40                         ` Bart Schaefer
  0 siblings, 1 reply; 26+ messages in thread
From: Dominik Vogt @ 2023-01-26 17:26 UTC (permalink / raw)
  To: Zsh Users

On Thu, Jan 26, 2023 at 08:56:34AM -0800, Bart Schaefer wrote:
> On Thu, Jan 26, 2023 at 8:23 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> >
> > Is there a more elegant way to chek if the command is in a
> > blacklist than this one?
> >
> >   if [[ -z "${1:|_zsh_recordtime_skip_list}" ]]; then

Thanks.

> Alternate methods, judgement on elegance reserved:
>
> if (( ${_zsh_recordtime_skip_list[(Ie)$1]} )); then
                                   ^^^^^^^^

What is the meaning of flags inside brackets?  I can't find
anything in the man page.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-26 17:26                       ` Dominik Vogt
@ 2023-01-26 17:40                         ` Bart Schaefer
  0 siblings, 0 replies; 26+ messages in thread
From: Bart Schaefer @ 2023-01-26 17:40 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Thu, Jan 26, 2023 at 9:26 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> What is the meaning of flags inside brackets?  I can't find
> anything in the man page.

Search for "Subscript Flags" in man zshall

       If the opening bracket, or the comma in a range, in any subscript  ex‐
       pression is directly followed by an opening parenthesis, the string up
       to the matching closing one is considered to be a list of flags, as in
       `name[(flags)exp]'.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-01-26 16:23                   ` Dominik Vogt
  2023-01-26 16:56                     ` Bart Schaefer
@ 2023-02-02 18:10                     ` Dominik Vogt
  2023-02-02 18:28                       ` Bart Schaefer
  1 sibling, 1 reply; 26+ messages in thread
From: Dominik Vogt @ 2023-02-02 18:10 UTC (permalink / raw)
  To: Zsh Users

On Thu, Jan 26, 2023 at 05:23:23PM +0100, Dominik Vogt wrote:
> On Wed, Jan 25, 2023 at 01:42:43AM +0100, Dominik Vogt wrote:
> > On Tue, Jan 24, 2023 at 03:36:51PM -0800, Bart Schaefer wrote:
> > > On Tue, Jan 24, 2023 at 3:14 PM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> > > >
> > > > As far as I understand there's no reliable access to
> > > > which command is being executed in preexec.
> > >
> > > There's reliable access to what the user typed and to what that
> > > expands to after alias replacement.  What else would you be looking
> > > for?
> >
> > Well, it's more or less "if whatever is being executed is
> > interactive, I'm not interested in the time".  This is impossible
> > to guess from the command name, except in some manually specified
> > cases.  Maye a simple "if command is one of emacs, vi, vim, sleep,
> > mutt, visudo, bash, zsh, sh" is good enough.  Or I just get used to
> > having unnecessary information in the prompt.
>
> Is there a more elegant way to chek if the command is in a
> blacklist than this one?
>
> -- snip --
> _zsh_recordtime_skip_list=( emacs vi vim zsh bash sh viduso mutt sleep xemacs )
> function preexec_recordtime() {
>   if [[ -z "${1:|_zsh_recordtime_skip_list}" ]]; then
>     psvar[2]=''
>   ...
> }
> -- snip --

Well, is there a way to detect inside preexec() wether a command
is handled by the shell or some external binary?  The usual
REPORTTIME mechanism works for external commands, so using
preexec/precmd to print run time for shell builtins is good enough.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-02-02 18:10                     ` Dominik Vogt
@ 2023-02-02 18:28                       ` Bart Schaefer
  2023-02-02 19:15                         ` Dominik Vogt
  0 siblings, 1 reply; 26+ messages in thread
From: Bart Schaefer @ 2023-02-02 18:28 UTC (permalink / raw)
  To: dominik.vogt, Zsh Users

On Thu, Feb 2, 2023 at 10:10 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> Well, is there a way to detect inside preexec() wether a command
> is handled by the shell or some external binary?

If you actually have the command name, you can use
  if (( $+commands[$thename] ))

That won't work (or will be complicated) if the buffer that's about to
be executed is a complex structure (braces, subshell parens,
while/for/repeat/if/case/select/etc.).


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-02-02 18:28                       ` Bart Schaefer
@ 2023-02-02 19:15                         ` Dominik Vogt
  2023-02-02 19:15                           ` Dominik Vogt
  2023-02-02 19:31                           ` Bart Schaefer
  0 siblings, 2 replies; 26+ messages in thread
From: Dominik Vogt @ 2023-02-02 19:15 UTC (permalink / raw)
  To: Zsh Users

On Thu, Feb 02, 2023 at 10:28:36AM -0800, Bart Schaefer wrote:
> On Thu, Feb 2, 2023 at 10:10 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
> >
> > Well, is there a way to detect inside preexec() wether a command
> > is handled by the shell or some external binary?
>
> If you actually have the command name, you can use
>   if (( $+commands[$thename] ))
>
> That won't work (or will be complicated) if the buffer that's about to
> be executed is a complex structure (braces, subshell parens,
> while/for/repeat/if/case/select/etc.).

Okay, that sounds good enough.  The new solution works without a
blacklist.  It may still print statistics with REPORTTIME and on
the prompt in some cases (e.g. "{ /usr/bin/foobar" }" etc.).  But
I can live with that.  Note that it now uses two slots in the
psvar array.  In some scenarios with ctrl-c using psvar[2] for the
raw time and the string to print resulted in error messages
because the variable's value was just ' s'.

-- snip --
autoload -Uz add-zsh-hook
zmodload zsh/datetime
function preexec_recordtime() {
	local CL=( $3 )
	psvar[3]=''
	if (( $+commands[${CL[1]}] )); then
		psvar[2]=''
	elif [[ -n $REPORTTIME ]]; then
		psvar[2]="$EPOCHSECONDS"
	else
		psvar[2]=''
	fi
}
precmd_reporttime () {
	if [[ -n "$REPORTTIME" && -n "$psvar[2]" ]]; then
		psvar[2]=$(( $EPOCHSECONDS - $psvar[2] ))
		if (( $psvar[2] <= $REPORTTIME )); then
			psvar[3]=''
		else
			psvar[3]=" $psvar[2]s"
		fi
	fi
}
add-zsh-hook preexec preexec_recordtime
add-zsh-hook precmd precmd_reporttime
PS1="...%3v..."
-- snip --

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-02-02 19:15                         ` Dominik Vogt
@ 2023-02-02 19:15                           ` Dominik Vogt
  2023-02-02 19:31                           ` Bart Schaefer
  1 sibling, 0 replies; 26+ messages in thread
From: Dominik Vogt @ 2023-02-02 19:15 UTC (permalink / raw)
  To: Zsh Users

P.S.:  It's not necessary to CC me on replies.  I'm subscribed to
the list.

Ciao

Dominik ^_^  ^_^

--

Dominik Vogt


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: time command with shell builtins
  2023-02-02 19:15                         ` Dominik Vogt
  2023-02-02 19:15                           ` Dominik Vogt
@ 2023-02-02 19:31                           ` Bart Schaefer
  1 sibling, 0 replies; 26+ messages in thread
From: Bart Schaefer @ 2023-02-02 19:31 UTC (permalink / raw)
  To: Zsh Users

On Thu, Feb 2, 2023 at 11:15 AM Dominik Vogt <dominik.vogt@gmx.de> wrote:
>
> In some scenarios with ctrl-c using psvar[2] for the
> raw time and the string to print resulted in error messages
> because the variable's value was just ' s'.

You could try using prompt conditionals to decide whether to prepend
the space/append the 's' so that $psvar[2] remains either a pure
number or nothing. Then you might not need psvar[3].

E.g. %2(v. %2vs..) in conjunction with

        if (( $+commands[${CL[1]}] )); then
                psvar[2]=()
and
                if (( $psvar[2] <= $REPORTTIME )); then
                        psvar[2]=()

(this presumes you're not using psvar[4] and subsequent for other values)


^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2023-02-02 19:31 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-23 13:40 time command with shell builtins Dominik Vogt
2023-01-23 13:42 ` Roman Perepelitsa
2023-01-23 14:17   ` zeurkous
2023-01-23 14:23     ` Roman Perepelitsa
2023-01-23 14:40       ` zeurkous
2023-01-23 14:28   ` Dominik Vogt
2023-01-23 14:46     ` zeurkous
2023-01-23 16:31     ` Bart Schaefer
2023-01-23 18:31     ` Mikael Magnusson
2023-01-23 18:49       ` Dominik Vogt
2023-01-24  9:32         ` Mikael Magnusson
2023-01-24 10:48           ` Dominik Vogt
2023-01-24 23:12             ` Dominik Vogt
2023-01-24 23:36               ` Bart Schaefer
     [not found]                 ` <Y9B7A8dWLiZNXKfW@localhost>
2023-01-26 16:23                   ` Dominik Vogt
2023-01-26 16:56                     ` Bart Schaefer
2023-01-26 17:26                       ` Dominik Vogt
2023-01-26 17:40                         ` Bart Schaefer
2023-02-02 18:10                     ` Dominik Vogt
2023-02-02 18:28                       ` Bart Schaefer
2023-02-02 19:15                         ` Dominik Vogt
2023-02-02 19:15                           ` Dominik Vogt
2023-02-02 19:31                           ` Bart Schaefer
2023-01-24 23:32             ` Bart Schaefer
2023-01-25  7:43               ` Mikael Magnusson
2023-01-25 12:58                 ` Dominik Vogt

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).