Re: How do get elapsed time in milliseconds in a shell script?

From: Ian Smith <smithi_at_nimnet.asn.au>
Date: Wed, 20 Jul 2022 15:35:42 UTC
On 19 July 2022 12:42:27 am AEST, Steve O'Hara-Smith <steve@sohara.org> wrote:
 > On Mon, 18 Jul 2022 14:01:01 +0100
 > freebsd-doc@fjl.co.uk wrote:
 > 
 > > I think what may be needed is a base utility to produce the
 > accurate 
 > > tick since the epoch or boot - it doesn't' matter for timeing.
 > Possibly 
 > > an extension to "uptime", which I assume must know.
 > 
 > 	There are some counters exposed via sysctl which might be useful,
 > kern.timecounter.tc.HPET.counter looks promising, the rest seem to
 > cycle
 > rather quickly. Of course portability is an issue with using these.

I must admit to being puzzled as to the efficacy of looking for millisecond precision for event timing or uptime on a non-realtime OS, when there are so many things that bend time going on.  Sure, the kernel has a pretty good idea of what's what and when's when, but out here in userland it's pretty fluid.

One's system may have a good lock to network time, at boot anyway, but once we're talking about something that can be called up in a script, anything past 100ms is slippery.

In concord about HPET being the likely best timecounter for this, if it's also on non-Intel systems? So I've had a bit of a play in the script below.  HPET wraps at ~300 seconds, so anything longer term has to be driven by interrupts off that.  We have kernel hackers for that ...

Anyway, I think running this should illustrate, if nothing else, the vagaries of userland timesharing especially in scripts.  This tested on 12.3-RELEASE, 2.6GHz i5 3320M, otherwise idle.

Also, csh's time command already reports millisecond system and user times, with decisecond elapsed time for process timing; it's in base; and can be invoked from sh by such as
$ csh -c 'time sh -c "${myscript}"'

cheers, Ian

* tabs may not survive pasting
<code>
#!/bin/sh
# kern.timecounter.tc.HPET.frequency: 14318180	period: 69.841ns
# kern.timecounter.tc.HPET.mask: 4294967295	repeat: 299.966s
period=69.841	# ns
[ "$1" ] && j="$1" || j=25
j=$((j+1))

for i in `jot - 1 $j`; do
	this=`sysctl -n kern.timecounter.tc.HPET.counter`
	if [ $i -eq 1 ]; then
		echo "this		prev		step	msec"
	else
		step=`echo "scale=12; $this - $prev" | bc`
		msec=`echo "scale=3; $step * $period / 10^6" | bc`
		echo "$this	$prev	$step	$msec"
	fi
	prev=$this
done
exit 0
</code>