From patchwork Wed Jul 25 17:15:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 10544503 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 259669093 for ; Wed, 25 Jul 2018 17:15:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 08DDF2A77D for ; Wed, 25 Jul 2018 17:15:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F13952A84E; Wed, 25 Jul 2018 17:15:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 53CAE2A77D for ; Wed, 25 Jul 2018 17:15:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729367AbeGYS2S (ORCPT ); Wed, 25 Jul 2018 14:28:18 -0400 Received: from bhuna.collabora.co.uk ([46.235.227.227]:37080 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728841AbeGYS2S (ORCPT ); Wed, 25 Jul 2018 14:28:18 -0400 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: ezequiel) with ESMTPSA id 87D1527D9E2 From: Ezequiel Garcia To: linux-media@vger.kernel.org Cc: Hans Verkuil , kernel@collabora.com, paul.kocialkowski@bootlin.com, maxime.ripard@bootlin.com, Hans Verkuil , Shuah Khan , linux-kselftest@vger.kernel.org, Ezequiel Garcia Subject: [PATCH v2 5/5] selftests: media_tests: Add a memory-to-memory concurrent stress test Date: Wed, 25 Jul 2018 14:15:16 -0300 Message-Id: <20180725171516.11210-6-ezequiel@collabora.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180725171516.11210-1-ezequiel@collabora.com> References: <20180725171516.11210-1-ezequiel@collabora.com> Sender: linux-kselftest-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add a test for the memory-to-memory framework, to exercise the scheduling of concurrent jobs, using multiple contexts. This test needs to be run using the vim2m virtual driver, and so needs no hardware. Signed-off-by: Ezequiel Garcia --- tools/testing/selftests/media_tests/Makefile | 4 +- .../selftests/media_tests/m2m_job_test.c | 283 ++++++++++++++++++ 2 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/media_tests/m2m_job_test.c diff --git a/tools/testing/selftests/media_tests/Makefile b/tools/testing/selftests/media_tests/Makefile index 60826d7d37d4..d2e8a6b685fb 100644 --- a/tools/testing/selftests/media_tests/Makefile +++ b/tools/testing/selftests/media_tests/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 # CFLAGS += -I../ -I../../../../usr/include/ -TEST_GEN_PROGS := media_device_test media_device_open video_device_test +TEST_GEN_PROGS := media_device_test media_device_open video_device_test m2m_job_test include ../lib.mk + +LDLIBS += -lpthread diff --git a/tools/testing/selftests/media_tests/m2m_job_test.c b/tools/testing/selftests/media_tests/m2m_job_test.c new file mode 100644 index 000000000000..673e7b5cea3a --- /dev/null +++ b/tools/testing/selftests/media_tests/m2m_job_test.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) Collabora, Ltd. + +/* + * This file adds a test for the memory-to-memory + * framework. + * + * This test opens a user specified video device and then + * queues concurrent jobs. The jobs are totally dummy, + * its purpose is only to verify that each of the queued + * jobs is run, and is run only once. + * + * The vim2m driver is needed in order to run the test. + * + * Usage: + * ./m2m-job-test -d /dev/videoX + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000) +#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001) + +#define MAX_TRANS_TIME_MSEC 500 +#define MAX_COUNT 300 +#define MAX_BUFFERS 5 +#define W 100 +#define H 100 + +#ifndef DEBUG +#define dprintf(fmt, arg...) \ + do { \ + } while (0) +#else +#define dprintf(fmt, arg...) printf(fmt, ## arg) +#endif + +static char video_device[256]; +static int thread_count; + +struct context { + int vfd; + unsigned int width; + unsigned int height; + int buffers; +}; + +static int req_src_buf(struct context *ctx, int buffers) +{ + struct v4l2_requestbuffers reqbuf; + struct v4l2_buffer buf; + int i, ret; + + memset(&reqbuf, 0, sizeof(reqbuf)); + memset(&buf, 0, sizeof(buf)); + + reqbuf.count = buffers; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf.memory = V4L2_MEMORY_MMAP; + ret = ioctl(ctx->vfd, VIDIOC_REQBUFS, &reqbuf); + if (ret) + return ret; + + for (i = 0; i < buffers; i++) { + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_QUERYBUF, &buf); + if (ret) + return ret; + buf.bytesused = W*H*2; + ret = ioctl(ctx->vfd, VIDIOC_QBUF, &buf); + if (ret) + return ret; + } + + return 0; +} + +static int req_dst_buf(struct context *ctx, int buffers) +{ + struct v4l2_requestbuffers reqbuf; + struct v4l2_buffer buf; + int i, ret; + + memset(&reqbuf, 0, sizeof(reqbuf)); + memset(&buf, 0, sizeof(buf)); + + reqbuf.count = buffers; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + reqbuf.memory = V4L2_MEMORY_MMAP; + + ret = ioctl(ctx->vfd, VIDIOC_REQBUFS, &reqbuf); + if (ret) + return ret; + + for (i = 0; i < buffers; i++) { + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_QUERYBUF, &buf); + if (ret) + return ret; + ret = ioctl(ctx->vfd, VIDIOC_QBUF, &buf); + if (ret) + return ret; + } + return 0; +} + +static int streamon(struct context *ctx) +{ + enum v4l2_buf_type type; + int ret; + + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ret = ioctl(ctx->vfd, VIDIOC_STREAMON, &type); + if (ret) + return ret; + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = ioctl(ctx->vfd, VIDIOC_STREAMON, &type); + if (ret) + return ret; + + return ret; +} + +static int dqbuf(struct context *ctx) +{ + struct v4l2_buffer buf; + struct pollfd fds[] = { + { .fd = ctx->vfd, .events = POLLIN }, + }; + int i, ret, tout; + + tout = (MAX_TRANS_TIME_MSEC + 10) * thread_count * 2; + for (i = 0; i < ctx->buffers; i++) { + ret = poll(fds, 1, tout); + if (ret == -1) { + if (errno == EINTR) + continue; + return -1; + } + + if (ret == 0) { + dprintf("%s: timeout on %p\n", __func__, ctx); + return -1; + } + + dprintf("%s: event on %p\n", __func__, ctx); + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_DQBUF, &buf); + if (ret) { + dprintf("%s: VIDIOC_DQBUF failed %p\n", __func__, ctx); + return ret; + } + + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + ret = ioctl(ctx->vfd, VIDIOC_DQBUF, &buf); + if (ret) { + dprintf("%s: VIDIOC_DQBUF failed %p\n", __func__, ctx); + return ret; + } + } + + return 0; +} + +static void *job(void *arg) +{ + struct context *ctx = (struct context *)arg; + + dprintf("%s: running %p\n", __func__, ctx); + + assert(streamon(ctx) == 0); + assert(dqbuf(ctx) == 0); + assert(dqbuf(ctx) != 0); + close(ctx->vfd); + + dprintf("%s: %p done\n", __func__, ctx); + return NULL; +} + +static void init(struct context *ctx) +{ + struct v4l2_ext_controls ext_ctrls; + struct v4l2_ext_control ctrls[2]; + struct v4l2_capability cap; + int ret, buffers; + + memset(ctx, 0, sizeof(*ctx)); + + ctx->vfd = open(video_device, O_RDWR | O_NONBLOCK, 0); + ctx->width = W; + ctx->height = H; + assert(ctx->vfd >= 0); + + ret = ioctl(ctx->vfd, VIDIOC_QUERYCAP, &cap); + assert(ret == 0); + assert(cap.device_caps & V4L2_CAP_VIDEO_M2M); + assert(strcmp((const char *)cap.driver, "vim2m") == 0); + + ctrls[0].id = V4L2_CID_TRANS_TIME_MSEC; + ctrls[0].value = rand() % MAX_TRANS_TIME_MSEC + 10; + ctrls[1].id = V4L2_CID_TRANS_NUM_BUFS; + ctrls[1].value = 1; + + memset(&ext_ctrls, 0, sizeof(ext_ctrls)); + ext_ctrls.count = 2; + ext_ctrls.controls = ctrls; + ret = ioctl(ctx->vfd, VIDIOC_S_EXT_CTRLS, &ext_ctrls); + assert(ret == 0); + + buffers = rand() % MAX_BUFFERS + 1; + assert(req_src_buf(ctx, buffers) == 0); + assert(req_dst_buf(ctx, buffers) == 0); + ctx->buffers = buffers; +} + +int main(int argc, char * const argv[]) +{ + int i, opt; + + if (argc < 2) { + printf("Usage: %s [-d ]\n", argv[0]); + exit(-1); + } + + /* Process arguments */ + while ((opt = getopt(argc, argv, "d:")) != -1) { + switch (opt) { + case 'd': + strncpy(video_device, optarg, sizeof(video_device) - 1); + video_device[sizeof(video_device)-1] = '\0'; + break; + default: + printf("Usage: %s [-d ]\n", argv[0]); + exit(-1); + } + } + + /* Generate random number of interations */ + srand((unsigned int) time(NULL)); + thread_count = rand() % MAX_COUNT + 1; + + pthread_t in_thread[thread_count]; + struct context ctx[thread_count]; + + printf("Running %d threads\n", thread_count); + + for (i = 0; i < thread_count; i++) + init(&ctx[i]); + + for (i = 0; i < thread_count; i++) + pthread_create(&in_thread[i], NULL, job, &ctx[i]); + + for (i = 0; i < thread_count; i++) + pthread_join(in_thread[i], NULL); + + return 0; +}