Skip to content

Commit

Permalink
Tools: Testbench: Cleanup and move common and IPC3 specific functions
Browse files Browse the repository at this point in the history
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
singalsu committed Sep 19, 2024
1 parent 7c045a1 commit 29b3d19
Show file tree
Hide file tree
Showing 7 changed files with 630 additions and 548 deletions.
1 change: 1 addition & 0 deletions tools/testbench/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(default_asoc_h "/usr/include/alsa/sound/uapi/asoc.h")

add_executable(testbench
testbench.c
common_test.c
common_test_ipc3.c
file.c
topology_ipc3.c
Expand Down
264 changes: 264 additions & 0 deletions tools/testbench/common_test.c
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
}
Loading

0 comments on commit 29b3d19

Please sign in to comment.