Skip to content

Commit fec6034

Browse files
tobonexlgirdwood
authored andcommitted
performance measurements: global perf meas backend
Implement global performance measurement which measure performance of .copy functions of multiple components. Signed-off-by: Tobiasz Dryjanski <tobiaszx.dryjanski@intel.com>
1 parent 32132a7 commit fec6034

10 files changed

Lines changed: 306 additions & 6 deletions

File tree

src/audio/base_fw.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <sof/schedule/dp_schedule.h>
2424
#include <sof/schedule/ll_schedule.h>
2525
#include <sof/debug/telemetry/telemetry.h>
26+
#include <sof/debug/telemetry/performance_monitor.h>
2627
/* FIXME:
2728
* Builds for some platforms like tgl fail because their defines related to memory windows are
2829
* already defined somewhere else. Remove this ifdef after it's cleaned up

src/audio/component.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <sof/audio/component_ext.h>
88
#include <sof/common.h>
9+
#include <sof/debug/telemetry/performance_monitor.h>
910
#include <rtos/panic.h>
1011
#include <rtos/interrupt.h>
1112
#include <sof/ipc/msg.h>
@@ -493,8 +494,18 @@ int comp_copy(struct comp_dev *dev)
493494
perf_cnt_init(&dev->pcd);
494495
#endif
495496

497+
#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS
498+
const uint32_t begin_stamp = (uint32_t)sof_cycle_get_64();
499+
#endif
500+
496501
ret = dev->drv->ops.copy(dev);
497502

503+
#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS
504+
const uint32_t cycles_consumed = (uint32_t)sof_cycle_get_64() - begin_stamp;
505+
506+
comp_update_performance_data(dev, cycles_consumed);
507+
#endif
508+
498509
#if CONFIG_PERFORMANCE_COUNTERS
499510
perf_cnt_stamp(&dev->pcd, perf_trace_null, dev);
500511
perf_cnt_average(&dev->pcd, comp_perf_avg_info, dev);
@@ -504,6 +515,56 @@ int comp_copy(struct comp_dev *dev)
504515
return ret;
505516
}
506517

518+
#ifdef CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS
519+
void comp_init_performance_data(struct comp_dev *dev)
520+
{
521+
struct perf_data_item_comp *item = dev->perf_data.perf_data_item;
522+
523+
if (item)
524+
perf_data_item_comp_init(item, dev->ipc_config.id, 0);
525+
}
526+
527+
/* returns true if budget violation occurred */
528+
static bool update_peak_of_measured_cpc(struct comp_dev *dev, size_t measured_cpc)
529+
{
530+
if (measured_cpc <= dev->perf_data.peak_of_measured_cpc)
531+
return false;
532+
dev->perf_data.peak_of_measured_cpc = measured_cpc;
533+
return measured_cpc > dev->cpc;
534+
}
535+
536+
bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used)
537+
{
538+
struct perf_data_item_comp *item = dev->perf_data.perf_data_item;
539+
540+
if (perf_meas_get_state() == IPC4_PERF_MEASUREMENTS_STARTED) {
541+
/* we divide by ibs so we need to check if its set */
542+
if (item && dev->ibs != 0) {
543+
item->total_iteration_count++;
544+
if (item->total_iteration_count == 0) {
545+
/* We can't allow count to overflow to 0. Overflow will also make
546+
* some of the results incorrect. We don't want to crash in this
547+
* case, so we just log it. We also reset cycles counter to make
548+
* avg correct again.
549+
*/
550+
item->total_iteration_count = 1;
551+
item->total_cycles_consumed = 0;
552+
tr_err(&ipc_tr,
553+
"overflow for module %#x, performance measurement incorrect",
554+
dev_comp_id(dev));
555+
}
556+
item->total_cycles_consumed += cycles_used;
557+
item->item.avg_kcps = item->total_cycles_consumed * dev->ll_chunk_size
558+
/ (dev->ibs * item->total_iteration_count);
559+
item->item.peak_kcps =
560+
MAX(item->item.peak_kcps, (cycles_used * dev->ll_chunk_size)
561+
/ dev->ibs);
562+
}
563+
}
564+
return update_peak_of_measured_cpc(dev, cycles_used);
565+
}
566+
#endif
567+
507568
#if CONFIG_IPC_MAJOR_4
508569
static uint32_t get_sample_group_size_in_bytes(const struct ipc4_audio_format fmt)
509570
{

src/debug/telemetry/performance_monitor.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,40 @@
44
//
55
// Author: Tobiasz Dryjanski <tobiaszx.dryjanski@intel.com>
66

7+
#include <sof/debug/telemetry/performance_monitor.h>
78
#include <zephyr/sys/bitarray.h>
89

10+
#include <errno.h>
11+
#include <limits.h>
12+
#include <stdbool.h>
13+
#include <stddef.h>
14+
#include <stdint.h>
15+
16+
#include <adsp_debug_window.h>
17+
18+
#include <ipc4/base_fw.h>
19+
20+
#define PERFORMANCE_DATA_ENTRIES_COUNT \
21+
(CONFIG_MEMORY_WIN_3_SIZE / sizeof(struct perf_data_item_comp))
22+
23+
SYS_BITARRAY_DEFINE_STATIC(performance_data_bit_array, PERFORMANCE_DATA_ENTRIES_COUNT);
24+
925
struct perf_bitmap {
1026
sys_bitarray_t *array;
1127
uint16_t occupied;
1228
size_t size;
1329
};
1430

31+
struct perf_bitmap performance_data_bitmap;
32+
33+
struct perf_data_item_comp *perf_data;
34+
35+
/* Note that ref. FW used one state per core, all set together to the same state
36+
* by one IPC but only for active cores. It may work slightly different in case
37+
* where we enable a core while perf meas is started.
38+
*/
39+
enum ipc4_perf_measurements_state_set perf_measurements_state = IPC4_PERF_MEASUREMENTS_DISABLED;
40+
1541
static int perf_bitmap_init(struct perf_bitmap * const bitmap, sys_bitarray_t *array, size_t size)
1642
{
1743
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
81107
return false;
82108
return !val;
83109
}
110+
111+
struct perf_data_item_comp *perf_data_getnext(void)
112+
{
113+
int idx;
114+
int ret = perf_bitmap_alloc(&performance_data_bitmap, &idx);
115+
116+
if (ret < 0)
117+
return NULL;
118+
/* ref. FW did not set the bits, but here we do it to not have to use
119+
* isFree() check that the bitarray does not provide yet. Instead we will use isClear
120+
* ,and always set bit on bitmap alloc.
121+
*/
122+
ret = perf_bitmap_setbit(&performance_data_bitmap, idx);
123+
if (ret < 0)
124+
return NULL;
125+
return &perf_data[idx];
126+
}
127+
128+
int perf_data_free(struct perf_data_item_comp * const item)
129+
{
130+
/* find index of item */
131+
int idx = (item - perf_data) / sizeof(*item);
132+
int ret = perf_bitmap_clearbit(&performance_data_bitmap, idx);
133+
134+
if (ret < 0)
135+
return ret;
136+
ret = perf_bitmap_free(&performance_data_bitmap, idx);
137+
if (ret < 0)
138+
return ret;
139+
140+
return 0;
141+
}
142+
143+
void perf_data_item_comp_reset(struct perf_data_item_comp *perf)
144+
{
145+
perf->total_iteration_count = 0;
146+
perf->total_cycles_consumed = 0;
147+
perf->restricted_total_iterations = 0;
148+
perf->restricted_total_cycles = 0;
149+
perf->restricted_peak_cycles = 0;
150+
perf->item.peak_kcps = 0;
151+
perf->item.avg_kcps = 0;
152+
}
153+
154+
void perf_data_item_comp_init(struct perf_data_item_comp *perf, uint32_t resource_id,
155+
uint32_t power_mode)
156+
{
157+
perf_data_item_comp_reset(perf);
158+
perf->item.resource_id = resource_id;
159+
perf->item.is_removed = false;
160+
perf->item.power_mode = power_mode;
161+
}
162+
163+
int free_performance_data(struct perf_data_item_comp *item)
164+
{
165+
int ret;
166+
167+
if (item) {
168+
item->item.is_removed = true;
169+
/* if we don't get the disabled state now, item will be
170+
* deleted on next disable perf meas message
171+
*/
172+
if (perf_measurements_state == IPC4_PERF_MEASUREMENTS_DISABLED) {
173+
ret = perf_data_free(item);
174+
if (ret < 0)
175+
return ret;
176+
}
177+
}
178+
return 0;
179+
}
180+
181+
enum ipc4_perf_measurements_state_set perf_meas_get_state(void)
182+
{
183+
return perf_measurements_state;
184+
}
185+
186+
void perf_meas_set_state(enum ipc4_perf_measurements_state_set state)
187+
{
188+
perf_measurements_state = state;
189+
}
190+
191+
int performance_monitor_init(void)
192+
{
193+
/* init global performance measurement */
194+
perf_data = (struct perf_data_item_comp *)ADSP_PMW;
195+
perf_bitmap_init(&performance_data_bitmap, &performance_data_bit_array,
196+
PERFORMANCE_DATA_ENTRIES_COUNT);
197+
198+
return 0;
199+
}
200+
201+
/* init performance monitor using Zephyr */
202+
SYS_INIT(performance_monitor_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);

src/debug/telemetry/telemetry.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sof/debug/telemetry/telemetry.h>
1111

1212
#include <ipc/trace.h>
13+
#include <ipc4/base_fw.h>
1314

1415
#include <adsp_debug_window.h>
1516
#include <errno.h>
@@ -90,6 +91,7 @@ int telemetry_init(void)
9091
systick_info[i].peak_utilization_4k = 0;
9192
systick_info[i].peak_utilization_8k = 0;
9293
}
94+
9395
return 0;
9496
}
9597

src/include/ipc4/base_fw.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,4 +731,31 @@ struct ipc4_system_time_info *basefw_get_system_time_info(void);
731731
/* Specifies I2S IPC4 version for PTL platform */
732732
static const uint32_t I2S_VER_30_PTL = 0x40000;
733733

734+
struct perf_data_item {
735+
/* ID of the FW component */
736+
uint32_t resource_id;
737+
/* 0 - D0, 1 - D0i3. */
738+
uint32_t power_mode : 1;
739+
uint32_t rsvd : 30;
740+
/* the component still exists (0) or has been already deleted (1) */
741+
uint32_t is_removed : 1;
742+
/* Peak KCPS captured */
743+
uint32_t peak_kcps;
744+
/* Average KCPS measured */
745+
uint32_t avg_kcps;
746+
} __packed __aligned(4);
747+
748+
struct perf_data_item_comp {
749+
struct perf_data_item item;
750+
/* Total iteration count of module instance */
751+
uint32_t total_iteration_count;
752+
/* Total cycles consumed by module instance */
753+
uint64_t total_cycles_consumed;
754+
/* <restricted> usage statistics against DSP wallclock cycles */
755+
uint32_t restricted_peak_cycles;
756+
uint64_t restricted_total_iterations;
757+
uint64_t restricted_total_cycles;
758+
759+
} __packed __aligned(4);
760+
734761
#endif /* __SOF_IPC4_BASE_FW_H__ */

src/include/sof/audio/component.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <sof/audio/buffer.h>
2020
#include <sof/audio/format.h>
2121
#include <sof/audio/pipeline.h>
22+
#include <sof/debug/telemetry/telemetry.h>
2223
#include <rtos/idc.h>
2324
#include <sof/lib/dai.h>
2425
#include <sof/schedule/schedule.h>
@@ -554,6 +555,18 @@ struct comp_ipc_config {
554555
#endif
555556
};
556557

558+
struct comp_perf_data {
559+
/* maximum measured cpc on run-time.
560+
*
561+
* if current measured cpc exceeds peak_of_measured_cpc_ then
562+
* ResoruceEvent(BUDGET_VIOLATION) notification must be send.
563+
* Otherwise there is no new information for host to care about
564+
*/
565+
size_t peak_of_measured_cpc;
566+
/* Pointer to performance data structure. */
567+
struct perf_data_item_comp *perf_data_item;
568+
};
569+
557570
/**
558571
* Audio component base device "class"
559572
* - used by other component types.
@@ -598,6 +611,8 @@ struct comp_dev {
598611
struct list_item bsource_list; /**< list of source buffers */
599612
struct list_item bsink_list; /**< list of sink buffers */
600613

614+
/* performance data*/
615+
struct comp_perf_data perf_data;
601616
/* Input Buffer Size for pin 0, add array for other pins if needed */
602617
size_t ibs;
603618
/* 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,
941956
*/
942957
void comp_update_ibs_obs_cpc(struct comp_dev *dev);
943958

959+
/**
960+
* If component has assigned slot in performance measurement window,
961+
* initialize its fields.
962+
* @param dev Component to init.
963+
*/
964+
void comp_init_performance_data(struct comp_dev *dev);
965+
966+
/**
967+
* Update performance data entry for component. Also checks for budget violation.
968+
*
969+
* @param dev Component to update.
970+
* @param cycles_used Execution time.
971+
* @return true if budget violation occurred
972+
*/
973+
bool comp_update_performance_data(struct comp_dev *dev, uint32_t cycles_used);
974+
944975
#endif /* __SOF_AUDIO_COMPONENT_H__ */

src/include/sof/debug/telemetry/performance_monitor.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,48 @@
88
#ifndef __SOF_PERFORMANCE_MONITOR_H__
99
#define __SOF_PERFORMANCE_MONITOR_H__
1010

11+
/* to be moved to Zephyr */
12+
#define WIN3_MBASE DT_REG_ADDR(DT_PHANDLE(DT_NODELABEL(mem_window3), memory))
13+
#define ADSP_PMW ((volatile uint32_t *) \
14+
(sys_cache_uncached_ptr_get((__sparse_force void __sparse_cache *) \
15+
(WIN3_MBASE + WIN3_OFFSET))))
16+
17+
/**
18+
* Initializer for struct perf_data_item_comp
19+
*
20+
* @param[out] perf Struct to be initialized
21+
* @param[in] resource_id
22+
* @param[in] power_mode
23+
*/
24+
void perf_data_item_comp_init(struct perf_data_item_comp *perf, uint32_t resource_id,
25+
uint32_t power_mode);
26+
27+
/**
28+
* Get next free performance data slot from Memory Window 3
29+
*
30+
* @return performance data record
31+
*/
32+
struct perf_data_item_comp *perf_data_getnext(void);
33+
34+
/**
35+
* Free a performance data slot in Memory Window 3
36+
*
37+
* @return 0 if succeeded, in other case the slot is already free
38+
*/
39+
int free_performance_data(struct perf_data_item_comp *item);
40+
41+
/**
42+
* Set performance measurements state
43+
*
44+
* @param[in] state Value to be set.
45+
*/
46+
void perf_meas_set_state(enum ipc4_perf_measurements_state_set state);
47+
48+
/**
49+
* Get performance measurements state
50+
*
51+
* @return performance measurements state
52+
*/
53+
enum ipc4_perf_measurements_state_set perf_meas_get_state(void);
54+
1155
#endif

0 commit comments

Comments
 (0)