double timespec_delta2milliseconds(struct timespec *last, struct timespec *previous)
{
    
 return (last->tv_sec - previous->tv_sec) + (last->tv_nsec - previous->tv_nsec)*pow(10,-3); 

}

This function computes the difference (last - previous) and returns the result expressed in milliseconds as a double. I tried a lot of different ways but if I don't do like this i receve in output segmentation fault. I think that this solution works but it's wrong, someone can help me ?

2

There are 2 answers

0
Jonathan Leffler On BEST ANSWER

You need two functions: sub_timespec(), which calculates the difference between two time spec values, and timespec_as_milliseconds(), which returns the number of milliseconds in a time spec value as an integer.

enum { NS_PER_SECOND = 1000000000 };

void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td)
{
    td->tv_nsec = t2.tv_nsec - t1.tv_nsec;
    td->tv_sec  = t2.tv_sec - t1.tv_sec;
    if (td->tv_sec > 0 && td->tv_nsec < 0)
    {
        td->tv_nsec += NS_PER_SECOND;
        td->tv_sec--;
    }
    else if (td->tv_sec < 0 && td->tv_nsec > 0)
    {
        td->tv_nsec -= NS_PER_SECOND;
        td->tv_sec++;
    }
}

int64_t timespec_as_milliseconds(struct timespec ts)
{
    int64_t rv = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
    return rv;
}

If you want to round the milliseconds, it gets trickier because you have to worry about carries and negative numbers and so on. You should not encounter a timespec value where the tv_sec and tv_nsec values have opposite signs (zeros aren't a problem).

In your code, adding pow(10, -3) mixes floating point arithmetic with integer arithmetic — usually not a good idea.

If you want a double value with up to 3 decimal places of fractional seconds, then you need:

double timespec_to_double_milliseconds(struct timespec ts)
{
    double rv = ts.tv_sec + (ts.tv_nsec / 1000000) / 1000.0;
    return rv;
}

The first division is (deliberately) integer division; the second gives a floating-point value. Again, rounding has problems with carrying and so on.

Your function then becomes:

double timespec_delta2milliseconds(struct timespec *last, struct timespec *previous)
{
    struct timespec delta = sub_timespec(*last, *previous);
    return timespec_to_double_milliseconds(delta); 
}

You can use an extra value in the function so it is easier to print the value returned in a debugger: double rv = timespec_to_double_milliseconds(delta); return rv;.

The key idea, though, is to do separate tasks in separate functions. Taking the difference between two struct timespec values is one task; converting a struct timespec value to an appropriate double is a separate task. When you can split things into separate tasks, you should.

I often pass struct timespec values by value rather than pointer. The structure size is typically small enough that it is not a stress on the stack or registers. I return them by value too, which simplifies memory management — YMMV.

And, just in case it isn't clear, the tv_sec member of a struct timespec contains an integer number of seconds, and the tv_nsec contains the fractional part of a second expressed as a number of nanoseconds (0 to 999,999,999). It requires care in printing the tv_nsec value; you need a format such as %.9ld to print 9 digits with leading zeros, and the type is long. To print microseconds, divide the tv_nsec value by 1,000 and change 9 to 6; to print milliseconds, divide by 1,000,000 and change 9 to 3. Beware negative values!

4
Some programmer dude On

The timespec structure can handle fractions of a second, and the tv_nsec is the fractions, represented as nanoseconds.

That means getting the difference between two timespec structures isn't as straight-forward as you make it seem in your code.

Here's an example on how to get the difference, returned as a new timesepc structure:

struct timespec diff_timespec(const struct timespec *time1, const struct timespec *time0)
{
    struct timespec diff = {
        .tv_sec = time1->tv_sec - time0->tv_sec,
        .tv_nsec = time1->tv_nsec - time0->tv_nsec
    };

    if (diff.tv_nsec < 0)
    {
        diff.tv_nsec += 1000000000;
        diff.tv_sec--;
    }

    return diff;
}