From 96082f29637e801622c1ca2c78115ce59b5f6e8a Mon Sep 17 00:00:00 2001 From: Tobiasz Dryjanski Date: Tue, 21 May 2024 12:43:44 +0200 Subject: [PATCH] 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 | 12 ++- src/audio/component.c | 16 +-- src/debug/telemetry/telemetry.c | 107 +++++++++++++++++++- src/include/sof/debug/telemetry/telemetry.h | 7 ++ src/ipc/ipc4/helper.c | 3 +- 5 files changed, 132 insertions(+), 13 deletions(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index c84e37e6b5f9..5c01ec0260b1 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -413,13 +413,21 @@ int set_perf_meas_state(const char *data) 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/audio/component.c b/src/audio/component.c index 17020cf2ffd5..4cb2c7d635bc 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -542,14 +542,18 @@ bool update_peak_of_measured_cpc(struct comp_dev *dev, size_t measured_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; - /* we divide by ibs so we need to check if its set */ - if (item && dev->ibs != 0) { - item->total_iteration_count++; - item->total_cycles_consumed += cycles_used; - item->item.avg_kcps = item->total_cycles_consumed * dev->ll_chunk_size_ + + 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++; + 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_) + 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); } diff --git a/src/debug/telemetry/telemetry.c b/src/debug/telemetry/telemetry.c index 29bc3cdf6c42..0a5ad6f471b6 100644 --- a/src/debug/telemetry/telemetry.c +++ b/src/debug/telemetry/telemetry.c @@ -21,6 +21,9 @@ #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)) @@ -37,6 +40,12 @@ struct perf_bitmap performance_data_bitmap; volatile 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; + int perf_bitmap_init(struct perf_bitmap * const bitmap, sys_bitarray_t *array, size_t size) { bitmap->array = array; @@ -198,9 +207,15 @@ int free_performance_data(struct perf_data_item_comp *item) if (item) { item->item.is_removed = true; - ret = perf_data_free(item); - if (ret < 0) - return -EINVAL; + /* 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) { + int ret = perf_data_free(item); + + if (ret < 0) + return -EINVAL; + } } return IPC4_SUCCESS; } @@ -266,7 +281,91 @@ int get_extended_performance_data(struct extended_global_perf_data * const ext_g return IPC4_SUCCESS; } -//============================================================================================== +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; +} + +void disable_performance_counters(void) +{ + for (size_t 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_fw_header header; + 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; + + 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 totaldspcycles here once implemented */ + return IPC4_SUCCESS; +} + +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 (size_t 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 (size_t 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 IPC4_SUCCESS; +} /* Systic variables, one set per core */ static int telemetry_systick_counter[CONFIG_MAX_CORE_COUNT]; diff --git a/src/include/sof/debug/telemetry/telemetry.h b/src/include/sof/debug/telemetry/telemetry.h index f0644bc5b2de..7580c3f9da7f 100644 --- a/src/include/sof/debug/telemetry/telemetry.h +++ b/src/include/sof/debug/telemetry/telemetry.h @@ -106,4 +106,11 @@ 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); +int reset_performance_counters(void); +int enable_performance_counters(void); +void disable_performance_counters(void); + +void perf_meas_set_state(enum ipc4_perf_measurements_state_set state); +enum ipc4_perf_measurements_state_set perf_meas_get_state(void); + #endif /*__SOF_TELEMETRY_H__ */ diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 6034e6e5f447..9062282bf14b 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -163,7 +163,8 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) /* 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; - comp_init_performance_data(dev); + if (perf_meas_get_state() != IPC4_PERF_MEASUREMENTS_DISABLED) + comp_init_performance_data(dev); } ipc4_add_comp_dev(dev);