diff --git a/common/include/villas/tsc.hpp b/common/include/villas/tsc.hpp index ca8c1bf26..ce8496d04 100644 --- a/common/include/villas/tsc.hpp +++ b/common/include/villas/tsc.hpp @@ -1,4 +1,4 @@ -/* Measure time and sleep with IA-32 time-stamp counter. +/* Measure time and sleep with IA-32 time-stamp counter (x86) or a generic cycle-based timing. * * Author: Steffen Vogel * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University @@ -7,11 +7,10 @@ #pragma once -#if !(__x86_64__ || __i386__) -#error this header is for x86 only -#endif - #include + +#if defined(__x86_64__) || defined(__i386__) + #include #include @@ -24,17 +23,41 @@ #define bit_TSC_INVARIANT (1 << 8) #define bit_RDTSCP (1 << 27) +#else + +#include + +#ifndef NSEC_PER_SEC +#define NSEC_PER_SEC 1000000000L +#endif + +#ifndef CLOCK_MONOTONIC_RAW +#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC // Fallback for macOS/BSD +#endif + +#endif + struct Tsc { uint64_t frequency; - +#if defined(__x86_64__) || defined(__i386__) bool rdtscp_supported; bool is_invariant; +#endif }; +#if defined(__x86_64__) || defined(__i386__) __attribute__((unused)) static uint64_t tsc_now(struct Tsc *t) { uint32_t tsc_aux; return t->rdtscp_supported ? __rdtscp(&tsc_aux) : __rdtsc(); } +#else +// Fallback for CLOCK_MONOTONIC_RAW (linux/BSD/mac specific) +__attribute__((unused)) static uint64_t tsc_now(struct Tsc *t) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + return (ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec) * t->frequency / NSEC_PER_SEC; +} +#endif int tsc_init(struct Tsc *t) __attribute__((warn_unused_result)); diff --git a/common/lib/CMakeLists.txt b/common/lib/CMakeLists.txt index 74581897c..0f9680bfb 100644 --- a/common/lib/CMakeLists.txt +++ b/common/lib/CMakeLists.txt @@ -33,10 +33,6 @@ add_library(villas-common SHARED version.cpp ) -if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - target_sources(villas-common PRIVATE tsc.cpp) -endif() - if(CMAKE_SYSTEM_NAME STREQUAL Linux) target_sources(villas-common PRIVATE kernel/devices/ip_device.cpp @@ -46,6 +42,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux) kernel/vfio_device.cpp kernel/vfio_group.cpp kernel/vfio_container.cpp + tsc.cpp ) endif() diff --git a/common/lib/tsc.cpp b/common/lib/tsc.cpp index c132caeff..b097652d2 100644 --- a/common/lib/tsc.cpp +++ b/common/lib/tsc.cpp @@ -7,9 +7,8 @@ #include -using namespace villas; - int tsc_init(struct Tsc *t) { +#if defined(__x86_64__) || defined(__i386__) uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; // Check if TSC is supported @@ -32,15 +31,25 @@ int tsc_init(struct Tsc *t) { if (ecx != 0) t->frequency = ecx * ebx / eax; else { - int ret; #ifdef __linux__ - ret = kernel::get_cpu_frequency(&t->frequency); + int ret = kernel::get_cpu_frequency(&t->frequency); if (ret) return ret; #endif } - - return 0; +#elif defined(__aarch64__) + // Read counter frequency from system register + uint64_t cntfrq; + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + t->frequency = cntfrq; +#else +#ifdef __linux__ + int ret = kernel::get_cpu_frequency(&t->frequency); + if (ret) + return ret; +#endif +#endif + return (int)(t->frequency); } uint64_t tsc_rate_to_cycles(struct Tsc *t, double rate) {