diff --git a/arch/arm/core/aarch32/cortex_m/timing.c b/arch/arm/core/aarch32/cortex_m/timing.c index 9647025ecb..ae9b029b03 100644 --- a/arch/arm/core/aarch32/cortex_m/timing.c +++ b/arch/arm/core/aarch32/cortex_m/timing.c @@ -121,48 +121,48 @@ static inline uint64_t z_arm_dwt_freq_get(void) #endif /* CONFIG_SOC_FAMILY_NRF */ } -void timing_init(void) +void arch_timing_init(void) { z_arm_dwt_init(NULL); } -void timing_start(void) +void arch_timing_start(void) { z_arm_dwt_cycle_count_start(); } -void timing_stop(void) +void arch_timing_stop(void) { DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; } -timing_t timing_counter_get(void) +timing_t arch_timing_counter_get(void) { return (timing_t)z_arm_dwt_get_cycles(); } -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t arch_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) { return (*end - *start); } -uint64_t timing_freq_get(void) +uint64_t arch_timing_freq_get(void) { return z_arm_dwt_freq_get(); } -uint64_t timing_cycles_to_ns(uint64_t cycles) +uint64_t arch_timing_cycles_to_ns(uint64_t cycles) { - return (cycles) * (NSEC_PER_USEC) / timing_freq_get_mhz(); + return (cycles) * (NSEC_PER_USEC) / arch_timing_freq_get_mhz(); } -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) { - return timing_cycles_to_ns(cycles) / count; + return arch_timing_cycles_to_ns(cycles) / count; } -uint32_t timing_freq_get_mhz(void) +uint32_t arch_timing_freq_get_mhz(void) { - return (uint32_t)(timing_freq_get() / 1000000); + return (uint32_t)(arch_timing_freq_get() / 1000000); } diff --git a/arch/common/timing.c b/arch/common/timing.c index 77ed1dfe09..72b0f053e3 100644 --- a/arch/common/timing.c +++ b/arch/common/timing.c @@ -8,46 +8,46 @@ #include #include -void timing_init(void) +void arch_timing_init(void) { } -void timing_start(void) +void arch_timing_start(void) { } -void timing_stop(void) +void arch_timing_stop(void) { } -timing_t timing_counter_get(void) +timing_t arch_timing_counter_get(void) { return k_cycle_get_32(); } -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t arch_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) { return (*end - *start); } -uint64_t timing_freq_get(void) +uint64_t arch_timing_freq_get(void) { return sys_clock_hw_cycles_per_sec(); } -uint64_t timing_cycles_to_ns(uint64_t cycles) +uint64_t arch_timing_cycles_to_ns(uint64_t cycles) { return k_cyc_to_ns_floor64(cycles); } -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) { - return timing_cycles_to_ns(cycles) / count; + return arch_timing_cycles_to_ns(cycles) / count; } -uint32_t timing_freq_get_mhz(void) +uint32_t arch_timing_freq_get_mhz(void) { - return (uint32_t)(timing_freq_get() / 1000000); + return (uint32_t)(arch_timing_freq_get() / 1000000); } diff --git a/arch/nios2/core/timing.c b/arch/nios2/core/timing.c index ebd4fa3a14..bae3320aaa 100644 --- a/arch/nios2/core/timing.c +++ b/arch/nios2/core/timing.c @@ -20,46 +20,46 @@ << 16) | \ ((uint32_t)IORD_ALTERA_AVALON_TIMER_SNAPL(TIMER_0_BASE)))) -void timing_init(void) +void arch_timing_init(void) { } -void timing_start(void) +void arch_timing_start(void) { } -void timing_stop(void) +void arch_timing_stop(void) { } -timing_t timing_counter_get(void) +timing_t arch_timing_counter_get(void) { IOWR_ALTERA_AVALON_TIMER_SNAPL(TIMER_0_BASE, 10); return TIMING_INFO_OS_GET_TIME(); } -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t arch_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) { return (*end - *start); } -uint64_t timing_freq_get(void) +uint64_t arch_timing_freq_get(void) { return sys_clock_hw_cycles_per_sec(); } -uint64_t timing_cycles_to_ns(uint64_t cycles) +uint64_t arch_timing_cycles_to_ns(uint64_t cycles) { return k_cyc_to_ns_floor64(cycles); } -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) { - return timing_cycles_to_ns(cycles) / count; + return arch_timing_cycles_to_ns(cycles) / count; } -uint32_t timing_freq_get_mhz(void) +uint32_t arch_timing_freq_get_mhz(void) { - return (uint32_t)(timing_freq_get() / 1000000); + return (uint32_t)(arch_timing_freq_get() / 1000000); } diff --git a/arch/x86/timing.c b/arch/x86/timing.c index 42051a6466..f608fac539 100644 --- a/arch/x86/timing.c +++ b/arch/x86/timing.c @@ -11,7 +11,7 @@ static uint64_t tsc_freq; -void timing_x86_init(void) +void arch_timing_x86_init(void) { uint32_t cyc_start = k_cycle_get_32(); uint64_t tsc_start = z_tsc_read(); @@ -35,51 +35,52 @@ void timing_x86_init(void) tsc_freq = (cyc_freq * dtsc) / dcyc; } -uint64_t timing_x86_freq_get(void) +uint64_t arch_timing_x86_freq_get(void) { return tsc_freq; } -void timing_init(void) +void arch_timing_init(void) { - timing_x86_init(); + arch_timing_x86_init(); } -void timing_start(void) + +void arch_timing_start(void) { } -void timing_stop(void) +void arch_timing_stop(void) { } -timing_t timing_counter_get(void) +timing_t arch_timing_counter_get(void) { return k_cycle_get_32(); } -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t arch_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) { return (*end - *start); } -uint64_t timing_freq_get(void) +uint64_t arch_timing_freq_get(void) { - return timing_x86_freq_get(); + return arch_timing_x86_freq_get(); } -uint64_t timing_cycles_to_ns(uint64_t cycles) +uint64_t arch_timing_cycles_to_ns(uint64_t cycles) { return k_cyc_to_ns_floor64(cycles); } -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) { - return timing_cycles_to_ns(cycles) / count; + return arch_timing_cycles_to_ns(cycles) / count; } -uint32_t timing_freq_get_mhz(void) +uint32_t arch_timing_freq_get_mhz(void) { - return (uint32_t)(timing_freq_get() / 1000000); + return (uint32_t)(arch_timing_freq_get() / 1000000); } diff --git a/include/sys/arch_interface.h b/include/sys/arch_interface.h index d8f28715e8..cb45990ec1 100644 --- a/include/sys/arch_interface.h +++ b/include/sys/arch_interface.h @@ -845,6 +845,109 @@ size_t arch_cache_line_size_get(void); #endif /** @} */ +#ifdef CONFIG_TIMING_FUNCTIONS +#include + +/** + * @ingroup arch-interface timing_api + */ + +/** + * @brief Initialize the timing subsystem. + * + * Perform the necessary steps to initialize the timing subsystem. + * + * @see timing_init() + */ +void arch_timing_init(void); + +/** + * @brief Signal the start of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * will be gathered from this point forward. + * + * @see timing_start() + */ +void arch_timing_start(void); + +/** + * @brief Signal the end of the timing information gathering. + * + * Signal to the timing subsystem that timing information + * is no longer being gathered from this point forward. + * + * @see timing_stop() + */ +void arch_timing_stop(void); + +/** + * @brief Return timing counter. + * + * @return Timing counter. + * + * @see timing_counter_get() + */ +timing_t arch_timing_counter_get(void); + +/** + * @brief Get number of cycles between @p start and @p end. + * + * For some architectures or SoCs, the raw numbers from counter + * need to be scaled to obtain actual number of cycles. + * + * @param start Pointer to counter at start of a measured execution. + * @param end Pointer to counter at stop of a measured execution. + * @return Number of cycles between start and end. + * + * @see timing_cycles_get() + */ +uint64_t arch_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end); + +/** + * @brief Get frequency of counter used (in Hz). + * + * @return Frequency of counter used for timing in Hz. + * + * @see timing_freq_get() + */ +uint64_t arch_timing_freq_get(void); + +/** + * @brief Convert number of @p cycles into nanoseconds. + * + * @param cycles Number of cycles + * @return Converted time value + * + * @see timing_cycles_to_ns() + */ +uint64_t arch_timing_cycles_to_ns(uint64_t cycles); + +/** + * @brief Convert number of @p cycles into nanoseconds with averaging. + * + * @param cycles Number of cycles + * @param count Times of accumulated cycles to average over + * @return Converted time value + * + * @see timing_cycles_to_ns_avg() + */ +uint64_t arch_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); + +/** + * @brief Get frequency of counter used (in MHz). + * + * @return Frequency of counter used for timing in MHz. + * + * @see timing_freq_get_mhz() + */ +uint32_t arch_timing_freq_get_mhz(void); + +/* @} */ + +#endif /* CONFIG_TIMING_FUNCTIONS */ + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/timing/timing.h b/include/timing/timing.h index 059ead1b49..e46ac3f4d4 100644 --- a/include/timing/timing.h +++ b/include/timing/timing.h @@ -7,7 +7,30 @@ #ifndef ZEPHYR_INCLUDE_TIMING_TIMING_H_ #define ZEPHYR_INCLUDE_TIMING_TIMING_H_ -#include +#include +#include + +void soc_timing_init(void); +void soc_timing_start(void); +void soc_timing_stop(void); +timing_t soc_timing_counter_get(void); +uint64_t soc_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end); +uint64_t soc_timing_freq_get(void); +uint64_t soc_timing_cycles_to_ns(uint64_t cycles); +uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); +uint32_t soc_timing_freq_get_mhz(void); + +void board_timing_init(void); +void board_timing_start(void); +void board_timing_stop(void); +timing_t board_timing_counter_get(void); +uint64_t board_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end); +uint64_t board_timing_freq_get(void); +uint64_t board_timing_cycles_to_ns(uint64_t cycles); +uint64_t board_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); +uint32_t board_timing_freq_get_mhz(void); /** @@ -17,8 +40,6 @@ */ -typedef uint64_t timing_t; - /** * @brief Initialize the timing subsystem. * @@ -47,7 +68,16 @@ void timing_stop(void); * * @return Timing counter. */ -timing_t timing_counter_get(void); +static inline timing_t timing_counter_get(void) +{ +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + return board_timing_counter_get(); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + return soc_timing_counter_get(); +#else + return arch_timing_counter_get(); +#endif +} /** * @brief Get number of cycles between @p start and @p end. @@ -59,15 +89,33 @@ timing_t timing_counter_get(void); * @param end Pointer to counter at stop of a measured execution. * @return Number of cycles between start and end. */ -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end); +static inline uint64_t timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) +{ +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + return board_timing_cycles_get(start, end); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + return soc_timing_cycles_get(start, end); +#else + return arch_timing_cycles_get(start, end); +#endif +} /** * @brief Get frequency of counter used (in Hz). * * @return Frequency of counter used for timing in Hz. */ -uint64_t timing_freq_get(void); +static inline uint64_t timing_freq_get(void) +{ +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + return board_timing_freq_get(); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + return soc_timing_freq_get(); +#else + return arch_timing_freq_get(); +#endif +} /** * @brief Convert number of @p cycles into nanoseconds. @@ -75,16 +123,50 @@ uint64_t timing_freq_get(void); * @param cycles Number of cycles * @return Converted time value */ -uint64_t timing_cycles_to_ns(uint64_t cycles); +static inline uint64_t timing_cycles_to_ns(uint64_t cycles) +{ +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + return board_timing_cycles_to_ns(cycles); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + return soc_timing_cycles_to_ns(cycles); +#else + return arch_timing_cycles_to_ns(cycles); +#endif +} -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count); +/** + * @brief Convert number of @p cycles into nanoseconds with averaging. + * + * @param cycles Number of cycles + * @param count Times of accumulated cycles to average over + * @return Converted time value + */ +static inline uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +{ +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + return board_timing_cycles_to_ns_avg(cycles, count); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + return soc_timing_cycles_to_ns_avg(cycles, count); +#else + return arch_timing_cycles_to_ns_avg(cycles, count); +#endif +} /** * @brief Get frequency of counter used (in MHz). * * @return Frequency of counter used for timing in MHz. */ -uint32_t timing_freq_get_mhz(void); +static inline uint32_t timing_freq_get_mhz(void) +{ +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + return board_timing_freq_get_mhz(); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + return soc_timing_freq_get_mhz(); +#else + return arch_timing_freq_get_mhz(); +#endif +} /** * @} diff --git a/include/timing/types.h b/include/timing/types.h new file mode 100644 index 0000000000..6196dd53be --- /dev/null +++ b/include/timing/types.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_TIMING_TYPES_H_ +#define ZEPHYR_INCLUDE_TIMING_TYPES_H_ + +typedef uint64_t timing_t; + +#endif /* ZEPHYR_INCLUDE_TIMING_TYPES_H_ */ diff --git a/soc/arm/microchip_mec/mec1501/timing.c b/soc/arm/microchip_mec/mec1501/timing.c index e2a918eac1..5ce2892550 100644 --- a/soc/arm/microchip_mec/mec1501/timing.c +++ b/soc/arm/microchip_mec/mec1501/timing.c @@ -10,7 +10,7 @@ #include #include -void timing_init(void) +void soc_timing_init(void) { /* Setup counter */ B32TMR1_REGS->CTRL = MCHP_BTMR_CTRL_ENABLE | @@ -24,43 +24,43 @@ void timing_init(void) B32TMR1_REGS->STS = 1; /* Clear interrupt */ } -void timing_start(void) +void soc_timing_start(void) { B32TMR1_REGS->CTRL |= MCHP_BTMR_CTRL_START; } -void timing_stop(void) +void soc_timing_stop(void) { B32TMR1_REGS->CTRL &= ~MCHP_BTMR_CTRL_START; } -timing_t timing_counter_get(void) +timing_t soc_timing_counter_get(void) { return B32TMR1_REGS->CNT; } -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t soc_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) { return (*end - *start); } -uint64_t timing_freq_get(void) +uint64_t soc_timing_freq_get(void) { return CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; } -uint64_t timing_cycles_to_ns(uint64_t cycles) +uint64_t soc_timing_cycles_to_ns(uint64_t cycles) { return (cycles) * (NSEC_PER_SEC) / (CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); } -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) { - return (uint32_t)timing_cycles_to_ns(cycles) / count; + return (uint32_t)soc_timing_cycles_to_ns(cycles) / count; } -uint32_t timing_freq_get_mhz(void) +uint32_t soc_timing_freq_get_mhz(void) { - return (uint32_t)(timing_freq_get() / 1000000); + return (uint32_t)(soc_timing_freq_get() / 1000000); } diff --git a/soc/arm/nordic_nrf/Kconfig.defconfig b/soc/arm/nordic_nrf/Kconfig.defconfig index e89d92e6ed..3cf69684c5 100644 --- a/soc/arm/nordic_nrf/Kconfig.defconfig +++ b/soc/arm/nordic_nrf/Kconfig.defconfig @@ -33,7 +33,7 @@ config SYS_POWER_MANAGEMENT config BUILD_OUTPUT_HEX default y -if !CORTEX_M_DWT +if !CORTEX_M_DWT && NRF_RTC_TIMER config SOC_HAS_TIMING_FUNCTIONS default y endif diff --git a/soc/arm/nordic_nrf/timing.c b/soc/arm/nordic_nrf/timing.c index cc336b4ee5..6619d6ed15 100644 --- a/soc/arm/nordic_nrf/timing.c +++ b/soc/arm/nordic_nrf/timing.c @@ -14,7 +14,7 @@ #define CYCLES_PER_SEC (16000000 / (1 << NRF_TIMER2->PRESCALER)) -void timing_init(void) +void soc_timing_init(void) { NRF_TIMER2->TASKS_CLEAR = 1; /* Clear Timer */ NRF_TIMER2->MODE = 0; /* Timer Mode */ @@ -26,24 +26,24 @@ void timing_init(void) #endif } -void timing_start(void) +void soc_timing_start(void) { NRF_TIMER2->TASKS_START = 1; } -void timing_stop(void) +void soc_timing_stop(void) { NRF_TIMER2->TASKS_STOP = 1; /* Stop Timer */ } -timing_t timing_counter_get(void) +timing_t soc_timing_counter_get(void) { NRF_TIMER2->TASKS_CAPTURE[0] = 1; return NRF_TIMER2->CC[0] * ((SystemCoreClock) / CYCLES_PER_SEC); } -uint64_t timing_cycles_get(volatile timing_t *const start, - volatile timing_t *const end) +uint64_t soc_timing_cycles_get(volatile timing_t *const start, + volatile timing_t *const end) { #if defined(CONFIG_SOC_SERIES_NRF51X) #define COUNTER_SPAN BIT(16) @@ -57,24 +57,24 @@ uint64_t timing_cycles_get(volatile timing_t *const start, #endif } -uint64_t timing_freq_get(void) +uint64_t soc_timing_freq_get(void) { return SystemCoreClock; } -uint64_t timing_cycles_to_ns(uint64_t cycles) +uint64_t soc_timing_cycles_to_ns(uint64_t cycles) { return (cycles) * (NSEC_PER_SEC) / (SystemCoreClock); } -uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) +uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count) { - return timing_cycles_to_ns(cycles) / count; + return soc_timing_cycles_to_ns(cycles) / count; } -uint32_t timing_freq_get_mhz(void) +uint32_t soc_timing_freq_get_mhz(void) { - return (uint32_t)(timing_freq_get() / 1000000); + return (uint32_t)(soc_timing_freq_get() / 1000000); } #endif diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index c7f74c9783..d528abafbf 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -24,3 +24,4 @@ add_subdirectory(testsuite) add_subdirectory(tracing) add_subdirectory_ifdef(CONFIG_JWT jwt) add_subdirectory(canbus) +add_subdirectory_ifdef(CONFIG_TIMING_FUNCTIONS timing) diff --git a/subsys/timing/CMakeLists.txt b/subsys/timing/CMakeLists.txt new file mode 100644 index 0000000000..dae6521c2a --- /dev/null +++ b/subsys/timing/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2020 Intel Corporation. +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(timing.c) diff --git a/subsys/timing/timing.c b/subsys/timing/timing.c new file mode 100644 index 0000000000..8472b909f0 --- /dev/null +++ b/subsys/timing/timing.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +static bool has_inited; +static atomic_val_t started_ref; + +void timing_init(void) +{ + if (has_inited) { + return; + } + +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + board_timing_init(); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + soc_timing_init(); +#else + arch_timing_init(); +#endif + + has_inited = true; +} + +void timing_start(void) +{ + if (atomic_inc(&started_ref) != 0) { + return; + } + +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + board_timing_start(); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + soc_timing_start(); +#else + arch_timing_start(); +#endif +} + +void timing_stop(void) +{ + if (atomic_dec(&started_ref) > 1) { + return; + } + +#if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS) + board_timing_stop(); +#elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS) + soc_timing_stop(); +#else + arch_timing_stop(); +#endif +}