|
1 | 1 | /* Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc.
|
2 |
| - Use is subject to license terms. |
| 2 | + Copyright (c) 2019, MariaDB Corporation. |
3 | 3 |
|
4 | 4 | This program is free software; you can redistribute it and/or modify
|
5 | 5 | it under the terms of the GNU General Public License as published by
|
|
23 | 23 | #ifndef MY_RDTSC_H
|
24 | 24 | #define MY_RDTSC_H
|
25 | 25 |
|
| 26 | +# ifndef __has_builtin |
| 27 | +# define __has_builtin(x) 0 /* Compatibility with non-clang compilers */ |
| 28 | +# endif |
| 29 | +# if __has_builtin(__builtin_readcyclecounter) |
| 30 | +# elif defined _WIN32 |
| 31 | +# include <intrin.h> |
| 32 | +# elif defined __i386__ || defined __x86_64__ |
| 33 | +# include <x86intrin.h> |
| 34 | +# elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) |
| 35 | +# include <ia64intrin.h> |
| 36 | +# elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) |
| 37 | +# include <sys/times.h> |
| 38 | +# endif |
| 39 | + |
26 | 40 | /**
|
27 | 41 | Characteristics of a timer.
|
28 | 42 | */
|
@@ -62,12 +76,104 @@ C_MODE_START
|
62 | 76 |
|
63 | 77 | /**
|
64 | 78 | A cycle timer.
|
| 79 | +
|
| 80 | + On clang, we use __builtin_readcyclecounter(). |
| 81 | + On other compilers: |
| 82 | +
|
| 83 | + On IA-32 and AMD64, we use the RDTSC instruction. |
| 84 | + On IA-64, we read the ar.itc register. |
| 85 | + On SPARC, we read the tick register. |
| 86 | + On POWER, we read the Time Base Register (which is not really a cycle count |
| 87 | + but a separate counter with less than nanosecond resolution). |
| 88 | + On IBM S/390 System z we use the STCK instruction. |
| 89 | + On ARM, we probably should use the Generic Timer, but should figure out |
| 90 | + how to ensure that it can be accessed. |
| 91 | +
|
| 92 | + Sadly, we have nothing for the Digital Alpha, MIPS, Motorola m68k, |
| 93 | + HP PA-RISC or other non-mainstream (or obsolete) processors. |
| 94 | +
|
| 95 | + TODO: consider C++11 std::chrono::high_resolution_clock. |
| 96 | +
|
| 97 | + We fall back to gethrtime() where available. |
| 98 | +
|
| 99 | + On the platforms that do not have a CYCLE timer, |
| 100 | + "wait" events are initialized to use NANOSECOND instead of CYCLE |
| 101 | + during performance_schema initialization (at the server startup). |
| 102 | +
|
| 103 | + Linux performance monitor (see "man perf_event_open") can |
| 104 | + provide cycle counter on the platforms that do not have |
| 105 | + other kinds of cycle counters. But we don't use it so far. |
| 106 | +
|
| 107 | + ARM notes |
| 108 | + --------- |
| 109 | + During tests on ARMv7 Debian, perf_even_open() based cycle counter provided |
| 110 | + too low frequency with too high overhead: |
| 111 | + MariaDB [performance_schema]> SELECT * FROM performance_timers; |
| 112 | + +-------------+-----------------+------------------+----------------+ |
| 113 | + | TIMER_NAME | TIMER_FREQUENCY | TIMER_RESOLUTION | TIMER_OVERHEAD | |
| 114 | + +-------------+-----------------+------------------+----------------+ |
| 115 | + | CYCLE | 689368159 | 1 | 970 | |
| 116 | + | NANOSECOND | 1000000000 | 1 | 308 | |
| 117 | + | MICROSECOND | 1000000 | 1 | 417 | |
| 118 | + | MILLISECOND | 1000 | 1000 | 407 | |
| 119 | + | TICK | 127 | 1 | 612 | |
| 120 | + +-------------+-----------------+------------------+----------------+ |
| 121 | + Therefore, it was decided not to use perf_even_open() on ARM |
| 122 | + (i.e. go without CYCLE and have "wait" events use NANOSECOND by default). |
| 123 | +
|
65 | 124 | @return the current timer value, in cycles.
|
66 | 125 | */
|
67 |
| -ulonglong my_timer_cycles(void); |
| 126 | +static inline ulonglong my_timer_cycles(void) |
| 127 | +{ |
| 128 | +# if __has_builtin(__builtin_readcyclecounter) |
| 129 | + return __builtin_readcyclecounter(); |
| 130 | +# elif defined _WIN32 || defined __i386__ || defined __x86_64__ |
| 131 | + return __rdtsc(); |
| 132 | +# elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H) |
| 133 | + return (ulonglong) __getReg(_IA64_REG_AR_ITC); /* (3116) */ |
| 134 | +#elif defined(__GNUC__) && defined(__ia64__) |
| 135 | + { |
| 136 | + ulonglong result; |
| 137 | + __asm __volatile__ ("mov %0=ar.itc" : "=r" (result)); |
| 138 | + return result; |
| 139 | + } |
| 140 | +#elif defined __GNUC__ && defined __powerpc__ |
| 141 | + return __builtin_ppc_get_timebase(); |
| 142 | +#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) |
| 143 | + { |
| 144 | + ulonglong result; |
| 145 | + __asm __volatile__ ("rd %%tick,%0" : "=r" (result)); |
| 146 | + return result; |
| 147 | + } |
| 148 | +#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) |
| 149 | + { |
| 150 | + union { |
| 151 | + ulonglong wholeresult; |
| 152 | + struct { |
| 153 | + ulong high; |
| 154 | + ulong low; |
| 155 | + } splitresult; |
| 156 | + } result; |
| 157 | + __asm __volatile__ ("rd %%tick,%1; srlx %1,32,%0" : "=r" (result.splitresult.high), "=r" (result.splitresult.low)); |
| 158 | + return result.wholeresult; |
| 159 | + } |
| 160 | +#elif defined(__GNUC__) && defined(__s390__) |
| 161 | + /* covers both s390 and s390x */ |
| 162 | + { |
| 163 | + ulonglong result; |
| 164 | + __asm__ __volatile__ ("stck %0" : "=Q" (result) : : "cc"); |
| 165 | + return result; |
| 166 | + } |
| 167 | +#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME) |
| 168 | + /* gethrtime may appear as either cycle or nanosecond counter */ |
| 169 | + return (ulonglong) gethrtime(); |
| 170 | +#else |
| 171 | + return 0; |
| 172 | +#endif |
| 173 | +} |
68 | 174 |
|
69 | 175 | /**
|
70 |
| - A namoseconds timer. |
| 176 | + A nanosecond timer. |
71 | 177 | @return the current timer value, in nanoseconds.
|
72 | 178 | */
|
73 | 179 | ulonglong my_timer_nanoseconds(void);
|
@@ -98,33 +204,22 @@ void my_timer_init(MY_TIMER_INFO *mti);
|
98 | 204 |
|
99 | 205 | C_MODE_END
|
100 | 206 |
|
101 |
| -#define MY_TIMER_ROUTINE_ASM_X86 1 |
102 |
| -#define MY_TIMER_ROUTINE_ASM_X86_64 2 |
103 |
| -#define MY_TIMER_ROUTINE_RDTSCLL 3 |
104 |
| -#define MY_TIMER_ROUTINE_ASM_X86_WIN 4 |
105 | 207 | #define MY_TIMER_ROUTINE_RDTSC 5
|
106 | 208 | #define MY_TIMER_ROUTINE_ASM_IA64 6
|
107 |
| -#define MY_TIMER_ROUTINE_ASM_PPC 7 |
108 |
| -#define MY_TIMER_ROUTINE_SGI_CYCLE 8 |
| 209 | +#define MY_TIMER_ROUTINE_PPC_GET_TIMEBASE 7 |
109 | 210 | #define MY_TIMER_ROUTINE_GETHRTIME 9
|
110 | 211 | #define MY_TIMER_ROUTINE_READ_REAL_TIME 10
|
111 | 212 | #define MY_TIMER_ROUTINE_CLOCK_GETTIME 11
|
112 |
| -#define MY_TIMER_ROUTINE_NXGETTIME 12 |
113 | 213 | #define MY_TIMER_ROUTINE_GETTIMEOFDAY 13
|
114 | 214 | #define MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER 14
|
115 | 215 | #define MY_TIMER_ROUTINE_GETTICKCOUNT 15
|
116 | 216 | #define MY_TIMER_ROUTINE_TIME 16
|
117 | 217 | #define MY_TIMER_ROUTINE_TIMES 17
|
118 | 218 | #define MY_TIMER_ROUTINE_FTIME 18
|
119 |
| -#define MY_TIMER_ROUTINE_ASM_PPC64 19 |
120 |
| -#define MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC64 20 |
121 |
| -#define MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC32 21 |
122 |
| -#define MY_TIMER_ROUTINE_ASM_SUNPRO_I386 22 |
123 | 219 | #define MY_TIMER_ROUTINE_ASM_GCC_SPARC64 23
|
124 | 220 | #define MY_TIMER_ROUTINE_ASM_GCC_SPARC32 24
|
125 | 221 | #define MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME 25
|
126 | 222 | #define MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME 26
|
127 |
| -#define MY_TIMER_ROUTINE_ASM_SUNPRO_X86_64 27 |
128 | 223 | #define MY_TIMER_ROUTINE_ASM_S390 28
|
129 | 224 |
|
130 | 225 | #endif
|
|
0 commit comments