elapsed time in negative value - c

struct timeval start, end;
start.tv_usec = 0;
end.tv_usec = 0;
gettimeofday(&start, NULL);
functionA();
gettimeofday(&end, NULL);
long t = end.tv_usec - start.tv_usec;
printf("Total elapsed time %ld us \n", t);
I am calculating the total elapsed time like this but it sometimes shows a negative value.
What might be cause the problem?
Thanks in advance.

Keep in mind that there is both a seconds and micro-seconds field of that structure. Therefore if you are simply subtracting the micro-seconds field, you could have a time that is later in seconds, but the microseconds field is less. For instance, and end-time of 5 seconds, 100 microseconds will have a negative result compared to 4 seconds and 5000 microseconds with the subtraction method you're using. In order to get the proper result, you have to take into account both the seconds and micro-seconds fields of the structure. This can be done doing the following:
long seconds = end.tv_sec - start.tv_sec;
long micro_seconds = end.tv_usec - start.tv_usec;
if (micro_seconds < 0)
{
seconds -= 1;
}
long total_micro_seconds = (seconds * 1000000) + abs(micro_seconds);

maybe something along the lines of:
long t = (end.tv_sec*1e6 + end.tv_usec) - (start.tv_sec*1e6 + start.tv_usec);

From The GNU C Library:
Data Type: struct timeval
The struct timeval structure represents an elapsed time. It is declared in sys/time.h and has the following members:
long int tv_sec
This represents the number of whole seconds of elapsed time.
long int tv_usec
This is the rest of the elapsed time (a fraction of a second), represented as the number of microseconds. It is always less than one million.
The only thing you're subtracting is the microseconds in tv_usec above the full seconds value in tv_sec. You need to work with both values in order to find the exact microsecond difference between the two times.

Related

gettimeofday to calculate elapsed when day changes

The typical example that I see when trying to do measure elapsed time goes something like this:
#include <sys/time.h>
#include <stdio.h>
int main() {
struct timeval start, end;
gettimeofday(&start, NULL);
//Do some operation
gettimeofday(&end, NULL);
unsigned long long end_time = (end.tv_sec * 1000000 + end.tv_usec);
unsigned long long start_time = (start.tv_sec * 1000000 + start.tv_usec);
printf("Time taken : %ld micro seconds\n", end_time - start_time);
return 0;
}
This is great when it's somewhere mid day, but if someone were to run some tests late at night this wouldn't work. My approach is something like this to address it:
#include <sys/time.h>
#include <stdio.h>
int main() {
struct timeval start, end;
gettimeofday(&start, NULL);
//Do some operation
gettimeofday(&end, NULL);
unsigned long long end_time = (end.tv_sec * 1000000 + end.tv_usec);
unsigned long long start_time = (start.tv_sec * 1000000 + start.tv_usec);
unsigned long long elapsed_time = 0;
if ( end_time < start_time )
//Made up some constant that defines 86,400,000,000 microseconds in a day
elapsed_time = end_time + (NUM_OF_USEC_IN_A_DAY - start_time);
else
elapsed_time = end_time - start_time;
printf("Time taken : %ld micro seconds\n", elapsed_time);
return 0;
}
Is there a better way of anticipating day change using gettimeofday?
Despite the name, gettimeofday results do not roll over daily. The gettimeofday seconds count, just like the time seconds count, started at zero on the first day of 1970 (specifically 1970-01-01 00:00:00 +00:00) and has been incrementing steadily ever since. On a system with 32-bit time_t, it will roll over sometime in 2038; people are working right now to phase out the use of 32-bit time_t for this exact reason and we expect to be done well before 2038.
gettimeofday results are also independent of time zone and not affected by daylight savings shifts. They can go backward when the computer's clock is reset. If you don't want to worry about that, you can use clock_gettime(CLOCK_MONOTONIC) jnstead.
Why would you want to handle the case where end.tv_sec is less than start.tv_sec? Are you trying to account for ntpd changes? If so, and especially if you want to record only elapsed time, then use clock_gettime instead of gettimeofday as the former is immune to wall clock changes.
but if someone were to run some tests late at night this wouldn't work
That's an incorrect statement because gettimeofday is not relative to the start of each day but rather relative to a fixed point in time. From the gettimeofday manual:
gives the number of seconds and microseconds since the Epoch
So the first example will work as long as there are no jumps in time (e.g. due to manual time setting or NTP). Again from the manual:
The time returned by gettimeofday() is affected by discontinuous
jumps in the system time (e.g., if the system administrator manually
changes the system time). If you need a monotonically increasing
clock, see clock_gettime(2).
Is there a better way of anticipating day change using gettimeofday?
In addition to other problems identified in various answers, the following is also subject integer overflow when time_t is only 32-bit. Instead scale by a (unsigned) long long constant.
// unsigned long long end_time = (end.tv_sec * 1000000 + end.tv_usec);
long long end_time = (end.tv_sec * 1000000ll + end.tv_usec);
// Use correct specifier, not %ld for unsigned long long
// printf("Time taken : %ld micro seconds\n", elapsed_time);
long long elapsed_time = end_time - start_time;
printf("Time taken : %lld micro seconds\n", elapsed_time);
Tip: enables all compiler warnings.

Formatted elapsed time in C

I'm writing a function that, among other things, must print out an elapsed time counter. It receives by reference a start time _start, and compares it to current, both typed as time_t. I want to use strftime() to print out the observed time delta in ISO 8601 format. Here's what I attempted to do:
// Negative start time implies program has not begun
if (*_start > 0) {
time_t elapsed = current - *_start;
strftime(time_str, sizeof(time_str) - 1, "%T", localtime(&elapsed));
printf("%s\n", time_str);
}
And here is the output I get immediately after running the program
01:00:00
01:00:00
01:00:01
01:00:01
01:00:01
The seconds work fine, if I let it run longer they get incremented as expected, so do the minutes, however the hour starts as 01 as opposed to 00. Why is this happening? How can I get the hours to start zeroed, like the minutes?
time_t typically (see edit) stores absolute timestamps (the number of seconds since midnight UTC, January 1, 1970). By calculating current - *_start, you're getting elapsed time in seconds (as desired), but by then passing that to localtime and strftime, you're telling the computer to take the time elapsed since the start of your program and treat it as the time elapsed since midnight UTC 1-1-1970.
I'm guessing that happens to be 01:00:00 in your system's local time zone.
I'm not aware of a C99 function to print elapsed time, but it's not hard to write one yourself.
void format_elapsed_time(char *time_str, int total_seconds_elapsed) {
int hours_elapsed = total_seconds_elapsed / 3600;
int minutes_elapsed = (total_seconds_elapsed % 3600) / 60;
int seconds_elapsed = total_seconds_elapsed % 60;
sprintf(time_str, "%02i:%02i:%02i", hours_elapsed, minutes_elapsed, seconds_elapsed);
}
Edit: As #chux points out, time_t doesn't have to store timestamps as seconds since 1-1-1970. See this answer for details.
To portably find the number of elapsed seconds between 2 time_t, use difftime() as subtracting 2 time_t values is not specified in C to be a difference in seconds.
double difftime(time_t time1, time_t time0); C11dr ยง7.26.2.2
The difftime function returns the difference expressed in seconds as a double.
double elapsed_seconds = difftime(current, *_start);
printf("elapsed_seconds: %f\n", elapsed_seconds);
If you want to use this method, you should be aware that time() returns UTC. If you then subtract that from your local time (as returned by localtime()), time zones will have an effect on the result (it's likely your particular time zone is removed from UTC by one hour).
Consider the following complete program, similar to your snippet:
#include <stdio.h>
#include <time.h>
#include <unistd.h>
int main(void) {
time_t start = time(0);
char time_str[100];
for (int i = 5; i > 0; i--) {
sleep (1);
time_t elapsed = time(0) - start;
strftime(time_str, sizeof(time_str) - 1, "%T", localtime(&elapsed));
printf("%s\n", time_str);
}
return 0;
}
Also consider that my particular time zone is removed from UTC by eight hours:
pax> date ; date -u
Thursday 30 March 10:25:57 AWST 2017
Thursday 30 March 02:25:57 UTC 2017
When I run it, I see:
08:00:01
08:00:02
08:00:03
08:00:04
08:00:05
You can see there that the eight-hour time difference from UTC affects the value. The fix for that is actually quite simple: don't use local time at all. If you replace the localtime() call with gmtime(), you get the output you expect:
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05
I realize this question already has an answer, but I thought I might shift the focus a little and expand on the accepted answer. Since the OP specified that they are dealing with elapsed times, one can avoid dealing with absolute timestamps altogether using the clock() function.
clock_t start = clock();
.
.
clock_t end = clock();
double elapsed = (end - start) / (double)CLOCKS_PER_SEC;
then you can call the notionally revised format_elapsed_time() function, like so:
void format_elapsed_time(char *time_str, double elapsed) {
int h, m, s, ms;
h = m = s = ms = 0;
ms = elapsed * 1000; // promote the fractional part to milliseconds
h = ms / 3600000;
ms -= (h * 3600000);
m = ms / 60000;
ms -= (m * 60000);
s = ms / 1000;
ms -= (s * 1000);
sprintf(time_str, "%02i:%02i:%02i.%03i", h, m, s, ms);
}

C - Timing my program in seconds with microsecond precision on

I'm trying to find out the user time (on a Linux machine) of C program I've written. Currently I'm calling gettimeofday() once at the beginning of my code and once at the end. I'm using the timeval struct and difftime(stop.tv_sec,start.tv_sec) to get the number of seconds elapsed. This returns whole seconds, like "1.000000". However, my project requires that my program be timed in seconds with microsecond precision, for example "1.234567". How can I find this value? I know gettimeofday() also records microseconds in .tv_usec, but I'm not sure how to use this value and format it correctly.
Use the timersub function. It takes three arguments: the first is the initial time, the second the final one, and the third is the result (the diference). All of the three arguments are pointers to timeval struct.
Try putting the initial time into storage then subtract that from the final time when you are done.
storedValue = timer.tv_sec + 0.000001 * timer.tv_usec
timer.tv_sec + 0.000001 * timer.tv_usec - storedValue
If you want microseconds:
long long usec;
usec = tv.tv_sec;
usec *= 1000000;
usec += tv.tv_usec;
If you want fractional seconds [floating point]:
double asec;
asec = tv.tv_usec;
asec /= 1e6;
asec += tv.tv_sec;
Here are some complete functions:
// tvsec -- get current time in absolute microseconds
long long
tvsec(void)
{
struct timeval tv;
long long usec;
gettimeofday(&tv,NULL);
usec = tv.tv_sec;
usec *= 1000000;
usec += tv.tv_usec;
return usec;
}
// tvsecf -- get current time in fractional seconds
double
tvsecf(void)
{
struct timeval tv;
double asec;
gettimeofday(&tv,NULL);
asec = tv.tv_usec;
asec /= 1e6;
asec += tv.tv_sec;
return asec;
}
Note: If you want even higher accuracy (e.g. nanoseconds), you can use clock_gettime(CLOCK_REALTIME,...) and apply similar conversions

High-resolutin (100 nsec) timing on Linux/C

I use Raspian on the Raspberry B+ to get 1700 nsec (+- 10%) pulses on a GPIO output. Thus, I need a high-resolution wallclock timer. There are several references to clock_gettime for high-resolution timing (e.g. 1, 2). However, I get 1. only a microsecond resolution and 2. not sufficient minimum time with this short code:
int start_time, current_time, elapsed_time;
struct timespec resolution;
clock_gettime(CLOCK_MONOTONIC, &resolution);
start_time = Resolution.tv_nsec;
clock_gettime(CLOCK_MONOTONIC, &resolution);
current_time = resolution.tv_nsec;
elapsed_time = current_time - start_time;
if(elapsed_time < 0) {
elapsed_time = elapsed_time + 1000000000; //in case clock_gettime wraps around
}
printf("%i\n", elapsed_time);
The result is 3000 (nanoseconds), i.e. even this shortest possible piece of code takes too much time. If I add some time-consuming code, the next greater result is 4000.
How I can I get a wallclock timer that will result in at least 100 nsec resolution and a smallest possible time of less than 1700 nsec? That the Raspberry Pi can do faster (100 nsec pulses with WiringPi) shows the GPIO Benchmark. I am aware that additional electronics (monoflop) can help me but I hope to solve the problem in a simpler way. Thank you.

C find elapsed time in C Linux

I have to calculate the time taken by a function to complete.
This function is called in a loop and I want to find out the total time.
Usually the time is very less in either nano or micro seconds.
To find out the elapsed time I used functions gettimeofday() using struct timeval and clock_gettime() using struct timespec.
Problem is time return by timeval in seconds is correct but in micro seconds wrong.
Similarly the time returned by timespec in nano seconds is wrong.
Wrong in the sense they do not tally with the time returned in seconds.
For clock_gettime() I tried both CLOCK_PROCESS_CPUTIME_ID and CLOCK_MONOTONIC.
Using clock() also does not help.
Code snippet:
struct timeval funcTimestart_timeval, funcTimeEnd_timeval;
struct timespec funcTimeStart_timespec, funcTimeEnd_timespec;
unsigned long elapsed_nanos = 0;
unsigned long elapsed_seconds = 0;
unsigned long diffInNanos = 0;
unsigned long Func_elapsed_nanos = 0;
unsigned long Func_elapsed_seconds = 0;
while(...)
{
gettimeofday(&funcTimestart_timeval, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &funcTimeStart_timespec);
...
demo_func();
...
gettimeofday(&funcTimeEnd_timeval, NULL);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &funcTimeEnd_timespec);
elapsed_seconds = funcTimeEnd_timeval.tv_sec - funcTimestart_timeval.tv_sec;
Func_elapsed_seconds+= elapsed_seconds;
elapsed_nanos = funcTimeEnd_timespec.tv_nsec - funcTimeStart_timespec.tv_nsec;
Func_elapsed_nanos+ = elapsed_nanos;
}
printf("Total time taken by demo_func() is %lu seconds( %lu nanoseconds )\n", Func_elapsed_seconds, Func_elapsed_nanos );
Printf output:
Total time taken by demo_func() is 60 seconds( 76806787 nanoseconds )
See that the time in seconds and nanoseconds do not match.
How to resolve this issue or any other appropriate method to find elapsed time?
Did you read the documentation of time(7) and clock_gettime(2)? Please read it twice.
The struct timespec is not supposed to express twice the same time. The field tv_sec gives the second part ts, and the field tv_nsec gives the nanosecond part tn to express the time t = ts + 10-9 tn
I would suggest to convert that to a floating point, e.g.
printf ("total time %g\n",
(double)Func_elapsed_seconds + 1.0e-9*Func_elapsed_nanos);
Using floating point is simpler and generally the precision is enough for most needs. Otherwise, when you add or substract struct timespec you need to handle the case when the added/substracted tv_nsec field sum/difference is negative or more than 1000000000....
The problem is you are printing/comparing wrong values.
76,806,787 nanoseconds is equal to ~76 milliseconds, you cannot compare it with 60 seconds.
You are ignoring the time in seconds stored in funcTimeEnd_timespec.tv_sec.
You should also print funcTimeEnd_timespec.tv_sec - funcTimeStart_timespec.tv_sec, and as #Basile Starynkevitch suggested, add with it the nanoseconds part after multiplying it with 10e-9. Then you can compare time elapsed shown by both functions.
I am replying to the previous answers as answer as I wanted to paste code snippets.
Question is to find out elapsed time whether
first I should subtract the corresponding times with each other and then add
(end.tv_sec - start.tv_sec) + 1.0e-9*(end.tv_nsec - start.tv_nsec)
or
first add the times and then compute the difference
(end.tv_sec + 1.0e-9*end.tv_nsec) - (start.tv_sec + 1.0e-9*start.tv_nsec)
In the first case quite often end.tv_nsec is less in number then start.tv_nsec and hence the difference becomes negative number nd this give me wrong number.

Resources