Add a getnanotime() function that returns nanoseconds since 01/01/1970 as
unsigned 64-bit integer (i.e. overflows in july 2554). This is easier to
work with than e.g. struct timeval or struct timespec.

The implementation uses gettimeofday() by default; supports high precision
time sources on the following platforms:
 * Linux: using clock_gettime(CLOCK_MONOTONIC)
 * Windows: using QueryPerformanceCounter()

Todo:
 * enable clock_gettime() on more platforms
 * implement Mac OSX version using mach_absolute_time

Signed-off-by: Karsten Blees <bl...@dcon.de>
---
 Makefile         |  7 +++++
 cache.h          |  1 +
 config.mak.uname |  1 +
 trace.c          | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 91 insertions(+)

diff --git a/Makefile b/Makefile
index a53f3a8..3c05f8c 100644
--- a/Makefile
+++ b/Makefile
@@ -341,6 +341,8 @@ all::
 #
 # Define GMTIME_UNRELIABLE_ERRORS if your gmtime() function does not
 # return NULL when it receives a bogus time_t.
+#
+# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt.
 
 GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -1497,6 +1499,11 @@ ifdef GMTIME_UNRELIABLE_ERRORS
        BASIC_CFLAGS += -DGMTIME_UNRELIABLE_ERRORS
 endif
 
+ifdef HAVE_CLOCK_GETTIME
+       BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
+       EXTLIBS += -lrt
+endif
+
 ifeq ($(TCLTK_PATH),)
 NO_TCLTK = NoThanks
 endif
diff --git a/cache.h b/cache.h
index 107ac61..48fc616 100644
--- a/cache.h
+++ b/cache.h
@@ -1362,6 +1362,7 @@ extern int trace_want(const char *key);
 __attribute__((format (printf, 2, 3)))
 extern void trace_printf_key(const char *key, const char *fmt, ...);
 extern void trace_strbuf(const char *key, const struct strbuf *buf);
+extern uint64_t getnanotime(void);
 
 void packet_trace_identity(const char *prog);
 
diff --git a/config.mak.uname b/config.mak.uname
index 23a8803..5e3b1dd 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -33,6 +33,7 @@ ifeq ($(uname_S),Linux)
        HAVE_PATHS_H = YesPlease
        LIBC_CONTAINS_LIBINTL = YesPlease
        HAVE_DEV_TTY = YesPlease
+       HAVE_CLOCK_GETTIME = YesPlease
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
diff --git a/trace.c b/trace.c
index 08180a9..3d72084 100644
--- a/trace.c
+++ b/trace.c
@@ -187,3 +187,85 @@ int trace_want(const char *key)
                return 0;
        return 1;
 }
+
+#ifdef HAVE_CLOCK_GETTIME
+
+static inline uint64_t highres_nanos(void)
+{
+       struct timespec ts;
+       if (clock_gettime(CLOCK_MONOTONIC, &ts))
+               return 0;
+       return (uint64_t) ts.tv_sec * 1000000000 + ts.tv_nsec;
+}
+
+#elif defined (GIT_WINDOWS_NATIVE)
+
+static inline uint64_t highres_nanos(void)
+{
+       static uint64_t high_ns, scaled_low_ns;
+       static int scale;
+       LARGE_INTEGER cnt;
+
+       if (!scale) {
+               if (!QueryPerformanceFrequency(&cnt))
+                       return 0;
+
+               /* high_ns = number of ns per cnt.HighPart */
+               high_ns = (1000000000LL << 32) / (uint64_t) cnt.QuadPart;
+
+               /*
+                * Number of ns per cnt.LowPart is 10^9 / frequency (or
+                * high_ns >> 32). For maximum precision, we scale this factor
+                * so that it just fits within 32 bit (i.e. won't overflow if
+                * multiplied with cnt.LowPart).
+                */
+               scaled_low_ns = high_ns;
+               scale = 32;
+               while (scaled_low_ns >= 0x100000000LL) {
+                       scaled_low_ns >>= 1;
+                       scale--;
+               }
+       }
+
+       /* if QPF worked on initialization, we expect QPC to work as well */
+       QueryPerformanceCounter(&cnt);
+
+       return (high_ns * cnt.HighPart) +
+              ((scaled_low_ns * cnt.LowPart) >> scale);
+}
+
+#else
+# define highres_nanos() 0
+#endif
+
+static inline uint64_t gettimeofday_nanos(void)
+{
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       return (uint64_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
+}
+
+/*
+ * Returns nanoseconds since the epoch (01/01/1970), for performance tracing
+ * (i.e. favoring high precision over wall clock time accuracy).
+ */
+inline uint64_t getnanotime(void)
+{
+       static uint64_t offset;
+       if (offset > 1) {
+               /* initialization succeeded, return offset + high res time */
+               return offset + highres_nanos();
+       } else if (offset == 1) {
+               /* initialization failed, fall back to gettimeofday */
+               return gettimeofday_nanos();
+       } else {
+               /* initialize offset if high resolution timer works */
+               uint64_t now = gettimeofday_nanos();
+               uint64_t highres = highres_nanos();
+               if (highres)
+                       offset = now - highres;
+               else
+                       offset = 1;
+               return now;
+       }
+}
-- 
1.9.2.msysgit.0.493.g47a82c3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to