LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   how to calculate time difference in milliseconds in C/C++ (https://www.linuxquestions.org/questions/programming-9/how-to-calculate-time-difference-in-milliseconds-in-c-c-711096/)

waqasdaar 03-12-2009 11:52 AM

how to calculate time difference in milliseconds in C/C++
 
Hi

I want to calculate the time difference between two events in C++ in milliseconds. I am using difftime which returns me the time in seconds. but I want to calculate the time in milliseconds. Please help me.

Because problem is that time difference between two events is mostly is zero seconds. But I want more precision in milliseconds.

Thanks in Advanced,

Waqas Daar

wje_lq 03-12-2009 12:40 PM

You are using time() to get the time of day at the beginning of the interval and at its end, correct?

Use gettimeofday() for this instead. That puts the time of day in something of type struct timeval, which you will find defined by doing this at the command line:
Code:

man gettimeofday
Then do the obvious arithmetic.

graemef 03-12-2009 06:18 PM

For an OS agnostic approach you could use the Boost libraries, but there is nothing defined in the C++ standard to help you.

jiml8 03-13-2009 04:31 PM

Code:

#include <sys/time.h>

        struct timeval starttime,endtime,timediff;
        gettimeofday(&starttime,0x0);
(etc)
      gettimeofday(&endtime,0x0);
        timeval_subtract(&timediff,&endtime,&starttime);

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 = (y->tv_usec - x->tv_usec) / 1000000;
    y->tv_usec += 1000000 * nsec;
    y->tv_sec -= nsec;
  }


wje_lq 03-14-2009 10:16 AM

Um, jiml8? Your code seems incomplete. (I've tucked a copy of it at the end of this post.) As it stands, it's not clear what sort of int value is supposed to be returned by timeval_subtract(), and in any event your sample calling code at the beginning doesn't use that value at all. But the function also doesn't even use its parameter result in any way, which is puzzling.

I'd like to see jiml8's full code. In the meantime, here's another way to do it. I suspect the guts of the code (in red, ewwww) are simpler than jiml8's will end up being, which is always better if it's at least as fast and just as accurate. But, um, time will tell.

Here's my code, complete with sample calling code.
Code:

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

long long
timeval_diff(struct timeval *difference,
            struct timeval *end_time,
            struct timeval *start_time
            )
{
  struct timeval temp_diff;

  if(difference==NULL)
  {
    difference=&temp_diff;
  }

  difference->tv_sec =end_time->tv_sec -start_time->tv_sec ;
  difference->tv_usec=end_time->tv_usec-start_time->tv_usec;

  /* Using while instead of if below makes the code slightly more robust. */

  while(difference->tv_usec<0)
  {
    difference->tv_usec+=1000000;
    difference->tv_sec -=1;
  }

  return 1000000LL*difference->tv_sec+
                  difference->tv_usec;

} /* timeval_diff() */

int
main(void)
{
  struct timeval earlier;
  struct timeval later;
  struct timeval interval;

  /*
  * There are two ways to call timeval_diff.  The first way simply returns
  * the time difference as microseconds, a single integer.
  */

  if(gettimeofday(&earlier,NULL))
  {
    perror("first gettimeofday()");

    exit(1);
  }

  sleep(3);

  if(gettimeofday(&later,NULL))
  {
    perror("second gettimeofday()");

    exit(1);
  }

  printf("difference is %lld microseconds\n",
        timeval_diff(NULL,&later,&earlier)
        );

  /*
  * The second way to call timeval_diff returns the difference broken down as
  * seconds and microseconds.
  */

  if(gettimeofday(&earlier,NULL))
  {
    perror("third gettimeofday()");

    exit(1);
  }

  sleep(4);

  if(gettimeofday(&later,NULL))
  {
    perror("fourth gettimeofday()");

    exit(1);
  }

  timeval_diff(&interval,&later,&earlier);

  printf("difference is %ld seconds, %ld microseconds\n",
        interval.tv_sec,
        interval.tv_usec
        );

  /*
  * Well, actually there's a third way.  You can actually combine the first
  * two ways.
  */

  if(gettimeofday(&earlier,NULL))
  {
    perror("fifth gettimeofday()");

    exit(1);
  }

  sleep(5);

  if(gettimeofday(&later,NULL))
  {
    perror("sixth gettimeofday()");

    exit(1);
  }

  printf("difference is %lld microseconds",
        timeval_diff(&interval,&later,&earlier)
        );

  printf(" (%ld seconds, %ld microseconds)\n",
        interval.tv_sec,
        interval.tv_usec
        );

  return 0;

} /* main() */

Sample output:
Code:

difference is 3002435 microseconds
difference is 4 seconds, 841 microseconds
difference is 5002351 microseconds (5 seconds, 2351 microseconds)

You want the time in milliseconds? Divide the function result by 1000.

Here's jiml8's code so far:
Quote:

Originally Posted by jiml8 (Post 3474748)
Code:

#include <sys/time.h>

        struct timeval starttime,endtime,timediff;
        gettimeofday(&starttime,0x0);
(etc)
      gettimeofday(&endtime,0x0);
        timeval_subtract(&timediff,&endtime,&starttime);

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 = (y->tv_usec - x->tv_usec) / 1000000;
    y->tv_usec += 1000000 * nsec;
    y->tv_sec -= nsec;
  }



jiml8 03-15-2009 10:31 AM

Oops!

I lifted the code out of a working project of mine, and stopped copying at the wrong right brace.

Code:

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 = (y->tv_usec - x->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;
}


wje_lq 03-15-2009 01:17 PM

battle of the banjos
 
Comparison of the two functions:
  1. His modifies one of the inputs; mine leaves them alone.
  2. Both of them return a struct with the difference.
  3. Mine also returns the difference as a single integer, a potential convenience for some users.
  4. As the value of the function, his returns a warning if the "later" time is actually earlier. In some situations, that could be a huge plus.
  5. Which function is faster? I was skeered of those division operations in his function, but I ran some timing tests, and the results are pretty much a wash. In some runs his function was faster; in some, mine.

    Incidentally, running timing tests on these elapsed time measurement functions gave me a feeling that surely must be similar to finding myself being slowly lowered into a shielded box containing a geiger counter, a very weak source of radioactivity, a flask of hydrocyanic acid, and supporting materials from the hardware store up the street.

jiml8 03-16-2009 09:47 AM

I needed the input data only for this computation so didn't worry about changing it. If that is an issue, copying the data would only take a few clock cycles.

Biddle 03-17-2009 07:00 AM

The difference between wje_lq's code and jiml8's code (lets just call it jims code for the time being) is that jims is bullet proof where as wje_lq's is not. There are systems where tv_sec is unsigned and this is where the code would fail.
Quote:

I lifted the code out of a working project of mine
That is not the only place you lifted if from.

wje_lq 03-17-2009 10:12 AM

Quote:

Originally Posted by Biddle (Post 3478160)
The difference between wje_lq's code and jiml8's code (lets just call it jims code for the time being) is that jims is bullet proof where as wje_lq's is not. There are systems where tv_sec is unsigned and this is where the code would fail.

I'd prefer to call it jim's code, but maybe that's just me. :)

I'm guessing that you got the tv_sec information (which is useful, by the way, thank you) from the link that you provided:
Quote:

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.
But, see, making tv_sec unsigned will not invalidate my code. You'd have to make tv_usec unsigned to do that.

wje_lq 03-17-2009 10:16 AM

Quote:

Originally Posted by Biddle (Post 3478160)

I'm going to stick my neck out here. Some people might read this as a gentle assertion that jiml8 was claiming original authorship, even though Biddle might not have meant to say that he was claiming that. And I don't think he was. He was describing not its ultimate source, but the process during which he erred in copying the code to this thread.

Least-wise, that's my guess.

jiml8 03-17-2009 10:29 AM

Quote:

Originally Posted by Biddle (Post 3478160)
The difference between wje_lq's code and jiml8's code (lets just call it jims code for the time being) is that jims is bullet proof where as wje_lq's is not. There are systems where tv_sec is unsigned and this is where the code would fail.

That is not the only place you lifted if from.

You are probably right about that. I've used the code for awhile, and don't/didn't recall where it came from though from the style I knew I hadn't originally written it.

jiml8 03-17-2009 10:30 AM

Quote:

Originally Posted by wje_lq (Post 3478331)
I'm going to stick my neck out here. Some people might read this as a gentle assertion that jiml8 was claiming original authorship, even though Biddle might not have meant to say that he was claiming that. And I don't think he was. He was describing not its ultimate source, but the process during which he erred in copying the code to this thread.

Least-wise, that's my guess.

yup.

Biddle 03-17-2009 12:04 PM

Quote:

Originally Posted by wje_lq (Post 3478325)
I'd prefer to call it jim's code, but maybe that's just me. :)

I was just making people aware of the origin and why the code is as it is, maybe a little sarcastically.

Quote:

But, see, making tv_sec unsigned will not invalidate my code. You'd have to make tv_usec unsigned to do that.
This is not true, see the following line
Code:

difference->tv_sec =end_time->tv_sec -start_time->tv_sec ;
If end is earlier the start and tv_sec is unsigned then the result will be huge and incorrect, yet not in the jims code. Like I said it is bullet proof and coded that way for a reason.

wje_lq 03-17-2009 12:42 PM

Quote:

Originally Posted by Biddle (Post 3478411)
I was just making people aware of the origin and why the code is as it is, maybe a little sarcastically.

And I was making a gratuitous, completely unsportsmanlike reference to the lack of the apostrophe one would have expected in the possessive adjective "jim's". Sometimes I hate myself. ;)
Quote:

Originally Posted by Biddle (Post 3478411)
Quote:

Originally Posted by wje_lq (Post 3478325)
But, see, making tv_sec unsigned will not invalidate my code. You'd have to make tv_usec unsigned to do that.

This is not true, see the following line
Code:

difference->tv_sec =end_time->tv_sec -start_time->tv_sec ;
If end is earlier the start and tv_sec is unsigned then the result will be huge and incorrect, yet not in the jims code. Like I said it is bullet proof and coded that way for a reason.

I had not considered the situation where earlier was actually later. In that case, having an unsigned tv_sec yields a huge and incorrect result in both jiml8's code and mine.

To see that, let's revisit his code after redefining struct timeval to have an unsigned member tv_sec, shall we? And treat it as unsigned throughout.

Run this bash script:
Code:

#!/bin/bash

cat > 7.c <<EOD

#include <stdio.h>

typedef struct timeval
{
  unsigned int tv_sec;
  signed  int tv_usec;

} xxx;

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 = (y->tv_usec - x->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;
}

int
main(int    argc,
    char **argv
    )
{
  struct timeval difference;
  struct timeval earlier;
  struct timeval later;

  /* ... but we'll make "earlier" contain a value later than "later". */

  earlier.tv_sec=5;
  earlier.tv_usec=0;

  later.tv_sec=3;
  later.tv_usec=0;

  timeval_subtract(&difference,&later,&earlier);

  printf("%ud sec, %d usec\n",difference.tv_sec,difference.tv_usec);

  return 0;

} /* main() */
EOD
gcc -Wall 7.c -o 7
./7

On a system with four-byte ints, you'll get this output:
Code:

4294967294d sec, 0 usec
Edit: Note the typo using ud in the printf() statement. The d shouldn't be there, and shows up as extra noise in the output. I believe, though, that this does not invalidate my point.


All times are GMT -5. The time now is 06:45 PM.