[Sound-open-firmware] [PATCH v4 4/5] testbench: MUX component testbench added
Ranjani Sridharan
ranjani.sridharan at linux.intel.com
Thu Sep 7 17:01:30 CEST 2017
This patch adds the testbench code for the MUX component. The testbench
simulates a pipeline with a MUX comp connected to 1 source buffer
and 2 sink buffers. The sink buffers are switched after every 100 periods
resulting in the samples being written out to 2 separate output files.
Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
---
tune/mux/Makefile.am | 28 +++++
tune/mux/mux_test.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 359 insertions(+)
create mode 100644 tune/mux/Makefile.am
create mode 100644 tune/mux/mux_test.c
diff --git a/tune/mux/Makefile.am b/tune/mux/Makefile.am
new file mode 100644
index 0000000..17fdfef
--- /dev/null
+++ b/tune/mux/Makefile.am
@@ -0,0 +1,28 @@
+AUTOMAKE_OPTIONS = subdir-objects
+
+SOF = ../../../sof.git
+SRCADIR = $(SOF)/src/audio
+INCDIR1 = ../c/include
+INCDIR2 = $(SOF)/src/include
+INCDIR3 = $(SOF)/src/arch/xtensa/include
+INCDIR4 = $(SOF)/src/platform/baytrail/include
+INCLUDE = -I$(INCDIR1) -I$(INCDIR2) -I$(INCDIR3) -I$(INCDIR4) -I$(SRCADIR)
+DEFINE = -DCONFIG_BAYTRAIL -D__XTENSA__ -DMODULE_TEST
+
+AM_CPPFLAGS = $(INCLUDE) $(DEFINE)
+AM_CFLAGS = -m32 -g -Wall
+LDADD = -lm
+
+bin_PROGRAMS = mux_test
+
+mux_test_SOURCES = mux_test.c \
+ ../../../sof.git/src/audio/mux.c \
+ ../../../sof.git/src/include/reef/audio/mux.h \
+ ../../../sof.git/src/audio/component.c \
+ ../../../sof.git/src/audio/pipeline.c \
+ ../../../sof.git/src/audio/buffer.c \
+ ../../../sof.git/src/ipc/ipc.c \
+ ../c/src/fileread.c \
+ ../c/src/filewrite.c \
+ ../c/src/common_test.h \
+ ../c/src/common_test.c
diff --git a/tune/mux/mux_test.c b/tune/mux/mux_test.c
new file mode 100644
index 0000000..133a31d
--- /dev/null
+++ b/tune/mux/mux_test.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2017, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Intel Corporation nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
+ */
+
+#include "common_test.h"
+
+/* Internal buffer */
+#define TEST_BENCH_DEADLINE 5000 /* 5 ms */
+#define TEST_BENCH_NCH 2 /* Stereo */
+#define TEST_BENCH_RATE_MAX 192000 /* Hz */
+#define TEST_BENCH_FRAME_SIZE (4 * TEST_BENCH_NCH) /* 4bytes x NCH */
+#define TEST_BENCH_PERIOD_FRAMES (TEST_BENCH_RATE_MAX*TEST_BENCH_DEADLINE/1e6)
+#define INT_PERIOD_SIZE (TEST_BENCH_PERIOD_FRAMES * TEST_BENCH_FRAME_SIZE)
+#define MUX_SWITCH_PERIODS 100
+
+/* main firmware context */
+static struct reef reef;
+
+/*
+ * Test Pipeline (ID=0)
+ *
+ * +---> B(5) ---> Filewrite(2)
+ * Fileread(0) ---> B(4)---> Mux(1) ---|
+ * +---> B(6) ---> Filewrite(3)
+ */
+
+#define FR_ID 0
+#define MUX_ID 1 /* scheduling component */
+#define FW_ID1 2
+#define FW_ID2 3
+#define PIPE_ID 0
+#define PIPE_COMP_ID 7
+#define SCHED_ID MUX_ID
+
+
+/* components used in static pipeline */
+static struct sof_ipc_comp_fileread fileread_p0[] = {
+ SPIPE_FILEREAD(SPIPE_COMP(0, SOF_COMP_FILEREAD, sof_ipc_comp_fileread),
+ "mux_in.txt"), /* ID = 0 */
+};
+
+static struct sof_ipc_comp_filewrite filewrite_p0[] = {
+ SPIPE_FILEWRITE(SPIPE_COMP(2, SOF_COMP_FILEWRITE,
+ sof_ipc_comp_filewrite), "mux_out_1.txt"), /* ID = 2 */
+ SPIPE_FILEWRITE(SPIPE_COMP(3, SOF_COMP_FILEWRITE,
+ sof_ipc_comp_filewrite), "mux_out_2.txt"), /* ID = 3 */
+};
+
+static struct sof_ipc_comp_mux mux_p0[] = {
+ SPIPE_MUX(SPIPE_COMP(1, SOF_COMP_MUX, sof_ipc_comp_mux)), /* ID = 1 */
+};
+
+static struct scomps scomps_p0[] = {
+ SCOMP(fileread_p0),
+ SCOMP(mux_p0),
+ SCOMP(filewrite_p0),
+};
+
+/*
+ * Buffers used in static pipeline 2.
+ */
+static struct sof_ipc_buffer buffers_p0[] = {
+ SPIPE_BUFFER(4, INT_PERIOD_SIZE * 2), /* B(4) */
+ SPIPE_BUFFER(5, INT_PERIOD_SIZE * 2), /* B(5) */
+ SPIPE_BUFFER(6, INT_PERIOD_SIZE * 2), /* B(5) */
+};
+
+/* pipeline 0 component/buffer connections */
+static struct sof_ipc_pipe_comp_connect connect_p0[] = {
+ SPIPE_COMP_CONNECT(0, 4), /* p(0): Fileread(0) -> B(4) */
+ SPIPE_COMP_CONNECT(4, 1), /* p(0): B(3) -> Mux(1) */
+ SPIPE_COMP_CONNECT(1, 5), /* p(0): Mux(1) -> B(5) */
+ SPIPE_COMP_CONNECT(1, 6), /* p(0): Mux(1) -> B(6) */
+ SPIPE_COMP_CONNECT(5, 2), /* p(0): B(5) -> Filewrite(2) */
+ SPIPE_COMP_CONNECT(6, 3), /* p(0): B(5) -> Filewrite(3) */
+};
+
+/* the static pipelines */
+static struct spipe spipe[] = {
+ SPIPE(scomps_p0, buffers_p0, connect_p0),
+};
+
+/* pipelines */
+struct sof_ipc_pipe_new pipeline[] = {
+ SPIPE_PIPE(PIPE_ID, 0, PIPE_COMP_ID, SCHED_ID, TEST_BENCH_DEADLINE,
+ TASK_PRI_LOW, TEST_BENCH_PERIOD_FRAMES),
+};
+
+/* pipeline setup, params and start */
+static int pipeline_calls(int i)
+{
+ int ret = 0;
+ struct pipeline *p;
+ struct ipc_comp_dev *pcm_dev;
+
+ /* construct pipeline */
+ ret = test_bench_pipeline_setup(&reef, &pipeline[i], &spipe[i]);
+ if (ret < 0) {
+ printf("error: pipeline setup\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* set up pipeline params */
+ ret = test_bench_pipeline_params(reef.ipc, TEST_BENCH_RATE_MAX,
+ TEST_BENCH_NCH, FR_ID, TEST_BENCH_DEADLINE,
+ pipeline[i].pipeline_id);
+ if (ret < 0) {
+ printf("error: pipeline params\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* prepare pipeline and initialize default MUX config */
+ pcm_dev = ipc_get_comp(reef.ipc, FR_ID);
+ p = pcm_dev->cd->pipeline;
+ ret = pipeline_prepare(p, pcm_dev->cd);
+ if (ret < 0) {
+ printf("error: pipeline prepare\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* start pipeline */
+ ret = pipeline_cmd(p, pcm_dev->cd, COMP_CMD_START, NULL);
+ if (ret < 0) {
+ printf("error: start pipeline cmd\n");
+ ret = -EINVAL;
+ }
+
+out:
+ return ret;
+}
+
+/* copy frames from input file until EOF */
+static int schedule_pipeline(struct ipc_comp_dev *pcm_dev,
+ struct pipeline *p, struct fileread_comp_data *frcd)
+{
+ int ret = 0, period = 0;
+ struct sof_ipc_ctrl_data *data;
+
+ data = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
+ COMP_SIZE(struct sof_ipc_ctrl_data));
+ if (data == NULL) {
+ printf("error: mem alloc ipc ctrl data\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* set route ctrl cmd data */
+ data->num_elems = 1;
+ data->comp_id = MUX_ID;
+ data->cmd = SOF_CTRL_CMD_ROUTE;
+ data->type = SOF_CTRL_TYPE_VALUE_COMP_SET;
+ data->compv[0].index = 1;
+ data->compv[0].uvalue = 0;
+
+ /* copy period frames from input file to output files
+ * switching output buffers every MUX_SWITCH_PERIODS periods
+ */
+ while (frcd->frs.reached_eof == 0) {
+ if ((period % MUX_SWITCH_PERIODS == 0) && (period > 0)) {
+ /* pause pipeline
+ * stopping the pipeline results in the loss of 1 or 2
+ * period samples
+ */
+ ret = pipeline_cmd(p, pcm_dev->cd, COMP_CMD_PAUSE,
+ NULL);
+ if (ret < 0) {
+ printf("error: pause pipeline cmd\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*switch output buffer index */
+ if (data->compv[0].uvalue == 0)
+ data->compv[0].uvalue = 1;
+ else
+ data->compv[0].uvalue = 0;
+
+ /* re-route MUX */
+ ret = pipeline_cmd(p, pcm_dev->cd, COMP_CMD_SET_VALUE,
+ data);
+ if (ret < 0) {
+ printf("error: mux route cmd\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* re-start pipeline */
+ ret = pipeline_cmd(p, pcm_dev->cd, COMP_CMD_START,
+ NULL);
+ if (ret < 0) {
+ printf("error: start pipeline cmd\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ pipeline_schedule_copy(p, pcm_dev->cd);
+ period++;
+ }
+
+ rfree(data);
+
+ return ret;
+}
+
+void usage(char *executable)
+{
+ fprintf(stderr, "Usage: %s <input.txt> <output1.txt> <output2.txt>\n",
+ executable);
+}
+
+int main(int argc, char **argv)
+{
+ struct ipc_comp_dev *pcm_dev;
+ struct pipeline *p;
+ struct comp_dev *cd;
+ int ret = 0, samples_in, samples_out, i = 0;
+ struct fileread_comp_data *frcd;
+ struct filewrite_comp_data *fwcd1, *fwcd2;
+ clock_t tic, toc;
+ double c_realtime, t_exec;
+
+ /* handle command line arguments*/
+ if (argc > 3) {
+ switch (argc) {
+ case 4:
+ fileread_p0[0].fn = argv[1];
+ filewrite_p0[0].fn = argv[2];
+ filewrite_p0[1].fn = argv[3];
+ break;
+ default:
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+ } else {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+
+ /* init components */
+ sys_comp_init();
+ sys_comp_fileread_init();
+ sys_comp_filewrite_init();
+ sys_comp_mux_init();
+
+
+
+ for (i = 0; i < ARRAY_SIZE(pipeline); i++) {
+ pipeline[i].frames_per_sched = (int)
+ (0.9999 + TEST_BENCH_RATE_MAX *
+ TEST_BENCH_DEADLINE / 1e6);
+ /* perform pipeline set up and start*/
+ ret = pipeline_calls(i);
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ /* Reduce print output */
+ test_bench_disable_trace();
+
+ /* fileread and filewrite component data */
+ pcm_dev = ipc_get_comp(reef.ipc, FW_ID1);
+ fwcd1 = comp_get_drvdata(pcm_dev->cd);
+ pcm_dev = ipc_get_comp(reef.ipc, FW_ID2);
+ fwcd2 = comp_get_drvdata(pcm_dev->cd);
+ pcm_dev = ipc_get_comp(reef.ipc, FR_ID);
+ frcd = comp_get_drvdata(pcm_dev->cd);
+ p = pcm_dev->cd->pipeline;
+ cd = pcm_dev->cd;
+
+ tic = clock();
+
+ /*
+ * Run copy until EOF from fileread
+ */
+ ret = schedule_pipeline(pcm_dev, p, frcd);
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ toc = clock();
+
+ /* samples read in and written out */
+ samples_in = frcd->frs.n;
+ samples_out = fwcd1->fws.n + fwcd2->fws.n;
+
+ test_bench_enable_trace();
+
+ /* reset and free pipeline */
+ ret = pipeline_reset(p, cd);
+ if (ret < 0) {
+ printf("error: pipeline reset\n");
+ exit(EXIT_FAILURE);
+ }
+ pipeline_free(p);
+
+ /* report test results */
+ t_exec = (double) (toc - tic) / CLOCKS_PER_SEC;
+ c_realtime = (double) samples_out / TEST_BENCH_NCH /
+ TEST_BENCH_RATE_MAX / t_exec;
+ printf("Read %d input samples,\n", samples_in);
+ printf("wrote %d output samples,\n", samples_out);
+ printf("test execution time was %.2f us, %.2fx realtime.\n",
+ 1e3 * t_exec, c_realtime);
+ }
+
+ return EXIT_SUCCESS;
+}
--
2.9.3
More information about the Sound-open-firmware
mailing list