Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance measurements: Add Global Performance Measurements #9186

Merged
merged 9 commits into from
Jul 10, 2024
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace15_mtpm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace20_lnl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with these changes performance measurements would be unconditionally enabled on MTL and LNL? Is this desirable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the performance measurement itself is enabled by IPC, so there's little to no overhead. But now that you mention it, disabling only CONFIG_SOF_TELEMETRY may break the build. It would be good if performance measurements could be enabled regardless of telemetry, I'll think about it.


CONFIG_HEAP_MEM_POOL_SIZE=8192
CONFIG_L3_HEAP=y
Expand Down
60 changes: 52 additions & 8 deletions src/audio/base_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/schedule/dp_schedule.h>
#include <sof/schedule/ll_schedule.h>
#include <sof/debug/telemetry/performance_monitor.h>
#include <sof/debug/telemetry/telemetry.h>
#include <sof/debug/telemetry/performance_monitor.h>
/* 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
Expand Down Expand Up @@ -406,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;
Expand All @@ -428,6 +433,42 @@ 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
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,
Expand Down Expand Up @@ -467,13 +508,16 @@ 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 */
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;
Expand Down
105 changes: 105 additions & 0 deletions src/audio/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <sof/audio/component_ext.h>
#include <sof/common.h>
#include <sof/debug/telemetry/performance_monitor.h>
#include <rtos/panic.h>
#include <rtos/interrupt.h>
#include <sof/ipc/msg.h>
Expand Down Expand Up @@ -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);
Expand All @@ -505,3 +516,97 @@ int comp_copy(struct comp_dev *dev)

return ret;
}

#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS
void comp_init_performance_data(struct comp_dev *dev)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this all new code really belong to component.c?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... it doesn't need to be here, but those were the methods in "component" class in reference FW.

{
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++;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how often does this run? If this runs every millisecond, then in a couple of days this will overflow and the division below will divide by zero

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it may as well be every ms. Doubt it will be used for a couple of days , but still I should add some check here, true.

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));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but like this after such an overflow they'll stay incorrect? Can we reset total_cycles_consumed to start producing valid data again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, we can either do that, or zero everything and set a flag to stop the measurement to further indicate that something went wrong.

}
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)
{
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
}

1 change: 1 addition & 0 deletions src/debug/telemetry/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
9 changes: 9 additions & 0 deletions src/debug/telemetry/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Loading
Loading