blob: 3ac3497a2b98f18e0aecee1e884dfacf9119736c [file] [log] [blame]
Kshitij Sisodiada2ec062022-04-01 14:43:53 +01001/*
2 * Copyright (c) 2022 Arm Limited. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "ethosu_profiler.h"
19#include "log_macros.h"
20
21#include <string.h>
22
23extern struct ethosu_driver ethosu_drv; /* Default Arm Ethos-U NPU device driver object */
24static ethosu_pmu_counters npu_counters; /* NPU counter local instance */
25
26/**
27 * @brief Gets the npu counter instance to be used.
28 * @return Pointer to the npu counter instance.
29 */
30static ethosu_pmu_counters* get_counter_instance(void)
31{
32 return &npu_counters;
33}
34
35/**
36 * @brief Checks if the counter has overflown.
37 * @param pmu_counter_mask Mask for the event counter.
38 * @return true if overflow is detected, false otherwise.
39 */
40static bool counter_overflow(uint32_t pmu_counter_mask)
41{
42 /* Check for overflow: The idle counter is 32 bit while the
43 total cycle count is 64 bit. */
44 const uint32_t overflow_status = ETHOSU_PMU_Get_CNTR_OVS(&ethosu_drv);
45 return pmu_counter_mask & overflow_status ? true : false;
46}
47
48void ethosu_pmu_init(void)
49{
50 uint32_t i = 0;
51 uint32_t evt_mask = ETHOSU_PMU_CCNT_Msk;
52 ethosu_pmu_counters* counters = get_counter_instance();
53 memset(counters, 0, sizeof(*counters));
54
55 /* Total counters = event counters + derived counters + total cycle count */
56 counters->num_total_counters = ETHOSU_PROFILER_NUM_COUNTERS;
57
58#if ETHOSU_PMU_NCOUNTERS >= 4
59 counters->npu_evt_counters[0].event_type = ETHOSU_PMU_NPU_IDLE;
60 counters->npu_evt_counters[0].event_mask = ETHOSU_PMU_CNT1_Msk;
61 counters->npu_evt_counters[0].name = "NPU IDLE";
62 counters->npu_evt_counters[0].unit = "cycles";
63
64 counters->npu_evt_counters[1].event_type = ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED;
65 counters->npu_evt_counters[1].event_mask = ETHOSU_PMU_CNT2_Msk;
66 counters->npu_evt_counters[1].name = "NPU AXI0_RD_DATA_BEAT_RECEIVED";
67 counters->npu_evt_counters[1].unit = "beats";
68
69 counters->npu_evt_counters[2].event_type = ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN;
70 counters->npu_evt_counters[2].event_mask = ETHOSU_PMU_CNT3_Msk;
71 counters->npu_evt_counters[2].name = "NPU AXI0_WR_DATA_BEAT_WRITTEN";
72 counters->npu_evt_counters[2].unit = "beats";
73
74 counters->npu_evt_counters[3].event_type = ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED;
75 counters->npu_evt_counters[3].event_mask = ETHOSU_PMU_CNT4_Msk;
76 counters->npu_evt_counters[3].name = "NPU AXI1_RD_DATA_BEAT_RECEIVED";
77 counters->npu_evt_counters[3].unit = "beats";
78#else /* ETHOSU_PMU_NCOUNTERS >= 4 */
79 #error "NPU PMU expects a minimum of 4 available event triggered counters!"
80#endif /* ETHOSU_PMU_NCOUNTERS >= 4 */
81
82#if ETHOSU_DERIVED_NCOUNTERS >= 1
83 counters->npu_derived_counters[0].name = "NPU ACTIVE";
84 counters->npu_derived_counters[0].unit = "cycles";
85#endif /* ETHOSU_DERIVED_NCOUNTERS >= 1 */
86
87 for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
88 ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, i, counters->npu_evt_counters[i].event_type);
89 evt_mask |= counters->npu_evt_counters[i].event_mask;
90 }
91
92 /* Reset overflow status. */
93 ETHOSU_PMU_Set_CNTR_OVS(&ethosu_drv, evt_mask);
94
95 /* Enable PMU. */
96 ETHOSU_PMU_Enable(&ethosu_drv);
97
98 /* Enable counters for cycle and event counters. */
99 ETHOSU_PMU_CNTR_Disable(&ethosu_drv, evt_mask);
100 ethosu_pmu_reset_counters();
101 ETHOSU_PMU_CNTR_Enable(&ethosu_drv, evt_mask);
102}
103
104/**
105 * @brief Resets the Arm Ethos-U NPU PMU counters.
106 */
107void ethosu_pmu_reset_counters(void)
108{
109 /* Reset all cycle and event counters. */
110 ETHOSU_PMU_CYCCNT_Reset(&ethosu_drv);
111 ETHOSU_PMU_EVCNTR_ALL_Reset(&ethosu_drv);
112}
113
114/**
115 * @brief Get the Arm Ethos-U NPU PMU counters
116 * @return ethosu_pmu_counters
117 */
118ethosu_pmu_counters ethosu_get_pmu_counters(void)
119{
120 ethosu_pmu_counters* counters = get_counter_instance();
121 uint32_t i = 0;
122
123 /* Event counters */
124 for (i = 0; i < ETHOSU_PMU_NCOUNTERS; ++i) {
125 if (counter_overflow(counters->npu_evt_counters[i].event_mask)) {
126 warn("Counter overflow detected for %s.\n", counters->npu_evt_counters[i].name);
127 }
128 counters->npu_evt_counters[i].counter_value =
129 ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, i);
130 }
131
132 /* Total cycle count */
133 counters->npu_total_ccnt = ETHOSU_PMU_Get_CCNTR(&ethosu_drv);
134
135 /* Derived counters */
136#if ETHOSU_DERIVED_NCOUNTERS >= 1
137 if (counters->npu_evt_counters[0].event_type == ETHOSU_PMU_NPU_IDLE) {
138 counters->npu_derived_counters[0].counter_value =
139 counters->npu_total_ccnt - counters->npu_evt_counters[0].counter_value;
140 }
141#endif /* ETHOSU_DERIVED_NCOUNTERS >= 1 */
142
143 return *counters;
144}