bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [minor] "precision" of $SECONDS


From: Stephane Chazelas
Subject: Re: [minor] "precision" of $SECONDS
Date: Thu, 25 Feb 2016 13:18:17 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

2016-02-25 03:03:41 -0800, Linda Walsh:

> Stephane Chazelas wrote:
> >$ time bash -c 'while ((SECONDS < 1)); do :; done'
> >bash -c 'while ((SECONDS < 1)); do :; done'  0.39s user 0.00s system 99% cpu 
> >0.387 total
> >
> >That can take in between 0 and 1 seconds. Or in other words,
> >$SECONDS becomes 1 in between 0 and 1 second after the shell was
> >started.
> The format you are using to display output of 'time' doesn't show
> real time -- only CPU seconds.

It does. The last number (0.387 total) is the elapsed time in
the output of zsh (my interactive shell)'s "time" keyword. CPU
times are 0.39s user and 0.00s system totalling to 0.39s

Because it's a busy loop, CPU time is close to 100% (99%) so
elapsed and CPU time are roughly the same.

> Try:
> 
> TIMEFORMAT='%2Rsec %2Uusr %2Ssys (%P%% cpu)'

That would be for bash. In anycase, bash does already include
the elapsed time in its default time output like zsh.

But the problem here is not about the time keyword, but about the
$SECONDS variable.

[...]
>    With linux, one can read /proc/uptime to 100th's of a sec, or
> use date to get more digits.  A middle of the road I used for
> trace timing was something like:
> 
> function __age { declare ns=$(date +"%N"); declare -i
> ms=${ns##+(0)}/1000000;
>  printf "%4d.%03d\n" $SECONDS $ms
> }
[...]

I'm not sure how that gives you the time since startup.
Currently, if bash is started at

00:00:00.7

After 0.4 seconds (at 00:00:01.1), $SECONDS will be 1 (the "bug"
I'm raising here). "ms" will be 100, so you'll print 1.100
instead of 0.600. And with my suggested fix, you'd print 0.100.

[...]
> As you can see, I wanted the times
> relative to the start of a given script, thus used SECONDS for that.

Note that all of zsh, ksh93 and mksh have builtin support to get
elapsed time information with subsecond granularity.

zsh has:
  - $SECONDS: time since shell start. floating point after
    typeset -F SECONDS
  - $EPOCHSECONDS (unix time) (in zsh/datetime module)
  - $EPOCHREALTIME: same as floating point
  - zselect builtin to sleep with 1/100s granularity
    (in zsh/zselect module)
  - the "time" keyword, without a command prints CPU and real
    time for the shell and waited-for ancestors (and other
    getrusage statistics you can add with TIMEFMT)

ksh93 has:
  - $SECONDS: time since shell start. floating point after
    typeset -F SECONDS
  - EPOCHREALTIME=$(printf '%(%s.%N)T' now) for unix time as a
    float (note that you need a locale where the decimal
    separator is a period to be able to use that in ksh
    arithmetic expressions, or you need to replace that "." with
    a "," above).
  - builtin sleep with sub-second granularity

mksh has:
  - $EPOCHREALTIME: unix time as floating point (note however
  that mksh doesn't support floating point arithmetic).
  - builtin "sleep" command with sub-second granularity.

Similar features would be welcome in bash.

bash has "times" that gives you CPU time with sub-second
granularity. It's got a "printf %T" a la ksh93, but no %N, its
$SECOND is only integer (and currently has that issue discussed
here).

It does supports a $TMOUT with sub-second granularity though.
You can use that to sleep for sub-second durations if you find a
blocking file to read from. On Linux, that could be:

TMOUT=0.4 read < /dev/fd/1 | :

but that still means forking processes.

-- 
Stephane



reply via email to

[Prev in Thread] Current Thread [Next in Thread]