LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-09-2007, 04:29 AM   #1
George2
Member
 
Registered: Oct 2003
Posts: 354

Rep: Reputation: 30
a bug of gettimeofday?


Hello everyone,


I found sometimes the time will not be increased, but will be decreased. It does not happen each time, but happens rarely.

Here is my program and output, are there anything wrong.

Output
--------------------
begin second and micro-second is: 1155819609 -- 653911
print begin time
2006-08-17 13:00:09.653
end second and micro-second is: 1155819609 -- 635116
print end time
2006-08-17 13:00:09.635
--------------------

Source code
--------------------

Code:
struct timeval begin, end
gettimeofday(&begin,NULL);
// operations
gettimeofday(&end,NULL);
timeDiff (&begin, &end);

void print_time (timeval tv)
{
struct tm* ptm;
char time_string[40];
long milliseconds;

/* Obtain the time of day, and convert it to a tm struct. */
ptm = localtime (&tv.tv_sec);
/* Format the date and time, down to a single second. */
strftime (time_string, sizeof (time_string), "%Y-%m-%d %H:%M:%S", ptm);
/* Compute milliseconds from microseconds. */
milliseconds = tv.tv_usec / 1000;
/* Print the formatted time, in seconds, followed by a decimal point
and the milliseconds. */
printf ("%s.%03ld\n", time_string, milliseconds);
}

long timeDiff(struct timeval* begin,struct timeval* end)
{
long milliSeconds=0;
milliSeconds = (long)(1000L*(end->tv_sec - begin->tv_sec) + (end->tv_usec - begin->tv_usec)/1000L);
if(milliSeconds <= 0)
{
printf ("begin second and micro-second is: %ld -- %ld \n", begin->tv_sec, begin->tv_usec);
printf ("print begin time \n");
print_time (*begin);
printf ("end second and micro-second is: %ld -- %ld \n", end->tv_sec, end->tv_usec);
printf ("print end time \n");
print_time (*end);
}
return milliSeconds;
}
--------------------

thanks in advance,
George
 
Old 02-09-2007, 10:27 PM   #2
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
I'm not certain what your problem is but...
  1. You are multiplying seconds by a 1000 AND dividing micro seconds by 1000 (I think that you only want to do one of these - the former see next point)
  2. dividing by 1000 and storing into an integer will lead to truncation and if the maximum value stored is 1000 will lead to zero.
  3. I'm not certain what data type time_t is on your system but is it possible that they have wrapped around the data type limit?
  4. You may want to consider the type conversion at an earlier point
 
Old 02-10-2007, 12:12 AM   #3
George2
Member
 
Registered: Oct 2003
Posts: 354

Original Poster
Rep: Reputation: 30
Quote:
Originally Posted by graemef
I'm not certain what your problem is but...
You are multiplying seconds by a 1000 AND dividing micro seconds by 1000 (I think that you only want to do one of these - the former see next point)
I have to output by million second, since I need to input the time data into some Excel Sheet, and it has the pre-defined template. Anyway, I could change the template. Do you have any suggestions, which metrics (million second or micro second or?) is appropriate?

Quote:
Originally Posted by graemef
dividing by 1000 and storing into an integer will lead to truncation and if the maximum value stored is 1000 will lead to zero.
I agree with this point in general senses. I have read my code again, and I am wondering which line of code do you mean I have issues in your above item?

Quote:
Originally Posted by graemef
I'm not certain what data type time_t is on your system but is it possible that they have wrapped around the data type limit?
I have read my code again. I find I am not using time_t type explicitly. Which line of code do you mean?


regards,
George
 
Old 02-10-2007, 01:08 AM   #4
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
Sorry much of what I said came about from not thinking properly. I've now had a cup of coffee and hopefully I will be more accurate.

The conversion you are doing is fine (for some reason I had milliseconds in my small brain despite writing microseconds).

The element tv_sec is of type time_t (according to my man page) and time_t according to the C standard is implementation-defined. So end->tv_sec - begin->tv_sec should result in a data type time_t. But again I don't think that it matters...

I can see an issue in the following scenario. If the difference is a month, then you will have 30*24*60*60 seconds = 2,592,000 seconds. Now multiply that by 1000 you will get 2,592,000,000 milliseconds. A signed long can hold 2,147,483,647, so the value will wrap around to give you a negative value. So you would get a negative value if you are measuring large time intervals.

What I would do is break the code into two parts, calculate the second different and the millisecond difference, and then construct it as a string. You just need to be careful with negative milliseconds. Something like:

Code:
secondsDiff = (long)(1000L*(end->tv_sec - begin->tv_sec);
millisecDiff = (end->tv_usec - begin->tv_usec)/1000L);
if (millisecDiff < 0)
{
   secondsDiff = secondsDiff -1;
   millisecDiff = millisecDiff + 1000;
}
sprintf(&diff,"%ld.%ld",secondsDiff,millisecDiff);
Can you give an example of the time when you get a negative difference value?
As an aside the C library does give a function to measure the difference, difftime (which returns a double)
 
Old 02-10-2007, 08:24 AM   #5
George2
Member
 
Registered: Oct 2003
Posts: 354

Original Poster
Rep: Reputation: 30
Thanks graemef,


Quote:
Originally Posted by graemef
Sorry much of what I said came about from not thinking properly. I've now had a cup of coffee and hopefully I will be more accurate.

The conversion you are doing is fine (for some reason I had milliseconds in my small brain despite writing microseconds).

The element tv_sec is of type time_t (according to my man page) and time_t according to the C standard is implementation-defined. So end->tv_sec - begin->tv_sec should result in a data type time_t. But again I don't think that it matters...

I can see an issue in the following scenario. If the difference is a month, then you will have 30*24*60*60 seconds = 2,592,000 seconds. Now multiply that by 1000 you will get 2,592,000,000 milliseconds. A signed long can hold 2,147,483,647, so the value will wrap around to give you a negative value. So you would get a negative value if you are measuring large time intervals.

What I would do is break the code into two parts, calculate the second different and the millisecond difference, and then construct it as a string. You just need to be careful with negative milliseconds. Something like:

Code:
secondsDiff = (long)(1000L*(end->tv_sec - begin->tv_sec);
millisecDiff = (end->tv_usec - begin->tv_usec)/1000L);
if (millisecDiff < 0)
{
   secondsDiff = secondsDiff -1;
   millisecDiff = millisecDiff + 1000;
}
sprintf(&diff,"%ld.%ld",secondsDiff,millisecDiff);
Can you give an example of the time when you get a negative difference value?
As an aside the C library does give a function to measure the difference, difftime (which returns a double)
I have several samples of the time I got, but it is in another Linux machine which I can not access now. I will collect 1-2 samples and send to you later. All the samples I could get have the same regulations/rules, which is,

1. the second field of begin and end variable are the same;
2. the micro-second field of begin and end variable are different, and the value of begin is greater than that of end -- this is why my timeDiff function will return negative value.

Your above code sample should work -- considering the 1 and 2 conditions I posted above. But I do not quite understnad why you do adjustment by,

secondsDiff = secondsDiff -1;
millisecDiff = millisecDiff + 1000;

And why this condition millisecDiff < 0 will happen? Since you have divide the microsecond by 1000 (millisecDiff = (end->tv_usec - begin->tv_usec)/1000L);
), a long should be enough to hold (without in-correct wrap to negative values), right?

Could you explain why you do that *hacking* code please?


regards,
George

Last edited by George2; 02-10-2007 at 08:28 AM.
 
Old 02-10-2007, 08:41 AM   #6
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
Quote:
Originally Posted by George2
Could you explain why you do that *hacking* code please?
Sure,

Assume the following input:
Start = 1.9
Finish = 3.3

seconds = 3-1 = 2
milliseconds = 300 - 900 = -600

with your code it was resolved with seconds * 1000 + milliseconds giving 2000 - 600 = 1400

by holding them separately the carry needs to be sorted out, hence the hack:

seconds = 2 - 1 = 1
milliseconds = -600 + 1000 = 400
 
Old 02-11-2007, 01:08 AM   #7
George2
Member
 
Registered: Oct 2003
Posts: 354

Original Poster
Rep: Reputation: 30
Thanks graemef,


Quote:
Originally Posted by graemef
Sure,

Assume the following input:
Start = 1.9
Finish = 3.3

seconds = 3-1 = 2
milliseconds = 300 - 900 = -600

with your code it was resolved with seconds * 1000 + milliseconds giving 2000 - 600 = 1400

by holding them separately the carry needs to be sorted out, hence the hack:

seconds = 2 - 1 = 1
milliseconds = -600 + 1000 = 400
I think the reason why my previous program will produce negative values is because the data type (long) I used will over-flow. I think your program should be able to solve this issue. But I can not see why it solves my issue. Could you help to have a description please?


regards,
George
 
Old 02-11-2007, 01:20 AM   #8
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
The maximum number that a long can hold is 2,147,483,647 (or 2 to the power 31 -1), an unsigned int can hold roughly double that (2 to the power 32 -1). Because you want to hold the time difference in milliseconds rather than seconds the number of seconds that a long can hold will be reduced by 1000. Hence a long will be able to hold a maximum of 2,147,483 seconds which is slightly under a month (2,147,483 / 60 / 60 / 24 = 24.855 days).

My solution was to have a long to hold the seconds and another long to hold the milliseconds. These are then combined into a string to represent the final value. So the maximum number of seconds is 2,147,483,647, which is about 68 years (2,147,483,647 / 60 / 60 / 24 = 24855 days), using an unsigned int will double that.

Last edited by graemef; 02-11-2007 at 01:21 AM.
 
Old 02-11-2007, 08:22 PM   #9
George2
Member
 
Registered: Oct 2003
Posts: 354

Original Poster
Rep: Reputation: 30
Thanks graemef,


Quote:
Originally Posted by graemef
The maximum number that a long can hold is 2,147,483,647 (or 2 to the power 31 -1), an unsigned int can hold roughly double that (2 to the power 32 -1). Because you want to hold the time difference in milliseconds rather than seconds the number of seconds that a long can hold will be reduced by 1000. Hence a long will be able to hold a maximum of 2,147,483 seconds which is slightly under a month (2,147,483 / 60 / 60 / 24 = 24.855 days).

My solution was to have a long to hold the seconds and another long to hold the milliseconds. These are then combined into a string to represent the final value. So the maximum number of seconds is 2,147,483,647, which is about 68 years (2,147,483,647 / 60 / 60 / 24 = 24855 days), using an unsigned int will double that.
Your reply makes senses. Do you think using double other than using long is better? Thanks.


regards,
George
 
Old 02-11-2007, 09:28 PM   #10
graemef
Senior Member
 
Registered: Nov 2005
Location: Hanoi
Distribution: Fedora 13, Ubuntu 10.04
Posts: 2,379

Rep: Reputation: 148Reputation: 148
The advantage of the double is that it will not overflow.
The disadvantage of the double is the possible loss of precision with the milliseconds.

I'd go for two unsigned longs and then convert to a string (assuming your output to excel can handle that format and that you are never going to be handling time differences over 100 odd years)
 
Old 02-13-2007, 06:34 AM   #11
jtshaw
Senior Member
 
Registered: Nov 2000
Location: Seattle, WA USA
Distribution: Ubuntu @ Home, RHEL @ Work
Posts: 3,892
Blog Entries: 1

Rep: Reputation: 67
Just a suggestion... on most unix boxes these days the timeval struct consists of two longs (32 bit int). Casting up to a long long
(64 bit int) before you do your math should give you plenty of room for any overflow.
 
Old 02-13-2007, 07:14 AM   #12
George2
Member
 
Registered: Oct 2003
Posts: 354

Original Poster
Rep: Reputation: 30
Thanks graemef, why double will lose precision? Could you show me an example please?


Quote:
Originally Posted by graemef
The advantage of the double is that it will not overflow.
The disadvantage of the double is the possible loss of precision with the milliseconds.

I'd go for two unsigned longs and then convert to a string (assuming your output to excel can handle that format and that you are never going to be handling time differences over 100 odd years)

regards,
George
 
Old 02-13-2007, 07:15 AM   #13
George2
Member
 
Registered: Oct 2003
Posts: 354

Original Poster
Rep: Reputation: 30
Good suggestion, thanks jtshaw!


Quote:
Originally Posted by jtshaw
Just a suggestion... on most unix boxes these days the timeval struct consists of two longs (32 bit int). Casting up to a long long
(64 bit int) before you do your math should give you plenty of room for any overflow.

regards,
George
 
Old 02-13-2007, 08:34 AM   #14
jtshaw
Senior Member
 
Registered: Nov 2000
Location: Seattle, WA USA
Distribution: Ubuntu @ Home, RHEL @ Work
Posts: 3,892
Blog Entries: 1

Rep: Reputation: 67
The way double precision numbers are stored it is impossible to perfectly represent all numbers.

The Wikipedia article on double precision numbers explains how we store them and why they can only be so accurate...

The IEEE Floading Point Standard article is a good read on the subject as well.

Last edited by jtshaw; 02-13-2007 at 08:35 AM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
BUG: soft lockup detected on CPU#0 and BUG: spinlock recursion on CPU#0 ... BloodyCat Linux - Hardware 3 11-07-2006 01:14 PM
Is this a bug???? CruelEssence Debian 1 06-17-2005 12:11 AM
Possible bug MBH LQ Suggestions & Feedback 3 01-21-2005 10:12 AM
Free86 bug or nVidia bug?? ProtoformX Linux - Software 2 05-12-2004 02:38 AM
time, gettimeofday h/w Programming 13 12-08-2003 05:17 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:10 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration