Run unix command precisely at very short intervals WITHOUT accumulating time lag over time

The POSIX ualarm() function lets you schedule the kernel to periodically signal your process, with microsecond precision.

Whip up a simple program:

 #include<unistd.h>
 #include<signal.h>
 void tick(int sig){
     write(1, "\n", 1);
 }
 int main(){
     signal(SIGALRM, tick);
     ualarm(1000000, 1000000); //alarm in a second, and every second after that.
     for(;;)
         pause();
 }

Compile

 gcc -O2 tick.c -o tick

Then attach it to whatever you need done periodically like so:

./tick | while read x; do
    date "+%Y-%m-%d %H:%M:%S"
done | tee timelog-sleep.txt

Have you tried watch with the parameter --precise?

watch -n 1 --precise "date '+%Y-%m-%d %H:%M:%S.%N' >> ~/Desktop/timelog-watch.txt"

From the man page:

Normally, this interval is interpreted as the amout of time between the completion of one run of command and the beginning of the next run. However, with the -p or --precise option, you can make watch attempt to run command every interval seconds. Try it with ntptime and notice how the fractional seconds stays (nearly) the same, as opposed to normal mode where they continuously increase.

The parameter might not be available on your system, though.

You should also consider what should happen when the execution of your program needs more than one second. Should the next scheduled execution be skipped, or should it be run late?

Update: I ran the script for some time, and it didn't loose a single step:

2561 lines
start: 2012-07-17 09:46:34.938805108
end:   2012-07-17 10:29:14.938547796

Update: The --precise flag is a Debian addition, the patch is however rather simple: http://patch-tracker.debian.org/patch/series/view/procps/1:3.2.8-9squeeze1/watch_precision_time.patch


crontab has a resolution of 1 minute. If you're fine with lag time accumulating per that minute and then resetting on the next minute, this basic idea could work:

* * * * * for second in $(seq 0 59); do /path/to/script.sh & sleep 1s;done

Note that script.sh is also run in the background. This should help to minimize the lag that accumulates with each iteration of the loop.

Depending on how much lag sleep generates, there is however the chance of second 59 overlapping with second 0 of the next minute.

EDIT to toss in some results, in the same format as in the question:

$ cat timelog-cron
2012-07-16 20:51:01
...
2012-07-16 22:43:00

1 hour 52 minutes = 6720 seconds

$ wc -l timelog-cron
6720 timelog-cron

0 timing problems, 0% off. Any time accumulation resets every minute.

Tags:

Cron

Real Time