diff options
Diffstat (limited to 'source/hal')
23 files changed, 687 insertions, 742 deletions
diff --git a/source/hal/CMakeLists.txt b/source/hal/CMakeLists.txt index 19f152c..10016c2 100644 --- a/source/hal/CMakeLists.txt +++ b/source/hal/CMakeLists.txt @@ -30,20 +30,10 @@ project(${HAL_TARGET} # Create static library add_library(${HAL_TARGET} STATIC) -# Select which profile needs to be used: -if (${CMAKE_CROSSCOMPILING}) - set(PLATFORM_PROFILE bare-metal) -else() - set(PLATFORM_PROFILE native) -endif() - -set(PLATFORM_PROFILE_DIR source/profiles/${PLATFORM_PROFILE}) - ## Common include directories - public target_include_directories(${HAL_TARGET} PUBLIC - include - ${PLATFORM_PROFILE_DIR}/timer/include) + include) ## Common sources for all profiles target_sources(${HAL_TARGET} @@ -51,7 +41,7 @@ target_sources(${HAL_TARGET} source/hal.c source/data_psn.c source/data_acq.c - ${PLATFORM_PROFILE_DIR}/timer/platform_timer.c) + source/hal_timer.c) if (DEFINED VERIFY_TEST_OUTPUT) message(STATUS "Test output verification flag is: ${VERIFY_TEST_OUTPUT}") diff --git a/source/hal/include/timer.h b/source/hal/include/timer.h index 4429388..9910fcf 100644 --- a/source/hal/include/timer.h +++ b/source/hal/include/timer.h @@ -17,54 +17,20 @@ #ifndef HAL_TIMER_H #define HAL_TIMER_H -#include "platform_timer.h" - -/** Struct for describing the capabilities available for - * the timer provided by HAL */ -typedef struct _platform_timer_capability { - uint32_t npu_cycles: 1; - uint32_t cpu_cycles: 1; - uint32_t duration_ms: 1; - uint32_t duration_us: 1; -} timer_capability; +#include "platform_drivers.h" /* Platform package API */ +#include "user_input.h" /* PMU structs and API */ /* Structure to hold a platform specific timer implementation */ typedef struct _platform_timer { - int inited; /**< initialised or not */ - timer_capability cap; /**< capability of this timer */ - - /* reset the timer */ - void (* reset)(void); - - /* Gets the current time counter. */ - time_counter (* get_time_counter)(void); - - /* Gets the duration in milliseconds. */ - time_t (* get_duration_ms)(time_counter *start, time_counter *end); - - /* Gets duration in microseconds. */ - time_t (* get_duration_us)(time_counter *start, time_counter *end); - - /* Gets difference in CPU cycle counts. */ - uint64_t (* get_cpu_cycle_diff)(time_counter *start, time_counter *end); - - /* Gets the difference in terms of cycle counts for collected pmu counters. */ - int (* get_npu_cycles_diff)(time_counter *start, time_counter *end, - uint64_t* pmu_counters_values, size_t size); - - /* Wraps get_time_counter function with additional profiling - * initialisation, if required. */ - time_counter (* start_profiling)(void); - - /* Wraps get_time_counter function along with additional instructions when - * profiling ends, if required. */ - time_counter (* stop_profiling)(void); + int inited; /**< Initialised or not. */ + void (* reset)(void); /**< Reset the timer. */ + pmu_counters (* get_counters)(void); /**< Gets the current time counter. */ } platform_timer; /** * @brief Initialise the timer available for the platform. **/ -void init_timer(platform_timer *timer); +void init_timer(platform_timer* timer); #endif /* HAL_TIMER_H */ diff --git a/source/hal/source/components/npu/CMakeLists.txt b/source/hal/source/components/npu/CMakeLists.txt index c53dd02..9d0bf42 100644 --- a/source/hal/source/components/npu/CMakeLists.txt +++ b/source/hal/source/components/npu/CMakeLists.txt @@ -126,7 +126,8 @@ target_include_directories(${ETHOS_U_NPU_COMPONENT} target_sources(${ETHOS_U_NPU_COMPONENT} PRIVATE ethosu_npu_init.c - ethosu_cpu_cache.c) + ethosu_cpu_cache.c + ethosu_profiler.c) ## Add dependencies: target_link_libraries(${ETHOS_U_NPU_COMPONENT} PUBLIC diff --git a/source/hal/source/components/npu/ethosu_profiler.c b/source/hal/source/components/npu/ethosu_profiler.c new file mode 100644 index 0000000..3ac3497 --- /dev/null +++ b/source/hal/source/components/npu/ethosu_profiler.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022 Arm Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ethosu_profiler.h" +#include "log_macros.h" + +#include <string.h> + +extern struct ethosu_driver ethosu_drv; /* Default Arm Ethos-U NPU device driver object */ +static ethosu_pmu_counters npu_counters; /* NPU counter local instance */ + +/** + * @brief Gets the npu counter instance to be used. + * @return Pointer to the npu counter instance. + */ +static ethosu_pmu_counters* get_counter_instance(void) +{ + return &npu_counters; +} + +/** + * @brief Checks if the counter has overflown. + * @param pmu_counter_mask Mask for the event counter. + * @return true if overflow is detected, false otherwise. + */ +static bool counter_overflow(uint32_t pmu_counter_mask) +{ + /* Check for overflow: The idle counter is 32 bit while the + total cycle count is 64 bit. */ + const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS(ðosu_drv); + return pmu_counter_mask & overflow_status ? true : false; +} + +void ethosu_pmu_init(void) +{ + uint32_t i = 0; + uint32_t evt_mask = ETHOSU_PMU_CCNT_Msk; + ethosu_pmu_counters* counters = get_counter_instance(); + memset(counters, 0, sizeof(*counters)); + + /* Total counters = event counters + derived counters + total cycle count */ + counters->num_total_counters = ETHOSU_PROFILER_NUM_COUNTERS; + +#if ETHOSU_PMU_NCOUNTERS >= 4 + counters->npu_evt_counters[0].event_type = ETHOSU_PMU_NPU_IDLE; + counters->npu_evt_counters[0].event_mask = ETHOSU_PMU_CNT1_Msk; + counters->npu_evt_counters[0].name = "NPU IDLE"; + counters->npu_evt_counters[0].unit = "cycles"; + + counters->npu_evt_counters[1].event_type = ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED; + counters->npu_evt_counters[1].event_mask = ETHOSU_PMU_CNT2_Msk; + counters->npu_evt_counters[1].name = "NPU AXI0_RD_DATA_BEAT_RECEIVED"; + counters->npu_evt_counters[1].unit = "beats"; + + counters->npu_evt_counters[2].event_type = ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN; + counters->npu_evt_counters[2].event_mask = ETHOSU_PMU_CNT3_Msk; + counters->npu_evt_counters[2].name = "NPU AXI0_WR_DATA_BEAT_WRITTEN"; + counters->npu_evt_counters[2].unit = "beats"; + + counters->npu_evt_counters[3].event_type = ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED; + counters->npu_evt_counters[3].event_mask = ETHOSU_PMU_CNT4_Msk; + counters->npu_evt_counters[3].name = "NPU AXI1_RD_DATA_BEAT_RECEIVED"; + counters->npu_evt_counters[3].unit = "beats"; +#else /* ETHOSU_PMU_NCOUNTERS >= 4 */ + #error "NPU PMU expects a minimum of 4 available event triggered counters!" +#endif /* ETHOSU_PMU_NCOUNTERS >= 4 */ + +#if ETHOSU_DERIVED_NCOUNTERS >= 1 + counters->npu_derived_counters[0].name = "NPU ACTIVE"; + counters->npu_derived_counters[0].unit = "cycles"; +#endif /* ETHOSU_DERIVED_NCOUNTERS >= 1 */ + + for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) { + ETHOSU_PMU_Set_EVTYPER(ðosu_drv, i, counters->npu_evt_counters[i].event_type); + evt_mask |= counters->npu_evt_counters[i].event_mask; + } + + /* Reset overflow status. */ + ETHOSU_PMU_Set_CNTR_OVS(ðosu_drv, evt_mask); + + /* Enable PMU. */ + ETHOSU_PMU_Enable(ðosu_drv); + + /* Enable counters for cycle and event counters. */ + ETHOSU_PMU_CNTR_Disable(ðosu_drv, evt_mask); + ethosu_pmu_reset_counters(); + ETHOSU_PMU_CNTR_Enable(ðosu_drv, evt_mask); +} + +/** + * @brief Resets the Arm Ethos-U NPU PMU counters. + */ +void ethosu_pmu_reset_counters(void) +{ + /* Reset all cycle and event counters. */ + ETHOSU_PMU_CYCCNT_Reset(ðosu_drv); + ETHOSU_PMU_EVCNTR_ALL_Reset(ðosu_drv); +} + +/** + * @brief Get the Arm Ethos-U NPU PMU counters + * @return ethosu_pmu_counters + */ +ethosu_pmu_counters ethosu_get_pmu_counters(void) +{ + ethosu_pmu_counters* counters = get_counter_instance(); + uint32_t i = 0; + + /* Event counters */ + for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) { + if (counter_overflow(counters->npu_evt_counters[i].event_mask)) { + warn("Counter overflow detected for %s.\n", counters->npu_evt_counters[i].name); + } + counters->npu_evt_counters[i].counter_value = + ETHOSU_PMU_Get_EVCNTR(ðosu_drv, i); + } + + /* Total cycle count */ + counters->npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(ðosu_drv); + + /* Derived counters */ +#if ETHOSU_DERIVED_NCOUNTERS >= 1 + if (counters->npu_evt_counters[0].event_type == ETHOSU_PMU_NPU_IDLE) { + counters->npu_derived_counters[0].counter_value = + counters->npu_total_ccnt - counters->npu_evt_counters[0].counter_value; + } +#endif /* ETHOSU_DERIVED_NCOUNTERS >= 1 */ + + return *counters; +} diff --git a/source/hal/source/components/npu/include/ethosu_profiler.h b/source/hal/source/components/npu/include/ethosu_profiler.h new file mode 100644 index 0000000..ca95b19 --- /dev/null +++ b/source/hal/source/components/npu/include/ethosu_profiler.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 Arm Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef ETHOS_U_PROFILER_H +#define ETHOS_U_PROFILER_H + +#include "pmu_ethosu.h" + +#define ETHOSU_DERIVED_NCOUNTERS 1 /**< Number of counters derived from event counters */ +#define ETHOSU_PROFILER_NUM_COUNTERS ( \ + ETHOSU_DERIVED_NCOUNTERS + \ + ETHOSU_PMU_NCOUNTERS + \ + 1 /* total CCNT */) + +typedef struct npu_event_counter_ { + enum ethosu_pmu_event_type event_type; + uint32_t event_mask; + uint32_t counter_value; + char* unit; + char* name; +} npu_evt_counter; + +typedef struct npu_derived_counter_ { + uint32_t counter_value; + char* unit; + char* name; +} npu_derived_counter; + +typedef struct ethosu_pmu_counters_ { + uint64_t npu_total_ccnt; /**< Total NPU cycles */ + npu_evt_counter npu_evt_counters[ETHOSU_PMU_NCOUNTERS]; + npu_derived_counter npu_derived_counters[ETHOSU_DERIVED_NCOUNTERS]; + uint32_t num_total_counters; /**< Total number of counters */ +} ethosu_pmu_counters; + +/** + * @brief Initialise the Arm Ethos-U NPU performance monitoring unit. + */ +void ethosu_pmu_init(void); + +/** + * @brief Resets the Arm Ethos-U NPU PMU counters. + */ +void ethosu_pmu_reset_counters(void); + +/** + * @brief Get the Arm Ethos-U NPU PMU counters + * @return ethosu_pmu_counters + */ +ethosu_pmu_counters ethosu_get_pmu_counters(void); + +#endif /* ETHOS_U_PROFILER_H */ diff --git a/source/hal/source/components/npu_ta/CMakeLists.txt b/source/hal/source/components/npu_ta/CMakeLists.txt index 6f7dac5..73bbef7 100644 --- a/source/hal/source/components/npu_ta/CMakeLists.txt +++ b/source/hal/source/components/npu_ta/CMakeLists.txt @@ -36,6 +36,10 @@ if (NOT DEFINED SOURCE_GEN_DIR) set(SOURCE_GEN_DIR ${CMAKE_BINARY_DIR}/generated/ta) endif() +# Base address definitions for the two timing adapters (platform should override these): +set(TA0_BASE "0x58103000" CACHE STRING "Ethos-U NPU timing adapter 0") +set(TA1_BASE "0x58103200" CACHE STRING "Ethos-U NPU timing adapter 1") + ## If a TA config file is provided, we generate a settings file if (DEFINED TA_CONFIG_FILE) include(${TA_CONFIG_FILE}) diff --git a/source/hal/source/components/npu_ta/ethosu_ta_init.c b/source/hal/source/components/npu_ta/ethosu_ta_init.c index 323ab73..f3c95b6 100644 --- a/source/hal/source/components/npu_ta/ethosu_ta_init.c +++ b/source/hal/source/components/npu_ta/ethosu_ta_init.c @@ -42,13 +42,13 @@ int arm_ethosu_timing_adapter_init(void) .histbin = TA0_HISTBIN, .histcnt = TA0_HISTCNT}; - if (0 != ta_init(&ta_0, TA0_BASE)) - { + if (0 != ta_init(&ta_0, TA0_BASE)) { printf_err("TA0 initialisation failed\n"); return 1; } ta_set_all(&ta_0, &ta_0_settings); + info("TA0 values set\n"); #endif /* defined (TA0_BASE) */ #if defined(TA1_BASE) @@ -76,6 +76,7 @@ int arm_ethosu_timing_adapter_init(void) } ta_set_all(&ta_1, &ta_1_settings); + info("TA1 values set\n"); #endif /* defined (TA1_BASE) */ return 0; diff --git a/source/hal/source/components/platform_pmu/CMakeLists.txt b/source/hal/source/components/platform_pmu/CMakeLists.txt new file mode 100644 index 0000000..3ef407d --- /dev/null +++ b/source/hal/source/components/platform_pmu/CMakeLists.txt @@ -0,0 +1,30 @@ +#---------------------------------------------------------------------------- +# Copyright (c) 2022 Arm Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#---------------------------------------------------------------------------- + +##################################################################### +# Interface library for platform performance monitoring unit # +##################################################################### +cmake_minimum_required(VERSION 3.15.6) + +project(platform_pmu + DESCRIPTION "Header/interface for platform PMU" + LANGUAGES C) + +# Interface library: +set(PLATFORM_PMU_TARGET platform_pmu) +add_library(${PLATFORM_PMU_TARGET} INTERFACE) +target_include_directories(${PLATFORM_PMU_TARGET} INTERFACE include) diff --git a/source/hal/source/components/platform_pmu/include/platform_pmu.h b/source/hal/source/components/platform_pmu/include/platform_pmu.h new file mode 100644 index 0000000..3724e57 --- /dev/null +++ b/source/hal/source/components/platform_pmu/include/platform_pmu.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022 Arm Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef PLATFORM_PMU_INTERFACE_H +#define PLATFORM_PMU_INTERFACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include <stdbool.h> + +#define NUM_PMU_COUNTERS (10) /**< Maximum number of available counters. */ + +/** + * @brief Container for a single unit for a PMU counter. + */ +typedef struct _pmu_counter_unit { + uint64_t value; /**< Value of the counter expressed as 64 bits unsigned integer. */ + const char* name; /**< Name for the counter. */ + const char* unit; /**< Unit that the counter value represents (like cycles, beats, or milliseconds). */ +} pmu_counter_unit; + +/** + * @brief Container for a an array of counters + */ +typedef struct _pmu_counters { + pmu_counter_unit counters[NUM_PMU_COUNTERS]; /**< Counter array. */ + uint32_t num_counters; /**< Number of valid counters. */ + bool initialised; /**< Initialised or not. */ +} pmu_counters; + +/** + * @brief Resets the counters. + */ +void platform_reset_counters(void); + +/** + * @brief Gets the current counter values. + * @returns A populated instance of pmu_counters struct. + **/ +pmu_counters platform_get_counters(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PLATFORM_PMU_INTERFACE_H */ diff --git a/source/hal/source/profiles/bare-metal/timer/include/platform_timer.h b/source/hal/source/hal_timer.c index dd3934e..0488afa 100644 --- a/source/hal/source/profiles/bare-metal/timer/include/platform_timer.h +++ b/source/hal/source/hal_timer.c @@ -14,25 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef BAREMETAL_TIMER_H -#define BAREMETAL_TIMER_H - +#include "timer.h" +#include "log_macros.h" #include "platform_drivers.h" -#include <stdint.h> -#include <time.h> - -typedef struct bm_time_counter { - base_time_counter counter; +#include <assert.h> +#include <string.h> +#include <inttypes.h> -#if defined (ARM_NPU) - uint64_t npu_total_ccnt; - uint32_t npu_idle_ccnt; - uint32_t npu_axi0_read_beats; - uint32_t npu_axi0_write_beats; - uint32_t npu_axi1_read_beats; -#endif /* ARM_NPU */ +/** + * @brief Initialiser for HAL timer. + * @param[in] timer Platform timer to initialize. + **/ +void init_timer(platform_timer* timer) +{ + assert(timer); + memset(timer, 0, sizeof(*timer)); -} time_counter; + timer->reset = platform_reset_counters; + timer->get_counters = platform_get_counters; -#endif /* BAREMETAL_TIMER_H */ + timer->reset(); + timer->inited = 1; +} diff --git a/source/hal/source/platform/mps3/CMakeLists.txt b/source/hal/source/platform/mps3/CMakeLists.txt index 31cd004..2f0174b 100644 --- a/source/hal/source/platform/mps3/CMakeLists.txt +++ b/source/hal/source/platform/mps3/CMakeLists.txt @@ -32,14 +32,19 @@ endif() # Define target specific base addresses here (before adding the components) if (TARGET_SUBSYSTEM STREQUAL sse-300) - set(UART0_BASE "0x49303000" CACHE STRING "UART base address") - set(UART0_BAUDRATE "115200" CACHE STRING "UART baudrate") - set(SYSTEM_CORE_CLOCK "25000000" CACHE STRING "System peripheral clock (Hz)") - set(CLCD_CONFIG_BASE "0x4930A000" CACHE STRING "LCD configuration base address") - set(ETHOS_U_BASE_ADDR "0x58102000" CACHE STRING "Ethos-U NPU base address") - set(ETHOS_U_IRQN "56" CACHE STRING "Ethos-U55 Interrupt") + set(UART0_BASE "0x49303000" CACHE STRING "UART base address") + set(UART0_BAUDRATE "115200" CACHE STRING "UART baudrate") + set(SYSTEM_CORE_CLOCK "25000000" CACHE STRING "System peripheral clock (Hz)") + set(CLCD_CONFIG_BASE "0x4930A000" CACHE STRING "LCD configuration base address") + set(ETHOS_U_BASE_ADDR "0x58102000" CACHE STRING "Ethos-U NPU base address") + set(ETHOS_U_IRQN "56" CACHE STRING "Ethos-U55 Interrupt") set(ETHOS_U_SEC_ENABLED "1" CACHE STRING "Ethos-U NPU Security enable") set(ETHOS_U_PRIV_ENABLED "1" CACHE STRING "Ethos-U NPU Privilege enable") + + if (ETHOS_U_NPU_TIMING_ADAPTER_ENABLED) + set(TA0_BASE "0x58103000" CACHE STRING "Ethos-U NPU timing adapter 0") + set(TA1_BASE "0x58103200" CACHE STRING "Ethos-U NPU timing adapter 1") + endif() endif() # 2. Create static library @@ -77,13 +82,22 @@ add_subdirectory(${COMPONENTS_DIR}/stdout ${CMAKE_BINARY_DIR}/stdout) ## Platform component: lcd add_subdirectory(${COMPONENTS_DIR}/lcd ${CMAKE_BINARY_DIR}/lcd) +## Platform component: PMU +add_subdirectory(${COMPONENTS_DIR}/platform_pmu ${CMAKE_BINARY_DIR}/platform_pmu) + # Add dependencies: target_link_libraries(${PLATFORM_DRIVERS_TARGET} PUBLIC log cmsis_device + platform_pmu lcd_mps3 $<IF:$<BOOL:STDOUT_RETARGET>,stdout_retarget_cmsdk,stdout>) +# Set the CPU profiling definition +if (CPU_PROFILE_ENABLED) + target_compile_definitions(${PLATFORM_DRIVERS_TARGET} PUBLIC CPU_PROFILE_ENABLED) +endif() + # If Ethos-U is enabled, we need the driver library too if (ETHOS_U_NPU_ENABLED) diff --git a/source/hal/source/platform/mps3/include/timer_mps3.h b/source/hal/source/platform/mps3/include/timer_mps3.h index e1faf69..b370e89 100644 --- a/source/hal/source/platform/mps3/include/timer_mps3.h +++ b/source/hal/source/platform/mps3/include/timer_mps3.h @@ -17,10 +17,17 @@ #ifndef TIMER_MPS3_H #define TIMER_MPS3_H +#include "platform_pmu.h" + #include <stdint.h> +#include <stdbool.h> + +#if defined (ARM_NPU) + #include "ethosu_profiler.h" /* Arm Ethos-U NPU profiling functions. */ +#endif /* defined (ARM_NPU) */ /* Container for timestamp up-counters. */ -typedef struct _mps3_time_counter { +typedef struct mps3_pmu_counters_ { uint32_t counter_1Hz; uint32_t counter_100Hz; @@ -29,65 +36,24 @@ typedef struct _mps3_time_counter { /* Running at processor core's internal clock rate, triggered by SysTick. */ uint64_t counter_systick; -} base_time_counter; - - -/** - * @brief Gets the MPS3 core clock - * @return Clock rate in Hz expressed as 32 bit unsigned integer. - */ -uint32_t get_mps3_core_clock(void); +} mps3_pmu_counters; /** * @brief Resets the counters. */ -void timer_reset(void); +void platform_reset_counters(void); /** * @brief Gets the current counter values. - * @returns Mps3 timer counter. - **/ -base_time_counter get_time_counter(void); - -/** - * @brief Gets the duration elapsed between two counters in milliseconds. - * @param[in] start Pointer to base_time_counter value at start time. - * @param[in] end Pointer to base_time_counter value at end. - * @returns Difference in milliseconds between the two give counters - * expressed as an unsigned integer. - **/ -uint32_t get_duration_milliseconds(base_time_counter *start, - base_time_counter *end); - -/** - * @brief Gets the duration elapsed between two counters in microseconds. - * @param[in] start Pointer to base_time_counter value at start time. - * @param[in] end Pointer to base_time_counter value at end. - * @returns Difference in microseconds between the two give counters - * expressed as an unsigned integer. + * @returns A populated instance of pmu_counters struct. **/ -uint32_t get_duration_microseconds(base_time_counter *start, - base_time_counter *end); +pmu_counters platform_get_counters(void); /** - * @brief Gets the cycle counts elapsed between start and end. - * @param[in] start Pointer to base_time_counter value at start time. - * @param[in] end Pointer to base_time_counter value at end. - * @return Difference in counter values as 32 bit unsigned integer. - **/ -uint64_t get_cycle_count_diff(base_time_counter *start, - base_time_counter *end); - -/** - * @brief Enables or triggers cycle counting mechanism, if required - * by the platform. - **/ -void start_cycle_counter(void); - -/** - * @brief Stops cycle counting mechanism, if required by the platform. - **/ -void stop_cycle_counter(void); + * @brief Gets the MPS3 core clock + * @return Clock rate in Hz expressed as 32 bit unsigned integer. + */ +uint32_t get_mps3_core_clock(void); /** * @brief System tick interrupt handler. diff --git a/source/hal/source/platform/mps3/source/timer_mps3.c b/source/hal/source/platform/mps3/source/timer_mps3.c index 3511883..6330269 100644 --- a/source/hal/source/platform/mps3/source/timer_mps3.c +++ b/source/hal/source/platform/mps3/source/timer_mps3.c @@ -32,7 +32,28 @@ static uint64_t Get_SysTick_Cycle_Count(void); */ static int Init_SysTick(void); -void timer_reset(void) +/** + * @brief Adds one PMU counter to the counters' array + * @param value Value of the counter + * @param name Name for the given counter + * @param unit Unit for the "value" + * @param counters Pointer to the counter struct - the one to be populated. + * @return true if successfully added, false otherwise + */ +static bool add_pmu_counter( + uint64_t value, + const char* name, + const char* unit, + pmu_counters* counters); + +/** + * @brief Gets the evaluated millisecond timestamp from the given MPS3 counter struct. + * @param mps3_counters Pointer to the MPS3 counters. + * @return microseconds timestamp as 32 bit unsigned integer. + */ +static uint32_t get_tstamp_milliseconds(mps3_pmu_counters* mps3_counters); + +void platform_reset_counters(void) { MPS3_FPGAIO->CLK1HZ = 0; MPS3_FPGAIO->CLK100HZ = 0; @@ -42,85 +63,93 @@ void timer_reset(void) printf_err("Failed to initialise system tick config\n"); } debug("system tick config ready\n"); -} -base_time_counter get_time_counter(void) -{ - base_time_counter t = { - .counter_1Hz = MPS3_FPGAIO->CLK1HZ, - .counter_100Hz = MPS3_FPGAIO->CLK100HZ, - .counter_fpga = MPS3_FPGAIO->COUNTER, - .counter_systick = Get_SysTick_Cycle_Count() - }; - debug("Timestamp:\n"); - debug("\tCounter 1 Hz: %" PRIu32 "\n", t.counter_1Hz); - debug("\tCounter 100 Hz: %" PRIu32 "\n", t.counter_100Hz); - debug("\tCounter FPGA: %" PRIu32 "\n", t.counter_fpga); - debug("\tCounter CPU: %" PRIu64 "\n", t.counter_systick); - return t; +#if defined (ARM_NPU) + ethosu_pmu_init(); +#endif /* defined (ARM_NPU) */ } -/** - * Please note, that there are no checks for overflow in this function => if - * the time elapsed has been big (in days) this could happen and is currently - * not handled. - **/ -uint32_t get_duration_milliseconds(base_time_counter *start, - base_time_counter *end) +pmu_counters platform_get_counters(void) { - uint32_t time_elapsed = 0; - if (end->counter_100Hz > start->counter_100Hz) { - time_elapsed = (end->counter_100Hz - start->counter_100Hz) * 10; - } else { - time_elapsed = (end->counter_1Hz - start->counter_1Hz) * 1000 + - ((0xFFFFFFFF - start->counter_100Hz) + end->counter_100Hz + 1) * 10; + pmu_counters platform_counters = { + .num_counters = 0, + .initialised = true + }; + uint32_t i = 0; + +#if defined (ARM_NPU) + ethosu_pmu_counters npu_counters = ethosu_get_pmu_counters(); + for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) { + add_pmu_counter( + npu_counters.npu_evt_counters[i].counter_value, + npu_counters.npu_evt_counters[i].name, + npu_counters.npu_evt_counters[i].unit, + &platform_counters); } - - /* If the time elapsed is less than 100ms, use microseconds count to be - * more precise */ - if (time_elapsed < 100) { - debug("Using the microsecond function instead..\n"); - return get_duration_microseconds(start, end)/1000; + for (i = 0; i < ETHOSU_DERIVED_NCOUNTERS; ++i) { + add_pmu_counter( + npu_counters.npu_derived_counters[i].counter_value, + npu_counters.npu_derived_counters[i].name, + npu_counters.npu_derived_counters[i].unit, + &platform_counters); } + add_pmu_counter( + npu_counters.npu_total_ccnt, + "NPU TOTAL", + "cycles", + &platform_counters); +#endif /* defined (ARM_NPU) */ + +#if defined(CPU_PROFILE_ENABLED) + mps3_pmu_counters mps3_counters = { + .counter_1Hz = MPS3_FPGAIO->CLK1HZ, + .counter_100Hz = MPS3_FPGAIO->CLK100HZ, + .counter_fpga = MPS3_FPGAIO->COUNTER, + .counter_systick = Get_SysTick_Cycle_Count() + }; - return time_elapsed; + add_pmu_counter( + mps3_counters.counter_systick, + "CPU TOTAL", + "cycles", + &platform_counters); + + add_pmu_counter( + get_tstamp_milliseconds(&mps3_counters), + "DURATION", + "milliseconds", + &platform_counters); +#endif /* defined(CPU_PROFILE_ENABLED) */ + +#if !defined(CPU_PROFILE_ENABLED) + UNUSED(get_tstamp_milliseconds); + UNUSED(Get_SysTick_Cycle_Count); +#if !defined(ARM_NPU) + UNUSED(add_pmu_counter); + UNUSED(i); +#endif /* !defined(ARM_NPU) */ +#endif /* !defined(CPU_PROFILE_ENABLED) */ + + return platform_counters; } -/** - * Like the microsecond counterpart, this function could return wrong results when - * the counter (MAINCLK) overflows. There are no overflow counters available. - **/ -uint32_t get_duration_microseconds(base_time_counter *start, - base_time_counter *end) +uint32_t get_mps3_core_clock(void) { - const int divisor = get_mps3_core_clock()/1000000; - uint32_t time_elapsed = 0; - if (end->counter_fpga > start->counter_fpga) { - time_elapsed = (end->counter_fpga - start->counter_fpga)/divisor; - } else { - time_elapsed = ((0xFFFFFFFF - end->counter_fpga) - + start->counter_fpga + 1)/divisor; + const uint32_t default_clock = 32000000 /* 32 MHz clock */; + static int warned_once = 0; + if (0 != MPS3_SCC->CFG_ACLK) { + if (default_clock != MPS3_SCC->CFG_ACLK) { + warn("System clock is different to the MPS3 config set clock.\n"); + } + return MPS3_SCC->CFG_ACLK; } - return time_elapsed; -} -uint64_t get_cycle_count_diff(base_time_counter *start, - base_time_counter *end) -{ - if (start->counter_systick > end->counter_systick) { - warn("start > end; counter might have overflown\n"); + if (!warned_once) { + warn("MPS3_SCC->CFG_ACLK reads 0. Assuming default clock of %" PRIu32 "\n", + default_clock); + warned_once = 1; } - return end->counter_systick - start->counter_systick; -} - -void start_cycle_counter(void) -{ - /* Nothing to do for FPGA */ -} - -void stop_cycle_counter(void) -{ - /* Nothing to do for FPGA */ + return default_clock; } void SysTick_Handler(void) @@ -173,21 +202,30 @@ static int Init_SysTick(void) return err; } -uint32_t get_mps3_core_clock(void) +static bool add_pmu_counter(uint64_t value, + const char* name, + const char* unit, + pmu_counters* counters) { - const uint32_t default_clock = 32000000 /* 32 MHz clock */; - static int warned_once = 0; - if (0 != MPS3_SCC->CFG_ACLK) { - if (default_clock != MPS3_SCC->CFG_ACLK) { - warn("System clock is different to the MPS3 config set clock.\n"); - } - return MPS3_SCC->CFG_ACLK; + const uint32_t idx = counters->num_counters; + if (idx < NUM_PMU_COUNTERS) { + counters->counters[idx].value = value; + counters->counters[idx].name = name; + counters->counters[idx].unit = unit; + ++counters->num_counters; + + debug("%s: %" PRIu64 " %s\n", name, value, unit); + return true; } + printf_err("Failed to add PMU counter!\n"); + return false; +} - if (!warned_once) { - warn("MPS3_SCC->CFG_ACLK reads 0. Assuming default clock of %" PRIu32 "\n", - default_clock); - warned_once = 1; +static uint32_t get_tstamp_milliseconds(mps3_pmu_counters* mps3_counters) +{ + const uint32_t divisor = get_mps3_core_clock() / 1000; + if (mps3_counters->counter_100Hz > 100) { + return (mps3_counters->counter_100Hz * 10); } - return default_clock; -}
\ No newline at end of file + return (mps3_counters->counter_systick/divisor); +} diff --git a/source/hal/source/platform/native/CMakeLists.txt b/source/hal/source/platform/native/CMakeLists.txt index 9673fef..e0cc711 100644 --- a/source/hal/source/platform/native/CMakeLists.txt +++ b/source/hal/source/platform/native/CMakeLists.txt @@ -43,7 +43,8 @@ target_include_directories(${PLATFORM_DRIVERS_TARGET} ## Platform sources target_sources(${PLATFORM_DRIVERS_TARGET} PRIVATE - source/platform_drivers.c) + source/platform_drivers.c + source/timer_native.c) ## Platform component directory if (NOT DEFINED COMPONENTS_DIR) @@ -57,10 +58,14 @@ add_subdirectory(${COMPONENTS_DIR}/stdout ${CMAKE_BINARY_DIR}/stdout) ## Platform component: lcd add_subdirectory(${COMPONENTS_DIR}/lcd ${CMAKE_BINARY_DIR}/lcd) +## Platform component: PMU +add_subdirectory(${COMPONENTS_DIR}/platform_pmu ${CMAKE_BINARY_DIR}/platform_pmu) + # Add dependencies: target_link_libraries(${PLATFORM_DRIVERS_TARGET} PUBLIC log + platform_pmu stdout lcd_stubs) diff --git a/source/hal/source/platform/native/include/platform_drivers.h b/source/hal/source/platform/native/include/platform_drivers.h index d93e31c..a203618 100644 --- a/source/hal/source/platform/native/include/platform_drivers.h +++ b/source/hal/source/platform/native/include/platform_drivers.h @@ -21,6 +21,7 @@ #include "log_macros.h" /* Logging related helpers. */ #include "lcd_img.h" /* LCD functions */ #include "user_input.h" /* User input function */ +#include "timer_native.h" /* Native platform timer/profiler support */ /** * @brief Initialises the platform components. diff --git a/source/hal/source/profiles/native/timer/include/platform_timer.h b/source/hal/source/platform/native/include/timer_native.h index df7b493..c8eeda2 100644 --- a/source/hal/source/profiles/native/timer/include/platform_timer.h +++ b/source/hal/source/platform/native/include/timer_native.h @@ -14,18 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef TIMER_H -#define TIMER_H +#ifndef NATIVE_TIMER_H +#define NATIVE_TIMER_H + +#include "platform_pmu.h" #include <stdint.h> #include <time.h> -/* Container for time struct */ -typedef struct _time_counter { - /* Current POSIX time in secs. */ - time_t current_secs; - /* Nanoseconds expired in current second. */ - time_t current_nsecs; -} time_counter; +/** + * @brief Resets the counters. + */ +void platform_reset_counters(void); + +/** + * @brief Gets the current counter values. + * @returns A populated instance of pmu_counters struct. + **/ +pmu_counters platform_get_counters(void); -#endif /* TIMER_H */
\ No newline at end of file +#endif /* NATIVE_TIMER_H */ diff --git a/source/hal/source/platform/native/source/timer_native.c b/source/hal/source/platform/native/source/timer_native.c new file mode 100644 index 0000000..590975f --- /dev/null +++ b/source/hal/source/platform/native/source/timer_native.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Arm Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "timer_native.h" + +#include "log_macros.h" + +#include <time.h> +#include <string.h> + +#define MILLISECONDS_IN_SECOND 1000 +#define MICROSECONDS_IN_SECOND 1000000 +#define NANOSECONDS_IN_MILLISECOND 1000000 +#define NANOSECONDS_IN_MICROSECOND 1000 + +void platform_reset_counters() { /* Nothing to do */ } + +pmu_counters platform_get_counters(void) +{ + struct timespec current_time; + pmu_counters platform_counters = { + .num_counters = 0, + .initialised = true + }; + clock_gettime(1, ¤t_time); + uint64_t microseconds = (current_time.tv_sec * MICROSECONDS_IN_SECOND) + + (current_time.tv_nsec / NANOSECONDS_IN_MICROSECOND); + +#if NUM_PMU_COUNTERS > 0 + platform_counters.counters[0].value = microseconds; + platform_counters.counters[0].name = "Duration"; + platform_counters.counters[0].unit = "microseconds"; + ++platform_counters.num_counters; +#endif /* NUM_PMU_COUNTERS > 0 */ + + return platform_counters; +} + +#ifdef __cplusplus +} +#endif diff --git a/source/hal/source/platform/simple/CMakeLists.txt b/source/hal/source/platform/simple/CMakeLists.txt index e11d9a9..119f711 100644 --- a/source/hal/source/platform/simple/CMakeLists.txt +++ b/source/hal/source/platform/simple/CMakeLists.txt @@ -31,14 +31,19 @@ if (NOT ${CMAKE_CROSSCOMPILING}) endif() # Define target specific values here (before adding the components) -set(UART0_BASE "0x49303000" CACHE STRING "UART base address") -set(UART0_BAUDRATE "115200" CACHE STRING "UART baudrate") -set(SYSTEM_CORE_CLOCK "25000000" CACHE STRING "System peripheral clock (Hz)") -set(ETHOS_U_BASE_ADDR "0x58102000" CACHE STRING "Ethos-U NPU base address") -set(ETHOS_U_IRQN "56" CACHE STRING "Ethos-U55 Interrupt") +set(UART0_BASE "0x49303000" CACHE STRING "UART base address") +set(UART0_BAUDRATE "115200" CACHE STRING "UART baudrate") +set(SYSTEM_CORE_CLOCK "25000000" CACHE STRING "System peripheral clock (Hz)") +set(ETHOS_U_BASE_ADDR "0x58102000" CACHE STRING "Ethos-U NPU base address") +set(ETHOS_U_IRQN "56" CACHE STRING "Ethos-U55 Interrupt") set(ETHOS_U_SEC_ENABLED "1" CACHE STRING "Ethos-U NPU Security enable") set(ETHOS_U_PRIV_ENABLED "1" CACHE STRING "Ethos-U NPU Privilege enable") +if (ETHOS_U_NPU_TIMING_ADAPTER_ENABLED) + set(TA0_BASE "0x58103000" CACHE STRING "Ethos-U NPU timing adapter 0") + set(TA1_BASE "0x58103200" CACHE STRING "Ethos-U NPU timing adapter 1") +endif() + # 2. Create static library add_library(${PLATFORM_DRIVERS_TARGET} STATIC) @@ -69,13 +74,22 @@ add_subdirectory(${COMPONENTS_DIR}/stdout ${CMAKE_BINARY_DIR}/stdout) ## Platform component: lcd add_subdirectory(${COMPONENTS_DIR}/lcd ${CMAKE_BINARY_DIR}/lcd) +## Platform component: PMU +add_subdirectory(${COMPONENTS_DIR}/platform_pmu ${CMAKE_BINARY_DIR}/platform_pmu) + # Add dependencies: target_link_libraries(${PLATFORM_DRIVERS_TARGET} PUBLIC cmsis_device log + platform_pmu lcd_stubs $<IF:$<BOOL:STDOUT_RETARGET>,stdout_retarget_pl011,stdout>) +# Set the CPU profiling definition +if (CPU_PROFILE_ENABLED) + target_compile_definitions(${PLATFORM_DRIVERS_TARGET} PUBLIC CPU_PROFILE_ENABLED) +endif() + # If Ethos-U is enabled, we need the driver library too if (ETHOS_U_NPU_ENABLED) diff --git a/source/hal/source/platform/simple/include/platform_drivers.h b/source/hal/source/platform/simple/include/platform_drivers.h index 5f2ed33..31bb682 100644 --- a/source/hal/source/platform/simple/include/platform_drivers.h +++ b/source/hal/source/platform/simple/include/platform_drivers.h @@ -23,7 +23,8 @@ /* Platform components */ #include "RTE_Components.h" /* For CPU related defintiions */ #include "timer_simple_platform.h" /* timer implementation */ -#include "user_input.h" /* User input function */ +#include "platform_pmu.h" /* PMU definitions and API */ +#include "user_input.h" /* User input functions */ #include "lcd_img.h" /* LCD functions */ /** diff --git a/source/hal/source/platform/simple/include/timer_simple_platform.h b/source/hal/source/platform/simple/include/timer_simple_platform.h index 683a207..40acd03 100644 --- a/source/hal/source/platform/simple/include/timer_simple_platform.h +++ b/source/hal/source/platform/simple/include/timer_simple_platform.h @@ -16,42 +16,25 @@ */ #ifndef TIMER_SIMPLE_PLATFORM_H #define TIMER_SIMPLE_PLATFORM_H -#include <stdint.h> -#include "RTE_Components.h" +#include "platform_pmu.h" + +#if defined (ARM_NPU) + #include "ethosu_profiler.h" /* Arm Ethos-U NPU profiling functions. */ +#endif /* defined (ARM_NPU) */ -/* Container for timestamp for simple platform. */ -typedef struct _generic_time_counter { - uint64_t counter_systick; -} base_time_counter; +#include <stdint.h> /** * @brief Resets the counters. */ -void timer_reset(void); +void platform_reset_counters(void); /** * @brief Gets the current counter values. - * @returns counter struct. + * @returns A populated instance of pmu_counters struct. **/ -base_time_counter get_time_counter(void); - -/** - * @brief Gets the cycle counts elapsed between start and end. - * @return difference in counter values as 32 bit unsigned integer. - */ -uint64_t get_cycle_count_diff(base_time_counter *start, base_time_counter *end); - -/** - * @brief Enables or triggers cycle counting mechanism, if required - * by the platform. - */ -void start_cycle_counter(void); - -/** - * @brief Stops cycle counting mechanism, if required by the platform. - */ -void stop_cycle_counter(void); +pmu_counters platform_get_counters(void); /** * @brief System tick interrupt handler. diff --git a/source/hal/source/platform/simple/source/timer_simple_platform.c b/source/hal/source/platform/simple/source/timer_simple_platform.c index f7917b0..94af308 100644 --- a/source/hal/source/platform/simple/source/timer_simple_platform.c +++ b/source/hal/source/platform/simple/source/timer_simple_platform.c @@ -16,8 +16,8 @@ */ #include "timer_simple_platform.h" -#include "log_macros.h" /* Logging macros */ -#include "RTE_Components.h" /* For CPU related defintiions */ +#include "log_macros.h" /* Logging macros. */ +#include "RTE_Components.h" /* CPU definitions and functions. */ #include <inttypes.h> @@ -35,44 +35,84 @@ static uint64_t Get_SysTick_Cycle_Count(void); */ static int Init_SysTick(void); +/** + * @brief Adds one PMU counter to the counters' array + * @param value Value of the counter + * @param name Name for the given counter + * @param unit Unit for the "value" + * @param counters Pointer to the counter struct - the one to be populated. + * @return true if successfully added, false otherwise + */ +static bool add_pmu_counter( + uint64_t value, + const char* name, + const char* unit, + pmu_counters* counters); -base_time_counter get_time_counter(void) -{ - base_time_counter t = { - .counter_systick = Get_SysTick_Cycle_Count() - }; - debug("counter_systick: %" PRIu64 "\n", t.counter_systick); - return t; -} - -void timer_reset(void) +void platform_reset_counters(void) { if (0 != Init_SysTick()) { printf_err("Failed to initialise system tick config\n"); + return; } - debug("system tick config ready\n"); -} -uint64_t get_cycle_count_diff(base_time_counter *start, - base_time_counter *end) -{ - if (start->counter_systick > end->counter_systick) { - warn("start > end; counter might have overflown\n"); - } - return end->counter_systick - start->counter_systick; -} +#if defined(ARM_NPU) + ethosu_pmu_init(); +#endif /* defined (ARM_NPU) */ -void start_cycle_counter(void) -{ - /* Add any custom requirement for this platform here */ + debug("system tick config ready\n"); } -void stop_cycle_counter(void) +pmu_counters platform_get_counters(void) { - /* Add any custom requirement for this platform here */ + pmu_counters platform_counters = { + .num_counters = 0, + .initialised = true + }; + uint32_t i = 0; + +#if defined (ARM_NPU) + ethosu_pmu_counters npu_counters = ethosu_get_pmu_counters(); + for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) { + add_pmu_counter( + npu_counters.npu_evt_counters[i].counter_value, + npu_counters.npu_evt_counters[i].name, + npu_counters.npu_evt_counters[i].unit, + &platform_counters); + } + for (i = 0; i < ETHOSU_DERIVED_NCOUNTERS; ++i) { + add_pmu_counter( + npu_counters.npu_derived_counters[i].counter_value, + npu_counters.npu_derived_counters[i].name, + npu_counters.npu_derived_counters[i].unit, + &platform_counters); + } + add_pmu_counter( + npu_counters.npu_total_ccnt, + "NPU TOTAL", + "cycles", + &platform_counters); +#endif /* defined (ARM_NPU) */ + +#if defined(CPU_PROFILE_ENABLED) + add_pmu_counter( + Get_SysTick_Cycle_Count(), + "CPU TOTAL", + "cycles", + &platform_counters); +#endif /* defined(CPU_PROFILE_ENABLED) */ + +#if !defined(CPU_PROFILE_ENABLED) + UNUSED(Get_SysTick_Cycle_Count); +#if !defined(ARM_NPU) + UNUSED(add_pmu_counter); + UNUSED(i); +#endif /* !defined(ARM_NPU) */ +#endif /* !defined(CPU_PROFILE_ENABLED) */ + + return platform_counters; } - void SysTick_Handler(void) { /* Increment the cycle counter based on load value. */ @@ -120,4 +160,21 @@ static int Init_SysTick(void) } return err; -}
\ No newline at end of file +} + +static bool add_pmu_counter(uint64_t value, + const char* name, + const char* unit, + pmu_counters* counters) +{ + const uint32_t idx = counters->num_counters; + if (idx < NUM_PMU_COUNTERS) { + counters->counters[idx].value = value; + counters->counters[idx].name = name; + counters->counters[idx].unit = unit; + ++counters->num_counters; + return true; + } + printf_err("Failed to add PMU counter!\n"); + return false; +} diff --git a/source/hal/source/profiles/bare-metal/timer/platform_timer.c b/source/hal/source/profiles/bare-metal/timer/platform_timer.c deleted file mode 100644 index 0388198..0000000 --- a/source/hal/source/profiles/bare-metal/timer/platform_timer.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2022 Arm Limited. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "timer.h" -#include "log_macros.h" -#include "platform_drivers.h" - -#include <assert.h> -#include <string.h> -#include <inttypes.h> - -#if defined (ARM_NPU) - -#include "pmu_ethosu.h" - -extern struct ethosu_driver ethosu_drv; /* Default Ethos-U55 device driver */ - -/** - * @brief Initialises the PMU and enables the cycle counter. - **/ -static void _init_ethosu_cyclecounter(void); - -/** - * @brief Gets the difference of total NPU cycle counts. - * (includes active and idle) - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Total NPU cycle counts difference between the arguments expressed - * as unsigned 64 bit integer. - **/ -static uint64_t bm_get_npu_total_cycle_diff(time_counter *st, - time_counter *end); - -/** - * @brief Gets the difference in active NPU cycle counts. - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Active NPU cycle counts difference between the arguments expressed - * as unsigned 64 bit integer. - **/ -static uint64_t bm_get_npu_active_cycle_diff(time_counter *st, - time_counter *end); - -/** @brief Gets the difference in idle NPU cycle counts - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Idle NPU cycle counts difference between the arguments expressed - * as unsigned 64 bit integer. - **/ -static uint64_t bm_get_npu_idle_cycle_diff(time_counter *st, - time_counter *end); - -/** @brief Gets the difference in axi0 bus reads cycle counts - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return NPU AXI0 read cycle counts difference between the arguments expressed - * as unsigned 64 bit integer. - **/ -static uint64_t bm_get_npu_axi0_read_cycle_diff(time_counter *st, - time_counter *end); - -/** @brief Gets the difference in axi0 bus writes cycle counts - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return NPU AXI0 write cycle counts difference between the arguments expressed - * as unsigned 64 bit integer. - **/ -static uint64_t bm_get_npu_axi0_write_cycle_diff(time_counter *st, - time_counter *end); - -/** @brief Gets the difference in axi1 bus reads cycle counts - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return NPU AXI1 read cycle counts difference between the arguments expressed - * as unsigned 64 bit integer. - **/ -static uint64_t bm_get_npu_axi1_read_cycle_diff(time_counter *st, - time_counter *end); - -/** @brief Gets the difference for 6 collected cycle counts: - * 1) total NPU - * 2) active NPU - * 3) idle NPU - * 4) axi0 read - * 5) axi0 write - * 6) axi1 read - * */ -static int bm_get_npu_cycle_diff(time_counter *st, time_counter *end, - uint64_t* pmu_counters_values, const size_t size); - -#endif /* defined (ARM_NPU) */ - -#if defined(MPS3_PLATFORM) -/** - * @brief Wrapper for getting milliseconds duration between time counters - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Difference in milliseconds between given time counters. - **/ -static time_t bm_get_duration_ms(time_counter *st, time_counter *end); - -/** - * @brief Wrapper for getting microseconds duration between time counters - * @param[in] st Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Difference in microseconds between given time counters. - **/ -static time_t bm_get_duration_us(time_counter *st, time_counter *end); -#endif /* defined(MPS3_PLATFORM) */ - -/** - * @brief Wrapper for resetting timer. - **/ -static void bm_timer_reset(void); - -/** - * @brief Wrapper for getting the current timer counter. - * @return Current time counter value. - **/ -static time_counter bm_get_time_counter(void); - -/** - * @brief Wrapper for profiler start. - * @return Current profiler start timer counter. - **/ -static time_counter bm_start_profiling(void); - -/** - * @brief Wrapper for profiler end. - * @return Current profiler end timer counter. - **/ -static time_counter bm_stop_profiling(void); - -/** - * @brief Wrapper for getting CPU cycle difference between time counters. - * @return CPU cycle difference between given time counters expressed - * as unsigned 32 bit integer. - **/ -static uint64_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end); - -/** - * @brief Initialiser for bare metal timer. - * @param[in] timer Platform timer to initialize. - **/ -void init_timer(platform_timer *timer) -{ - assert(timer); - memset(timer, 0, sizeof(*timer)); - - timer->reset = bm_timer_reset; - timer->get_time_counter = bm_get_time_counter; - timer->start_profiling = bm_start_profiling; - timer->stop_profiling = bm_stop_profiling; - timer->get_cpu_cycle_diff = bm_get_cpu_cycles_diff; - timer->cap.cpu_cycles = 1; - -#if defined (MPS3_PLATFORM) - timer->cap.duration_ms = 1; - timer->cap.duration_us = 1; - timer->get_duration_ms = bm_get_duration_ms; - timer->get_duration_us = bm_get_duration_us; -#endif /* defined (MPS3_PLATFORM) */ - -#if defined (ARM_NPU) - /* We are capable of reporting npu cycle counts. */ - timer->cap.npu_cycles = 1; - timer->get_npu_cycles_diff = bm_get_npu_cycle_diff; - _init_ethosu_cyclecounter(); -#endif /* defined (ARM_NPU) */ - - timer->reset(); - timer->inited = 1; -} - -#if defined (ARM_NPU) -static void _reset_ethosu_counters() -{ - /* Reset all cycle and event counters. */ - ETHOSU_PMU_CYCCNT_Reset(ðosu_drv); - ETHOSU_PMU_EVCNTR_ALL_Reset(ðosu_drv); -} -static void _init_ethosu_cyclecounter() -{ - /* Reset overflow status. */ - ETHOSU_PMU_Set_CNTR_OVS(ðosu_drv, ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CCNT_Msk); - /* We can retrieve only 4 PMU counters: */ - ETHOSU_PMU_Set_EVTYPER(ðosu_drv, 0, ETHOSU_PMU_NPU_IDLE); - ETHOSU_PMU_Set_EVTYPER(ðosu_drv, 1, ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED); - ETHOSU_PMU_Set_EVTYPER(ðosu_drv, 2, ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN); - ETHOSU_PMU_Set_EVTYPER(ðosu_drv, 3, ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED); - /* Enable PMU. */ - ETHOSU_PMU_Enable(ðosu_drv); - /* Enable counters for cycle and counter# 0. */ - ETHOSU_PMU_CNTR_Enable(ðosu_drv, ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CNT2_Msk | ETHOSU_PMU_CNT3_Msk | ETHOSU_PMU_CNT4_Msk| ETHOSU_PMU_CCNT_Msk); - _reset_ethosu_counters(); -} - -static int bm_get_npu_cycle_diff(time_counter *st, time_counter *end, - uint64_t* pmu_counters_values, const size_t size) -{ - if (size == 6) { - pmu_counters_values[0] = bm_get_npu_total_cycle_diff(st, end); - pmu_counters_values[1] = bm_get_npu_active_cycle_diff(st, end); - pmu_counters_values[2] = bm_get_npu_idle_cycle_diff(st, end); - pmu_counters_values[3] = bm_get_npu_axi0_read_cycle_diff(st, end); - pmu_counters_values[4] = bm_get_npu_axi0_write_cycle_diff(st, end); - pmu_counters_values[5] = bm_get_npu_axi1_read_cycle_diff(st, end); - return 0; - } else { - return 1; - } -} - -static uint64_t bm_get_npu_total_cycle_diff(time_counter *st, time_counter *end) -{ - return end->npu_total_ccnt - st->npu_total_ccnt; -} - -static uint32_t counter_overflow(uint32_t pmu_counter_mask) -{ - /* Check for overflow: The idle counter is 32 bit while the - total cycle count is 64 bit. */ - const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS(ðosu_drv); - return pmu_counter_mask & overflow_status; -} - -static uint64_t bm_get_npu_idle_cycle_diff(time_counter *st, time_counter *end) -{ - if (counter_overflow(ETHOSU_PMU_CNT1_Msk)) { - printf_err("EthosU PMU idle counter overflow.\n"); - return 0; - } - return (uint64_t)(end->npu_idle_ccnt - st->npu_idle_ccnt); -} - -static uint64_t bm_get_npu_active_cycle_diff(time_counter *st, time_counter *end) -{ - /* Active NPU time = total time - idle time */ - return bm_get_npu_total_cycle_diff(st, end) - bm_get_npu_idle_cycle_diff(st, end); -} - -static uint64_t bm_get_npu_axi0_read_cycle_diff(time_counter *st, time_counter *end) -{ - if (counter_overflow(ETHOSU_PMU_CNT2_Msk)) { - printf_err("EthosU PMU axi0 read counter overflow.\n"); - return 0; - } - return (uint64_t)(end->npu_axi0_read_beats - st->npu_axi0_read_beats); -} - -static uint64_t bm_get_npu_axi0_write_cycle_diff(time_counter *st, time_counter *end) -{ - if (counter_overflow(ETHOSU_PMU_CNT3_Msk)) { - printf_err("EthosU PMU axi0 write counter overflow.\n"); - return 0; - } - return (uint64_t)(end->npu_axi0_write_beats - st->npu_axi0_write_beats); -} - -static uint64_t bm_get_npu_axi1_read_cycle_diff(time_counter *st, time_counter *end) -{ - if (counter_overflow(ETHOSU_PMU_CNT4_Msk)) { - printf_err("EthosU PMU axi1 read counter overflow.\n"); - return 0; - } - return (uint64_t)(end->npu_axi1_read_beats - st->npu_axi1_read_beats); -} - -#endif /* defined (ARM_NPU) */ - -static void bm_timer_reset(void) -{ -#if defined (ARM_NPU) - _init_ethosu_cyclecounter(); -#endif /* defined (ARM_NPU) */ - - timer_reset(); -} - -static time_counter bm_get_time_counter(void) -{ - time_counter t = { - .counter = get_time_counter(), - -#if defined (ARM_NPU) - .npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(ðosu_drv), - .npu_idle_ccnt = ETHOSU_PMU_Get_EVCNTR(ðosu_drv, 0), - .npu_axi0_read_beats = ETHOSU_PMU_Get_EVCNTR(ðosu_drv, 1), - .npu_axi0_write_beats = ETHOSU_PMU_Get_EVCNTR(ðosu_drv, 2), - .npu_axi1_read_beats = ETHOSU_PMU_Get_EVCNTR(ðosu_drv, 3) -#endif /* defined (ARM_NPU) */ - - }; - -#if defined (ARM_NPU) - debug("NPU total cc: %" PRIu64 - "; NPU idle cc: %" PRIu32 - "; NPU axi0 read beats: %" PRIu32 - "; NPU axi0 write beats: %" PRIu32 - "; NPU axi1 read beats: %" PRIu32 "\n", - t.npu_total_ccnt, - t.npu_idle_ccnt, - t.npu_axi0_read_beats, - t.npu_axi0_write_beats, - t.npu_axi1_read_beats); -#endif /* defined (ARM_NPU) */ - - return t; -} - -static time_counter bm_start_profiling(void) -{ - start_cycle_counter(); - return bm_get_time_counter(); -} - -static time_counter bm_stop_profiling(void) -{ - stop_cycle_counter(); - return bm_get_time_counter(); -} - -static uint64_t bm_get_cpu_cycles_diff(time_counter *st, time_counter *end) -{ - return get_cycle_count_diff(&(st->counter), &(end->counter)); -} - -#if defined(MPS3_PLATFORM) -static time_t bm_get_duration_ms(time_counter *st, time_counter *end) -{ - return get_duration_milliseconds(&(st->counter), &(end->counter)); -} - -static time_t bm_get_duration_us(time_counter *st, time_counter *end) -{ - return get_duration_microseconds(&(st->counter), &(end->counter)); -} -#endif /* defined(MPS3_PLATFORM) */ diff --git a/source/hal/source/profiles/native/timer/platform_timer.c b/source/hal/source/profiles/native/timer/platform_timer.c deleted file mode 100644 index c311125..0000000 --- a/source/hal/source/profiles/native/timer/platform_timer.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2021 Arm Limited. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifdef __cplusplus -extern "C" { -#endif - -#include "timer.h" - -#include <assert.h> -#include <time.h> -#include <string.h> - -#define MILLISECONDS_IN_SECOND 1000 -#define MICROSECONDS_IN_SECOND 1000000 -#define NANOSECONDS_IN_MILLISECOND 1000000 -#define NANOSECONDS_IN_MICROSECOND 1000 - -/** - * @brief Gets the current time counter value. - * @return Counter value expressed in terms of time_counter struct. - **/ -static time_counter get_time_counter(void) -{ - struct timespec current_time; - clock_gettime(1, ¤t_time); - time_counter t = { - .current_secs = current_time.tv_sec, - .current_nsecs = current_time.tv_nsec - }; - - return t; -} - -/** - * @brief Gets the time duration elapsed between start and end. - * @param[in] start Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Difference in milliseconds between the arguments expressed - * as unsigned 32 bit integer. - **/ -static time_t get_duration_milliseconds(time_counter *start, time_counter *end) -{ - /* Convert both parts of time struct to ms then add for complete time. */ - time_t seconds_part = - (end->current_secs - start->current_secs) * MILLISECONDS_IN_SECOND; - time_t nanoseconds_part = - (end->current_nsecs - start->current_nsecs) / NANOSECONDS_IN_MILLISECOND; - - return seconds_part + nanoseconds_part; -} - -/** - * @brief Gets the time duration elapsed between start and end. - * @param[in] start Pointer to time_counter value at start time. - * @param[in] end Pointer to time_counter value at end. - * @return Difference in microseconds between the arguments expressed - * as unsigned 32 bit integer. - **/ -static time_t get_duration_microseconds(time_counter *start, time_counter *end) -{ - /* Convert both parts of time struct to us then add for complete time. */ - time_t seconds_part = - (end->current_secs - start->current_secs) * MICROSECONDS_IN_SECOND; - time_t nanoseconds_part = - (end->current_nsecs - start->current_nsecs) / NANOSECONDS_IN_MICROSECOND; - - return seconds_part + nanoseconds_part; -} - -/** - * @brief Stub for timer reset. - **/ -void reset_timer() {} - -/** - * @brief Initialise the timer for this platform. - **/ -void init_timer(platform_timer *timer) -{ - assert(timer); - memset(timer, 0, sizeof(*timer)); - - timer->get_time_counter = get_time_counter; - timer->start_profiling = get_time_counter; - timer->stop_profiling = get_time_counter; - timer->get_duration_ms = get_duration_milliseconds; - timer->cap.duration_ms = 1; - timer->get_duration_us = get_duration_microseconds; - timer->cap.duration_us = 1; - timer->reset = reset_timer; - timer->inited = 1; -} - -#ifdef __cplusplus -} -#endif |