summaryrefslogtreecommitdiff
path: root/source/hal/source/components/npu/ethosu_profiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/hal/source/components/npu/ethosu_profiler.c')
-rw-r--r--source/hal/source/components/npu/ethosu_profiler.c144
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(&ethosu_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(&ethosu_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(&ethosu_drv, evt_mask);
+
+ /* Enable PMU. */
+ ETHOSU_PMU_Enable(&ethosu_drv);
+
+ /* Enable counters for cycle and event counters. */
+ ETHOSU_PMU_CNTR_Disable(&ethosu_drv, evt_mask);
+ ethosu_pmu_reset_counters();
+ ETHOSU_PMU_CNTR_Enable(&ethosu_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(&ethosu_drv);
+ ETHOSU_PMU_EVCNTR_ALL_Reset(&ethosu_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(&ethosu_drv, i);
+ }
+
+ /* Total cycle count */
+ counters->npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(&ethosu_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;
+}