Skip to content

Commit

Permalink
performance measurements: global perf meas backend
Browse files Browse the repository at this point in the history
Implement global performance measurement which measure performance of .copy
functions of multiple components.

Signed-off-by: Tobiasz Dryjanski <tobiaszx.dryjanski@intel.com>
  • Loading branch information
tobonex committed Jun 3, 2024
1 parent 9707980 commit ccaa897
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/audio/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,18 @@ int comp_copy(struct comp_dev *dev)
perf_cnt_init(&dev->pcd);
#endif

#ifdef CONFIG_SOF_TELEMETRY
const uint32_t begin_stamp = (uint32_t)sof_cycle_get_64();
#endif

ret = dev->drv->ops.copy(dev);

#ifdef CONFIG_SOF_TELEMETRY
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 @@ -506,6 +516,44 @@ int comp_copy(struct comp_dev *dev)
return ret;
}

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 occured */
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;
if (measured_cpc <= dev->cpc)
{
return false;
}
return true;
}

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_
/ (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);
}

inline uint32_t get_sample_group_size_in_bytes(const struct ipc4_audio_format fmt)
{
return ((fmt.depth >> 3) * fmt.channels_count);
Expand Down
80 changes: 80 additions & 0 deletions src/debug/telemetry/telemetry.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <sof/debug/telemetry/telemetry.h>

#include <ipc/trace.h>
#include <ipc4/base_fw.h>

#include <adsp_debug_window.h>
#include <errno.h>
Expand All @@ -22,12 +23,20 @@

LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL);

#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;

volatile struct perf_data_item_comp *perf_data_;

int perf_bitmap_init(struct perf_bitmap * const bitmap, sys_bitarray_t *array, size_t size)
{
bitmap->array = array;
Expand Down Expand Up @@ -94,6 +103,71 @@ int perf_bitmap_is_bit_clear(struct perf_bitmap * const bitmap, size_t bit)
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;
/* original 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 -EINVAL;
ret = perf_bitmap_free(&performance_data_bitmap, idx);
if (ret < 0)
return -EINVAL;

return IPC4_SUCCESS;
}

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;
ret = perf_data_free(item);
if (ret < 0)
return -EINVAL;
}
return IPC4_SUCCESS;
}

//==============================================================================================

/* Systic variables, one set per core */
Expand Down Expand Up @@ -161,6 +235,12 @@ int telemetry_init(void)
systick_info[i].peak_utilization_4k = 0;
systick_info[i].peak_utilization_8k = 0;
}

/* init global performance measurement */
perf_data_ = (volatile struct perf_data_item_comp *)ADSP_PMW;
perf_bitmap_init(&performance_data_bitmap, &performance_data_bit_array,
PERFORMANCE_DATA_ENTRIES_COUNT);

return 0;
}

Expand Down
27 changes: 27 additions & 0 deletions src/include/ipc4/base_fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -728,4 +728,31 @@ struct schedulers_info {

struct ipc4_system_time_info *basefw_get_system_time_info(void);

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;
/* <restricted> 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__ */
17 changes: 17 additions & 0 deletions src/include/sof/audio/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <sof/audio/buffer.h>
#include <sof/audio/format.h>
#include <sof/audio/pipeline.h>
#include <sof/debug/telemetry/telemetry.h>
#include <rtos/idc.h>
#include <sof/lib/dai.h>
#include <sof/schedule/schedule.h>
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -594,6 +607,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 */
Expand Down Expand Up @@ -923,5 +938,7 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag,

void comp_update_chunk_size(struct comp_dev *dev);
void comp_update_ibs_obs_cpc(struct comp_dev *dev);
void comp_init_performance_data(struct comp_dev *dev);
bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used);

#endif /* __SOF_AUDIO_COMPONENT_H__ */
11 changes: 11 additions & 0 deletions src/include/sof/debug/telemetry/telemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#ifndef __SOF_TELEMETRY_H__
#define __SOF_TELEMETRY_H__

#include <ipc4/base_fw.h>

/* 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 */
Expand Down Expand Up @@ -89,6 +91,15 @@ struct telemetry_perf_queue {
size_t sum;
};

void perf_data_item_comp_init(struct perf_data_item_comp *perf, uint32_t resource_id,
uint32_t power_mode);

void telemetry_update(uint32_t begin_ccount, uint32_t current_ccount);

struct perf_data_item_comp *perf_data_getnext(void);

int perf_data_free(struct perf_data_item_comp *item);

int free_performance_data(struct perf_data_item_comp *item);

#endif /*__SOF_TELEMETRY_H__ */
3 changes: 3 additions & 0 deletions src/ipc/ipc-helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <sof/audio/component_ext.h>
#include <sof/audio/pipeline.h>
#include <sof/common.h>
#include <sof/debug/telemetry/telemetry.h>
#include <rtos/idc.h>
#include <rtos/interrupt.h>
#include <sof/ipc/topology.h>
Expand Down Expand Up @@ -281,6 +282,8 @@ int ipc_comp_free(struct ipc *ipc, uint32_t comp_id)
return -EINVAL;
}

free_performance_data(icd->cd->perf_data.perf_data_item);

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
Expand Down
10 changes: 10 additions & 0 deletions src/ipc/ipc4/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
#include <stddef.h>
#include <stdint.h>

#include <sof/debug/telemetry/telemetry.h>

LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL);

extern struct tr_ctx comp_tr;
Expand Down Expand Up @@ -156,6 +158,14 @@ struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init)
list_init(&dev->bsource_list);
list_init(&dev->bsink_list);

/* 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;
comp_init_performance_data(dev);
}

ipc4_add_comp_dev(dev);

comp_update_ibs_obs_cpc(dev);
Expand Down

0 comments on commit ccaa897

Please sign in to comment.