From 9f35546339433e977bf45c97cae280e892fd0e6e Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Fri, 28 Jun 2024 10:36:00 +0200 Subject: [PATCH 1/9] performance measurement: add bitmap functionality based on bitarray Implement wrapper to extend Zephyr's bitarray by adding a counter for allocated bits. This bitmap will be used to allocate performance data entries in memory window 3. Also adds new performance_monitor files. Signed-off-by: Tobiasz Dryjanski --- src/debug/telemetry/CMakeLists.txt | 1 + src/debug/telemetry/performance_monitor.c | 83 +++++++++++++++++++ .../sof/debug/telemetry/performance_monitor.h | 11 +++ 3 files changed, 95 insertions(+) create mode 100644 src/debug/telemetry/performance_monitor.c create mode 100644 src/include/sof/debug/telemetry/performance_monitor.h diff --git a/src/debug/telemetry/CMakeLists.txt b/src/debug/telemetry/CMakeLists.txt index f2249490db60..6be536afc0c5 100644 --- a/src/debug/telemetry/CMakeLists.txt +++ b/src/debug/telemetry/CMakeLists.txt @@ -1,3 +1,4 @@ # SPDX-License-Identifier: BSD-3-Clause add_local_sources_ifdef(CONFIG_SOF_TELEMETRY sof telemetry.c) +add_local_sources_ifdef(CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS sof performance_monitor.c) \ No newline at end of file diff --git a/src/debug/telemetry/performance_monitor.c b/src/debug/telemetry/performance_monitor.c new file mode 100644 index 000000000000..27a7b10b7109 --- /dev/null +++ b/src/debug/telemetry/performance_monitor.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Intel Corporation. All rights reserved. +// +// Author: Tobiasz Dryjanski + +#include + +struct perf_bitmap { + sys_bitarray_t *array; + uint16_t occupied; + size_t size; +}; + +static int perf_bitmap_init(struct perf_bitmap * const bitmap, sys_bitarray_t *array, size_t size) +{ + k_spinlock_key_t key = k_spin_lock(&array->lock); + + bitmap->array = array; + bitmap->size = size; + bitmap->occupied = 0; + + k_spin_unlock(&array->lock, key); + return 0; +} + +static int perf_bitmap_alloc(struct perf_bitmap * const bitmap, size_t *offset) +{ + k_spinlock_key_t key; + int ret = sys_bitarray_alloc(bitmap->array, 1, offset); + + if (!ret) { + key = k_spin_lock(&bitmap->array->lock); + bitmap->occupied++; + k_spin_unlock(&bitmap->array->lock, key); + } + + return ret; +} + +static int perf_bitmap_free(struct perf_bitmap * const bitmap, size_t offset) +{ + k_spinlock_key_t key; + int ret = sys_bitarray_free(bitmap->array, 1, offset); + + if (!ret) { + key = k_spin_lock(&bitmap->array->lock); + bitmap->occupied--; + k_spin_unlock(&bitmap->array->lock, key); + } + + return ret; +} + +static int perf_bitmap_setbit(struct perf_bitmap * const bitmap, size_t bit) +{ + return sys_bitarray_set_bit(bitmap->array, bit); +} + +static int perf_bitmap_clearbit(struct perf_bitmap * const bitmap, size_t bit) +{ + return sys_bitarray_clear_bit(bitmap->array, bit); +} + +static inline uint16_t perf_bitmap_get_occupied(struct perf_bitmap * const bitmap) +{ + return bitmap->occupied; +} + +static inline uint16_t perf_bitmap_get_size(struct perf_bitmap * const bitmap) +{ + return bitmap->size; +} + +static bool perf_bitmap_is_bit_clear(struct perf_bitmap * const bitmap, size_t bit) +{ + int val; + int ret = sys_bitarray_test_bit(bitmap->array, bit, &val); + + if (ret < 0) + return false; + return !val; +} diff --git a/src/include/sof/debug/telemetry/performance_monitor.h b/src/include/sof/debug/telemetry/performance_monitor.h new file mode 100644 index 000000000000..c98038f41d35 --- /dev/null +++ b/src/include/sof/debug/telemetry/performance_monitor.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Intel Corporation. All rights reserved. + * + * Author: Tobiasz Dryjanski + */ + +#ifndef __SOF_PERFORMANCE_MONITOR_H__ +#define __SOF_PERFORMANCE_MONITOR_H__ + +#endif From 7a92fb0eda3289c55abd28b8c72b99ce9915f2ba Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Fri, 10 May 2024 18:39:33 +0200 Subject: [PATCH 2/9] component: add chunk size, ibs and obs to component struct Add data to component struct for computing performance. Signed-off-by: Tobiasz Dryjanski --- src/audio/component.c | 44 +++++++++++++++++++++++++++++++ src/include/sof/audio/component.h | 16 +++++++++++ src/ipc/ipc4/helper.c | 2 ++ 3 files changed, 62 insertions(+) diff --git a/src/audio/component.c b/src/audio/component.c index 0186f5531dcd..569e93304e8f 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -505,3 +505,47 @@ int comp_copy(struct comp_dev *dev) return ret; } + +#if CONFIG_IPC_MAJOR_4 +static uint32_t get_sample_group_size_in_bytes(const struct ipc4_audio_format fmt) +{ + return (fmt.depth >> 3) * fmt.channels_count; +} + +static uint32_t get_one_ms_in_bytes(const struct ipc4_audio_format fmt) +{ + /* TODO Reference Firmware also has systick multiplier and divider in this equation */ + return get_sample_group_size_in_bytes(fmt) * + SOF_DIV_ROUND_UP(fmt.sampling_frequency, 1000); +} +#endif + +void comp_update_ibs_obs_cpc(struct comp_dev *dev) +{ +#if CONFIG_IPC_MAJOR_4 + int ret; + struct ipc4_base_module_cfg dev_cfg; + + ret = comp_get_attribute(dev, COMP_ATTR_BASE_CONFIG, &dev_cfg); + if (ret < 0) { + tr_err(&ipc_tr, "failed to get base config for module %#x", + dev_comp_id(dev)); + /* set neutral values */ + dev->ll_chunk_size = 0; + dev->cpc = 0; + dev->obs = 0; + dev->ibs = 0; + } + dev->ll_chunk_size = get_one_ms_in_bytes(dev_cfg.audio_fmt); + dev->obs = dev_cfg.obs; + dev->ibs = dev_cfg.ibs; + dev->cpc = dev_cfg.cpc; +#else + /* set neutral values */ + dev->ll_chunk_size = 0; + dev->cpc = 0; + dev->obs = 0; + dev->ibs = 0; +#endif +} + diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 4dfa2e66a26a..2a34961dcf0f 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -598,6 +598,15 @@ struct comp_dev { struct list_item bsource_list; /**< list of source buffers */ struct list_item bsink_list; /**< list of sink buffers */ + /* Input Buffer Size for pin 0, add array for other pins if needed */ + size_t ibs; + /* Output Buffers Size for pin 0, add array for other pins if needed */ + size_t obs; + /* max dsp cycles per chunk */ + size_t cpc; + /* size of 1ms for input format in bytes */ + size_t ll_chunk_size : 16; + /* private data - core does not touch this */ void *priv_data; /**< private data */ @@ -925,4 +934,11 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, /** @}*/ +/** + * Update ibs, obs, cpc, ll chunk size for component. + * + * @param dev Component to update. + */ +void comp_update_ibs_obs_cpc(struct comp_dev *dev); + #endif /* __SOF_AUDIO_COMPONENT_H__ */ diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index aa6505218854..36deaeb809f1 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -158,6 +158,8 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) ipc4_add_comp_dev(dev); + comp_update_ibs_obs_cpc(dev); + return dev; } From 19f0a989e84cd2af667650e8bea183dd595247af Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Wed, 22 May 2024 17:05:29 +0200 Subject: [PATCH 3/9] memory window: add MW3 access macro Add temporary macro for accessing memory window 3 data. Signed-off-by: Tobiasz Dryjanski --- src/include/sof/debug/telemetry/telemetry.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/include/sof/debug/telemetry/telemetry.h b/src/include/sof/debug/telemetry/telemetry.h index 959e379308e4..f3f80df83764 100644 --- a/src/include/sof/debug/telemetry/telemetry.h +++ b/src/include/sof/debug/telemetry/telemetry.h @@ -15,6 +15,12 @@ /* disables calculating systick_averages */ #define SOF_PERFORMANCE_MEASUREMENTS +/* to be moved to Zephyr */ +#define WIN3_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window3), memory)) +#define ADSP_PMW ((volatile uint32_t *) \ + (sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \ + (WIN3_MBASE + WIN3_OFFSET)))) + /* Systick here is not to be confused with neither Zephyr tick nor SOF scheduler tick, * it's a legacy name for counting execution time */ From fc73ecd4ce732eb59784de643118489c099672d8 Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Thu, 6 Jun 2024 10:53:30 +0200 Subject: [PATCH 4/9] performance measurements: add CONFIG for perf meas Add config to enable global performance measurements. Signed-off-by: Tobiasz Dryjanski --- src/debug/telemetry/Kconfig | 9 +++++++++ src/debug/telemetry/telemetry.c | 6 +++++- src/include/sof/debug/telemetry/telemetry.h | 2 -- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/debug/telemetry/Kconfig b/src/debug/telemetry/Kconfig index 54f4b66f590d..6aca1db92916 100644 --- a/src/debug/telemetry/Kconfig +++ b/src/debug/telemetry/Kconfig @@ -9,3 +9,12 @@ config SOF_TELEMETRY systick_info measurement which measures scheduler task performance and may slightly affect overall performance. +config SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + bool "enable performance measurements" + default n + help + Enables performance measurements. Requires ADSP_MW interface. Each created component + can have its performance checked by measuring execution time of copy function. + Performance records are stored in the limited number of slots in Memory Window 3, + so only a certain number (PERFORMANCE_DATA_ENTRIES_COUNT) of components can be measured. + diff --git a/src/debug/telemetry/telemetry.c b/src/debug/telemetry/telemetry.c index ffb0376d3473..7da7f9682197 100644 --- a/src/debug/telemetry/telemetry.c +++ b/src/debug/telemetry/telemetry.c @@ -23,11 +23,14 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); /* Systic variables, one set per core */ static int telemetry_systick_counter[CONFIG_MAX_CORE_COUNT]; +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS static int telemetry_prev_ccount[CONFIG_MAX_CORE_COUNT]; static int telemetry_perf_period_sum[CONFIG_MAX_CORE_COUNT]; static int telemetry_perf_period_cnt[CONFIG_MAX_CORE_COUNT]; static struct telemetry_perf_queue telemetry_perf_queue[CONFIG_MAX_CORE_COUNT]; +#endif +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS static void telemetry_perf_queue_append(struct telemetry_perf_queue *q, size_t element) { if (!q->full) { @@ -59,6 +62,7 @@ static size_t telemetry_perf_queue_avg(struct telemetry_perf_queue *q) return 0; return q->sum / q->size; } +#endif int telemetry_init(void) { @@ -107,7 +111,7 @@ void telemetry_update(uint32_t begin_stamp, uint32_t current_stamp) systick_info[prid].max_time_elapsed); systick_info[prid].last_ccount = current_stamp; -#ifdef SOF_PERFORMANCE_MEASUREMENTS +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS const size_t measured_systick = begin_stamp - telemetry_prev_ccount[prid]; telemetry_prev_ccount[prid] = begin_stamp; diff --git a/src/include/sof/debug/telemetry/telemetry.h b/src/include/sof/debug/telemetry/telemetry.h index f3f80df83764..1156dc166a6e 100644 --- a/src/include/sof/debug/telemetry/telemetry.h +++ b/src/include/sof/debug/telemetry/telemetry.h @@ -12,8 +12,6 @@ #define SOF_AVG_PERF_MEAS_DEPTH 64 /* Number of runs taken to calculate average (algorithm resolution) */ #define SOF_AVG_PERF_MEAS_PERIOD 16 -/* disables calculating systick_averages */ -#define SOF_PERFORMANCE_MEASUREMENTS /* to be moved to Zephyr */ #define WIN3_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window3), memory)) From 59eea9fe7302605bd37f89ea3fee58590227d5f4 Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Thu, 6 Jun 2024 10:54:29 +0200 Subject: [PATCH 5/9] performance measurements: enable performance measurements Enable global performance measutements. Signed-off-by: Tobiasz Dryjanski --- app/boards/intel_adsp_ace15_mtpm.conf | 1 + app/boards/intel_adsp_ace20_lnl.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 0348c9da5aa9..2170ba7f6620 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -45,6 +45,7 @@ CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y CONFIG_AMS=y CONFIG_COUNTER=y CONFIG_SOF_TELEMETRY=y +CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_L3_HEAP=y diff --git a/app/boards/intel_adsp_ace20_lnl.conf b/app/boards/intel_adsp_ace20_lnl.conf index 42dea6d096ee..82643863e837 100644 --- a/app/boards/intel_adsp_ace20_lnl.conf +++ b/app/boards/intel_adsp_ace20_lnl.conf @@ -40,6 +40,7 @@ CONFIG_MM_DRV_INTEL_ADSP_TLB_REMAP_UNUSED_RAM=y CONFIG_AMS=y CONFIG_COUNTER=y CONFIG_SOF_TELEMETRY=y +CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=y CONFIG_HEAP_MEM_POOL_SIZE=8192 CONFIG_L3_HEAP=y From ac590b6e446b7148256ac6067a8667047e5e23ef Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Wed, 22 May 2024 17:19:31 +0200 Subject: [PATCH 6/9] performance measurements: global perf meas backend Implement global performance measurement which measure performance of .copy functions of multiple components. Signed-off-by: Tobiasz Dryjanski --- src/audio/base_fw.c | 1 + src/audio/component.c | 61 +++++++++ src/debug/telemetry/performance_monitor.c | 119 ++++++++++++++++++ src/debug/telemetry/telemetry.c | 2 + src/include/ipc4/base_fw.h | 27 ++++ src/include/sof/audio/component.h | 31 +++++ .../sof/debug/telemetry/performance_monitor.h | 44 +++++++ src/include/sof/debug/telemetry/telemetry.h | 8 +- src/ipc/ipc-helper.c | 5 + src/ipc/ipc4/helper.c | 14 +++ 10 files changed, 306 insertions(+), 6 deletions(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 9ba6fc087606..880ef11008f9 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -23,6 +23,7 @@ #include #include #include +#include /* FIXME: * Builds for some platforms like tgl fail because their defines related to memory windows are * already defined somewhere else. Remove this ifdef after it's cleaned up diff --git a/src/audio/component.c b/src/audio/component.c index 569e93304e8f..3fa6cb7bf727 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -495,8 +496,18 @@ int comp_copy(struct comp_dev *dev) perf_cnt_init(&dev->pcd); #endif +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + const uint32_t begin_stamp = (uint32_t)sof_cycle_get_64(); +#endif + ret = dev->drv->ops.copy(dev); +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + const uint32_t cycles_consumed = (uint32_t)sof_cycle_get_64() - begin_stamp; + + comp_update_performance_data(dev, cycles_consumed); +#endif + #if CONFIG_PERFORMANCE_COUNTERS perf_cnt_stamp(&dev->pcd, perf_trace_null, dev); perf_cnt_average(&dev->pcd, comp_perf_avg_info, dev); @@ -506,6 +517,56 @@ int comp_copy(struct comp_dev *dev) return ret; } +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS +void comp_init_performance_data(struct comp_dev *dev) +{ + struct perf_data_item_comp *item = dev->perf_data.perf_data_item; + + if (item) + perf_data_item_comp_init(item, dev->ipc_config.id, 0); +} + +/* returns true if budget violation occurred */ +static bool update_peak_of_measured_cpc(struct comp_dev *dev, size_t measured_cpc) +{ + if (measured_cpc <= dev->perf_data.peak_of_measured_cpc) + return false; + dev->perf_data.peak_of_measured_cpc = measured_cpc; + return measured_cpc > dev->cpc; +} + +bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used) +{ + struct perf_data_item_comp *item = dev->perf_data.perf_data_item; + + if (perf_meas_get_state() == IPC4_PERF_MEASUREMENTS_STARTED) { + /* we divide by ibs so we need to check if its set */ + if (item && dev->ibs != 0) { + item->total_iteration_count++; + if (item->total_iteration_count == 0) { + /* We can't allow count to overflow to 0. Overflow will also make + * some of the results incorrect. We don't want to crash in this + * case, so we just log it. We also reset cycles counter to make + * avg correct again. + */ + item->total_iteration_count = 1; + item->total_cycles_consumed = 0; + tr_err(&ipc_tr, + "overflow for module %#x, performance measurement incorrect", + dev_comp_id(dev)); + } + item->total_cycles_consumed += cycles_used; + item->item.avg_kcps = item->total_cycles_consumed * dev->ll_chunk_size + / (dev->ibs * item->total_iteration_count); + item->item.peak_kcps = + MAX(item->item.peak_kcps, (cycles_used * dev->ll_chunk_size) + / dev->ibs); + } + } + return update_peak_of_measured_cpc(dev, cycles_used); +} +#endif + #if CONFIG_IPC_MAJOR_4 static uint32_t get_sample_group_size_in_bytes(const struct ipc4_audio_format fmt) { diff --git a/src/debug/telemetry/performance_monitor.c b/src/debug/telemetry/performance_monitor.c index 27a7b10b7109..f63be2aed843 100644 --- a/src/debug/telemetry/performance_monitor.c +++ b/src/debug/telemetry/performance_monitor.c @@ -4,14 +4,40 @@ // // Author: Tobiasz Dryjanski +#include #include +#include +#include +#include +#include +#include + +#include + +#include + +#define PERFORMANCE_DATA_ENTRIES_COUNT \ + (CONFIG_MEMORY_WIN_3_SIZE / sizeof(struct perf_data_item_comp)) + +SYS_BITARRAY_DEFINE_STATIC(performance_data_bit_array, PERFORMANCE_DATA_ENTRIES_COUNT); + struct perf_bitmap { sys_bitarray_t *array; uint16_t occupied; size_t size; }; +struct perf_bitmap performance_data_bitmap; + +struct perf_data_item_comp *perf_data; + +/* Note that ref. FW used one state per core, all set together to the same state + * by one IPC but only for active cores. It may work slightly different in case + * where we enable a core while perf meas is started. + */ +enum ipc4_perf_measurements_state_set perf_measurements_state = IPC4_PERF_MEASUREMENTS_DISABLED; + static int perf_bitmap_init(struct perf_bitmap * const bitmap, sys_bitarray_t *array, size_t size) { k_spinlock_key_t key = k_spin_lock(&array->lock); @@ -81,3 +107,96 @@ static bool perf_bitmap_is_bit_clear(struct perf_bitmap * const bitmap, size_t b return false; return !val; } + +struct perf_data_item_comp *perf_data_getnext(void) +{ + int idx; + int ret = perf_bitmap_alloc(&performance_data_bitmap, &idx); + + if (ret < 0) + return NULL; + /* ref. FW did not set the bits, but here we do it to not have to use + * isFree() check that the bitarray does not provide yet. Instead we will use isClear + * ,and always set bit on bitmap alloc. + */ + ret = perf_bitmap_setbit(&performance_data_bitmap, idx); + if (ret < 0) + return NULL; + return &perf_data[idx]; +} + +int perf_data_free(struct perf_data_item_comp * const item) +{ + /* find index of item */ + int idx = (item - perf_data) / sizeof(*item); + int ret = perf_bitmap_clearbit(&performance_data_bitmap, idx); + + if (ret < 0) + return ret; + ret = perf_bitmap_free(&performance_data_bitmap, idx); + if (ret < 0) + return ret; + + return 0; +} + +void perf_data_item_comp_reset(struct perf_data_item_comp *perf) +{ + perf->total_iteration_count = 0; + perf->total_cycles_consumed = 0; + perf->restricted_total_iterations = 0; + perf->restricted_total_cycles = 0; + perf->restricted_peak_cycles = 0; + perf->item.peak_kcps = 0; + perf->item.avg_kcps = 0; +} + +void perf_data_item_comp_init(struct perf_data_item_comp *perf, uint32_t resource_id, + uint32_t power_mode) +{ + perf_data_item_comp_reset(perf); + perf->item.resource_id = resource_id; + perf->item.is_removed = false; + perf->item.power_mode = power_mode; +} + +int free_performance_data(struct perf_data_item_comp *item) +{ + int ret; + + if (item) { + item->item.is_removed = true; + /* if we don't get the disabled state now, item will be + * deleted on next disable perf meas message + */ + if (perf_measurements_state == IPC4_PERF_MEASUREMENTS_DISABLED) { + ret = perf_data_free(item); + if (ret < 0) + return ret; + } + } + return 0; +} + +enum ipc4_perf_measurements_state_set perf_meas_get_state(void) +{ + return perf_measurements_state; +} + +void perf_meas_set_state(enum ipc4_perf_measurements_state_set state) +{ + perf_measurements_state = state; +} + +int performance_monitor_init(void) +{ + /* init global performance measurement */ + perf_data = (struct perf_data_item_comp *)ADSP_PMW; + perf_bitmap_init(&performance_data_bitmap, &performance_data_bit_array, + PERFORMANCE_DATA_ENTRIES_COUNT); + + return 0; +} + +/* init performance monitor using Zephyr */ +SYS_INIT(performance_monitor_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/src/debug/telemetry/telemetry.c b/src/debug/telemetry/telemetry.c index 7da7f9682197..9a644737d611 100644 --- a/src/debug/telemetry/telemetry.c +++ b/src/debug/telemetry/telemetry.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -90,6 +91,7 @@ int telemetry_init(void) systick_info[i].peak_utilization_4k = 0; systick_info[i].peak_utilization_8k = 0; } + return 0; } diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index 6f6c0091cc80..41f1e166fedd 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -731,4 +731,31 @@ struct ipc4_system_time_info *basefw_get_system_time_info(void); /* Specifies I2S IPC4 version for PTL platform */ static const uint32_t I2S_VER_30_PTL = 0x40000; +struct perf_data_item { + /* ID of the FW component */ + uint32_t resource_id; + /* 0 - D0, 1 - D0i3. */ + uint32_t power_mode : 1; + uint32_t rsvd : 30; + /* the component still exists (0) or has been already deleted (1) */ + uint32_t is_removed : 1; + /* Peak KCPS captured */ + uint32_t peak_kcps; + /* Average KCPS measured */ + uint32_t avg_kcps; +} __packed __aligned(4); + +struct perf_data_item_comp { + struct perf_data_item item; + /* Total iteration count of module instance */ + uint32_t total_iteration_count; + /* Total cycles consumed by module instance */ + uint64_t total_cycles_consumed; + /* usage statistics against DSP wallclock cycles */ + uint32_t restricted_peak_cycles; + uint64_t restricted_total_iterations; + uint64_t restricted_total_cycles; + +} __packed __aligned(4); + #endif /* __SOF_IPC4_BASE_FW_H__ */ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 2a34961dcf0f..47b1eab311f4 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -554,6 +555,18 @@ struct comp_ipc_config { #endif }; +struct comp_perf_data { + /* maximum measured cpc on run-time. + * + * if current measured cpc exceeds peak_of_measured_cpc_ then + * ResoruceEvent(BUDGET_VIOLATION) notification must be send. + * Otherwise there is no new information for host to care about + */ + size_t peak_of_measured_cpc; + /* Pointer to performance data structure. */ + struct perf_data_item_comp *perf_data_item; +}; + /** * Audio component base device "class" * - used by other component types. @@ -598,6 +611,8 @@ struct comp_dev { struct list_item bsource_list; /**< list of source buffers */ struct list_item bsink_list; /**< list of sink buffers */ + /* performance data*/ + struct comp_perf_data perf_data; /* Input Buffer Size for pin 0, add array for other pins if needed */ size_t ibs; /* Output Buffers Size for pin 0, add array for other pins if needed */ @@ -941,4 +956,20 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, */ void comp_update_ibs_obs_cpc(struct comp_dev *dev); +/** + * If component has assigned slot in performance measurement window, + * initialize its fields. + * @param dev Component to init. + */ +void comp_init_performance_data(struct comp_dev *dev); + +/** + * Update performance data entry for component. Also checks for budget violation. + * + * @param dev Component to update. + * @param cycles_used Execution time. + * @return true if budget violation occurred + */ +bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used); + #endif /* __SOF_AUDIO_COMPONENT_H__ */ diff --git a/src/include/sof/debug/telemetry/performance_monitor.h b/src/include/sof/debug/telemetry/performance_monitor.h index c98038f41d35..182c7427f77f 100644 --- a/src/include/sof/debug/telemetry/performance_monitor.h +++ b/src/include/sof/debug/telemetry/performance_monitor.h @@ -8,4 +8,48 @@ #ifndef __SOF_PERFORMANCE_MONITOR_H__ #define __SOF_PERFORMANCE_MONITOR_H__ +/* to be moved to Zephyr */ +#define WIN3_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window3), memory)) +#define ADSP_PMW ((volatile uint32_t *) \ + (sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \ + (WIN3_MBASE + WIN3_OFFSET)))) + +/** + * Initializer for struct perf_data_item_comp + * + * @param[out] perf Struct to be initialized + * @param[in] resource_id + * @param[in] power_mode + */ +void perf_data_item_comp_init(struct perf_data_item_comp *perf, uint32_t resource_id, + uint32_t power_mode); + +/** + * Get next free performance data slot from Memory Window 3 + * + * @return performance data record + */ +struct perf_data_item_comp *perf_data_getnext(void); + +/** + * Free a performance data slot in Memory Window 3 + * + * @return 0 if succeeded, in other case the slot is already free + */ +int free_performance_data(struct perf_data_item_comp *item); + +/** + * Set performance measurements state + * + * @param[in] state Value to be set. + */ +void perf_meas_set_state(enum ipc4_perf_measurements_state_set state); + +/** + * Get performance measurements state + * + * @return performance measurements state + */ +enum ipc4_perf_measurements_state_set perf_meas_get_state(void); + #endif diff --git a/src/include/sof/debug/telemetry/telemetry.h b/src/include/sof/debug/telemetry/telemetry.h index 1156dc166a6e..6c46cd88646f 100644 --- a/src/include/sof/debug/telemetry/telemetry.h +++ b/src/include/sof/debug/telemetry/telemetry.h @@ -6,6 +6,8 @@ #ifndef __SOF_TELEMETRY_H__ #define __SOF_TELEMETRY_H__ +#include + /* Slot in memory window 2 (Debug Window) to be used as telemetry slot */ #define SOF_DW_TELEMETRY_SLOT 1 /* Memory of average algorithm of performance queue */ @@ -13,12 +15,6 @@ /* Number of runs taken to calculate average (algorithm resolution) */ #define SOF_AVG_PERF_MEAS_PERIOD 16 -/* to be moved to Zephyr */ -#define WIN3_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window3), memory)) -#define ADSP_PMW ((volatile uint32_t *) \ - (sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \ - (WIN3_MBASE + WIN3_OFFSET)))) - /* Systick here is not to be confused with neither Zephyr tick nor SOF scheduler tick, * it's a legacy name for counting execution time */ diff --git a/src/ipc/ipc-helper.c b/src/ipc/ipc-helper.c index 23a14fade8e4..207645f1dd5b 100644 --- a/src/ipc/ipc-helper.c +++ b/src/ipc/ipc-helper.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -281,6 +282,10 @@ int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) return -EINVAL; } +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + free_performance_data(icd->cd->perf_data.perf_data_item); +#endif + if (!icd->cd->bsource_list.next || !icd->cd->bsink_list.next) { /* Unfortunate: the buffer list node gets initialized * at the component level and thus can contain NULLs diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 36deaeb809f1..3e9ce9016622 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -51,6 +51,9 @@ #include #include +#include +#include + LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); extern struct tr_ctx comp_tr; @@ -156,6 +159,17 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) list_init(&dev->bsource_list); list_init(&dev->bsink_list); +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + /* init global performance measurement */ + dev->perf_data.perf_data_item = perf_data_getnext(); + /* this can be null, just no performance measurements in this case */ + if (dev->perf_data.perf_data_item) { + dev->perf_data.perf_data_item->item.resource_id = comp_id; + if (perf_meas_get_state() != IPC4_PERF_MEASUREMENTS_DISABLED) + comp_init_performance_data(dev); + } +#endif + ipc4_add_comp_dev(dev); comp_update_ibs_obs_cpc(dev); From ecc69e4dcd6318729f1b6b55795d9633f82a01db Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Tue, 14 May 2024 13:05:59 +0200 Subject: [PATCH 7/9] performance measurements: add global perf data get ipc Implement global performance data get ipc which extracts performance data from MW3 Signed-off-by: Tobiasz Dryjanski --- src/audio/base_fw.c | 22 +++++++- src/debug/telemetry/performance_monitor.c | 53 +++++++++++++++++++ src/include/ipc4/base_fw.h | 8 +++ .../sof/debug/telemetry/performance_monitor.h | 8 +++ 4 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 880ef11008f9..e12a7f93dd83 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include /* FIXME: @@ -429,6 +430,24 @@ int set_perf_meas_state(const char *data) return IPC4_SUCCESS; } +static int global_perf_data_get(uint32_t *data_off_size, char *data) +{ +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + int ret; + struct global_perf_data *perf_data = (struct global_perf_data *)data; + + ret = get_performance_data(perf_data); + if (ret < 0) + return IPC4_ERROR_INVALID_PARAM; + *data_off_size = sizeof(*perf_data) + + perf_data->perf_item_count * sizeof(*perf_data->perf_items); + + return IPC4_SUCCESS; +#else + return IPC4_UNAVAILABLE; +#endif +} + static int basefw_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_block, @@ -468,13 +487,14 @@ static int basefw_get_large_config(struct comp_dev *dev, return basefw_modules_info_get(data_offset, data); case IPC4_LIBRARIES_INFO_GET: return basefw_libraries_info_get(data_offset, data); + case IPC4_GLOBAL_PERF_DATA: + return global_perf_data_get(data_offset, data); /* TODO: add more support */ case IPC4_DSP_RESOURCE_STATE: case IPC4_NOTIFICATION_MASK: case IPC4_PIPELINE_PROPS_GET: case IPC4_GATEWAYS_INFO_GET: case IPC4_PERF_MEASUREMENTS_STATE: - case IPC4_GLOBAL_PERF_DATA: COMPILER_FALLTHROUGH; default: break; diff --git a/src/debug/telemetry/performance_monitor.c b/src/debug/telemetry/performance_monitor.c index f63be2aed843..ef93223f1b43 100644 --- a/src/debug/telemetry/performance_monitor.c +++ b/src/debug/telemetry/performance_monitor.c @@ -4,7 +4,12 @@ // // Author: Tobiasz Dryjanski +#include #include +#include +#include +#include + #include #include @@ -15,7 +20,12 @@ #include +#include +#include #include +#include + +LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); #define PERFORMANCE_DATA_ENTRIES_COUNT \ (CONFIG_MEMORY_WIN_3_SIZE / sizeof(struct perf_data_item_comp)) @@ -188,6 +198,49 @@ void perf_meas_set_state(enum ipc4_perf_measurements_state_set state) perf_measurements_state = state; } +int get_performance_data(struct global_perf_data * const global_perf_data) +{ + if (!global_perf_data) { + tr_err(&ipc_tr, "IPC data is NULL"); + return -EINVAL; + } + + size_t slots_count; + size_t slot_idx = 0; + struct telemetry_wnd_data *wnd_data = + (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; + struct system_tick_info *systick_info = + (struct system_tick_info *)wnd_data->system_tick_info; + + /* Fill one performance record with performance stats per core */ + for (int core_id = 0; core_id < CONFIG_MAX_CORE_COUNT; ++core_id) { + if (!(cpu_enabled_cores() & BIT(core_id))) + continue; + memset(&global_perf_data->perf_items[slot_idx], 0, sizeof(struct perf_data_item)); + + global_perf_data->perf_items[slot_idx].resource_id = core_id; + global_perf_data->perf_items[slot_idx].avg_kcps = + systick_info[core_id].avg_utilization; + global_perf_data->perf_items[slot_idx].peak_kcps = + systick_info[core_id].peak_utilization; + ++slot_idx; + } + slots_count = perf_bitmap_get_occupied(&performance_data_bitmap) + slot_idx; + global_perf_data->perf_item_count = slots_count; + + /* fill the rest of the IPC records with data from + * components registered in MW3 for performance measurement + */ + for (int idx = 0; idx < perf_bitmap_get_size(&performance_data_bitmap) && + slot_idx < slots_count; ++idx) { + if (perf_bitmap_is_bit_clear(&performance_data_bitmap, idx)) + continue; + global_perf_data->perf_items[slot_idx] = perf_data[idx].item; + ++slot_idx; + } + return 0; +} + int performance_monitor_init(void) { /* init global performance measurement */ diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index 41f1e166fedd..83a41d329a48 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -758,4 +758,12 @@ struct perf_data_item_comp { } __packed __aligned(4); +struct global_perf_data { + /* Specifies number of items in perf_items array. */ + uint32_t perf_item_count; + /* Array of global performance measurements. */ + struct perf_data_item perf_items[0]; + +} __packed __aligned(4); + #endif /* __SOF_IPC4_BASE_FW_H__ */ diff --git a/src/include/sof/debug/telemetry/performance_monitor.h b/src/include/sof/debug/telemetry/performance_monitor.h index 182c7427f77f..9d6693e4dd00 100644 --- a/src/include/sof/debug/telemetry/performance_monitor.h +++ b/src/include/sof/debug/telemetry/performance_monitor.h @@ -52,4 +52,12 @@ void perf_meas_set_state(enum ipc4_perf_measurements_state_set state); */ enum ipc4_perf_measurements_state_set perf_meas_get_state(void); +/** + * Get global performance data entries. + * + * @param[out] global_perf_data Struct to be filled with data + * @return 0 if succeeded, error code otherwise. + */ +int get_performance_data(struct global_perf_data * const global_perf_data); + #endif From 6988d62591b632343046087e57931cf82092e3cb Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Wed, 22 May 2024 15:53:11 +0200 Subject: [PATCH 8/9] performance measurements: add extended performance data get ipc Implement extended global performance data get ipc which extracts performance data from MW3 Signed-off-by: Tobiasz Dryjanski --- src/audio/base_fw.c | 20 ++++++ src/debug/telemetry/performance_monitor.c | 67 +++++++++++++++++++ src/include/ipc4/base_fw.h | 33 +++++++++ .../sof/debug/telemetry/performance_monitor.h | 8 +++ 4 files changed, 128 insertions(+) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index e12a7f93dd83..940f4b917da3 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -430,6 +430,24 @@ int set_perf_meas_state(const char *data) return IPC4_SUCCESS; } +static int extended_global_perf_data_get(uint32_t *data_off_size, char *data) +{ +#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS + int ret; + struct extended_global_perf_data *perf_data = (struct extended_global_perf_data *)data; + + ret = get_extended_performance_data(perf_data); + if (ret < 0) + return IPC4_ERROR_INVALID_PARAM; + *data_off_size = sizeof(*perf_data) + + perf_data->perf_item_count * sizeof(*perf_data->perf_items); + + return IPC4_SUCCESS; +#else + return IPC4_UNAVAILABLE; +#endif +} + static int global_perf_data_get(uint32_t *data_off_size, char *data) { #ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS @@ -487,6 +505,8 @@ static int basefw_get_large_config(struct comp_dev *dev, return basefw_modules_info_get(data_offset, data); case IPC4_LIBRARIES_INFO_GET: return basefw_libraries_info_get(data_offset, data); + case IPC4_EXTENDED_GLOBAL_PERF_DATA: + return extended_global_perf_data_get(data_offset, data); case IPC4_GLOBAL_PERF_DATA: return global_perf_data_get(data_offset, data); /* TODO: add more support */ diff --git a/src/debug/telemetry/performance_monitor.c b/src/debug/telemetry/performance_monitor.c index ef93223f1b43..43a92cbef012 100644 --- a/src/debug/telemetry/performance_monitor.c +++ b/src/debug/telemetry/performance_monitor.c @@ -241,6 +241,73 @@ int get_performance_data(struct global_perf_data * const global_perf_data) return 0; } +int get_extended_performance_data(struct extended_global_perf_data * const ext_global_perf_data) +{ + if (!ext_global_perf_data) { + tr_err(&ipc_tr, "IPC data is NULL"); + return -EINVAL; + } + + size_t slots_count; + size_t slot_idx = 0; + uint64_t total_dsp_cycles[CONFIG_MAX_CORE_COUNT]; + + /* TODO + * Setting temporary values here. + * Replace this with actual total dsp cycles info once it is available. + */ + for (int core_id = 0; core_id < CONFIG_MAX_CORE_COUNT; ++core_id) + total_dsp_cycles[core_id] = 1; + + /* Fill one performance record per core with total dsp cycles */ + for (int core_id = 0; core_id < CONFIG_MAX_CORE_COUNT; ++core_id) { + if (!(cpu_enabled_cores() & BIT(core_id))) + continue; + + memset(&ext_global_perf_data->perf_items[slot_idx], 0, + sizeof(struct ext_perf_data_item)); + + ext_global_perf_data->perf_items[slot_idx].resource_id = core_id; + ext_global_perf_data->perf_items[slot_idx].module_total_dsp_cycles_consumed = + total_dsp_cycles[core_id]; + ++slot_idx; + } + + slots_count = perf_bitmap_get_occupied(&performance_data_bitmap) + slot_idx; + ext_global_perf_data->perf_item_count = slots_count; + + /* fill the rest of the IPC records with data from + * components registered in MW3 for performance measurement + */ + for (int idx = 0; idx < perf_bitmap_get_size(&performance_data_bitmap) && + slot_idx < slots_count; ++idx) { + if (perf_bitmap_is_bit_clear(&performance_data_bitmap, idx)) + continue; + + ext_global_perf_data->perf_items[slot_idx].resource_id = + perf_data[idx].item.resource_id; + ext_global_perf_data->perf_items[slot_idx].power_mode = + perf_data[idx].item.power_mode; + ext_global_perf_data->perf_items[slot_idx].is_removed = + perf_data[idx].item.is_removed; + ext_global_perf_data->perf_items[slot_idx].module_total_dsp_iterations = + perf_data[idx].total_iteration_count; + ext_global_perf_data->perf_items[slot_idx].module_total_dsp_cycles_consumed = + perf_data[idx].total_cycles_consumed; + ext_global_perf_data->perf_items[slot_idx].module_peak_dsp_cycles = + perf_data[idx].item.peak_kcps * 1000; + ext_global_perf_data->perf_items[slot_idx].module_peak_restricted_cycles = + perf_data[idx].restricted_peak_cycles; + ext_global_perf_data->perf_items[slot_idx].module_total_restricted_cycles_consumed = + perf_data[idx].restricted_total_cycles; + ext_global_perf_data->perf_items[slot_idx].module_total_restricted_iterations = + perf_data[idx].restricted_total_iterations; + ext_global_perf_data->perf_items[slot_idx].rsvd = 0; + ++slot_idx; + } + return 0; +} + int performance_monitor_init(void) { /* init global performance measurement */ diff --git a/src/include/ipc4/base_fw.h b/src/include/ipc4/base_fw.h index 83a41d329a48..b1367971ffcb 100644 --- a/src/include/ipc4/base_fw.h +++ b/src/include/ipc4/base_fw.h @@ -745,6 +745,39 @@ struct perf_data_item { uint32_t avg_kcps; } __packed __aligned(4); +struct ext_perf_data_item { + /* ID of the FW component */ + uint32_t resource_id; + /* 0 - D0, 1 - D0i3. */ + uint32_t power_mode : 1; + uint32_t rsvd : 30; + /* the component still exists (0) or has been already deleted (1) */ + uint32_t is_removed : 1; + /* peak number of DSP cycles used by a module */ + uint32_t module_peak_dsp_cycles; + /* total number of DSP used since by a module start of measurements, */ + uint64_t module_total_dsp_cycles_consumed; + /* how many times a module was executed */ + uint64_t module_total_dsp_iterations; + /* peak number of cycles used by a module. + * It is measured against DSP wall clock + */ + uint32_t module_peak_restricted_cycles; + /* total number of cycles used by a module since start of + * measurements. It is measured against DSP wall clock + */ + uint64_t module_total_restricted_cycles_consumed; + /* how many times a module invoke */ + uint64_t module_total_restricted_iterations; +} __packed __aligned(4); + +struct extended_global_perf_data { + /* Specifies number of items in perf_items array. */ + uint32_t perf_item_count; + /* Array of extended global performance measurements. */ + struct ext_perf_data_item perf_items[0]; +} __packed __aligned(4); + struct perf_data_item_comp { struct perf_data_item item; /* Total iteration count of module instance */ diff --git a/src/include/sof/debug/telemetry/performance_monitor.h b/src/include/sof/debug/telemetry/performance_monitor.h index 9d6693e4dd00..1b4ebecc4d28 100644 --- a/src/include/sof/debug/telemetry/performance_monitor.h +++ b/src/include/sof/debug/telemetry/performance_monitor.h @@ -60,4 +60,12 @@ enum ipc4_perf_measurements_state_set perf_meas_get_state(void); */ int get_performance_data(struct global_perf_data * const global_perf_data); +/** + * Get extended global performance data entries. + * + * @param[out] ext_global_perf_data Struct to be filled with data + * @return 0 if succeeded, error code otherwise. + */ +int get_extended_performance_data(struct extended_global_perf_data * const ext_global_perf_data); + #endif From 229033bb916355577e952809f6fa2c03b49e2338 Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Tue, 21 May 2024 12:43:44 +0200 Subject: [PATCH 9/9] performance measurements: extend perf meas state ipc Implement actual functionality for perf meas state ipc handling. This enables changing the state of global performance measurements. Signed-off-by: Tobiasz Dryjanski --- src/audio/base_fw.c | 17 ++-- src/debug/telemetry/performance_monitor.c | 77 +++++++++++++++++++ src/debug/telemetry/telemetry.c | 3 + .../sof/debug/telemetry/performance_monitor.h | 19 +++++ 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 940f4b917da3..f4bdb3cd688f 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -408,20 +408,23 @@ int set_perf_meas_state(const char *data) #ifdef CONFIG_SOF_TELEMETRY enum ipc4_perf_measurements_state_set state = *data; - struct telemetry_wnd_data *wnd_data = - (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; - struct system_tick_info *systick_info = - (struct system_tick_info *)wnd_data->system_tick_info; - switch (state) { case IPC4_PERF_MEASUREMENTS_DISABLED: + disable_performance_counters(); + perf_meas_set_state(IPC4_PERF_MEASUREMENTS_DISABLED); break; case IPC4_PERF_MEASUREMENTS_STOPPED: - for (int i = 0; i < CONFIG_MAX_CORE_COUNT; i++) - systick_info[i].peak_utilization = 0; + enable_performance_counters(); + reset_performance_counters(); + perf_meas_set_state(IPC4_PERF_MEASUREMENTS_STOPPED); break; case IPC4_PERF_MEASUREMENTS_STARTED: + enable_performance_counters(); + perf_meas_set_state(IPC4_PERF_MEASUREMENTS_STARTED); + break; case IPC4_PERF_MEASUREMENTS_PAUSED: + enable_performance_counters(); + perf_meas_set_state(IPC4_PERF_MEASUREMENTS_PAUSED); break; default: return -EINVAL; diff --git a/src/debug/telemetry/performance_monitor.c b/src/debug/telemetry/performance_monitor.c index 43a92cbef012..c99cc5eb1193 100644 --- a/src/debug/telemetry/performance_monitor.c +++ b/src/debug/telemetry/performance_monitor.c @@ -308,6 +308,82 @@ int get_extended_performance_data(struct extended_global_perf_data * const ext_g return 0; } +void disable_performance_counters(void) +{ + for (int idx = 0; idx < perf_bitmap_get_size(&performance_data_bitmap); ++idx) { + if (perf_bitmap_is_bit_clear(&performance_data_bitmap, idx)) + continue; + if (perf_data[idx].item.is_removed) + perf_data_free(&perf_data[idx]); + } +} + +int enable_performance_counters(void) +{ + struct sof_man_module *man_module; + struct comp_dev *dev; + uint32_t comp_id; + const struct sof_man_fw_desc *desc; + + if (perf_measurements_state != IPC4_PERF_MEASUREMENTS_DISABLED) + return -EINVAL; + + for (int lib_id = 0; lib_id < LIB_MANAGER_MAX_LIBS; ++lib_id) { + if (lib_id == 0) { + desc = basefw_vendor_get_manifest(); + } else { +#if CONFIG_LIBRARY_MANAGER + desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(lib_id); +#else + desc = NULL; +#endif + } + if (!desc) + continue; + + /* Reinitialize performance data for all created components */ + for (int mod_id = 0 ; mod_id < desc->header.num_module_entries; mod_id++) { + man_module = + (struct sof_man_module *)(desc + SOF_MAN_MODULE_OFFSET(mod_id)); + + for (int inst_id = 0; inst_id < man_module->instance_max_count; inst_id++) { + comp_id = IPC4_COMP_ID(mod_id, inst_id); + dev = ipc4_get_comp_dev(comp_id); + + if (dev) + comp_init_performance_data(dev); + } + } + } + + /* TODO clear total_dsp_ycles here once implemented */ + return 0; +} + +int reset_performance_counters(void) +{ + if (perf_measurements_state == IPC4_PERF_MEASUREMENTS_DISABLED) + return -EINVAL; + + struct telemetry_wnd_data *wnd_data = + (struct telemetry_wnd_data *)ADSP_DW->slots[SOF_DW_TELEMETRY_SLOT]; + struct system_tick_info *systick_info = + (struct system_tick_info *)wnd_data->system_tick_info; + + for (int core_id = 0; core_id < CONFIG_MAX_CORE_COUNT; ++core_id) { + if (!(cpu_enabled_cores() & BIT(core_id))) + continue; + systick_info[core_id].peak_utilization = 0; + } + for (int idx = 0; idx < perf_bitmap_get_size(&performance_data_bitmap); ++idx) { + if (!perf_bitmap_is_bit_clear(&performance_data_bitmap, idx)) + perf_data_item_comp_reset(&perf_data[idx]); + } + /* TODO clear totaldspcycles here once implemented */ + + return 0; +} + int performance_monitor_init(void) { /* init global performance measurement */ @@ -320,3 +396,4 @@ int performance_monitor_init(void) /* init performance monitor using Zephyr */ SYS_INIT(performance_monitor_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); + diff --git a/src/debug/telemetry/telemetry.c b/src/debug/telemetry/telemetry.c index 9a644737d611..3cbd28774543 100644 --- a/src/debug/telemetry/telemetry.c +++ b/src/debug/telemetry/telemetry.c @@ -6,11 +6,14 @@ #include +#include #include #include +#include #include #include +#include #include #include diff --git a/src/include/sof/debug/telemetry/performance_monitor.h b/src/include/sof/debug/telemetry/performance_monitor.h index 1b4ebecc4d28..d56462824ba0 100644 --- a/src/include/sof/debug/telemetry/performance_monitor.h +++ b/src/include/sof/debug/telemetry/performance_monitor.h @@ -68,4 +68,23 @@ int get_performance_data(struct global_perf_data * const global_perf_data); */ int get_extended_performance_data(struct extended_global_perf_data * const ext_global_perf_data); +/** + * Reset performance data values for all records. + * + * @return 0 if succeeded, error code otherwise. + */ +int reset_performance_counters(void); + +/** + * Reinitialize performance data values for all created components; + * + * @return 0 if succeeded, error code otherwise. + */ +int enable_performance_counters(void); + +/** + * Unregister performance data records marked for removal. + */ +void disable_performance_counters(void); + #endif