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
probeRequiredCPUFeatures()260b57cec5SDimitry Andric inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
270b57cec5SDimitry Andric
readTSC(uint8_t & CPU)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
getTSCFrequency()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"
450eae32dcSDimitry Andric #elif defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
46*06c3fb27SDimitry Andric defined(__hexagon__) || defined(__loongarch_lp64)
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
probeRequiredCPUFeatures()660b57cec5SDimitry Andric inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
670b57cec5SDimitry Andric
readTSC(uint8_t & CPU)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
getTSCFrequency()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