Skip to content
Permalink
Browse files

MDEV-19845: Define my_timer_cycles() inline

On clang, use __builtin_readcyclecounter() when available.
Hinted by Sergey Vojtovich. (This may lead to runtime failure
on ARM systems. The hardware should be available on ARMv8 (AArch64),
but access to it may require special privileges.)

We remove support for the proprietary Sun Microsystems compiler,
and rely on clang or the __GNUC__ assembler syntax instead.

For now, we retain support for IA-64 (Itanium) and 32-bit SPARC,
even though those platforms are likely no longer widely used.

We remove support for clock_gettime(CLOCK_SGI_CYCLE),
because Silicon Graphics ceased supporting IRIX in December 2013.
This was the only cycle timer interface available for MIPS.

On PowerPC, we rely on the GCC 4.8 __builtin_ppc_get_timebase()
(or clang __builtin_readcyclecounter()), which should be equivalent
to the old assembler code on both 64-bit and 32-bit targets.
  • Loading branch information...
dr-m committed Jun 28, 2019
1 parent 1635ea9 commit 5e929ee8a0487f8929386031e84b1884f503eb48
Showing with 124 additions and 295 deletions.
  1. +1 −1 cmake/os/SunOS.cmake
  2. +0 −2 cmake/os/WindowsCache.cmake
  3. +0 −2 config.h.cmake
  4. +0 −5 configure.cmake
  5. +110 −15 include/my_rdtsc.h
  6. +0 −6 mysys/CMakeLists.txt
  7. +5 −12 mysys/my_cpu.c
  8. +8 −213 mysys/my_rdtsc.c
  9. +0 −39 mysys/my_timer_cycles.il
@@ -70,7 +70,7 @@ CHECK_C_SOURCE_RUNS(


# Check is special processor flag needs to be set on older GCC
#that defaults to v8 sparc . Code here is taken from my_rdtsc.c
#that defaults to v8 sparc . Code here is taken from my_rdtsc.h
IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_SIZEOF_VOID_P EQUAL 4
AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc")
SET(SOURCE
@@ -25,7 +25,6 @@ SET(HAVE_ACCESS 1 CACHE INTERNAL "")
SET(HAVE_ALARM CACHE INTERNAL "")
SET(HAVE_ALLOCA_H CACHE INTERNAL "")
SET(HAVE_ARPA_INET_H CACHE INTERNAL "")
SET(HAVE_ASM_MSR_H CACHE INTERNAL "")
SET(HAVE_BACKTRACE CACHE INTERNAL "")
SET(HAVE_BACKTRACE_SYMBOLS CACHE INTERNAL "")
SET(HAVE_BACKTRACE_SYMBOLS_FD CACHE INTERNAL "")
@@ -132,7 +131,6 @@ SET(HAVE_PTHREAD_YIELD_NP CACHE INTERNAL "")
SET(HAVE_PTHREAD_YIELD_ZERO_ARG CACHE INTERNAL "")
SET(HAVE_PUTENV 1 CACHE INTERNAL "")
SET(HAVE_PWD_H CACHE INTERNAL "")
SET(HAVE_RDTSCLL CACHE INTERNAL "")
SET(HAVE_READDIR_R CACHE INTERNAL "")
SET(HAVE_READLINK CACHE INTERNAL "")
SET(HAVE_READ_REAL_TIME CACHE INTERNAL "")
@@ -21,7 +21,6 @@
#cmakedefine _GNU_SOURCE 1
#cmakedefine HAVE_ALLOCA_H 1
#cmakedefine HAVE_ARPA_INET_H 1
#cmakedefine HAVE_ASM_MSR_H 1
#cmakedefine HAVE_ASM_TERMBITS_H 1
#cmakedefine HAVE_CRYPT_H 1
#cmakedefine HAVE_CURSES_H 1
@@ -186,7 +185,6 @@
#cmakedefine HAVE_POSIX_FALLOCATE 1
#cmakedefine HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE 1
#cmakedefine HAVE_PREAD 1
#cmakedefine HAVE_RDTSCLL 1
#cmakedefine HAVE_READ_REAL_TIME 1
#cmakedefine HAVE_PTHREAD_ATTR_CREATE 1
#cmakedefine HAVE_PTHREAD_ATTR_GETGUARDSIZE 1
@@ -437,8 +437,6 @@ SET(CMAKE_REQUIRED_FLAGS)
CHECK_INCLUDE_FILES(time.h HAVE_TIME_H)
CHECK_INCLUDE_FILES(sys/time.h HAVE_SYS_TIME_H)
CHECK_INCLUDE_FILES(sys/times.h HAVE_SYS_TIMES_H)
CHECK_INCLUDE_FILES(asm/msr.h HAVE_ASM_MSR_H)
#msr.h has rdtscll()

CHECK_INCLUDE_FILES(ia64intrin.h HAVE_IA64INTRIN_H)

@@ -453,9 +451,6 @@ CHECK_FUNCTION_EXISTS(ftime HAVE_FTIME)
CHECK_FUNCTION_EXISTS(time HAVE_TIME)
# We can use time() on Macintosh if there is no ftime().

CHECK_FUNCTION_EXISTS(rdtscll HAVE_RDTSCLL)
# I doubt that we'll ever reach the check for this.


#
# Tests for symbols
@@ -1,5 +1,5 @@
/* Copyright (c) 2008 MySQL AB, 2009 Sun Microsystems, Inc.
Use is subject to license terms.
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
@@ -23,6 +23,20 @@
#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.
*/
@@ -62,12 +76,104 @@ C_MODE_START

/**
A cycle timer.
On clang, we use __builtin_readcyclecounter().
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.
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.
*/
ulonglong my_timer_cycles(void);
static inline ulonglong my_timer_cycles(void)
{
# if __has_builtin(__builtin_readcyclecounter)
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(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
/* gethrtime may appear as either cycle or nanosecond counter */
return (ulonglong) gethrtime();
#else
return 0;
#endif
}

/**
A namoseconds timer.
A nanosecond timer.
@return the current timer value, in nanoseconds.
*/
ulonglong my_timer_nanoseconds(void);
@@ -98,33 +204,22 @@ void my_timer_init(MY_TIMER_INFO *mti);

C_MODE_END

#define MY_TIMER_ROUTINE_ASM_X86 1
#define MY_TIMER_ROUTINE_ASM_X86_64 2
#define MY_TIMER_ROUTINE_RDTSCLL 3
#define MY_TIMER_ROUTINE_ASM_X86_WIN 4
#define MY_TIMER_ROUTINE_RDTSC 5
#define MY_TIMER_ROUTINE_ASM_IA64 6
#define MY_TIMER_ROUTINE_ASM_PPC 7
#define MY_TIMER_ROUTINE_SGI_CYCLE 8
#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_NXGETTIME 12
#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_PPC64 19
#define MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC64 20
#define MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC32 21
#define MY_TIMER_ROUTINE_ASM_SUNPRO_I386 22
#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_SUNPRO_X86_64 27
#define MY_TIMER_ROUTINE_ASM_S390 28

#endif
@@ -59,12 +59,6 @@ IF(HAVE_ALARM)
SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_alarm.c)
ENDIF()

IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_C_COMPILER_ID MATCHES "SunPro")
# Inline assembly template for rdtsc
SET_SOURCE_FILES_PROPERTIES(my_rdtsc.c
PROPERTIES COMPILE_FLAGS "${CMAKE_CURRENT_SOURCE_DIR}/my_timer_cycles.il")
ENDIF()

IF(HAVE_LINUX_LARGE_PAGES)
SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_largepage.c)
ENDIF()
@@ -16,19 +16,12 @@
#include <my_global.h>
#include <my_atomic.h>
#include <my_cpu.h>
#include <my_rdtsc.h>

#ifdef HAVE_PAUSE_INSTRUCTION
/** How many times to invoke PAUSE in a loop */
unsigned my_cpu_relax_multiplier = 200;

# include <stdint.h>

# ifdef _MSC_VER
# include <intrin.h>
# else
# include <x86intrin.h>
# endif

#define PAUSE4 MY_RELAX_CPU(); MY_RELAX_CPU(); MY_RELAX_CPU(); MY_RELAX_CPU()
#define PAUSE16 PAUSE4; PAUSE4; PAUSE4; PAUSE4

@@ -70,12 +63,12 @@ unsigned my_cpu_relax_multiplier = 200;
*/
void my_cpu_init(void)
{
uint64_t t0, t1, t2;
t0= __rdtsc();
ulonglong t0, t1, t2;
t0= my_timer_cycles();
PAUSE16;
t1= __rdtsc();
t1= my_timer_cycles();
PAUSE16;
t2= __rdtsc();
t2= my_timer_cycles();
if (t2 - t1 > 30 * 16 && t1 - t0 > 30 * 16)
my_cpu_relax_multiplier= 20;
}

0 comments on commit 5e929ee

Please sign in to comment.
You can’t perform that action at this time.