From patchwork Tue Aug 6 15:00:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 11079085 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 62A241398 for ; Tue, 6 Aug 2019 15:00:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 526E42892D for ; Tue, 6 Aug 2019 15:00:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 443AF28994; Tue, 6 Aug 2019 15:00:24 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 78F0D2898C for ; Tue, 6 Aug 2019 15:00:23 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id BAA5289DA6; Tue, 6 Aug 2019 15:00:22 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from fireflyinternet.com (mail.fireflyinternet.com [109.228.58.192]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2A5D489DA6; Tue, 6 Aug 2019 15:00:20 +0000 (UTC) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.65.138; Received: from haswell.alporthouse.com (unverified [78.156.65.138]) by fireflyinternet.com (Firefly Internet (M1)) with ESMTP id 17906958-1500050 for multiple; Tue, 06 Aug 2019 16:00:06 +0100 From: Chris Wilson To: intel-gfx@lists.freedesktop.org Date: Tue, 6 Aug 2019 16:00:04 +0100 Message-Id: <20190806150004.32357-1-chris@chris-wilson.co.uk> X-Mailer: git-send-email 2.23.0.rc1 In-Reply-To: <20190806123644.29194-1-chris@chris-wilson.co.uk> References: <20190806123644.29194-1-chris@chris-wilson.co.uk> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH i-g-t] Add i915/gem_ctx_persistence X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: igt-dev@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Sanity test existing persistence and new exciting non-persistent context behaviour. Signed-off-by: Chris Wilson Cc: Joonas Lahtinen Cc: Michał Winiarski Cc: Jon Bloomfield --- A couple of minor quick fixes, ickle@kabylake:~$ sudo ./intel-gpu-tools/build/tests/gem_ctx_persistence IGT-Version: 1.24-ge79c01a6e (x86_64) (Linux: 5.3.0-rc3+ x86_64) Starting subtest: idempotent Subtest idempotent: SUCCESS (0.000s) Starting subtest: persistence Subtest persistence: SUCCESS (0.220s) Starting subtest: cleanup Subtest cleanup: SUCCESS (0.031s) Starting subtest: hostile Subtest hostile: SUCCESS (0.134s) Starting subtest: process Subtest process: SUCCESS (0.023s) [ 40.326837] [IGT] gem_ctx_persistence: executing [ 40.330091] [IGT] gem_ctx_persistence: starting subtest idempotent [ 40.330151] [IGT] gem_ctx_persistence: starting subtest persistence [ 40.550073] [IGT] gem_ctx_persistence: starting subtest cleanup [ 40.581540] [IGT] gem_ctx_persistence: starting subtest hostile [ 40.689072] i915 0000:00:02.0: Resetting rcs0 for preemption time out [ 40.715172] [IGT] gem_ctx_persistence: starting subtest process [ 40.738741] [IGT] gem_ctx_persistence: exiting, ret=0 [ 40.738902] Setting dangerous option reset - tainting kernel --- lib/i915/gem_context.c | 37 +++++ lib/i915/gem_context.h | 9 ++ lib/ioctl_wrappers.c | 1 + tests/Makefile.sources | 3 + tests/i915/gem_ctx_persistence.c | 242 +++++++++++++++++++++++++++++++ tests/meson.build | 1 + 6 files changed, 293 insertions(+) create mode 100644 tests/i915/gem_ctx_persistence.c diff --git a/lib/i915/gem_context.c b/lib/i915/gem_context.c index 83c5df961..1fae5191f 100644 --- a/lib/i915/gem_context.c +++ b/lib/i915/gem_context.c @@ -272,6 +272,43 @@ void gem_context_set_priority(int fd, uint32_t ctx_id, int prio) igt_assert_eq(__gem_context_set_priority(fd, ctx_id, prio), 0); } +/** + * __gem_context_set_persistence: + * @i915: open i915 drm file descriptor + * @ctx: i915 context id + * @state: desired persistence + * + * Declare whether this context is allowed to persist after closing until + * its requests are complete (persistent=true) or if it should be + * immediately reaped on closing and its requests cancelled + * (persistent=false). + * + * Returns: An integer equal to zero for success and negative for failure + */ +int __gem_context_set_persistence(int i915, uint32_t ctx, bool state) +{ + struct drm_i915_gem_context_param p = { + .ctx_id = ctx, + .param = I915_CONTEXT_PARAM_PERSISTENCE, + .value = state, + }; + + return __gem_context_set_param(i915, &p); +} + +/** + * __gem_context_set_persistence: + * @i915: open i915 drm file descriptor + * @ctx: i915 context id + * @state: desired persistence + * + * Like __gem_context_set_persistence(), except we assert on failure. + */ +void gem_context_set_persistence(int i915, uint32_t ctx, bool state) +{ + igt_assert_eq(__gem_context_set_persistence(i915, ctx, state), 0); +} + int __gem_context_clone(int i915, uint32_t src, unsigned int share, diff --git a/lib/i915/gem_context.h b/lib/i915/gem_context.h index 8043c3401..6745c90c3 100644 --- a/lib/i915/gem_context.h +++ b/lib/i915/gem_context.h @@ -24,6 +24,11 @@ #ifndef GEM_CONTEXT_H #define GEM_CONTEXT_H +#include +#include + +struct drm_i915_gem_context_param; + uint32_t gem_context_create(int fd); int __gem_context_create(int fd, uint32_t *ctx_id); void gem_context_destroy(int fd, uint32_t ctx_id); @@ -58,6 +63,10 @@ int __gem_context_get_param(int fd, struct drm_i915_gem_context_param *p); int __gem_context_set_priority(int fd, uint32_t ctx, int prio); void gem_context_set_priority(int fd, uint32_t ctx, int prio); +#define I915_CONTEXT_PARAM_PERSISTENCE 0xb +int __gem_context_set_persistence(int i915, uint32_t ctx, bool state); +void gem_context_set_persistence(int i915, uint32_t ctx, bool state); + bool gem_context_has_engine(int fd, uint32_t ctx, uint64_t engine); #endif /* GEM_CONTEXT_H */ diff --git a/lib/ioctl_wrappers.c b/lib/ioctl_wrappers.c index 280fdd624..628f8b830 100644 --- a/lib/ioctl_wrappers.c +++ b/lib/ioctl_wrappers.c @@ -445,6 +445,7 @@ int gem_wait(int fd, uint32_t handle, int64_t *timeout_ns) ret = 0; if (igt_ioctl(fd, DRM_IOCTL_I915_GEM_WAIT, &wait)) ret = -errno; + errno = 0; if (timeout_ns) *timeout_ns = wait.timeout_ns; diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 250dbd33f..f452ad209 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -151,6 +151,9 @@ gem_ctx_isolation_SOURCES = i915/gem_ctx_isolation.c TESTS_progs += gem_ctx_param gem_ctx_param_SOURCES = i915/gem_ctx_param.c +TESTS_progs += gem_ctx_persistence +gem_ctx_persistence_SOURCES = i915/gem_ctx_ersistence.c + TESTS_progs += gem_ctx_shared gem_ctx_shared_SOURCES = i915/gem_ctx_shared.c diff --git a/tests/i915/gem_ctx_persistence.c b/tests/i915/gem_ctx_persistence.c new file mode 100644 index 000000000..fc52c799f --- /dev/null +++ b/tests/i915/gem_ctx_persistence.c @@ -0,0 +1,242 @@ +/* + * Copyright © 2019 Intel Corporation + * + * 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 +#include +#include +#include + +#include "drmtest.h" /* gem_quiescent_gpu()! */ +#include "i915/gem_context.h" +#include "i915/gem_submission.h" +#include "igt_dummyload.h" +#include "ioctl_wrappers.h" /* gem_wait()! */ +#include "sw_sync.h" + +static bool has_persistence(int i915) +{ + struct drm_i915_gem_context_param p = { + .param = I915_CONTEXT_PARAM_PERSISTENCE, + }; + uint64_t saved; + + if (__gem_context_get_param(i915, &p)) + return false; + + saved = p.value; + p.value = 0; + if (__gem_context_set_param(i915, &p)) + return false; + + p.value = saved; + return __gem_context_set_param(i915, &p) == 0; +} + +static void test_idempotent(int i915) +{ + struct drm_i915_gem_context_param p = { + .param = I915_CONTEXT_PARAM_PERSISTENCE, + }; + int expected; + + gem_context_get_param(i915, &p); + expected = !!p.value; + + expected = !expected; + p.value = expected; + gem_context_set_param(i915, &p); + gem_context_get_param(i915, &p); + igt_assert_eq(p.value, expected); + + expected = !expected; /* and restores */ + p.value = expected; + gem_context_set_param(i915, &p); + gem_context_get_param(i915, &p); + igt_assert_eq(p.value, expected); +} + +static void test_persistence(int i915) +{ + igt_spin_t *spin; + int64_t timeout; + uint32_t ctx; + + ctx = gem_context_create(i915); + gem_context_set_persistence(i915, ctx, true); + + spin = igt_spin_new(i915, ctx, .flags = IGT_SPIN_FENCE_OUT); + gem_context_destroy(i915, ctx); + + timeout = NSEC_PER_SEC / 5; + igt_assert_eq(gem_wait(i915, spin->handle, &timeout), -ETIME); + + igt_spin_end(spin); + + timeout = NSEC_PER_SEC / 5; + igt_assert_eq(gem_wait(i915, spin->handle, &timeout), 0); + igt_assert_eq(sync_fence_status(spin->out_fence), 1); + + igt_spin_free(i915, spin); + gem_quiescent_gpu(i915); +} + +static void test_nonpersistent_cleanup(int i915) +{ + int64_t timeout = NSEC_PER_SEC / 5; + igt_spin_t *spin; + uint32_t ctx; + + ctx = gem_context_create(i915); + gem_context_set_persistence(i915, ctx, false); + + spin = igt_spin_new(i915, ctx, .flags = IGT_SPIN_FENCE_OUT); + gem_context_destroy(i915, ctx); + + igt_assert_eq(gem_wait(i915, spin->handle, &timeout), 0); + igt_assert_eq(sync_fence_status(spin->out_fence), -EIO); + + igt_spin_free(i915, spin); + gem_quiescent_gpu(i915); +} + +static void test_nonpersistent_hostile(int i915) +{ + int64_t timeout = NSEC_PER_SEC / 2; + igt_spin_t *spin; + uint32_t ctx; + + ctx = gem_context_create(i915); + gem_context_set_persistence(i915, ctx, false); + + spin = igt_spin_new(i915, ctx, .flags = IGT_SPIN_NO_PREEMPTION); + gem_context_destroy(i915, ctx); + + igt_assert_eq(gem_wait(i915, spin->handle, &timeout), 0); + + igt_spin_free(i915, spin); + gem_quiescent_gpu(i915); +} + +static void sendfd(int socket, int fd) +{ + struct iovec io = { .iov_base = (char *)"ABC", .iov_len = 3 }; + struct msghdr msg = {}; + char buf[CMSG_SPACE(sizeof(fd))]; + struct cmsghdr *cmsg; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); + + *(int *)CMSG_DATA(cmsg) = fd; + msg.msg_controllen = cmsg->cmsg_len; + + igt_assert(sendmsg(socket, &msg, 0) != -1); +} + +static int recvfd(int socket) +{ + char m_buffer[256], c_buffer[256]; + struct iovec io = { + .iov_base = m_buffer, + .iov_len = sizeof(m_buffer), + }; + struct msghdr msg = { + .msg_iov = &io, + .msg_iovlen = 1, + .msg_control = c_buffer, + .msg_controllen = sizeof(c_buffer), + }; + + igt_assert(recvmsg(socket, &msg, 0) != -1); + return *(int *)CMSG_DATA(CMSG_FIRSTHDR(&msg)); +} + +static void test_nonpersistent_process(int i915) +{ + int fence, sv[2]; + + igt_require(socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) == 0); + + igt_fork(child, 1) { + igt_spin_t *spin; + + i915 = gem_reopen_driver(i915); + gem_context_set_persistence(i915, 0, false); + spin = igt_spin_new(i915, .flags = IGT_SPIN_FENCE_OUT); + + sendfd(sv[0], spin->out_fence); + + igt_list_del(&spin->link); /* prevent autocleanup */ + } + igt_waitchildren(); + + fence = recvfd(sv[1]); + close(sv[0]); + close(sv[1]); + + igt_assert_eq(sync_fence_wait(fence, MSEC_PER_SEC / 5), 0); + igt_assert_eq(sync_fence_status(fence), -EIO); + close(fence); + + gem_quiescent_gpu(i915); +} + +igt_main +{ + int i915; + + igt_fixture { + i915 = drm_open_driver(DRIVER_INTEL); + igt_require_gem(i915); + + igt_require(has_persistence(i915)); + } + + igt_subtest_group { + igt_subtest("idempotent") + test_idempotent(i915); + + igt_subtest("persistence") + test_persistence(i915); + + igt_subtest("cleanup") + test_nonpersistent_cleanup(i915); + + igt_subtest("hostile") + test_nonpersistent_hostile(i915); + + igt_subtest("process") + test_nonpersistent_process(i915); + } + + igt_fixture { + close(i915); + } +} diff --git a/tests/meson.build b/tests/meson.build index 34a74025a..d79e0c977 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -118,6 +118,7 @@ i915_progs = [ 'gem_ctx_exec', 'gem_ctx_isolation', 'gem_ctx_param', + 'gem_ctx_persistence', 'gem_ctx_shared', 'gem_ctx_switch', 'gem_ctx_thrash',