* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#ifndef MEMFABRIC_HYBRID_MONOTONIC_H
#define MEMFABRIC_HYBRID_MONOTONIC_H
#include <cstdio>
#include <cstdint>
#include <ctime>
namespace shm {
namespace store {
class MonotonicTime {
public:
* @brief Get monotonic time in us, is not absolution time
*/
static inline uint64_t TimeUs();
* @brief Get monotonic time in ns, is not absolution time
*/
static inline uint64_t TimeNs();
private:
template <uint64_t FAILURE_RET>
static uint64_t InitTickUs();
};
class MonoPerfTrace {
public:
MonoPerfTrace();
~MonoPerfTrace() = default;
* @brief Record start time
*/
void RecordStart() noexcept;
* @brief Record end time
*/
void RecordEnd() noexcept;
* @brief Get period in ns
*/
uint64_t PeriodNs() const noexcept;
* @brief Get period in us
*/
uint64_t PeriodUs() const noexcept;
* @brief Get period in ms
*/
uint64_t PeriodMs() const noexcept;
public:
uint64_t start = 0;
uint64_t end = 0;
};
#if defined(ENABLE_CPU_MONOTONIC) && defined(__aarch64__)
template <uint64_t FAILURE_RET>
inline uint64_t MonotonicTime::InitTickUs()
{
uint64_t tmpFreq = 0;
__asm__ volatile("mrs %0, cntfrq_el0" : "=r"(tmpFreq));
uint64_t freq = tmpFreq;
freq = freq / 1000ULL / 1000ULL;
if (freq == 0) {
printf("Failed to get tick as freq is %llu\n", freq);
return FAILURE_RET;
}
return freq;
}
inline uint64_t MonotonicTime::TimeUs()
{
const static uint64_t TICK_PER_US = InitTickUs<1>();
uint64_t timeValue = 0;
__asm__ volatile("mrs %0, cntvct_el0" : "=r"(timeValue));
return timeValue / TICK_PER_US;
}
inline uint64_t MonotonicTime::TimeNs()
{
const static uint64_t TICK_PER_US = InitTickUs<1>();
uint64_t timeValue = 0;
__asm__ volatile("mrs %0, cntvct_el0" : "=r"(timeValue));
return timeValue * 1000ULL / TICK_PER_US;
}
#else
template <uint64_t FAILURE_RET>
uint64_t MonotonicTime::InitTickUs()
{
return 0;
}
inline uint64_t MonotonicTime::TimeUs()
{
struct timespec ts{};
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<uint64_t>(ts.tv_sec) * 1000000L + static_cast<uint64_t>(ts.tv_nsec) / 1000L;
}
inline uint64_t MonotonicTime::TimeNs()
{
struct timespec ts{};
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<uint64_t>(ts.tv_sec) * 1000000000L + static_cast<uint64_t>(ts.tv_nsec);
}
#endif
inline MonoPerfTrace::MonoPerfTrace()
{
RecordStart();
}
inline void MonoPerfTrace::RecordStart() noexcept
{
start = MonotonicTime::TimeNs();
}
inline void MonoPerfTrace::RecordEnd() noexcept
{
end = MonotonicTime::TimeNs();
}
inline uint64_t MonoPerfTrace::PeriodNs() const noexcept
{
return end - start;
}
inline uint64_t MonoPerfTrace::PeriodUs() const noexcept
{
return (end - start) / 1000L;
}
inline uint64_t MonoPerfTrace::PeriodMs() const noexcept
{
return (end - start) / 100000L;
}
}
}
#endif