Adds an OS-agnostic header for TSC readings
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 29 Mar 2013 21:49:51 +0000 (14:49 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 29 Mar 2013 21:49:51 +0000 (14:49 -0700)
Linux programs can #include tsc-compat.h to get similar calls to Akaros
library calls for reading the tsc and gettings its frequency.

If someone feels inclined, they can write an overhead detector for
Linux, being mindful of IRQs and the ksched.

user/parlib/include/tsc-compat.h [new file with mode: 0644]

diff --git a/user/parlib/include/tsc-compat.h b/user/parlib/include/tsc-compat.h
new file mode 100644 (file)
index 0000000..b748d23
--- /dev/null
@@ -0,0 +1,108 @@
+/* Basic TSC compatability helpers, callable from Akaros or Linux. Supports:
+ *             uint64_t read_tsc()
+ *             uint64_t read_tsc_serialized()
+ *             uint64_t get_tsc_freq()
+ *             uint64_t get_tsc_overhead()
+ *
+ * Note this relies on specifics of procinfo, which isn't stable.  If procinfo
+ * changes, this will need to change as well.  You'll know when this doesn't
+ * compile (say, if timing_overhead moves).  */
+
+#ifndef _TSC_COMPAT_H
+#define _TSC_COMPAT_H
+
+#if defined(__i386__) || defined(__x86_64__)
+#else
+#error "Platform not supported for read_tsc()"
+#endif
+
+#ifdef __cplusplus
+       extern "C" {
+#endif
+
+#ifdef __ros__
+
+#include <arch/arch.h>
+#include <ros/procinfo.h>
+
+static inline uint64_t get_tsc_freq(void)
+{
+       return __procinfo.tsc_freq;
+}
+
+static inline uint64_t get_tsc_overhead(void)
+{
+       return __procinfo.timing_overhead;
+}
+
+#else /* ! _ros_ (linux) */
+
+#include <sys/time.h>
+#include <stdint.h>
+
+# ifdef __i386__
+
+static inline uint64_t read_tsc(void)
+{
+       uint64_t tsc;
+       asm volatile("rdtsc" : "=A" (tsc));
+       return tsc;
+}
+
+static inline uint64_t read_tsc_serialized(void)
+{
+       uint64_t tsc;
+       asm volatile("lfence; rdtsc" : "=A" (tsc));
+       return tsc;
+}
+
+# elif __x86_64__
+
+static inline uint64_t read_tsc(void)
+{
+       uint32_t lo, hi;
+       /* We cannot use "=A", since this would use %rax on x86_64 */
+       asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
+       return (uint64_t)hi << 32 | lo;
+}
+
+static inline uint64_t read_tsc_serialized(void)
+{
+       uint32_t lo, hi;
+       asm volatile("lfence; rdtsc" : "=a" (lo), "=d" (hi));
+       return (uint64_t)hi << 32 | lo;
+}
+
+# else
+#  error "Which arch is this?"
+# endif /* __i386__ | __x86_64__ */
+
+static inline uint64_t get_tsc_freq(void)
+{
+       struct timeval prev;
+       struct timeval curr;
+       uint64_t beg = read_tsc_serialized();
+       gettimeofday(&prev, 0);
+       while (1) {
+               gettimeofday(&curr, 0);
+               if (curr.tv_sec > (prev.tv_sec + 1) ||
+                       (curr.tv_sec > prev.tv_sec && curr.tv_usec > prev.tv_usec))
+                       break;
+       }
+       uint64_t end = read_tsc_serialized();
+       return end - beg;
+}
+
+/* Don't have a good way to get the overhead on Linux in userspace. */
+static inline uint64_t get_tsc_overhead(void)
+{
+       return 0;
+}
+
+#endif /* ! _ros_ */
+
+#ifdef __cplusplus
+       }
+#endif
+
+#endif /* _TSC_COMPAT_H */