简体   繁体   中英

Is time() from time.h monotonic?

I'm talking about the old-school time() function that returns the number of seconds since the epoch, in UTC. This should be monotonic, right?

In my tests (see below) it runs about 10x faster than clock_gettime with CLOCK_MONOTONIC, so I was wondering if it can be used as a monotonic timer for situations where I need a low latency low resolution monotonic timer. (eg to drop connections that have been around for longer than 15 seconds on a server)

Here is the code in case you're curious:

#include <cstdio>
#include <chrono>
#include <time.h>
#include <sys/time.h>
#include <x86intrin.h>

using namespace std;

class Timer {
    std::chrono::time_point<std::chrono::steady_clock> start;
public:
    inline double t() {
        auto end = std::chrono::steady_clock::now();
        std::chrono::duration<double> diff = end - start;
        return diff.count();
    }
    inline double milli() { return t() * 1000.0;}
    Timer() :start(std::chrono::steady_clock::now()) {}
};

const int nloop = 10000000;

void cpp_steady() {
    for (int i=0;i<nloop;i++) {
        chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    }
}

void get_tod() {
    timeval tv;
    for (int i=0;i<nloop;i++) {
        gettimeofday(&tv, 0);
    }
}

void get_clock() {
    for (int i=0;i<nloop;i++) {
        clock_t t = clock();
    }
}

void get_time() {
    int x =0;
    for (int i=0;i<nloop;i++) {
        time_t t = time(0);
        x+=t*3;
    }
    fprintf(stderr,"%d\n",x);    
}

void get_clock_gettime() {
    timespec ts;
    for (int i=0;i<nloop;i++) {
        clock_gettime(CLOCK_MONOTONIC, &ts);
    }
}

void get_rdtsc() {
    for (int i=0;i<nloop;i++) {
        __rdtsc();
    }
}

void emptyloop() {
    int x=0;
    for (int i=0;i<nloop;i++) {
        x+=3*i;
    }
    fprintf(stderr,"%d\n",x);
}

void measure(const char *name, void (*f)()) {
    Timer t;
    f();
    double dur = t.milli();
    printf(" %-15s : %.3f ms\n", name, dur);
}

int main () {

    measure("cpp_steady", cpp_steady);
    measure("gettimeofday", get_tod);
    //measure("clock", get_clock);  //too fking slow
    measure("time", get_time);
    measure("clock_gettime", get_clock_gettime);
    measure("rdtsc", get_rdtsc);
    measure("empty", emptyloop);

    return 0;
}

And here is the output:

./clk_bench 2>/dev/null
 cpp_steady      : 212.415 ms
 gettimeofday    : 200.733 ms
 time            : 19.526 ms
 clock_gettime   : 197.791 ms
 rdtsc           : 75.169 ms
 empty           : 2.821 ms

(By the way, I know it's only a matter of a few nanoseconds and doesn't really matter, but actually time_t also consumes less memory and is more portable than the alternatives...)

There is no definitive answer except that time is not guaranteed to be monotonic.

It just returns what the kernel think that the current time is. If there are operational procedure to guarantee the the clock can never go backwards and if those procedures are obeyed, then it should be monotonic. For example, on a Unix box using ntpd for time synchoronization, the clock should never run backwards. But if an administrator (a human being with administrator privileges on the machine) sees that the machine time is not accurate and fixes it backwards, then any monotonic assumption will be false.

The encoding of the value returned from std::time() is unspecified. However in most implementation it returns the current wall time in seconds since the unix epoch.

If your wall clock is monotonic then std::time() will also be monotonic. However the wall clock is not usually guaranteed to be monotonic. Many modern Linux systems adjust their clocks to NTP sources using clock smearing rather than jumping backwards but even in this case the user can intervene and manually set the clock backwards.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM