Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions tools/testbench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,37 @@ directions, use -p 1,2,3,4 and provide multiple input and output
files separated with comma. Use e.g. -i i1.raw,i2.raw
-o o1.raw,o2.raw.

### Apply controls to simulation

The testbench supports shell script like amixer and sleep commands for
the controls. Create e.g. this script file as controls.sh:

```
#!/bin/sh

# Example test sequence for DRC and volume components

amixer -c0 cset name='Post Mixer Analog Playback DRC switch' off
amixer -c0 cset name='Post Mixer Analog Playback Volume' 40,30
sleep 1
amixer -c0 cset name='Post Mixer Analog Playback Volume' 0
sleep 1
amixer -c0 cset name='Post Mixer Analog Playback Volume' 45
```

Then generarate sine wave (997 Hz, -3 dB level, 3 seconds) with sox
and check the impact to processed signal with next commands:

```
sox -n --encoding signed-integer -L -r 48000 -c 2 -b 32 in.raw synth 3 sine 997 norm -3

tools/testbench/build_testbench/install/bin/sof-testbench4 -r 48000 -c 2 -b S32_LE -p 1,2 \
-t tools/build_tools/topology/topology2/production/sof-hda-generic.tplg \
-i in.raw -o out.raw -s controls.sh

sox --encoding signed-integer -L -r 48000 -c 2 -b 32 out.raw out.wav
```

### Run testbench with helper script

The scripts/sof-testbench-helper.sh simplifies the task. See the help
Expand Down
8 changes: 4 additions & 4 deletions tools/testbench/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,8 +632,8 @@ static int file_init(struct processing_module *mod)

/* set file comp mode */
cd->fs.mode = ipc_file->mode;
cd->rate = ipc_file->rate;
cd->channels = ipc_file->channels;
cd->fs.rate = ipc_file->rate;
cd->fs.channels = ipc_file->channels;
cd->frame_fmt = ipc_file->frame_fmt;
dev->direction = ipc_file->direction;
dev->direction_set = true;
Expand Down Expand Up @@ -859,8 +859,8 @@ static int file_get_hw_params(struct comp_dev *dev,

tb_debug_print("file_hw_params()\n");
params->direction = dir;
params->rate = cd->rate;
params->channels = cd->channels;
params->rate = cd->fs.rate;
params->channels = cd->fs.channels;
params->buffer_fmt = 0;
params->frame_fmt = cd->frame_fmt;
return 0;
Expand Down
4 changes: 2 additions & 2 deletions tools/testbench/include/testbench/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ struct file_state {
FILE *rfh, *wfh; /* read/write file handle */
char *fn;
int copy_count;
int channels;
int rate;
int n;
enum file_mode mode;
enum file_format f_format;
Expand All @@ -56,8 +58,6 @@ struct file_comp_data;
struct file_comp_data {
struct file_state fs;
enum sof_ipc_frame frame_fmt;
uint32_t channels;
uint32_t rate;
int sample_container_bytes;
int (*file_func)(struct file_comp_data *cd, struct audio_stream *sink,
struct audio_stream *source, uint32_t frames);
Expand Down
4 changes: 4 additions & 0 deletions tools/testbench/include/testbench/topology_ipc4.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ int tb_new_process(struct testbench_prm *tp);
int tb_pipelines_set_state(struct testbench_prm *tp, int state, int dir);
int tb_send_bytes_data(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx,
uint32_t module_id, uint32_t instance_id, struct sof_abi_hdr *abi);
int tb_send_volume_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx,
struct tb_ctl *ctl, int *control_values, int num_values);
int tb_send_alsa_control(struct tb_mq_desc *ipc_tx, struct tb_mq_desc *ipc_rx, struct tb_ctl *ctl,
int *control_values, int num_values, int param_id);
int tb_set_reset_state(struct testbench_prm *tp);
int tb_set_running_state(struct testbench_prm *tp);
int tb_set_up_pipeline(struct testbench_prm *tp, struct tplg_pipeline_info *pipe_info);
Expand Down
61 changes: 35 additions & 26 deletions tools/testbench/include/testbench/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#define TB_MAX_INPUT_FILE_NUM 16
#define TB_MAX_OUTPUT_FILE_NUM 16
#define TB_MAX_PIPELINES_NUM 16
#define TB_MAX_CMD_CHARS 256
#define TB_MAX_CTL_NAME_CHARS 128
#define TB_MAX_VOLUME_SIZE 120
#define TB_MAX_BYTES_DATA_SIZE 8192

/* number of widgets types supported in testbench */
#define TB_NUM_WIDGETS_SUPPORTED 16
Expand All @@ -32,13 +36,34 @@ struct file_comp_lookup {
struct file_state *state;
};

struct tb_ctl {
struct tplg_comp_info *comp_info;
unsigned int module_id;
unsigned int instance_id;
unsigned int type;
unsigned int volume_table[TB_MAX_VOLUME_SIZE];
unsigned int index;
char *data;
char name[TB_MAX_CTL_NAME_CHARS];
union {
struct snd_soc_tplg_mixer_control mixer_ctl;
struct snd_soc_tplg_enum_control enum_ctl;
struct snd_soc_tplg_bytes_control bytes_ctl;
};
};

struct tb_glb_state {
char magic[8]; /* SOF_MAGIC */
uint32_t num_ctls; /* number of ctls */
size_t size; /* size of this structure in bytes */
struct tb_ctl *ctl;
};

#if CONFIG_IPC_MAJOR_4

#define TB_NAME_SIZE 256
#define TB_MAX_CONFIG_COUNT 2
#define TB_MAX_CONFIG_NAME_SIZE 64
#define TB_MAX_VOLUME_SIZE 120
#define TB_MAX_DATA_SIZE 512
#define TB_MAX_CTLS 16

struct tb_mq_desc {
Expand All @@ -55,27 +80,6 @@ struct tb_config {
int channels;
unsigned long format;
};

struct tb_ctl {
unsigned int module_id;
unsigned int instance_id;
unsigned int type;
unsigned int volume_table[TB_MAX_VOLUME_SIZE];
unsigned int index;
char data[TB_MAX_DATA_SIZE];
union {
struct snd_soc_tplg_mixer_control mixer_ctl;
struct snd_soc_tplg_enum_control enum_ctl;
struct snd_soc_tplg_bytes_control bytes_ctl;
};
};

struct tb_glb_state {
char magic[8]; /* SOF_MAGIC */
uint32_t num_ctls; /* number of ctls */
size_t size; /* size of this structure in bytes */
struct tb_ctl *ctl;
};
#endif

/*
Expand All @@ -93,15 +97,14 @@ struct testbench_prm {
char *output_file[TB_MAX_OUTPUT_FILE_NUM]; /* output file names */
char *tplg_file; /* topology file to use */
char *bits_in; /* input bit format */
char *control_file;
int input_file_num; /* number of input files */
int output_file_num; /* number of output files */
int pipeline_num;
int copy_iterations;
bool copy_check;
int trace_level;
int dynamic_pipeline_iterations;
int tick_period_us;
int pipeline_duration_ms;
char *pipeline_string;
int output_file_index;
int input_file_index;
Expand All @@ -125,6 +128,9 @@ struct testbench_prm {
/* topology */
struct tplg_context tplg;

FILE *control_fh;
struct tb_glb_state glb_ctx;

#if CONFIG_IPC_MAJOR_4
struct list_item widget_list;
struct list_item route_list;
Expand All @@ -138,12 +144,12 @@ struct testbench_prm {
struct tb_config config[TB_MAX_CONFIG_COUNT];
int num_configs;
int period_frames;
struct tb_glb_state glb_ctx;
#endif
};

extern int debug;

int tb_decode_enum(struct snd_soc_tplg_enum_control *enum_ctl, char *token);
int tb_find_file_components(struct testbench_prm *tp);
int tb_free_all_pipelines(struct testbench_prm *tp);
int tb_load_topology(struct testbench_prm *tp);
Expand All @@ -152,7 +158,10 @@ int tb_pipeline_params(struct testbench_prm *tp, struct ipc *ipc, struct pipelin
int tb_pipeline_reset(struct ipc *ipc, struct pipeline *p);
int tb_pipeline_start(struct ipc *ipc, struct pipeline *p);
int tb_pipeline_stop(struct ipc *ipc, struct pipeline *p);
int tb_read_controls(struct testbench_prm *tp, int64_t *sleep_ns);
int tb_set_enum_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params);
int tb_set_reset_state(struct testbench_prm *tp);
int tb_set_mixer_control(struct testbench_prm *tp, struct tb_ctl *ctl, char *control_params);
int tb_set_running_state(struct testbench_prm *tp);
int tb_set_up_all_pipelines(struct testbench_prm *tp);
int tb_setup(struct sof *sof, struct testbench_prm *tp);
Expand Down
100 changes: 57 additions & 43 deletions tools/testbench/testbench.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,8 @@ static void print_usage(char *executable)
printf(" 4 shows debug traces and previous, plus other testbench debug messages\n");
printf(" -p <pipeline1,pipeline2,...>\n");
printf(" -C <number of copy() iterations>\n");
printf(" -D <pipeline duration in ms>\n");
printf(" -P <number of dynamic pipeline iterations>\n");
printf(" -T <microseconds for tick, 0 for batch mode>\n\n");
printf(" -s <script file to set controls, with amixer and sleep commands>\n\n");
printf("Options for input and output format override:\n");
printf(" -b <input_format>, S16_LE, S24_LE, or S32_LE\n");
printf(" -c <input channels>\n");
Expand All @@ -148,7 +147,7 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp)
int option = 0;
int ret = 0;

while ((option = getopt(argc, argv, "hd:i:o:t:b:r:R:c:n:C:P:p:T:D:")) != -1) {
while ((option = getopt(argc, argv, "hd:i:o:t:b:r:R:c:n:C:P:p:s:")) != -1) {
switch (option) {
/* input sample file */
case 'i':
Expand Down Expand Up @@ -218,14 +217,9 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp)
ret = parse_pipelines(optarg, tp);
break;

/* Microseconds for tick, 0 = batch (tickless) */
case 'T':
tp->tick_period_us = atoi(optarg);
break;

/* pipeline duration in millisec, 0 = realtime (tickless) */
case 'D':
tp->pipeline_duration_ms = atoi(optarg);
/* control script file name */
case 's':
tp->control_file = strdup(optarg);
break;

/* print usage */
Expand Down Expand Up @@ -314,13 +308,14 @@ static void test_pipeline_stats(struct testbench_prm *tp, long long delta_t)
*/
static int pipline_test(struct testbench_prm *tp)
{
float samples_to_ns;
int dp_count = 0;
struct timespec ts;
struct timespec td0, td1;
struct file_state *out_stat;
long long delta_t;
int64_t next_control_ns;
int64_t time_ns;
int err;
int nsleep_time;
int nsleep_limit;

/* build, run and teardown pipelines */
while (dp_count < tp->dynamic_pipeline_iterations) {
Expand Down Expand Up @@ -356,37 +351,42 @@ static int pipline_test(struct testbench_prm *tp)
break;
}

/* Use first file writer to create simulation time. Calculate coefficient
* to calculate current time from file write samples count
*/
out_stat = tp->fw[0].state;
samples_to_ns = 1.0e9 / ((float)out_stat->channels * out_stat->rate);

/* Apply initial controls time to call again controls handler */
err = tb_read_controls(tp, &next_control_ns);
if (err) {
fprintf(stderr, "error: failed to read control commands.\n");
goto out;
}

tb_gettime(&td0);

/* sleep to let the pipeline work - we exit at timeout OR
* if copy iterations OR max_samples is reached (whatever first)
*/
nsleep_time = 0;
ts.tv_sec = tp->tick_period_us / 1000000;
ts.tv_nsec = (tp->tick_period_us % 1000000) * 1000;
if (!tp->copy_check)
nsleep_limit = INT_MAX;
else
nsleep_limit = tp->copy_iterations *
tp->pipeline_duration_ms;

while (nsleep_time < nsleep_limit) {
#if defined __XCC__
err = 0;
#else
/* wait for next tick */
err = nanosleep(&ts, &ts);
#endif
if (err == 0) {
nsleep_time += tp->tick_period_us; /* sleep fully completed */
if (tb_schedule_pipeline_check_state(tp))
break;
} else {
if (err == EINTR) {
continue; /* interrupted - keep going */
} else {
printf("error: sleep failed: %s\n", strerror(err));
while (true) {
if (tp->copy_check) {
if (tp->copy_iterations-- <= 0)
break;
}

if (tb_schedule_pipeline_check_state(tp))
break;

if (next_control_ns) {
time_ns = (int64_t)(samples_to_ns * out_stat->n);
if (time_ns >= next_control_ns) {
err = tb_read_controls(tp, &next_control_ns);
if (err) {
fprintf(stderr,
"error: failed to read control commands.\n");
goto out;
}

if (next_control_ns)
next_control_ns += time_ns;
}
}
}
Expand All @@ -395,6 +395,7 @@ static int pipline_test(struct testbench_prm *tp)

tb_gettime(&td1);

out:
err = tb_set_reset_state(tp);
if (err < 0) {
fprintf(stderr, "error: pipeline reset %d failed %d\n",
Expand Down Expand Up @@ -438,7 +439,6 @@ int main(int argc, char **argv)
tp->pipeline_string = calloc(1, TB_DEBUG_MSG_LEN);
tp->pipelines[0] = 1;
tp->pipeline_num = 1;
tp->pipeline_duration_ms = 5000;
tp->copy_iterations = 1;
tp->trace_level = LOG_LEVEL_INFO;

Expand Down Expand Up @@ -489,6 +489,16 @@ int main(int argc, char **argv)
goto out;
}

if (tp->control_file) {
tp->control_fh = fopen(tp->control_file, "r");
if (!tp->control_fh) {
fprintf(stderr, "error: opening script %s (%s).\n",
tp->control_file, strerror(errno));
ret = -errno;
goto out;
}
}

/* build, run and teardown pipelines */
pipline_test(tp);

Expand All @@ -500,6 +510,10 @@ int main(int argc, char **argv)
/* free all other data */
free(tp->bits_in);
free(tp->tplg_file);
free(tp->control_file);
if (tp->control_fh)
fclose(tp->control_fh);

for (i = 0; i < tp->output_file_num; i++)
free(tp->output_file[i]);

Expand Down
Loading
Loading