1

I am trying to implement a timer for 5mins(300secs) in millisecons, but it is taking more than 5 minutes for sleep 0.001.

If I change if [ $t -ge 300000 ] to if [ $t -ge 30000 ], it is completing within 3 minutes.

df1, df2 holds the value of disk usage value at time t1 and t2 respectively.

t=0
x=0
df1
    while [ $x -lt 10000 ]

        sleep 0.001
        df2
        x=(( df1-df2 ))
        if [ $t -ge 300000 ]
        then
        t=0
        df1            
        else
        (( t++ ))
        fi
    done
dosomething

I want test $x for every 0.001secs. df1 and df2 should hold new values for every 300 secs. how can I achieve this?

Zaheer
  • 66
  • 2
  • 7
  • Zaheer: Not sure about your complete requirements, why not directly put sleep 300(for 5 mins) in spite of writing a new code for it? – RavinderSingh13 Feb 21 '17 at 00:03
  • 1
    Why not just `sleep 300`? If you really need to iterate at that quick of a pace (that is a very short sleep interval, and probably explains the drift in duration), you should base your comparison on reading current time and comparing with previous time, not sleeping a predetermined duration and incrementing a counter. You can use `date +%s` to obtain an incrementing counter in seconds based on the system clock for that purpose. – Fred Feb 21 '17 at 00:04
  • I need to monitor disk usage for every t(0.001) secs, if there is any huge difference($x) within 300000 secs, it should take some action. If I use sleep 300, script will be idle and won't monitor df during this time period. I want take quick action, hence 0.001. – Zaheer Feb 21 '17 at 02:55
  • Since your loop condition is `[ $x -lt 10000 ]`, it is hard to tell when the loop ends without knowing what tha actual `df1` and `df2` value is. The best I can advice is `sleep 0.001` may be not so accurate. – ymonad Feb 21 '17 at 03:17
  • 1
    It may be worth looking into creating a small C program to calculate with more precision. see the answer for this post http://stackoverflow.com/questions/10192903/time-in-milliseconds – JayRugMan Feb 21 '17 at 06:05
  • duplicate of https://stackoverflow.com/q/16548528 I know the question doesn't seem to be a duplicate, but the answers respond to this question directly. – sondra.kinsey Mar 24 '19 at 23:05
  • Bash is **really** the wrong language for this job. Lots of folks say that when it isn't true (or is only marginally/questionably so), but this is a case where it is; low latency is not a design parameter the runtime was designed for. – Charles Duffy Apr 30 '19 at 00:41

3 Answers3

4

date %N, will get time in nano seconds, maybe this help

start_at=$(date +%s,%N)
# do something that requires timing here
end_at=$(date +%s,%N)
_s1=$(echo $start_at | cut -d',' -f1)   # sec
_s2=$(echo $start_at | cut -d',' -f2)   # nano sec
_e1=$(echo $end_at | cut -d',' -f1)
_e2=$(echo $end_at | cut -d',' -f2)
time_cost=$(bc <<< "scale=3; $_e1 - $_s1 + ($_e2 -$_s2)/1000000000")
Roel Van de Paar
  • 2,111
  • 1
  • 24
  • 38
dormi330
  • 1,273
  • 11
  • 18
1

I'm pretty sure that a single sleep like yours does not take several minutes. While it can and, in general, will take longer than the milisecond which you requested, the real sleep time should still be well below one second, or, if the system is heavily loaded, at most a couple of seconds.

One flaw in your application is that you don't take into account how long one iteration of your loop takes. You can't know this in advance; you only know that it will be longer than a milisecond, but not how much longer. Hence, you should end the loop after a certain time has passed - i.e. storing the start time somewhere and comparing the current time to the start time.

A second problem is that you don't set anywhere the variables df1 and df2, but maybe you left out this detail because you didn't consider it relevant for your question.

user1934428
  • 19,864
  • 7
  • 42
  • 87
0

If you are looking for a countdown timer which displays milli-sec, you are looking for this.

This shows timer to hundredth of a second.

Change the logic as required.

    timer() {
    time="`date '+%H:%M:%S' -d "$1"`"
    if [ $# -gt 0 ] && [ "$1" = "$time" ]; then
        echo 
        IFS=:
        set -- $*
        secs=$(( ${1#0} * 3600 + ${2#0} * 60 + ${3#0} ))
        while [ $secs -ge 0 ]; do
                for msec in {99..0}; do
                printf "\rCountdown Timer: %02d:%02d:%02d:%02d" $((secs/3600)) $(( (secs/60)%60)) $((secs%60))  $((msec))
                sleep .01
                done
                secs=$(( $secs - 1 ))
        done
        echo
    fi
    echo 
    }

    Usage: # timer HH:MM:SS
    Where: HH  Time in Hours
           MM  Time in Mins
           SS  Time in Secs
    Example: 
           # timer 00:10:00 
           Sets a countdown timer for 10 mins while displaying hundredth of a second.
  • There's no guarantee at all that `sleep 0.01` will only sleep for the given duration -- it can sleep much longer, if that's when the OS schedules it, and that delay will add up over multiple/subsequent calls. – Charles Duffy Apr 30 '19 at 00:45
  • I agree. It has worked fine for me upto hundredth of a second. I have noticed lags for milli-seconds and more... – Wizard0f0z Apr 30 '19 at 01:02