Switch to side-by-side view

--- a
+++ b/src/utils/chrono.cpp
@@ -0,0 +1,289 @@
+/* Copyright (C) 2014 J.F.Dockes
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the
+ *   Free Software Foundation, Inc.,
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#ifndef TEST_CHRONO
+#include "autoconfig.h"
+
+#include <time.h>
+#include <iostream>
+
+#include "chrono.h"
+
+using namespace std;
+
+#ifndef CLOCK_REALTIME
+typedef int clockid_t;
+#define CLOCK_REALTIME 1
+#endif
+
+
+#define SECONDS(TS1, TS2)                             \
+    (float((TS2).tv_sec - (TS1).tv_sec) +             \
+     float((TS2).tv_nsec - (TS1).tv_nsec) * 1e-9)
+
+#define MILLIS(TS1, TS2)                                        \
+    ((long long)((TS2).tv_sec - (TS1).tv_sec) * 1000LL +        \
+     ((TS2).tv_nsec - (TS1).tv_nsec) / 1000000)
+
+#define MICROS(TS1, TS2)                                          \
+    ((long long)((TS2).tv_sec - (TS1).tv_sec) * 1000000LL +       \
+     ((TS2).tv_nsec - (TS1).tv_nsec) / 1000)
+
+#define NANOS(TS1, TS2)                                           \
+    ((long long)((TS2).tv_sec - (TS1).tv_sec) * 1000000000LL +    \
+     ((TS2).tv_nsec - (TS1).tv_nsec))
+
+
+
+// Using clock_gettime() is nice because it gives us ns res and it helps with
+// computing threads work times, but it's also a pita because it forces linking
+// with -lrt. So keep it non-default, special development only.
+// #define USE_CLOCK_GETTIME
+
+// And wont' bother with gettime() on these.
+#if defined(__APPLE__) || defined(_WIN32)
+#undef USE_CLOCK_GETTIME
+#endif
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <stdint.h> // portable: uint64_t   MSVC: __int64 
+
+// MSVC defines this in winsock2.h!?
+typedef struct timeval {
+    long tv_sec;
+    long tv_usec;
+} timeval;
+
+int gettimeofday(struct timeval * tp, struct timezone * tzp)
+{
+    // Note: some broken versions only have 8 trailing zero's, the
+    // correct epoch has 9 trailing zero's
+    static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
+
+    SYSTEMTIME  system_time;
+    FILETIME    file_time;
+    uint64_t    time;
+
+    GetSystemTime( &system_time );
+    SystemTimeToFileTime( &system_time, &file_time );
+    time =  ((uint64_t)file_time.dwLowDateTime )      ;
+    time += ((uint64_t)file_time.dwHighDateTime) << 32;
+
+    tp->tv_sec  = (long) ((time - EPOCH) / 10000000L);
+    tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
+    return 0;
+}
+#else // -> Not _WIN32
+#ifndef USE_CLOCK_GETTIME
+// Using gettimeofday then, needs struct timeval
+#include <sys/time.h>
+#endif
+#endif
+
+
+
+// We use gettimeofday instead of clock_gettime for now and get only
+// uS resolution, because clock_gettime is more configuration trouble
+// than it's worth
+static void gettime(int
+#ifdef USE_CLOCK_GETTIME
+                    clk_id
+#endif
+                    , Chrono::TimeSpec *ts)
+{
+#ifdef USE_CLOCK_GETTIME
+    struct timespec mts;
+    clock_gettime(clk_id, &mts);
+    ts->tv_sec = mts.tv_sec;
+    ts->tv_nsec = mts.tv_nsec;
+#else
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    ts->tv_sec = tv.tv_sec;
+    ts->tv_nsec = tv.tv_usec * 1000;
+#endif
+}
+///// End system interface
+
+// Note: this not protected against multithread access and not
+// reentrant, but this is mostly debug code, and it won't crash, just
+// show bad results. Also the frozen thing is not used that much
+Chrono::TimeSpec Chrono::o_now;
+
+void Chrono::refnow()
+{
+    gettime(CLOCK_REALTIME, &o_now);
+}
+
+Chrono::Chrono()
+{
+    restart();
+}
+
+// Reset and return value before rest in milliseconds
+long Chrono::restart()
+{
+    TimeSpec now;
+    gettime(CLOCK_REALTIME, &now);
+    long ret = MILLIS(m_orig, now);
+    m_orig = now;
+    return ret;
+}
+
+long Chrono::urestart()
+{
+    TimeSpec now;
+    gettime(CLOCK_REALTIME, &now);
+    long ret = MICROS(m_orig, now);
+    m_orig = now;
+    return ret;
+}
+
+// Get current timer value, milliseconds
+long Chrono::millis(bool frozen)
+{
+    if (frozen) {
+        return MILLIS(m_orig, o_now);
+    } else {
+        TimeSpec now;
+        gettime(CLOCK_REALTIME, &now);
+        return MILLIS(m_orig, now);
+    }
+}
+
+//
+long Chrono::micros(bool frozen)
+{
+    if (frozen) {
+        return MICROS(m_orig, o_now);
+    } else {
+        TimeSpec now;
+        gettime(CLOCK_REALTIME, &now);
+        return MICROS(m_orig, now);
+    }
+}
+
+long long Chrono::amicros() const
+{
+    TimeSpec ts;
+    ts.tv_sec = 0;
+    ts.tv_nsec = 0;
+    return MICROS(ts, m_orig);
+}
+
+//
+long long Chrono::nanos(bool frozen)
+{
+    if (frozen) {
+        return NANOS(m_orig, o_now);
+    } else {
+        TimeSpec now;
+        gettime(CLOCK_REALTIME, &now);
+        return NANOS(m_orig, now);
+    }
+}
+
+float Chrono::secs(bool frozen)
+{
+    if (frozen) {
+        return SECONDS(m_orig, o_now);
+    } else {
+        TimeSpec now;
+        gettime(CLOCK_REALTIME, &now);
+        return SECONDS(m_orig, now);
+    }
+}
+
+#else
+
+///////////////////// test driver
+
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+#include "chrono.h"
+
+using namespace std;
+
+static char *thisprog;
+static void
+Usage(void)
+{
+    fprintf(stderr, "Usage : %s \n", thisprog);
+    exit(1);
+}
+
+Chrono achrono;
+Chrono rchrono;
+
+void
+showsecs(long msecs)
+{
+    fprintf(stderr, "%3.5f S", ((float)msecs) / 1000.0);
+}
+
+void
+sigint(int sig)
+{
+    signal(SIGINT, sigint);
+    signal(SIGQUIT, sigint);
+
+    fprintf(stderr, "Absolute interval: ");
+    showsecs(achrono.millis());
+    fprintf(stderr, ". Relative interval: ");
+    showsecs(rchrono.restart());
+    cerr <<  " Abs micros: " << achrono.amicros() <<
+        " Relabs micros: " << rchrono.amicros() - 1430477861905884LL
+         << endl;
+    fprintf(stderr, ".\n");
+    if (sig == SIGQUIT) {
+        exit(0);
+    }
+}
+
+int main(int argc, char **argv)
+{
+
+    thisprog = argv[0];
+    argc--;
+    argv++;
+
+    if (argc != 0) {
+        Usage();
+    }
+
+    for (int i = 0; i < 50000000; i++);
+
+    cerr << "Start secs: " << achrono.secs() << endl;
+
+    fprintf(stderr, "Type ^C for intermediate result, ^\\ to stop\n");
+    signal(SIGINT, sigint);
+    signal(SIGQUIT, sigint);
+    achrono.restart();
+    rchrono.restart();
+    while (1) {
+        pause();
+    }
+}
+
+#endif /*TEST_CHRONO*/