[igt-dev] [PATCH] tests/syncobj_sync_file: new test
Zbigniew Kempczyński
zbigniew.kempczynski at intel.com
Tue Jul 25 04:18:07 UTC 2023
Hi Erik.
+Petri, +Kamil
Please verify I'm not wrong with the uapi bumping procedure below.
On Mon, Jul 24, 2023 at 03:33:25PM -0700, Erik Kurzinger wrote:
> This test suite exercises the new DRM_IOCTL_IMPORT/EXPORT_SYNC_FILE
> ioctl introduced in [1].
>
> [1] https://lore.kernel.org/dri-devel/5e687ad8-78ad-0350-6052-a698b278cc8c@nvidia.com/
>
> Signed-off-by: Erik Kurzinger <ekurzinger at nvidia.com>
> ---
> include/drm-uapi/drm.h | 11 ++
> lib/igt_syncobj.c | 24 ++++
> lib/igt_syncobj.h | 2 +
> tests/meson.build | 1 +
> tests/syncobj_sync_file.c | 256 ++++++++++++++++++++++++++++++++++++++
> 5 files changed, 294 insertions(+)
> create mode 100644 tests/syncobj_sync_file.c
>
> diff --git a/include/drm-uapi/drm.h b/include/drm-uapi/drm.h
> index 5e54c3aa4..389dc138a 100644
> --- a/include/drm-uapi/drm.h
> +++ b/include/drm-uapi/drm.h
> @@ -878,6 +878,12 @@ struct drm_syncobj_transfer {
> __u32 pad;
> };
>
> +struct drm_syncobj_sync_file {
> + __u32 handle;
> + __u32 fd;
> + __u64 point;
> +};
> +
> #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
> #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
> #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */
> @@ -1090,8 +1096,13 @@ extern "C" {
> #define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer)
> #define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL DRM_IOWR(0xCD, struct drm_syncobj_timeline_array)
>
> +
> +
> #define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2)
>
> +#define DRM_IOCTL_SYNCOBJ_IMPORT_SYNC_FILE DRM_IOWR(0xD0, struct drm_syncobj_sync_file)
> +#define DRM_IOCTL_SYNCOBJ_EXPORT_SYNC_FILE DRM_IOWR(0xD1, struct drm_syncobj_sync_file)
> +
> /*
> * Device specific ioctls should only be in their respective headers
> * The device specific ioctl range is from 0x40 to 0x9f.
We allow changes in uapi headers which were previously accepted and merged
in the community. This is chicken-and-egg problem but prevent us from
exposing uapi which might be not accepted upstream.
> diff --git a/lib/igt_syncobj.c b/lib/igt_syncobj.c
> index a24ed10b7..ef0e297e3 100644
> --- a/lib/igt_syncobj.c
> +++ b/lib/igt_syncobj.c
> @@ -163,6 +163,18 @@ syncobj_fd_to_handle(int fd, int syncobj_fd, uint32_t flags)
> return args.handle;
> }
>
> +int
> +__syncobj_import_sync_file(int fd, struct drm_syncobj_sync_file *args)
> +{
> + int err = 0;
> + if (igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_IMPORT_SYNC_FILE, args)) {
> + err = -errno;
> + igt_assume(err);
> + errno = 0;
> + }
> + return err;
> +}
> +
> /**
> * syncobj_import_sync_file:
> * @fd: The DRM file descriptor
> @@ -181,6 +193,18 @@ syncobj_import_sync_file(int fd, uint32_t handle, int sync_file)
> igt_assert_eq(__syncobj_fd_to_handle(fd, &args), 0);
> }
>
> +int
> +__syncobj_export_sync_file(int fd, struct drm_syncobj_sync_file *args)
> +{
> + int err = 0;
> + if (igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_EXPORT_SYNC_FILE, args)) {
> + err = -errno;
> + igt_assume(err);
> + errno = 0;
> + }
> + return err;
> +}
> +
> int
> __syncobj_wait(int fd, struct drm_syncobj_wait *args)
> {
At the moment (before uapi will be accepted) I would add locally in the test:
- drm.h definitions naming them LOCAL_DRM_IOCTL_...
- two functions locally in the test. In this case names can stay, when
uapi will be accepted and merged just move them to igt_syncobj.c/h
(use inside LOCAL_DRM_IOCTL_... until official merge).
After uapi merge we do verbatim copy of header from the kernel
include directory and remove "localization" described above.
I'm sorry for inconvinience but that's the rules.
--
Zbigniew
> diff --git a/lib/igt_syncobj.h b/lib/igt_syncobj.h
> index e6725671d..01f5f062b 100644
> --- a/lib/igt_syncobj.h
> +++ b/lib/igt_syncobj.h
> @@ -34,7 +34,9 @@ int __syncobj_handle_to_fd(int fd, struct drm_syncobj_handle *args);
> int __syncobj_fd_to_handle(int fd, struct drm_syncobj_handle *args);
> int syncobj_handle_to_fd(int fd, uint32_t handle, uint32_t flags);
> uint32_t syncobj_fd_to_handle(int fd, int syncobj_fd, uint32_t flags);
> +int __syncobj_import_sync_file(int fd, struct drm_syncobj_sync_file *args);
> void syncobj_import_sync_file(int fd, uint32_t handle, int sync_file);
> +int __syncobj_export_sync_file(int fd, struct drm_syncobj_sync_file *args);
> int __syncobj_wait(int fd, struct drm_syncobj_wait *args);
> int syncobj_wait_err(int fd, uint32_t *handles, uint32_t count,
> uint64_t abs_timeout_nsec, uint32_t flags);
> diff --git a/tests/meson.build b/tests/meson.build
> index 944a0941f..1712c31ca 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -80,6 +80,7 @@ test_progs = [
> 'syncobj_basic',
> 'syncobj_wait',
> 'syncobj_timeline',
> + 'syncobj_sync_file',
> 'sw_sync',
> 'template',
> 'testdisplay',
> diff --git a/tests/syncobj_sync_file.c b/tests/syncobj_sync_file.c
> new file mode 100644
> index 000000000..6cbcc9dcd
> --- /dev/null
> +++ b/tests/syncobj_sync_file.c
> @@ -0,0 +1,256 @@
> +/*
> + * Copyright © 2023 NVIDIA
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "igt.h"
> +#include "igt_syncobj.h"
> +#include "sw_sync.h"
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include "drm.h"
> +
> +/**
> + * TEST: syncobj sync file
> + * Category: Infrastructure
> + * Description: Tests for DRM syncobj sync file import and export
> + * Feature: synchronization
> + * Functionality: semaphore
> + * Run type: FULL
> + * Sub-category: DRM
> + * Test category: GEM_Legacy
> + *
> + * SUBTEST: binary-import-export
> + * Description: Verifies importing and exporting sync files with a binary syncobj.
> + *
> + * SUBTEST: timeline-import-export
> + * Description: Verifies importing and exporting sync files with a timeline syncobj.
> + *
> + * SUBTEST: invalid-handle-import
> + * Description: Verifies that importing a sync file to an invalid syncobj fails.
> + *
> + * SUBTEST: invalid-handle-export
> + * Description: Verifies that exporting a sync file from an invalid syncobj fails.
> + *
> + * SUBTEST: invalid-fd-import
> + * Description: Verifies that importing an invalid sync file fails.
> + *
> + * SUBTEST: unsubmitted-export
> + * Description: Verifies that exporting a sync file for an unsubmitted point fails.
> + *
> + */
> +
> +IGT_TEST_DESCRIPTION("Tests for DRM syncobj sync file import and export");
> +
> +const char *test_binary_import_export_desc =
> + "Verifies importing and exporting a sync file with a binary syncobj.";
> +static void
> +test_binary_import_export(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> + int timeline = sw_sync_timeline_create();
> +
> + args.handle = syncobj_create(fd, 0);
> + args.fd = sw_sync_timeline_create_fence(timeline, 1);
> + args.point = 0;
> + igt_assert_eq(__syncobj_import_sync_file(fd, &args), 0);
> + close(args.fd);
> + args.fd = -1;
> + igt_assert_eq(__syncobj_export_sync_file(fd, &args), 0);
> +
> + igt_assert(!syncobj_wait(fd, &args.handle, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(args.fd), 0);
> +
> + sw_sync_timeline_inc(timeline, 1);
> + igt_assert(syncobj_wait(fd, &args.handle, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(args.fd), 1);
> +
> + close(args.fd);
> + close(timeline);
> + syncobj_destroy(fd, args.handle);
> +}
> +
> +const char *test_timeline_import_export_desc =
> + "Verifies importing and exporting sync files with a timeline syncobj.";
> +static void
> +test_timeline_import_export(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> + int timeline = sw_sync_timeline_create();
> + int fence1, fence2;
> + uint64_t point1 = 1, point2 = 2;
> +
> + args.handle = syncobj_create(fd, 0);
> + args.fd = sw_sync_timeline_create_fence(timeline, 1);
> + args.point = 1;
> + igt_assert_eq(__syncobj_import_sync_file(fd, &args), 0);
> + close(args.fd);
> + args.fd = -1;
> + igt_assert_eq(__syncobj_export_sync_file(fd, &args), 0);
> + fence1 = args.fd;
> +
> + args.fd = sw_sync_timeline_create_fence(timeline, 2);
> + args.point = 2;
> + igt_assert_eq(__syncobj_import_sync_file(fd, &args), 0);
> + close(args.fd);
> + args.fd = -1;
> + igt_assert_eq(__syncobj_export_sync_file(fd, &args), 0);
> + fence2 = args.fd;
> +
> + igt_assert(!syncobj_timeline_wait(fd, &args.handle, &point1, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(fence1), 0);
> + igt_assert(!syncobj_timeline_wait(fd, &args.handle, &point2, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(fence2), 0);
> +
> + sw_sync_timeline_inc(timeline, 1);
> + igt_assert(syncobj_timeline_wait(fd, &args.handle, &point1, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(fence1), 1);
> + igt_assert(!syncobj_timeline_wait(fd, &args.handle, &point2, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(fence2), 0);
> +
> + sw_sync_timeline_inc(timeline, 1);
> + igt_assert(syncobj_timeline_wait(fd, &args.handle, &point1, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(fence1), 1);
> + igt_assert(syncobj_timeline_wait(fd, &args.handle, &point2, 1, 0, 0, NULL));
> + igt_assert_eq(sync_fence_status(fence2), 1);
> +
> + close(fence1);
> + close(fence2);
> + close(timeline);
> + syncobj_destroy(fd, args.handle);
> +}
> +
> +const char *test_invalid_handle_import_desc =
> + "Verifies that importing a sync file to an invalid syncobj fails.";
> +static void
> +test_invalid_handle_import(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> + int timeline = sw_sync_timeline_create();
> +
> + args.handle = 0;
> + args.point = 0;
> + args.fd = sw_sync_timeline_create_fence(timeline, 1);
> + igt_assert_eq(__syncobj_import_sync_file(fd, &args), -EINVAL);
> +
> + close(args.fd);
> + close(timeline);
> +}
> +
> +const char *test_invalid_handle_export_desc =
> + "Verifies that exporting a sync file from an invalid syncobj fails.";
> +static void
> +test_invalid_handle_export(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> +
> + args.handle = 0;
> + args.point = 0;
> + args.fd = -1;
> + igt_assert_eq(__syncobj_export_sync_file(fd, &args), -EINVAL);
> +}
> +
> +const char *test_invalid_fd_import_desc =
> + "Verifies that importing an invalid sync file fails.";
> +static void
> +test_invalid_fd_import(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> +
> + args.handle = syncobj_create(fd, 0);
> + args.point = 0;
> + args.fd = -1;
> + igt_assert_eq(__syncobj_import_sync_file(fd, &args), -EINVAL);
> +
> + syncobj_destroy(fd, args.handle);
> +}
> +
> +const char *test_unsubmitted_export_desc =
> + "Verifies that exporting a sync file for an unsubmitted point fails.";
> +static void
> +test_unsubmitted_export(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> +
> + args.handle = syncobj_create(fd, 0);
> + args.point = 0;
> + args.fd = -1;
> + igt_assert_eq(__syncobj_export_sync_file(fd, &args), -EINVAL);
> +
> + syncobj_destroy(fd, args.handle);
> +}
> +
> +static bool has_syncobj_timeline(int fd)
> +{
> + uint64_t value;
> + return drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE,
> + &value) == 0 && value;
> +}
> +
> +static bool has_syncobj_sync_file_import_export(int fd)
> +{
> + struct drm_syncobj_sync_file args = { 0 };
> + args.handle = 0xffffffff;
> + /* if sync file import/export is supported this will fail with ENOENT,
> + * otherwise it will fail with EINVAL */
> + return __syncobj_export_sync_file(fd, &args) == -ENOENT;
> +}
> +
> +igt_main
> +{
> + int fd = -1;
> +
> + igt_fixture {
> + fd = drm_open_driver(DRIVER_ANY);
> + igt_require(has_syncobj_timeline(fd));
> + igt_require(has_syncobj_sync_file_import_export(fd));
> + igt_require_sw_sync();
> + }
> +
> + igt_describe(test_binary_import_export_desc);
> + igt_subtest("binary-import-export")
> + test_binary_import_export(fd);
> +
> + igt_describe(test_timeline_import_export_desc);
> + igt_subtest("timeline-import-export")
> + test_timeline_import_export(fd);
> +
> + igt_describe(test_invalid_handle_import_desc);
> + igt_subtest("invalid-handle-import")
> + test_invalid_handle_import(fd);
> +
> + igt_describe(test_invalid_handle_export_desc);
> + igt_subtest("invalid-handle-export")
> + test_invalid_handle_export(fd);
> +
> + igt_describe(test_invalid_fd_import_desc);
> + igt_subtest("invalid-fd-import")
> + test_invalid_fd_import(fd);
> +
> + igt_describe(test_unsubmitted_export_desc);
> + igt_subtest("unsubmitted-export")
> + test_unsubmitted_export(fd);
> +
> + igt_fixture {
> + drm_close_driver(fd);
> + }
> +
> +}
> --
> 2.41.0
>
>
More information about the igt-dev
mailing list