C – sleep()ing Correctly …

Recently I needed to do a write to a file every 1/25th of a second. I realised that there is no guarantees on a non-real time system (Debian in this case) that the code is executed exactly once every 0.04 seconds. This is how I did it.

Enter clockGetTime() -> this has precision in the nanoseconds in the time.h library. Be sure to include real time flag -lrt in your project’s linker.

actualSleep is the amount of sleep actually needed when you factor in the amount of time used to execute other statements like the print statement.

In this way, you only sleep() the amount of time you really need to sleep(), and not more. If sleep() were a constant value 1/25 , the amount of delay in between sleeps would be more than expected (by a little, but it adds up). If you do the measurements you would see your results skewing in terms of real time. I noticed this in the first place as my statement was logging GPS UTC time to a file.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <limits.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <wait.h>
#include <ctype.h>
#include <time.h>
#include <string.h>
#include <sys/statvfs.h>

int getUsecElapsedFromStart(const struct timespec* tstart) {
    
    struct timespec tnow; 
    clock_gettime(CLOCK_MONOTONIC, &tnow); 
    
    return (int)((tnow.tv_sec*10.0e9 + tnow.tv_nsec) - (tstart->tv_sec*10.0e9 + tstart->tv_nsec)); 
}

int getTimeSpecDiff(struct timespec start, struct timespec end) {
    struct timespec temp; 
    
    if (((end.tv_nsec-start.tv_nsec))<0) {
        temp.tv_sec = end.tv_sec - start.tv_sec - 1;
        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
    }
    else {
        temp.tv_sec = end.tv_sec - start.tv_sec;
        temp.tv_nsec = end.tv_nsec - start.tv_nsec; 
    }
    // -- convert difference to micro
    return (int)(temp.tv_sec * 10.0e6 + temp.tv_nsec * 10.0e-3);
}
/*
 * 
 */
int main(int argc, char** argv) {

    long  actualSleep = 0;
    long usecToSleep = 0;
    long usecElapsed = 0; 
    struct timespec tstart;
    struct timespec tend;
    clock_gettime(CLOCK_MONOTONIC, &tstart);
    while (1) { 
         
        // -- start recording to file only when GStreamer process finishes loading 

        printf("Recoridng!\n");

        usecToSleep = 40000; //(1.0f/(25.0f)) * 1000000;
        
        clock_gettime(CLOCK_MONOTONIC, &tend);
        usecElapsed = getTimeSpecDiff(tstart,tend);
        //printf("usecElapsed %d\n", usecElapsed); 
        actualSleep = usecToSleep - usecElapsed;
        printf("ActualSleep %d\n", actualSleep);
        
        if (actualSleep > 0) {
            usleep(actualSleep); 
        }
        clock_gettime(CLOCK_MONOTONIC, &tstart);
    }
    
    return (EXIT_SUCCESS);
}


Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s