-
Notifications
You must be signed in to change notification settings - Fork 309
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tools: Testbench: Cleanup and move common and IPC3 specific functions
The helper functions are moved from testbench.c to common_test.c and common_test_ipc3.c as preparation to add IPC4 support. The file components are looked up in test setup to arrays to ease finding them in test run and control ending the test. The parse string for command getopt() is fixed to match the supported options. The testbench parameter struct is changed to dynamically allocated and zeroed by calloc(). It also avoids issues found with valgrind about uninitialized. Signed-off-by: Seppo Ingalsuo <[email protected]>
- Loading branch information
Showing
7 changed files
with
630 additions
and
548 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// Copyright(c) 2018-2024 Intel Corporation. All rights reserved. | ||
|
||
#include <sof/audio/module_adapter/module/generic.h> | ||
#include <platform/lib/ll_schedule.h> | ||
#include <sof/audio/component.h> | ||
#include <sof/ipc/topology.h> | ||
#include <sof/lib/notifier.h> | ||
|
||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <time.h> | ||
|
||
#include "testbench/common_test.h" | ||
#include "testbench/trace.h" | ||
#include "testbench/file.h" | ||
|
||
#if defined __XCC__ | ||
#include <xtensa/tie/xt_timer.h> | ||
#endif | ||
|
||
int tb_load_topology(struct testbench_prm *tp) | ||
{ | ||
struct tplg_context *ctx = &tp->tplg; | ||
int ret; | ||
|
||
/* setup the thread virtual core config */ | ||
memset(ctx, 0, sizeof(*ctx)); | ||
ctx->comp_id = 1; | ||
ctx->core_id = 0; | ||
ctx->sof = sof_get(); | ||
ctx->tplg_file = tp->tplg_file; | ||
|
||
/* parse topology file and create pipeline */ | ||
ret = tb_parse_topology(tp); | ||
if (ret < 0) | ||
fprintf(stderr, "error: parsing topology\n"); | ||
|
||
tb_debug_print("topology parsing complete\n"); | ||
return ret; | ||
} | ||
|
||
int tb_find_file_components(struct testbench_prm *tp) | ||
{ | ||
struct ipc_comp_dev *icd; | ||
struct processing_module *mod; | ||
struct file_comp_data *fcd; | ||
int i; | ||
|
||
for (i = 0; i < tp->input_file_num; i++) { | ||
if (!tb_is_pipeline_enabled(tp, tp->fr[i].pipeline_id)) { | ||
tp->fr[i].id = -1; | ||
continue; | ||
} | ||
|
||
icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fr[i].id); | ||
if (!icd) { | ||
tp->fr[i].state = NULL; | ||
continue; | ||
} | ||
|
||
if (!icd->cd) { | ||
fprintf(stderr, "error: null cd.\n"); | ||
return -EINVAL; | ||
} | ||
|
||
mod = comp_mod(icd->cd); | ||
if (!mod) { | ||
fprintf(stderr, "error: null module.\n"); | ||
return -EINVAL; | ||
} | ||
fcd = module_get_private_data(mod); | ||
tp->fr[i].state = &fcd->fs; | ||
} | ||
|
||
for (i = 0; i < tp->output_file_num; i++) { | ||
if (!tb_is_pipeline_enabled(tp, tp->fw[i].pipeline_id)) { | ||
tp->fw[i].id = -1; | ||
continue; | ||
} | ||
|
||
icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fw[i].id); | ||
if (!icd) { | ||
tp->fr[i].state = NULL; | ||
continue; | ||
} | ||
|
||
if (!icd->cd) { | ||
fprintf(stderr, "error: null cd.\n"); | ||
return -EINVAL; | ||
} | ||
|
||
mod = comp_mod(icd->cd); | ||
if (!mod) { | ||
fprintf(stderr, "error: null module.\n"); | ||
return -EINVAL; | ||
} | ||
|
||
fcd = module_get_private_data(mod); | ||
tp->fw[i].state = &fcd->fs; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static bool tb_is_file_component_at_eof(struct testbench_prm *tp) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < tp->input_file_num; i++) { | ||
if (!tp->fr[i].state) | ||
continue; | ||
|
||
if (tp->fr[i].state->reached_eof) | ||
return true; | ||
} | ||
|
||
for (i = 0; i < tp->output_file_num; i++) { | ||
if (!tp->fw[i].state) | ||
continue; | ||
|
||
if (tp->fw[i].state->reached_eof || tp->fw[i].state->write_failed) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
void tb_show_file_stats(struct testbench_prm *tp, int pipeline_id) | ||
{ | ||
struct ipc_comp_dev *icd; | ||
struct comp_dev *dev; | ||
struct processing_module *mod; | ||
struct file_comp_data *fcd; | ||
int i; | ||
|
||
for (i = 0; i < tp->input_file_num; i++) { | ||
if (tp->fr[i].id < 0 || tp->fr[i].pipeline_id != pipeline_id) | ||
continue; | ||
|
||
icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fr[i].id); | ||
if (!icd) | ||
continue; | ||
|
||
dev = icd->cd; | ||
mod = comp_mod(dev); | ||
fcd = module_get_private_data(mod); | ||
printf("file %s: id %d: type %d: samples %d copies %d\n", | ||
fcd->fs.fn, dev->ipc_config.id, dev->drv->type, fcd->fs.n, | ||
fcd->fs.copy_count); | ||
} | ||
|
||
for (i = 0; i < tp->output_file_num; i++) { | ||
if (tp->fw[i].id < 0 || tp->fw[i].pipeline_id != pipeline_id) | ||
continue; | ||
|
||
icd = ipc_get_comp_by_id(sof_get()->ipc, tp->fw[i].id); | ||
if (!icd) | ||
continue; | ||
|
||
dev = icd->cd; | ||
mod = comp_mod(dev); | ||
fcd = module_get_private_data(mod); | ||
printf("file %s: id %d: type %d: samples %d copies %d\n", | ||
fcd->fs.fn, dev->ipc_config.id, dev->drv->type, fcd->fs.n, | ||
fcd->fs.copy_count); | ||
} | ||
} | ||
|
||
bool tb_is_pipeline_enabled(struct testbench_prm *tp, int pipeline_id) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < tp->pipeline_num; i++) { | ||
if (tp->pipelines[i] == pipeline_id) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool tb_schedule_pipeline_check_state(struct testbench_prm *tp) | ||
{ | ||
uint64_t cycles0, cycles1; | ||
|
||
tb_getcycles(&cycles0); | ||
|
||
schedule_ll_run_tasks(); | ||
|
||
tb_getcycles(&cycles1); | ||
tp->total_cycles += cycles1 - cycles0; | ||
|
||
/* Check if all file components are running */ | ||
return tb_is_file_component_at_eof(tp); | ||
} | ||
|
||
struct ipc_data { | ||
struct ipc_data_host_buffer dh_buffer; | ||
}; | ||
|
||
void tb_free(struct sof *sof) | ||
{ | ||
struct schedule_data *sch; | ||
struct schedulers **schedulers; | ||
struct list_item *slist, *_slist; | ||
struct notify **notify = arch_notify_get(); | ||
struct ipc_data *iipc; | ||
|
||
free(*notify); | ||
|
||
/* free all scheduler data */ | ||
schedule_free(0); | ||
schedulers = arch_schedulers_get(); | ||
list_for_item_safe(slist, _slist, &(*schedulers)->list) { | ||
sch = container_of(slist, struct schedule_data, list); | ||
free(sch); | ||
} | ||
free(*arch_schedulers_get()); | ||
|
||
/* free IPC data */ | ||
iipc = sof->ipc->private; | ||
free(sof->ipc->comp_data); | ||
free(iipc->dh_buffer.page_table); | ||
free(iipc); | ||
free(sof->ipc); | ||
} | ||
|
||
/* print debug messages */ | ||
void tb_debug_print(char *message) | ||
{ | ||
if (host_trace_level >= LOG_LEVEL_DEBUG) | ||
printf("debug: %s", message); | ||
} | ||
|
||
/* enable trace in testbench */ | ||
void tb_enable_trace(unsigned int log_level) | ||
{ | ||
host_trace_level = log_level; | ||
if (host_trace_level) | ||
tb_debug_print("trace print enabled\n"); | ||
else | ||
tb_debug_print("trace print disabled\n"); | ||
} | ||
|
||
void tb_gettime(struct timespec *td) | ||
{ | ||
#if !defined __XCC__ | ||
clock_gettime(CLOCK_MONOTONIC, td); | ||
#else | ||
td->tv_nsec = 0; | ||
td->tv_sec = 0; | ||
#endif | ||
} | ||
|
||
void tb_getcycles(uint64_t *cycles) | ||
{ | ||
#if defined __XCC__ | ||
*cycles = XT_RSR_CCOUNT(); | ||
#else | ||
*cycles = 0; | ||
#endif | ||
} |
Oops, something went wrong.