diff options
Diffstat (limited to 'source/hal/source/components/npu/ethosu_profiler.c')
-rw-r--r-- | source/hal/source/components/npu/ethosu_profiler.c | 144 |
1 files changed, 144 insertions, 0 deletions
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; +} |