[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