diff --git a/tools/testbench/common_test.c b/tools/testbench/common_test.c index 18606439f..765c13468 100644 --- a/tools/testbench/common_test.c +++ b/tools/testbench/common_test.c @@ -29,6 +29,10 @@ #include "testbench/trace.h" #include +#if defined __XCC__ +#include +#endif + /* testbench helper functions for pipeline setup and trigger */ int tb_setup(struct sof *sof, struct testbench_prm *tp) @@ -281,3 +285,22 @@ void tb_enable_trace(bool enable) else 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 +} diff --git a/tools/testbench/file.c b/tools/testbench/file.c index 55adcbbcc..87964a479 100644 --- a/tools/testbench/file.c +++ b/tools/testbench/file.c @@ -617,6 +617,7 @@ static struct comp_dev *file_new(const struct comp_driver *drv, cd->fs.write_failed = false; cd->fs.n = 0; cd->fs.copy_count = 0; + cd->fs.cycles_count = 0; dev->state = COMP_STATE_READY; return dev; @@ -803,11 +804,13 @@ static int file_copy(struct comp_dev *dev) struct comp_buffer *buffer; struct dai_data *dd = comp_get_drvdata(dev); struct file_comp_data *cd = comp_get_drvdata(dd->dai); + uint64_t cycles0, cycles1; int snk_frames; int src_frames; int bytes = cd->sample_container_bytes; int ret = 0; + tb_getcycles(&cycles0); switch (cd->fs.mode) { case FILE_READ: /* file component sink buffer */ @@ -859,6 +862,9 @@ static int file_copy(struct comp_dev *dev) cd->fs.reached_eof); schedule_task_cancel(dev->pipeline->pipe_task); } + + tb_getcycles(&cycles1); + cd->fs.cycles_count += cycles1 - cycles0; return ret; } diff --git a/tools/testbench/include/testbench/common_test.h b/tools/testbench/include/testbench/common_test.h index a707e5b05..dd43c29ab 100644 --- a/tools/testbench/include/testbench/common_test.h +++ b/tools/testbench/include/testbench/common_test.h @@ -36,6 +36,7 @@ struct tplg_context; * into per pipeline data and per topology data structures. */ struct testbench_prm { + long long total_cycles; char *tplg_file; /* topology file to use */ char *input_file[MAX_INPUT_FILE_NUM]; /* input file names */ char *output_file[MAX_OUTPUT_FILE_NUM]; /* output file names */ @@ -104,4 +105,8 @@ int tb_pipeline_reset(struct ipc *ipc, struct pipeline *p); void debug_print(char *message); +void tb_gettime(struct timespec *td); + +void tb_getcycles(uint64_t *cycles); + #endif diff --git a/tools/testbench/include/testbench/file.h b/tools/testbench/include/testbench/file.h index 14d5e80df..d18f97972 100644 --- a/tools/testbench/include/testbench/file.h +++ b/tools/testbench/include/testbench/file.h @@ -11,6 +11,8 @@ #ifndef _FILE_H #define _FILE_H +#include + /**< Convert with right shift a bytes count to samples count */ #define FILE_BYTES_TO_S16_SAMPLES(s) ((s) >> 1) #define FILE_BYTES_TO_S32_SAMPLES(s) ((s) >> 2) @@ -29,14 +31,15 @@ enum file_format { /* file component state */ struct file_state { - char *fn; + uint64_t cycles_count; FILE *rfh, *wfh; /* read/write file handle */ - bool reached_eof; - bool write_failed; + char *fn; + int copy_count; int n; enum file_mode mode; enum file_format f_format; - int copy_count; + bool reached_eof; + bool write_failed; }; /* file comp data */ diff --git a/tools/testbench/testbench.c b/tools/testbench/testbench.c index 8aa144654..f43027654 100644 --- a/tools/testbench/testbench.c +++ b/tools/testbench/testbench.c @@ -254,7 +254,7 @@ static void test_pipeline_get_file_stats(int pipeline_id) time = cd->pipeline->pipe_task->start; if (fcd->fs.copy_count == 0) fcd->fs.copy_count = 1; - printf("file %s: id %d: type %d: samples %d copies %d total time %zu uS avg time %zu uS\n", + printf("file %s: id %d: type %d: samples %d copies %d total time %lu uS avg time %lu uS\n", fcd->fs.fn, cd->ipc_config.id, cd->drv->type, fcd->fs.n, fcd->fs.copy_count, time, time / fcd->fs.copy_count); break; @@ -356,7 +356,7 @@ static int parse_input_args(int argc, char **argv, struct testbench_prm *tp) default: fprintf(stderr, "unknown option %c\n", option); ret = -EINVAL; - __attribute__ ((fallthrough)); + /* fallthrough */ case 'h': print_usage(argv[0]); exit(EXIT_SUCCESS); @@ -487,10 +487,16 @@ static int test_pipeline_start(struct testbench_prm *tp) static bool test_pipeline_check_state(struct testbench_prm *tp, int state) { struct pipeline *p; + uint64_t cycles0, cycles1; int i; + tb_getcycles(&cycles0); + schedule_ll_run_tasks(); + tb_getcycles(&cycles1); + tp->total_cycles += cycles1 - cycles0; + /* Run pipeline until EOF from fileread */ for (i = 0; i < tp->pipeline_num; i++) { p = get_pipeline_by_id(tp->pipelines[i]); @@ -522,7 +528,7 @@ static int test_pipeline_load(struct testbench_prm *tp, struct tplg_context *ctx } static void test_pipeline_stats(struct testbench_prm *tp, - struct tplg_context *ctx, uint64_t delta) + struct tplg_context *ctx, long long delta_t) { int count = 1; struct ipc_comp_dev *icd; @@ -530,7 +536,9 @@ static void test_pipeline_stats(struct testbench_prm *tp, struct dai_data *dd; struct pipeline *p; struct file_comp_data *frcd, *fwcd; - int n_in, n_out; + long long file_cycles, pipeline_cycles; + float pipeline_mcps; + int n_in, n_out, frames_out; int i; /* Get pointer to filewrite */ @@ -566,6 +574,7 @@ static void test_pipeline_stats(struct testbench_prm *tp, n_in = frcd->fs.n; n_out = fwcd->fs.n; + file_cycles = frcd->fs.cycles_count + fwcd->fs.cycles_count; /* print test summary */ printf("==========================================================\n"); @@ -586,10 +595,25 @@ static void test_pipeline_stats(struct testbench_prm *tp, printf("Output[%d] written to file: \"%s\"\n", i, tp->output_file[i]); } + frames_out = n_out / tp->channels_out; printf("Input sample (frame) count: %d (%d)\n", n_in, n_in / tp->channels_in); - printf("Output sample (frame) count: %d (%d)\n", n_out, n_out / tp->channels_out); - printf("Total execution time: %zu us, %.2f x realtime\n\n", - delta, (double)((double)n_out / tp->channels_out / tp->fs_out) * 1000000 / delta); + printf("Output sample (frame) count: %d (%d)\n", n_out, frames_out); + if (tp->total_cycles) { + pipeline_cycles = tp->total_cycles - file_cycles; + pipeline_mcps = (float)pipeline_cycles * tp->fs_out / frames_out / 1e6; + printf("Total execution cycles: %lld\n", tp->total_cycles); + printf("File component cycles: %lld\n", file_cycles); + printf("Pipeline cycles: %lld\n", pipeline_cycles); + printf("Pipeline MCPS: %6.2f\n", pipeline_mcps); + if (!tp->quiet) + printf("Warning: Use -q to avoid printing to increase MCPS.\n"); + } + + if (delta_t) + printf("Total execution time: %lld us, %.2f x realtime\n", + delta_t, (float)frames_out / tp->fs_out * 1000000 / delta_t); + + printf("\n"); } /* @@ -602,10 +626,10 @@ static int pipline_test(struct testbench_prm *tp) struct tplg_context ctx; struct timespec ts; struct timespec td0, td1; + long long delta_t; int err; int nsleep_time; int nsleep_limit; - uint64_t delta; /* build, run and teardown pipelines */ while (dp_count < tp->dynamic_pipeline_iterations) { @@ -637,7 +661,8 @@ static int pipline_test(struct testbench_prm *tp) dp_count, err); break; } - clock_gettime(CLOCK_MONOTONIC, &td0); + + tb_gettime(&td0); /* sleep to let the pipeline work - we exit at timeout OR * if copy iterations OR max_samples is reached (whatever first) @@ -652,8 +677,12 @@ static int pipline_test(struct testbench_prm *tp) 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 (test_pipeline_check_state(tp, SOF_TASK_STATE_CANCEL)) { @@ -670,7 +699,8 @@ static int pipline_test(struct testbench_prm *tp) } } - clock_gettime(CLOCK_MONOTONIC, &td1); + tb_gettime(&td1); + err = test_pipeline_stop(tp); if (err < 0) { fprintf(stderr, "error: pipeline stop %d failed %d\n", @@ -678,9 +708,9 @@ static int pipline_test(struct testbench_prm *tp) break; } - delta = (td1.tv_sec - td0.tv_sec) * 1000000; - delta += (td1.tv_nsec - td0.tv_nsec) / 1000; - test_pipeline_stats(tp, &ctx, delta); + delta_t = (td1.tv_sec - td0.tv_sec) * 1000000; + delta_t += (td1.tv_nsec - td0.tv_nsec) / 1000; + test_pipeline_stats(tp, &ctx, delta_t); err = test_pipeline_reset(tp); if (err < 0) { @@ -705,6 +735,7 @@ int main(int argc, char **argv) /* initialize input and output sample rates, files, etc. */ debug = 0; + tp.total_cycles = 0; tp.fs_in = 0; tp.fs_out = 0; tp.bits_in = 0; diff --git a/tools/testbench/topology.c b/tools/testbench/topology.c index b47cbf873..d943dc1a8 100644 --- a/tools/testbench/topology.c +++ b/tools/testbench/topology.c @@ -7,7 +7,6 @@ /* Topology loader to set up components and pipeline */ -#include #include #include #include @@ -161,7 +160,7 @@ static int tb_register_pga(struct testbench_prm *tp, struct tplg_context *ctx) static int tb_register_pipeline(struct testbench_prm *tp, struct tplg_context *ctx) { struct sof *sof = ctx->sof; - struct sof_ipc_pipe_new pipeline = {0}; + struct sof_ipc_pipe_new pipeline = {{0}}; int ret; ret = tplg_new_pipeline(ctx, &pipeline, sizeof(pipeline), NULL); diff --git a/tools/tplg_parser/include/tplg_parser/topology.h b/tools/tplg_parser/include/tplg_parser/topology.h index 0899c2320..e4e7a3a37 100644 --- a/tools/tplg_parser/include/tplg_parser/topology.h +++ b/tools/tplg_parser/include/tplg_parser/topology.h @@ -85,7 +85,7 @@ struct tplg_context { ({struct snd_soc_tplg_hdr *ptr; \ ptr = (struct snd_soc_tplg_hdr *)(ctx->tplg_base + ctx->tplg_offset); \ if (ptr->size != sizeof(*ptr)) { \ - printf("%s %d hdr size mismatch 0x%x:0x%lx at offset %ld\n", \ + printf("%s %d hdr size mismatch 0x%x:0x%zx at offset %ld\n", \ __func__, __LINE__, ptr->size, sizeof(*ptr), \ ctx->tplg_offset); assert(0); \ } \