summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/sections/building.md2
-rw-r--r--docs/sections/testing_benchmarking.md6
-rw-r--r--source/hal/CMakeLists.txt14
-rw-r--r--source/hal/include/timer.h46
-rw-r--r--source/hal/source/components/npu/CMakeLists.txt3
-rw-r--r--source/hal/source/components/npu/ethosu_profiler.c144
-rw-r--r--source/hal/source/components/npu/include/ethosu_profiler.h65
-rw-r--r--source/hal/source/components/npu_ta/CMakeLists.txt4
-rw-r--r--source/hal/source/components/npu_ta/ethosu_ta_init.c5
-rw-r--r--source/hal/source/components/platform_pmu/CMakeLists.txt30
-rw-r--r--source/hal/source/components/platform_pmu/include/platform_pmu.h62
-rw-r--r--source/hal/source/hal_timer.c (renamed from source/hal/source/profiles/bare-metal/timer/include/platform_timer.h)35
-rw-r--r--source/hal/source/platform/mps3/CMakeLists.txt26
-rw-r--r--source/hal/source/platform/mps3/include/timer_mps3.h66
-rw-r--r--source/hal/source/platform/mps3/source/timer_mps3.c200
-rw-r--r--source/hal/source/platform/native/CMakeLists.txt7
-rw-r--r--source/hal/source/platform/native/include/platform_drivers.h1
-rw-r--r--source/hal/source/platform/native/include/timer_native.h (renamed from source/hal/source/profiles/native/timer/include/platform_timer.h)25
-rw-r--r--source/hal/source/platform/native/source/timer_native.c58
-rw-r--r--source/hal/source/platform/simple/CMakeLists.txt24
-rw-r--r--source/hal/source/platform/simple/include/platform_drivers.h3
-rw-r--r--source/hal/source/platform/simple/include/timer_simple_platform.h35
-rw-r--r--source/hal/source/platform/simple/source/timer_simple_platform.c115
-rw-r--r--source/hal/source/profiles/bare-metal/timer/platform_timer.c351
-rw-r--r--source/hal/source/profiles/native/timer/platform_timer.c110
-rw-r--r--source/profiler/CMakeLists.txt9
-rw-r--r--source/profiler/Profiler.cc172
-rw-r--r--source/profiler/include/Profiler.hpp15
28 files changed, 734 insertions, 899 deletions
diff --git a/docs/sections/building.md b/docs/sections/building.md
index 699667b..5f8a3cb 100644
--- a/docs/sections/building.md
+++ b/docs/sections/building.md
@@ -206,7 +206,7 @@ The build parameters are:
`ETHOS_U_NPU_ID` is `U65`. Default value is 393216 (see [default_vela.ini](../../scripts/vela/default_vela.ini) ).
- `CPU_PROFILE_ENABLED`: Sets whether profiling information for the CPU core should be displayed. By default, this is
- set to false, but can be turned on for FPGA targets. The the FVP and the CPU core cycle counts are not meaningful and
+ set to false, but can be turned on for FPGA targets. The FVP and the CPU core cycle counts are **not** meaningful and
are not to be used.
- `LOG_LEVEL`: Sets the verbosity level for the output of the application over `UART`, or `stdout`. Valid values are:
diff --git a/docs/sections/testing_benchmarking.md b/docs/sections/testing_benchmarking.md
index d1cd9df..2641049 100644
--- a/docs/sections/testing_benchmarking.md
+++ b/docs/sections/testing_benchmarking.md
@@ -101,11 +101,7 @@ INFO - NPU TOTAL cycles: 1081634
INFO - Profile for Inference:
INFO - NPU AXI0_RD_DATA_BEAT_RECEIVED beats: 628122
INFO - NPU AXI0_WR_DATA_BEAT_WRITTEN beats: 135087
-INFO - NPU AXI1_RD_DATA_BEAT_RECEIVED beats: 62870
-INFO - NPU ACTIVE cycles: 1081007
-INFO - NPU IDLE cycles: 626
-INFO - NPU TOTAL cycles: 1081634
-INFO - CPU ACTIVE cycles (approx): 993553
+...
INFO - Time ms: 210
```
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(&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;
+}
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, &current_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(&ethosu_drv);
- ETHOSU_PMU_EVCNTR_ALL_Reset(&ethosu_drv);
-}
-static void _init_ethosu_cyclecounter()
-{
- /* Reset overflow status. */
- ETHOSU_PMU_Set_CNTR_OVS(&ethosu_drv, ETHOSU_PMU_CNT1_Msk | ETHOSU_PMU_CCNT_Msk);
- /* We can retrieve only 4 PMU counters: */
- ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 0, ETHOSU_PMU_NPU_IDLE);
- ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 1, ETHOSU_PMU_AXI0_RD_DATA_BEAT_RECEIVED);
- ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 2, ETHOSU_PMU_AXI0_WR_DATA_BEAT_WRITTEN);
- ETHOSU_PMU_Set_EVTYPER(&ethosu_drv, 3, ETHOSU_PMU_AXI1_RD_DATA_BEAT_RECEIVED);
- /* Enable PMU. */
- ETHOSU_PMU_Enable(&ethosu_drv);
- /* Enable counters for cycle and counter# 0. */
- ETHOSU_PMU_CNTR_Enable(&ethosu_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(&ethosu_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(&ethosu_drv),
- .npu_idle_ccnt = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 0),
- .npu_axi0_read_beats = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 1),
- .npu_axi0_write_beats = ETHOSU_PMU_Get_EVCNTR(&ethosu_drv, 2),
- .npu_axi1_read_beats = ETHOSU_PMU_Get_EVCNTR(&ethosu_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, &current_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
diff --git a/source/profiler/CMakeLists.txt b/source/profiler/CMakeLists.txt
index 8fcea1f..0a9c338 100644
--- a/source/profiler/CMakeLists.txt
+++ b/source/profiler/CMakeLists.txt
@@ -31,18 +31,9 @@ target_sources(profiler
target_include_directories(profiler PUBLIC include)
-# Set the CPU profiling defintiion
-if (CPU_PROFILE_ENABLED)
- target_compile_definitions(profiler PRIVATE CPU_PROFILE_ENABLED)
-endif()
-
# Profiling API depends on the logging interface and the HAL library.
target_link_libraries(profiler PRIVATE log hal)
-# Set the CPU profiling defintiion
-target_compile_definitions(profiler PUBLIC
- $<$<BOOL:${CPU_PROFILE_ENABLED}>:CPU_PROFILE_ENABLED>)
-
# Display status
message(STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "*******************************************************")
diff --git a/source/profiler/Profiler.cc b/source/profiler/Profiler.cc
index efbc64d..7e10097 100644
--- a/source/profiler/Profiler.cc
+++ b/source/profiler/Profiler.cc
@@ -40,7 +40,7 @@ namespace app {
}
if (this->m_pPlatform && !this->m_started) {
this->m_pPlatform->timer->reset();
- this->m_tstampSt = this->m_pPlatform->timer->start_profiling();
+ this->m_tstampSt = this->m_pPlatform->timer->get_counters();
this->m_started = true;
return true;
}
@@ -51,7 +51,7 @@ namespace app {
bool Profiler::StopProfiling()
{
if (this->m_pPlatform && this->m_started) {
- this->m_tstampEnd = this->m_pPlatform->timer->stop_profiling();
+ this->m_tstampEnd = this->m_pPlatform->timer->get_counters();
this->m_started = false;
this->AddProfilingUnit(this->m_tstampSt, this->m_tstampEnd, this->m_name);
@@ -99,111 +99,28 @@ namespace app {
result.name = item.first;
result.samplesNum = series.size();
- Statistics AXI0_RD {
- .name = "NPU AXI0_RD_DATA_BEAT_RECEIVED",
- .unit = "beats",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].axi0writes,
- .max = 0
- };
- Statistics AXI0_WR {
- .name = "NPU AXI0_WR_DATA_BEAT_WRITTEN",
- .unit = "beats",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].axi0reads,
- .max = 0
- };
- Statistics AXI1_RD {
- .name = "NPU AXI1_RD_DATA_BEAT_RECEIVED",
- .unit = "beats",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].axi1reads,
- .max = 0
- };
- Statistics NPU_ACTIVE {
- .name = "NPU ACTIVE",
- .unit = "cycles",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].activeNpuCycles,
- .max = 0
- };
- Statistics NPU_IDLE {
- .name = "NPU IDLE",
- .unit = "cycles",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].idleNpuCycles,
- .max = 0
- };
- Statistics NPU_Total {
- .name = "NPU TOTAL",
- .unit = "cycles",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].npuCycles,
- .max = 0,
- };
-#if defined(CPU_PROFILE_ENABLED)
- Statistics CPU_ACTIVE {
- .name = "CPU ACTIVE",
- .unit = "cycles (approx)",
- .total = 0,
- .avrg = 0.0,
- .min = series[0].cpuCycles - NPU_ACTIVE.min,
- .max = 0
- };
- Statistics TIME {
- .name = "Time",
- .unit = "ms",
- .total = 0,
- .avrg = 0.0,
- .min = static_cast<uint64_t>(series[0].time),
- .max = 0
- };
-#endif
- for(ProfilingUnit& unit: series){
-
- calcProfilingStat(unit.npuCycles,
- NPU_Total, result.samplesNum);
-
- calcProfilingStat(unit.activeNpuCycles,
- NPU_ACTIVE, result.samplesNum);
-
- calcProfilingStat(unit.idleNpuCycles,
- NPU_IDLE, result.samplesNum);
-
- calcProfilingStat(unit.axi0writes,
- AXI0_WR, result.samplesNum);
-
- calcProfilingStat(unit.axi0reads,
- AXI0_RD, result.samplesNum);
+ std::vector<Statistics> stats(series[0].counters.num_counters);
+ for (size_t i = 0; i < stats.size(); ++i) {
+ stats[i].name = series[0].counters.counters[i].name;
+ stats[i].unit = series[0].counters.counters[i].unit;
+ }
- calcProfilingStat(unit.axi1reads,
- AXI1_RD, result.samplesNum);
-#if defined(CPU_PROFILE_ENABLED)
- calcProfilingStat(static_cast<uint64_t>(unit.time),
- TIME, result.samplesNum);
+ for(ProfilingUnit& unit: series) {
+ for (size_t i = 0; i < stats.size(); ++i) {
+ calcProfilingStat(
+ unit.counters.counters[i].value,
+ stats[i],
+ result.samplesNum);
+ }
+ }
- calcProfilingStat(unit.cpuCycles - unit.activeNpuCycles,
- CPU_ACTIVE, result.samplesNum);
-#endif
+ for (Statistics& stat : stats) {
+ result.data.emplace_back(stat);
}
- result.data.emplace_back(AXI0_RD);
- result.data.emplace_back(AXI0_WR);
- result.data.emplace_back(AXI1_RD);
- result.data.emplace_back(NPU_ACTIVE);
- result.data.emplace_back(NPU_IDLE);
- result.data.emplace_back(NPU_Total);
-#if defined(CPU_PROFILE_ENABLED)
- result.data.emplace_back(CPU_ACTIVE);
- result.data.emplace_back(TIME);
-#endif
- results.emplace_back(result);
+
+ results.emplace_back(result);
}
+
this->Reset();
}
@@ -216,10 +133,11 @@ namespace app {
std::vector<ProfileResult> results{};
GetAllResultsAndReset(results);
for(ProfileResult& result: results) {
- info("Profile for %s:\n", result.name.c_str());
-
- if (printFullStat) {
- printStatisticsHeader(result.samplesNum);
+ if (result.data.size()) {
+ info("Profile for %s:\n", result.name.c_str());
+ if (printFullStat) {
+ printStatisticsHeader(result.samplesNum);
+ }
}
for (Statistics &stat: result.data) {
@@ -228,7 +146,7 @@ namespace app {
stat.name.c_str(), stat.unit.c_str(),
stat.total, stat.avrg, stat.min, stat.max);
} else {
- info("%s %s: %.0f\n", stat.name.c_str(), stat.unit.c_str(), stat.avrg);
+ info("%s: %.0f %s\n", stat.name.c_str(), stat.avrg, stat.unit.c_str());
}
}
}
@@ -239,7 +157,7 @@ namespace app {
this->m_name = std::string(str);
}
- void Profiler::AddProfilingUnit(time_counter start, time_counter end,
+ void Profiler::AddProfilingUnit(pmu_counters start, pmu_counters end,
const std::string& name)
{
if (!this->m_pPlatform) {
@@ -247,31 +165,23 @@ namespace app {
return;
}
- platform_timer * timer = this->m_pPlatform->timer;
+ struct ProfilingUnit unit = {
+ .counters = end
+ };
- struct ProfilingUnit unit;
-
- if (timer->cap.npu_cycles && timer->get_npu_cycles_diff)
- {
- const size_t size = 6;
- uint64_t pmuCounters[size] = {0};
- /* 6 values: total cc, active cc, idle cc, axi0 read, axi0 write, axi1 read*/
- if (0 == timer->get_npu_cycles_diff(&start, &end, pmuCounters, size)) {
- unit.npuCycles = pmuCounters[0];
- unit.activeNpuCycles = pmuCounters[1];
- unit.idleNpuCycles = pmuCounters[2];
- unit.axi0reads = pmuCounters[3];
- unit.axi0writes = pmuCounters[4];
- unit.axi1reads = pmuCounters[5];
- }
- }
-
- if (timer->cap.cpu_cycles && timer->get_cpu_cycle_diff) {
- unit.cpuCycles = timer->get_cpu_cycle_diff(&start, &end);
+ if (end.num_counters != start.num_counters ||
+ true != end.initialised || true != start.initialised) {
+ printf_err("Invalid start or end counters\n");
+ return;
}
- if (timer->cap.duration_ms && timer->get_duration_ms) {
- unit.time = timer->get_duration_ms(&start, &end);
+ for (size_t i = 0; i < unit.counters.num_counters; ++i) {
+ if (unit.counters.counters[i].value < start.counters[i].value) {
+ warn("Overflow detected for %s\n", unit.counters.counters[i].name);
+ unit.counters.counters[i].value = 0;
+ } else {
+ unit.counters.counters[i].value -= start.counters[i].value;
+ }
}
this->m_series[name].emplace_back(unit);
diff --git a/source/profiler/include/Profiler.hpp b/source/profiler/include/Profiler.hpp
index 503d805..b8f9089 100644
--- a/source/profiler/include/Profiler.hpp
+++ b/source/profiler/include/Profiler.hpp
@@ -45,14 +45,7 @@ namespace app {
/** A single profiling unit definition. */
struct ProfilingUnit {
- uint64_t npuCycles = 0;
- uint64_t activeNpuCycles = 0;
- uint64_t idleNpuCycles = 0;
- uint64_t axi0writes = 0;
- uint64_t axi0reads = 0;
- uint64_t axi1reads = 0;
- uint64_t cpuCycles = 0;
- time_t time = 0;
+ pmu_counters counters;
};
/* A collection of profiling units. */
@@ -108,8 +101,8 @@ namespace app {
private:
ProfilingMap m_series; /* Profiling series map. */
- time_counter m_tstampSt{}; /* Container for a current starting timestamp. */
- time_counter m_tstampEnd{}; /* Container for a current ending timestamp. */
+ pmu_counters m_tstampSt{}; /* Container for a current starting timestamp. */
+ pmu_counters m_tstampEnd{}; /* Container for a current ending timestamp. */
hal_platform * m_pPlatform = nullptr; /* Platform pointer - to get the timer. */
bool m_started = false; /* Indicates profiler has been started. */
@@ -125,7 +118,7 @@ namespace app {
* @param[in] name Name for the profiling unit series to be
* appended to.
**/
- void AddProfilingUnit(time_counter start, time_counter end,
+ void AddProfilingUnit(pmu_counters start, pmu_counters end,
const std::string& name);
};