8
\$\begingroup\$

Mac doesn't have the Unix clock_gettime so I am trying to create something that's really portable and only dependent on C.

So far I've come across this function:

static void current_utc_time(struct timespec *ts) {
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
    clock_serv_t cclock;
    mach_timespec_t mts;
    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);
    ts->tv_sec = mts.tv_sec;
    ts->tv_nsec = mts.tv_nsec;
#else
  clock_gettime(CLOCK_REALTIME, ts);
#endif
}

I would like to be able to get seconds and milliseconds for my purposes. This is what I am currently doing and would like some feedback on correctness:

struct timespec requestStart, requestEnd;
current_utc_time(&requestStart);
int i = 0;
while(i < 1000000000)
{
    ++i;
}
current_utc_time(&requestEnd);
printf("total: ms:  %lu\n", (requestStart.tv_nsec - requestEnd.tv_nsec) / (unsigned long)1000000);

This prints out: total: ms: 131

It seems to be correct but I just wanted to make sure before I proceeded. Am I doing my calculations correctly and how can I get the seconds as well as milliseconds?

\$\endgroup\$
8
\$\begingroup\$

A few notes:

  • clock_gettime() is not standard C, which means it's not guaranteed to be implemented on any system that supports C (including many Linux platforms, the few who implement it stuff it into time.h, but there are only a handful of standardized functions in that header). Relying on it for "portability" is not something you should do.
  • There is no standard C function that provides better than 1 second time resolution, but the POSIX function gettimeofday() provides microsecond resolution.

    You can use this function like this:

    struct timeval before = {};
    struct timeval after = {}; 
    struct timeval result = {};
    
    gettimeofday(&before, NULL);
    
    // Some code you want to time
    
    gettimeofday(&after, NULL);
    timersub(&after, &before, &result);
    
    printf("Time elapsed: %ld.%06ld\n", (size_t) result.tv_sec, (size_t) result.tv_usec);
    
  • The other option is to just use the clock() function in time.h which is part of the C standard, but as stated before the time resolution is not great.

  • Please don't use busy waiting (side note: that would be a place for a for loop, not a while loop). It's wasteful of CPU resources and could even be optimized out by the compiler. It would be much more efficient and easier to test your code with the sleep() function as then you know how many seconds long the process should take. If you want different resolutions for causing the current thread to be suspended from execution of your code, take a look at usleep() or nanosleep().

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.