0

I have to elapse the measuring time during multiple threads. I must get an output like this:

Starting Time | Thread Number

00000000000   |   1

00000000100   |   2

00000000200   |   3

Firstly, I used gettimeofday but I saw that there are some negative numbers then I made little research and learn that gettimeofday is not reliable to measure elapsed time. Then I decide to use clock_gettime(CLOCK_MONOTONIC).

However, there is a problem. When I use second to measure time, I cannot measure time precisely. When I use nanosecond, length of end.tv_nsec variable cannot exceed 9 digits (since it is a long variable). That means, when it has to move to the 10th digit, it still remains at 9 digits and actually the number gets smaller, causing the elapsed time to be negative.

That is my code:

long elapsedTime;
struct timespec end;
struct timespec start2;
//gettimeofday(&start2, NULL);
clock_gettime(CLOCK_MONOTONIC,&start2);

while(c <= totalCount)
{   
    if(strcmp(algorithm,"FCFS") == 0)
    {
        printf("In SErunner count=%d \n",count);
        if(count > 0)
        {
            printf("Count = %d \n",count);
        
            it = deQueue();
            c++;
            tid = it->tid;

            clock_gettime(CLOCK_MONOTONIC,&end);
            
            usleep( 1000*(it->value));
            elapsedTime = ( end.tv_sec - start2.tv_sec);
            
            printf("Process of thread %d finished with value %d\n",it->tid,it->value);
            fprintf(outputFile,"%ld %d %d\n",elapsedTime,it->value,it->tid+1);
        }
}

Unfortunately, timespec does not have microsecond variable. If you can help me I will be very happy.

F.Lazarescu
  • 1,385
  • 2
  • 16
  • 31
  • Read [clock_gettime(2)](https://man7.org/linux/man-pages/man2/clock_gettime.2.html) and [time(7)](https://man7.org/linux/man-pages/man7/time.7.html). You can get -in theory- nanoseconds, and a microsecond is 1000 nanoseconds – Basile Starynkevitch Nov 18 '20 at 13:31
  • Yes, but the nanosecond variable cannot exceed 9 digits. And while the loop iterates nd.tv_nsec gets smaller after some time. Like this: 2*10^9, 5*10^9, 8*10^9, 1*10^9, 4*10^9, 7*10^9.... It goes like this because in the definition of struct timespec, tv_nsec is defined as long. – Oğuz Kaan İmamoğlu Nov 18 '20 at 13:58

3 Answers3

4

Write a helper function that calculates the difference between two timespecs:

int64_t difftimespec_ns(const struct timespec after, const struct timespec before)
{
    return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)1000000000
         + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec);
}

If you want it in microseconds, just divide it by 1000, or use:

int64_t difftimespec_us(const struct timespec after, const struct timespec before)
{
    return ((int64_t)after.tv_sec - (int64_t)before.tv_sec) * (int64_t)1000000
         + ((int64_t)after.tv_nsec - (int64_t)before.tv_nsec) / 1000;
}

Remember to include <inttypes.h>, so that you can use conversion "%" PRIi64 to print integers of int64_t type:

    printf("%09" PRIi64 " | 5\n", difftimespec_ns(after, before));
Rachid K.
  • 4,490
  • 3
  • 11
  • 30
Glärbo
  • 156
  • 2
  • The functions do not work. If you compute 2s 10ns - 1s 30ns ==> The substration of the nanoseconds is negative. Hence the utility macros from my answer... – Rachid K. Nov 18 '20 at 16:11
  • @RachidK.: Yes, they do work. Verify them in practice if you disagree. The reason they work is that a full second is 1,000,000,000 nanoseconds. When the nanosecond difference is negative, the operation is equivalent to decreasing seconds by 1 and adding 1,000,000,000 to the (negative) nanoseconds. – Glärbo Nov 18 '20 at 17:06
  • Oh yes ! I missed that. I will up the answer :-) – Rachid K. Nov 18 '20 at 17:12
3

To calculate the delta (elapsed time), you need to make an substraction between two timeval or two timespec structures depending on the services you are using.

For timeval, there is a set of operations to manipulate struct timeval in <sys/time.h> (e.g. /usr/include/x86_64-linux-gnu/sys/time.h):

# define timersub(a, b, result)                        \
  do {                                                 \
    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;      \
    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;   \
    if ((result)->tv_usec < 0) {                       \
      --(result)->tv_sec;                              \
      (result)->tv_usec += 1000000;                    \
    }                                                  \
  } while (0)

For timespec, if you don't have them installed in your header files, copy something like the macro defined in this source code:

#define timespecsub(tsp, usp, vsp)                          \
    do {                                                    \
        (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;      \
        (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;   \
        if ((vsp)->tv_nsec < 0) {                           \
            (vsp)->tv_sec--;                                \
            (vsp)->tv_nsec += 1000000000L;                  \
        }                                                   \
    } while (0)
Rachid K.
  • 4,490
  • 3
  • 11
  • 30
0

You could convert the time to a double value using some code such as :

double
clocktime_BM (clockid_t clid)
{
  struct timespec ts = { 0, 0 };
  if (clock_gettime (clid, &ts))
    return NAN;
  return (double) ts.tv_sec + 1.0e-9 * ts.tv_nsec;
}    

The returned double value contains something in seconds. On most machines, double-s are IEEE 754 floating point numbers, and basic operations on them are fast (less than a µs each). Read the floating-point-gui.de for more about them. In 2020 x86-64 based laptops and servers have some HPET. Don't expect a microsecond precision on time measurements (since Linux runs many processes, and they might get scheduled at arbitrary times; read some good textbook about operating systems for explanations).

(the above code is from Bismon, funded thru CHARIOT; something similar appears in RefPerSys)

On Linux, be sure to read syscalls(2), clock_gettime(2), errno(3), time(7), vdso(7).

Consider studying the source code of the Linux kernel and/or of the GNU libc and/or of musl-libc. See LinuxFromScratch and OSDEV and kernelnewbies.

Be aware of The year 2038 problem on some 32 bits computers.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547