summaryrefslogtreecommitdiffstats
path: root/include/my_rdtsc.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--include/my_rdtsc.h236
1 files changed, 236 insertions, 0 deletions
diff --git a/include/my_rdtsc.h b/include/my_rdtsc.h
new file mode 100644
index 00000000..33d72276
--- /dev/null
+++ b/include/my_rdtsc.h
@@ -0,0 +1,236 @@
+/* Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc.
+ Copyright (c) 2019, MariaDB Corporation.
+
+ 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; version 2 of the License.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ rdtsc3 -- multi-platform timer code
+ pgulutzan@mysql.com, 2005-08-29
+ modified 2008-11-02
+*/
+
+#ifndef MY_RDTSC_H
+#define MY_RDTSC_H
+
+# ifndef __has_builtin
+# define __has_builtin(x) 0 /* Compatibility with non-clang compilers */
+# endif
+# if __has_builtin(__builtin_readcyclecounter)
+# elif defined _WIN32
+# include <intrin.h>
+# elif defined __i386__ || defined __x86_64__
+# include <x86intrin.h>
+# elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
+# include <ia64intrin.h>
+# elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
+# include <sys/times.h>
+# endif
+
+/**
+ Characteristics of a timer.
+*/
+struct my_timer_unit_info
+{
+ /** Routine used for the timer. */
+ ulonglong routine;
+ /** Overhead of the timer. */
+ ulonglong overhead;
+ /** Frequency of the timer. */
+ ulonglong frequency;
+ /** Resolution of the timer. */
+ ulonglong resolution;
+};
+
+/**
+ Characteristics of all the supported timers.
+ @sa my_timer_init().
+*/
+struct my_timer_info
+{
+ /** Characteristics of the cycle timer. */
+ struct my_timer_unit_info cycles;
+ /** Characteristics of the nanosecond timer. */
+ struct my_timer_unit_info nanoseconds;
+ /** Characteristics of the microsecond timer. */
+ struct my_timer_unit_info microseconds;
+ /** Characteristics of the millisecond timer. */
+ struct my_timer_unit_info milliseconds;
+ /** Characteristics of the tick timer. */
+ struct my_timer_unit_info ticks;
+};
+
+typedef struct my_timer_info MY_TIMER_INFO;
+
+C_MODE_START
+
+/**
+ A cycle timer.
+
+ On clang we use __builtin_readcyclecounter(), except for AARCH64.
+ On other compilers:
+
+ On IA-32 and AMD64, we use the RDTSC instruction.
+ On IA-64, we read the ar.itc register.
+ On SPARC, we read the tick register.
+ On POWER, we read the Time Base Register (which is not really a cycle count
+ but a separate counter with less than nanosecond resolution).
+ On IBM S/390 System z we use the STCK instruction.
+ On ARM, we probably should use the Generic Timer, but should figure out
+ how to ensure that it can be accessed.
+ On AARCH64, we use the generic timer base register. We override clang
+ implementation for aarch64 as it access a PMU register which is not
+ guarenteed to be active.
+
+ Sadly, we have nothing for the Digital Alpha, MIPS, Motorola m68k,
+ HP PA-RISC or other non-mainstream (or obsolete) processors.
+
+ TODO: consider C++11 std::chrono::high_resolution_clock.
+
+ We fall back to gethrtime() where available.
+
+ On the platforms that do not have a CYCLE timer,
+ "wait" events are initialized to use NANOSECOND instead of CYCLE
+ during performance_schema initialization (at the server startup).
+
+ Linux performance monitor (see "man perf_event_open") can
+ provide cycle counter on the platforms that do not have
+ other kinds of cycle counters. But we don't use it so far.
+
+ ARM notes
+ ---------
+ During tests on ARMv7 Debian, perf_even_open() based cycle counter provided
+ too low frequency with too high overhead:
+ MariaDB [performance_schema]> SELECT * FROM performance_timers;
+ +-------------+-----------------+------------------+----------------+
+ | TIMER_NAME | TIMER_FREQUENCY | TIMER_RESOLUTION | TIMER_OVERHEAD |
+ +-------------+-----------------+------------------+----------------+
+ | CYCLE | 689368159 | 1 | 970 |
+ | NANOSECOND | 1000000000 | 1 | 308 |
+ | MICROSECOND | 1000000 | 1 | 417 |
+ | MILLISECOND | 1000 | 1000 | 407 |
+ | TICK | 127 | 1 | 612 |
+ +-------------+-----------------+------------------+----------------+
+ Therefore, it was decided not to use perf_even_open() on ARM
+ (i.e. go without CYCLE and have "wait" events use NANOSECOND by default).
+
+ @return the current timer value, in cycles.
+*/
+static inline ulonglong my_timer_cycles(void)
+{
+# if __has_builtin(__builtin_readcyclecounter) && !defined (__aarch64__)
+ return __builtin_readcyclecounter();
+# elif defined _WIN32 || defined __i386__ || defined __x86_64__
+ return __rdtsc();
+# elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
+ return (ulonglong) __getReg(_IA64_REG_AR_ITC); /* (3116) */
+#elif defined(__GNUC__) && defined(__ia64__)
+ {
+ ulonglong result;
+ __asm __volatile__ ("mov %0=ar.itc" : "=r" (result));
+ return result;
+ }
+#elif defined __GNUC__ && defined __powerpc__
+ return __builtin_ppc_get_timebase();
+#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64)
+ {
+ ulonglong result;
+ __asm __volatile__ ("rd %%tick,%0" : "=r" (result));
+ return result;
+ }
+#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64)
+ {
+ union {
+ ulonglong wholeresult;
+ struct {
+ ulong high;
+ ulong low;
+ } splitresult;
+ } result;
+ __asm __volatile__ ("rd %%tick,%1; srlx %1,32,%0" : "=r" (result.splitresult.high), "=r" (result.splitresult.low));
+ return result.wholeresult;
+ }
+#elif defined(__GNUC__) && defined(__s390__)
+ /* covers both s390 and s390x */
+ {
+ ulonglong result;
+ __asm__ __volatile__ ("stck %0" : "=Q" (result) : : "cc");
+ return result;
+ }
+#elif defined(__GNUC__) && defined (__aarch64__)
+ {
+ ulonglong result;
+ __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (result));
+ return result;
+ }
+#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
+ /* gethrtime may appear as either cycle or nanosecond counter */
+ return (ulonglong) gethrtime();
+#else
+ return 0;
+#endif
+}
+
+/**
+ A nanosecond timer.
+ @return the current timer value, in nanoseconds.
+*/
+ulonglong my_timer_nanoseconds(void);
+
+/**
+ A microseconds timer.
+ @return the current timer value, in microseconds.
+*/
+ulonglong my_timer_microseconds(void);
+
+/**
+ A millisecond timer.
+ @return the current timer value, in milliseconds.
+*/
+ulonglong my_timer_milliseconds(void);
+
+/**
+ A ticks timer.
+ @return the current timer value, in ticks.
+*/
+ulonglong my_timer_ticks(void);
+
+/**
+ Timer initialization function.
+ @param [out] mti the timer characteristics.
+*/
+void my_timer_init(MY_TIMER_INFO *mti);
+
+C_MODE_END
+
+#define MY_TIMER_ROUTINE_RDTSC 5
+#define MY_TIMER_ROUTINE_ASM_IA64 6
+#define MY_TIMER_ROUTINE_PPC_GET_TIMEBASE 7
+#define MY_TIMER_ROUTINE_GETHRTIME 9
+#define MY_TIMER_ROUTINE_READ_REAL_TIME 10
+#define MY_TIMER_ROUTINE_CLOCK_GETTIME 11
+#define MY_TIMER_ROUTINE_GETTIMEOFDAY 13
+#define MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER 14
+#define MY_TIMER_ROUTINE_GETTICKCOUNT 15
+#define MY_TIMER_ROUTINE_TIME 16
+#define MY_TIMER_ROUTINE_TIMES 17
+#define MY_TIMER_ROUTINE_FTIME 18
+#define MY_TIMER_ROUTINE_ASM_GCC_SPARC64 23
+#define MY_TIMER_ROUTINE_ASM_GCC_SPARC32 24
+#define MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME 25
+#define MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME 26
+#define MY_TIMER_ROUTINE_ASM_S390 28
+#define MY_TIMER_ROUTINE_AARCH64 29
+
+#endif
+