[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