aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--config.mak.uname1
-rw-r--r--trace.c82
-rw-r--r--trace.h1
4 files changed, 91 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 07ea10583..80f4390ab 100644
--- a/Makefile
+++ b/Makefile
@@ -340,6 +340,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/config.mak.uname b/config.mak.uname
index 1ae675b05..dad261832 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -34,6 +34,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)
HAVE_ALLOCA_H = YesPlease
diff --git a/trace.c b/trace.c
index f013958d0..b9d727231 100644
--- a/trace.c
+++ b/trace.c
@@ -275,3 +275,85 @@ int trace_want(struct trace_key *key)
{
return !!get_trace_fd(key);
}
+
+#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;
+ }
+}
diff --git a/trace.h b/trace.h
index 7a5ba2e61..4b893a55c 100644
--- a/trace.h
+++ b/trace.h
@@ -16,6 +16,7 @@ struct trace_key {
extern void trace_repo_setup(const char *prefix);
extern int trace_want(struct trace_key *key);
extern void trace_disable(struct trace_key *key);
+extern uint64_t getnanotime(void);
#ifndef HAVE_VARIADIC_MACROS