Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement timespec accumulators?

Tags:

c

linux

time

In a program that accumulates struct timespec deltas, I am doing the following logic:

struct timespec accu, start, stop;

for (...) {
    // record start
    // perform some logic
    // record stop

    accu.tv_sec += stop.tv_sec - start.tv_sec;
    accu.tv_nsec += stop.tv_nsec - start.tv_nsec;
    if (accu.tv_nsec >= 1000000000L) {
        accu.tv_nsec -= 1000000000L;
        ++accu.tv_sec;
    }
} // end for loop

However, when I print the result using:

printf("%lld.%.9ld\n", (long long) accu.tv_sec, accu.tv_nsec);

I sometime see results like: 1.-611075708

What am I doing wrong to have a negative value in accu.tv_nsec?

Note: start & stop retrieved with clock_gettime().

like image 877
Patrick Allaert Avatar asked Jan 10 '23 08:01

Patrick Allaert


2 Answers

Convert struct timespec to a uint64_t number of nanoseconds since epoch and take deltas between those and accumulate them easily. E.g.:

#include <time.h>
#include <stdint.h>

inline uint64_t as_nanoseconds(struct timespec* ts) {
    return ts->tv_sec * (uint64_t)1000000000L + ts->tv_nsec;
}

int main() {
    struct timespec start, stop;
    uint64_t accu_nsec = 0;

    for (...) {
        // record start
        // perform some logic
        // record stop

        accu_nsec += as_nanoseconds(&stop) - as_nanoseconds(&start);
    } // end for loop
}
like image 58
Maxim Egorushkin Avatar answered Jan 16 '23 18:01

Maxim Egorushkin


You can't simply add the times like this without proper overflow/underflow handling of the second addition. Example: start = 1.99...s, stop = 2.01...s

This gives us:

accu.tv_sec += 2 - 1 = 1;
accu.tv_nsec += 01... - 99.. = -98...;

Therefore, you have to use a temporary variable to calculate nsec. If it's <0, then you need to substract 1s and add 1000000000L to nsec.

like image 26
Aaron Digulla Avatar answered Jan 16 '23 19:01

Aaron Digulla