From 4db9c82729c1e90aa488fda13452559c09568d63 Mon Sep 17 00:00:00 2001 From: Sergey Grivskiy Date: Thu, 8 Dec 2016 13:42:43 +0300 Subject: [PATCH 1/2] fix: wrong results for ARM: empty getCurrentTime() for ARM and other architectures --- easy_profiler_core/current_time.h | 91 +++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/easy_profiler_core/current_time.h b/easy_profiler_core/current_time.h index 3579323..d7492ae 100644 --- a/easy_profiler_core/current_time.h +++ b/easy_profiler_core/current_time.h @@ -40,6 +40,9 @@ along with this program.If not, see . #else #include #include +#ifdef __ARM_ARCH +#include +#endif//__ARM_ARCH #endif static inline profiler::timestamp_t getCurrentTime() @@ -50,23 +53,89 @@ static inline profiler::timestamp_t getCurrentTime() if (!QueryPerformanceCounter(&elapsedMicroseconds)) return 0; return (profiler::timestamp_t)elapsedMicroseconds.QuadPart; -#else +#else// not _WIN32 #if (defined(__GNUC__) || defined(__ICC)) + // part of code from google/benchmark library (Licensed under the Apache License, Version 2.0) + // see https://github.com/google/benchmark/blob/master/src/cycleclock.h#L111 #if defined(__i386__) - unsigned long long t; - __asm__ __volatile__("rdtsc" : "=A"(t)); - return t; - #elif defined(__x86_64__) - unsigned int hi, lo; - __asm__ __volatile__("rdtsc" : "=a" (lo), "=d" (hi)); - return ((uint64_t)hi << 32) | lo; - #endif + int64_t ret; + __asm__ volatile("rdtsc" : "=A"(ret)); + return ret; + #elif defined(__x86_64__) || defined(__amd64__) + uint64_t low, high; + __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); + return (high << 32) | low; + #elif defined(__powerpc__) || defined(__ppc__) + // This returns a time-base, which is not always precisely a cycle-count. + int64_t tbl, tbu0, tbu1; + asm("mftbu %0" : "=r"(tbu0)); + asm("mftb %0" : "=r"(tbl)); + asm("mftbu %0" : "=r"(tbu1)); + tbl &= -static_cast(tbu0 == tbu1); + // high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage) + return (tbu1 << 32) | tbl; + #elif defined(__sparc__) + int64_t tick; + asm(".byte 0x83, 0x41, 0x00, 0x00"); + asm("mov %%g1, %0" : "=r"(tick)); + return tick; + #elif defined(__ia64__) + int64_t itc; + asm("mov %0 = ar.itc" : "=r"(itc)); + return itc; + #elif defined(COMPILER_MSVC) && defined(_M_IX86) + // Older MSVC compilers (like 7.x) don't seem to support the + // __rdtsc intrinsic properly, so I prefer to use _asm instead + // when I know it will work. Otherwise, I'll use __rdtsc and hope + // the code is being compiled with a non-ancient compiler. + _asm rdtsc + #elif defined(COMPILER_MSVC) + return __rdtsc(); + #elif defined(__aarch64__) + // System timer of ARMv8 runs at a different frequency than the CPU's. + // The frequency is fixed, typically in the range 1-50MHz. It can be + // read at CNTFRQ special register. We assume the OS has set up + // the virtual timer properly. + int64_t virtual_timer_value; + asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); + return virtual_timer_value; + #elif defined(__ARM_ARCH) + #if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount + uint32_t pmccntr; + uint32_t pmuseren; + uint32_t pmcntenset; + // Read the user mode perf monitor counter access permissions. + asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading perfmon counters for user mode code. + asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000ul) { // Is it counting? + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return static_cast(pmccntr) * 64; // Should optimize to << 6 + } + } + #endif + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + #elif defined(__mips__) + // mips apparently only allows rdtsc for superusers, so we fall + // back to gettimeofday. It's possible clock_gettime would be better. + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + #else + #warning You need to define fast getCurrentTime() for your OS and CPU + return std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); + #define USE_STD_CHRONO + #endif -#else +#else // not _WIN32, __GNUC__, __ICC + #warning You need to define fast getCurrentTime() for your OS and CPU return std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); -#define USE_STD_CHRONO + #define USE_STD_CHRONO #endif #endif From 63e036f11aae385230dd003847fcf88c5fe0b05e Mon Sep 17 00:00:00 2001 From: Sergey Grivskiy Date: Thu, 8 Dec 2016 14:22:14 +0300 Subject: [PATCH 2/2] custom core library name (for cross-platform build, like easy_profiler_eabihf), ex: "cmake -DLIB_NAME=easy_profiler_x64 ../easy_profiler_core" --- easy_profiler_core/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/easy_profiler_core/CMakeLists.txt b/easy_profiler_core/CMakeLists.txt index 0252192..b49ff27 100644 --- a/easy_profiler_core/CMakeLists.txt +++ b/easy_profiler_core/CMakeLists.txt @@ -1,5 +1,9 @@ project(easy_profiler) +IF (NOT DEFINED LIB_NAME) + SET(LIB_NAME ${PROJECT_NAME}) +ENDIF() + set(CPP_FILES block.cpp profile_manager.cpp @@ -85,10 +89,10 @@ if(WIN32) ) endif(WIN32) -add_library(${PROJECT_NAME} SHARED ${SOURCES} resources.rc) +add_library(${LIB_NAME} SHARED ${SOURCES} resources.rc) if(UNIX) set(PLATFORM_LIBS pthread) endif(UNIX) -target_link_libraries(${PROJECT_NAME} ${PLATFORM_LIBS}) +target_link_libraries(${LIB_NAME} ${PLATFORM_LIBS})