Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monotonic Clock in C [duplicate]

I'm doing a algorithm project for my University. In the project I have to write some algorithms and evaluate their time using a monotonic clock.

I've already implemented everything using C but now I'm facing problems with the time measuring.

I'm currently using clock_gettime(CLOCK_MONOTONIC_RAW, ...) to get a clock. From the manpage of clock_gettime:

CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)
              Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjustments
              or  the  incremental  adjustments  performed by adjtime(3).  This clock does not count time that the system is sus‐
              pended.

The problem is the following: this clock sometimes returns a negative value when a measure like this is done:

struct timespec start,end;

clock_gettime(CLOCK_MONOTONIC_RAW, &start);
do{
    // do stuff in here
    clock_gettime(CLOCK_MONOTONIC_RAW, &end);
} while((double) (end.tv_nsec - start.tv_nsec) <= *a certain quantity needed for precision*);

In particular, sometimes end.tv_nsec - start.tv_nsec is negative and this causes the program to loop into this do-while.

As this should be a monotonic clock (which never goes back), things like having a negative elapsed time should not happen. But still, it seems to be happening.

Is this clock really monotonic? Am i doing something wrong? What can I try to figure out what is wrong?

I am really lost, I've tried lot of things in the past few days and none has worked out. In the case that more code is needed, see my repo: https://github.com/AlessandroZanatta/AlgorithmsProject/blob/dev/first_part/times.c

like image 776
Z. Alessandro Avatar asked Sep 05 '25 03:09

Z. Alessandro


1 Answers

Look at man timespec

There is written:

struct timespec {
                    time_t          tv_sec;
                    long            tv_nsec;
            };

The tv_sec member is again the elapsed time in whole seconds. The tv_nsec member represents the rest of the elapsed time in nanoseconds.

So tv_nsec is just the rest of the time not representable in whole seconds, so you need to subtract seconds and nanoseconds.

Subtracting timespecs

Also here https://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.5/html_node/Elapsed-Time.html is presented "the best way" to subtract two values of type struct timeval, as follows:

(For struct timespec just substitute timespec for timeval, tv_nsec for tv_usec and 1000000000 for 1000000.)

It is often necessary to subtract two values of type struct timeval or struct timespec. Here is the best way to do this. It works even on some peculiar operating systems where the tv_sec member has an unsigned type.

/* Subtract the `struct timeval' values X and Y,
   storing the result in RESULT.
   Return 1 if the difference is negative, otherwise 0.  */

int
timeval_subtract (result, x, y)
     struct timeval *result, *x, *y;
{
  /* Perform the carry for the later subtraction by updating y. */
  if (x->tv_usec < y->tv_usec) {
    int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
    y->tv_usec -= 1000000 * nsec;
    y->tv_sec += nsec;
  }
  if (x->tv_usec - y->tv_usec > 1000000) {
    int nsec = (x->tv_usec - y->tv_usec) / 1000000;
    y->tv_usec += 1000000 * nsec;
    y->tv_sec -= nsec;
  }

  /* Compute the time remaining to wait.
     tv_usec is certainly positive. */
  result->tv_sec = x->tv_sec - y->tv_sec;
  result->tv_usec = x->tv_usec - y->tv_usec;

  /* Return 1 if result is negative. */
  return x->tv_sec < y->tv_sec;
}
like image 183
Jan Avatar answered Sep 08 '25 20:09

Jan