10b57cec5SDimitry Andric //===-- xray_tsc.h ----------------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file is a part of XRay, a dynamic runtime instrumentation system. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric #ifndef XRAY_EMULATE_TSC_H 130b57cec5SDimitry Andric #define XRAY_EMULATE_TSC_H 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric namespace __xray { 180b57cec5SDimitry Andric static constexpr uint64_t NanosecondsPerSecond = 1000ULL * 1000 * 1000; 190b57cec5SDimitry Andric } 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric #if SANITIZER_FUCHSIA 220b57cec5SDimitry Andric #include <zircon/syscalls.h> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace __xray { 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT { 290b57cec5SDimitry Andric CPU = 0; 300b57cec5SDimitry Andric return _zx_ticks_get(); 310b57cec5SDimitry Andric } 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { 340b57cec5SDimitry Andric return _zx_ticks_per_second(); 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric } // namespace __xray 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric #else // SANITIZER_FUCHSIA 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric #if defined(__x86_64__) 420b57cec5SDimitry Andric #include "xray_x86_64.inc" 430b57cec5SDimitry Andric #elif defined(__powerpc64__) 440b57cec5SDimitry Andric #include "xray_powerpc64.inc" 45*0eae32dcSDimitry Andric #elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 46*0eae32dcSDimitry Andric defined(__hexagon__) 470b57cec5SDimitry Andric // Emulated TSC. 480b57cec5SDimitry Andric // There is no instruction like RDTSCP in user mode on ARM. ARM's CP15 does 490b57cec5SDimitry Andric // not have a constant frequency like TSC on x86(_64), it may go faster 500b57cec5SDimitry Andric // or slower depending on CPU turbo or power saving mode. Furthermore, 510b57cec5SDimitry Andric // to read from CP15 on ARM a kernel modification or a driver is needed. 520b57cec5SDimitry Andric // We can not require this from users of compiler-rt. 530b57cec5SDimitry Andric // So on ARM we use clock_gettime() which gives the result in nanoseconds. 540b57cec5SDimitry Andric // To get the measurements per second, we scale this by the number of 550b57cec5SDimitry Andric // nanoseconds per second, pretending that the TSC frequency is 1GHz and 560b57cec5SDimitry Andric // one TSC tick is 1 nanosecond. 570b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 580b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h" 590b57cec5SDimitry Andric #include "xray_defs.h" 600b57cec5SDimitry Andric #include <cerrno> 610b57cec5SDimitry Andric #include <cstdint> 620b57cec5SDimitry Andric #include <time.h> 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric namespace __xray { 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT { 690b57cec5SDimitry Andric timespec TS; 700b57cec5SDimitry Andric int result = clock_gettime(CLOCK_REALTIME, &TS); 710b57cec5SDimitry Andric if (result != 0) { 720b57cec5SDimitry Andric Report("clock_gettime(2) returned %d, errno=%d.", result, int(errno)); 730b57cec5SDimitry Andric TS.tv_sec = 0; 740b57cec5SDimitry Andric TS.tv_nsec = 0; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric CPU = 0; 770b57cec5SDimitry Andric return TS.tv_sec * NanosecondsPerSecond + TS.tv_nsec; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT { 810b57cec5SDimitry Andric return NanosecondsPerSecond; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric } // namespace __xray 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric #else 870b57cec5SDimitry Andric #error Target architecture is not supported. 880b57cec5SDimitry Andric #endif // CPU architecture 890b57cec5SDimitry Andric #endif // SANITIZER_FUCHSIA 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric #endif // XRAY_EMULATE_TSC_H 92