Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Brost <matthew.brost@intel.com>
To: Michal Wajdeczko <michal.wajdeczko@intel.com>
Cc: <intel-xe@lists.freedesktop.org>
Subject: Re: [PATCH 13/13] drm/xe/kunit: Add KUnit tests for GuC Buffer Cache
Date: Wed, 11 Dec 2024 19:36:23 -0800	[thread overview]
Message-ID: <Z1paN30DT2nu4glj@lstrano-desk.jf.intel.com> (raw)
In-Reply-To: <20241212010141.389-14-michal.wajdeczko@intel.com>

On Thu, Dec 12, 2024 at 02:01:41AM +0100, Michal Wajdeczko wrote:
> Add tests to make sure that recently added GuC Buffer Cache
> component is working as expected.
> 

My opinion is this selftest is a bit overkill, maybe other disagree, but
I'd drop this as it quite a bit of code to carry for little ROI (i.e. if
drm_suballoc is broken, the entire DRM subsystem is likely broken).

Matt

> Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
> ---
> v2: rebased (Michal)
> ---
>  drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c | 335 ++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_guc_buf.c             |   4 +
>  2 files changed, 339 insertions(+)
>  create mode 100644 drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c
> 
> diff --git a/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c b/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c
> new file mode 100644
> index 000000000000..8a90f832915b
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c
> @@ -0,0 +1,335 @@
> +// SPDX-License-Identifier: GPL-2.0 AND MIT
> +/*
> + * Copyright © 2024 Intel Corporation
> + */
> +
> +#include <kunit/static_stub.h>
> +#include <kunit/test.h>
> +#include <kunit/test-bug.h>
> +
> +#include "xe_device.h"
> +#include "xe_ggtt.h"
> +#include "xe_guc_ct.h"
> +#include "xe_kunit_helpers.h"
> +#include "xe_pci_test.h"
> +
> +#define DUT_GGTT_START		SZ_1M
> +#define DUT_GGTT_SIZE		SZ_2M
> +#define DUT_DATA		1
> +
> +static struct xe_bo *replacement_xe_managed_bo_create_pin_map(struct xe_device *xe,
> +							      struct xe_tile *tile,
> +							      size_t size, u32 flags)
> +{
> +	struct kunit *test = kunit_get_current_test();
> +	struct xe_bo *bo;
> +	void *buf;
> +
> +	bo = drmm_kzalloc(&xe->drm, sizeof(*bo), GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo);
> +
> +	buf = drmm_kzalloc(&xe->drm, size, GFP_KERNEL);
> +	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
> +
> +	bo->tile = tile;
> +	bo->ttm.bdev = &xe->ttm;
> +	bo->size = size;
> +	iosys_map_set_vaddr(&bo->vmap, buf);
> +
> +	if (flags & XE_BO_FLAG_GGTT) {
> +		struct xe_ggtt *ggtt = tile->mem.ggtt;
> +
> +		bo->ggtt_node[tile->id] = xe_ggtt_node_init(ggtt);
> +		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo->ggtt_node[tile->id]);
> +
> +		KUNIT_ASSERT_EQ(test, 0,
> +				drm_mm_insert_node_in_range(&ggtt->mm,
> +							    &bo->ggtt_node[tile->id]->base,
> +							    bo->size, SZ_4K,
> +							    0, 0, U64_MAX, 0));
> +	}
> +
> +	return bo;
> +}
> +
> +static int guc_buf_test_init(struct kunit *test)
> +{
> +	struct xe_pci_fake_data fake = {
> +		.sriov_mode = XE_SRIOV_MODE_PF,
> +		.platform = XE_TIGERLAKE, /* some random platform */
> +		.subplatform = XE_SUBPLATFORM_NONE,
> +	};
> +	struct xe_ggtt *ggtt;
> +	struct xe_guc *guc;
> +
> +	test->priv = &fake;
> +	xe_kunit_helper_xe_device_test_init(test);
> +
> +	ggtt = xe_device_get_root_tile(test->priv)->mem.ggtt;
> +	guc = &xe_device_get_gt(test->priv, 0)->uc.guc;
> +
> +	drm_mm_init(&ggtt->mm, DUT_GGTT_START, DUT_GGTT_SIZE);
> +	mutex_init(&ggtt->lock);
> +
> +	kunit_activate_static_stub(test, xe_managed_bo_create_pin_map,
> +				   replacement_xe_managed_bo_create_pin_map);
> +
> +	KUNIT_ASSERT_EQ(test, 0, xe_guc_buf_cache_init(&guc->buf));
> +
> +	test->priv = &guc->buf;
> +	return 0;
> +}
> +
> +static void test_smallest(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf buf;
> +
> +	buf = xe_guc_buf_reserve(cache, 1);
> +	KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +	KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
> +	KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
> +	KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
> +	KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
> +	xe_guc_buf_release(buf);
> +}
> +
> +static void test_largest(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf buf;
> +
> +	buf = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache));
> +	KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +	KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
> +	KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
> +	KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
> +	KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
> +	xe_guc_buf_release(buf);
> +}
> +
> +static void test_granular(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf *bufs;
> +	int n, dwords;
> +
> +	dwords = xe_guc_buf_cache_dwords(cache);
> +	bufs = kunit_kcalloc(test, dwords, sizeof(*bufs), GFP_KERNEL);
> +	KUNIT_EXPECT_NOT_NULL(test, bufs);
> +
> +	for (n = 0; n < dwords; n++)
> +		bufs[n] = xe_guc_buf_reserve(cache, 1);
> +
> +	for (n = 0; n < dwords; n++)
> +		KUNIT_EXPECT_TRUE_MSG(test, xe_guc_buf_is_valid(bufs[n]), "n=%d", n);
> +
> +	for (n = 0; n < dwords; n++)
> +		xe_guc_buf_release(bufs[n]);
> +}
> +
> +static void test_unique(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf *bufs;
> +	int n, m, dwords;
> +
> +	dwords = xe_guc_buf_cache_dwords(cache);
> +	bufs = kunit_kcalloc(test, dwords, sizeof(*bufs), GFP_KERNEL);
> +	KUNIT_EXPECT_NOT_NULL(test, bufs);
> +
> +	for (n = 0; n < dwords; n++)
> +		bufs[n] = xe_guc_buf_reserve(cache, 1);
> +
> +	for (n = 0; n < dwords; n++) {
> +		for (m = n + 1; m < dwords; m++) {
> +			KUNIT_EXPECT_PTR_NE_MSG(test, xe_guc_buf_cpu_ptr(bufs[n]),
> +						xe_guc_buf_cpu_ptr(bufs[m]), "n=%d, m=%d", n, m);
> +			KUNIT_ASSERT_NE_MSG(test, xe_guc_buf_gpu_addr(bufs[n]),
> +					    xe_guc_buf_gpu_addr(bufs[m]), "n=%d, m=%d", n, m);
> +		}
> +	}
> +
> +	for (n = 0; n < dwords; n++)
> +		xe_guc_buf_release(bufs[n]);
> +}
> +
> +static void test_overlap(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf b1, b2;
> +	u32 dwords = xe_guc_buf_cache_dwords(cache) / 2;
> +	u32 bytes = dwords * sizeof(u32);
> +	void *p1, *p2;
> +	u64 a1, a2;
> +
> +	b1 = xe_guc_buf_reserve(cache, dwords);
> +	b2 = xe_guc_buf_reserve(cache, dwords);
> +
> +	p1 = xe_guc_buf_cpu_ptr(b1);
> +	p2 = xe_guc_buf_cpu_ptr(b2);
> +
> +	a1 = xe_guc_buf_gpu_addr(b1);
> +	a2 = xe_guc_buf_gpu_addr(b2);
> +
> +	KUNIT_EXPECT_PTR_NE(test, p1, p2);
> +	if (p1 < p2)
> +		KUNIT_EXPECT_LT(test, (uintptr_t)(p1 + bytes - 1), (uintptr_t)p2);
> +	else
> +		KUNIT_EXPECT_LT(test, (uintptr_t)(p2 + bytes - 1), (uintptr_t)p1);
> +
> +	KUNIT_EXPECT_NE(test, a1, a2);
> +	if (a1 < a2)
> +		KUNIT_EXPECT_LT(test, a1 + bytes - 1, a2);
> +	else
> +		KUNIT_EXPECT_LT(test, a2 + bytes - 1, a1);
> +
> +	xe_guc_buf_release(b1);
> +	xe_guc_buf_release(b2);
> +}
> +
> +static void test_reusable(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf b1, b2;
> +	void *p1;
> +	u64 a1;
> +
> +	b1 = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache));
> +	KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(b1));
> +	KUNIT_EXPECT_NOT_NULL(test, p1 = xe_guc_buf_cpu_ptr(b1));
> +	KUNIT_EXPECT_NE(test, 0, a1 = xe_guc_buf_gpu_addr(b1));
> +	xe_guc_buf_release(b1);
> +
> +	b2 = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache));
> +	KUNIT_EXPECT_PTR_EQ(test, p1, xe_guc_buf_cpu_ptr(b2));
> +	KUNIT_EXPECT_EQ(test, a1, xe_guc_buf_gpu_addr(b2));
> +	xe_guc_buf_release(b2);
> +}
> +
> +static void test_too_big(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf buf;
> +
> +	buf = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache) + 1);
> +	KUNIT_EXPECT_FALSE(test, xe_guc_buf_is_valid(buf));
> +	xe_guc_buf_release(buf); /* shouldn't crash */
> +}
> +
> +static void test_flush(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf buf;
> +	const u32 dwords = xe_guc_buf_cache_dwords(cache);
> +	const u32 bytes = dwords * sizeof(u32);
> +	u32 *s, *p, *d;
> +	int n;
> +
> +	KUNIT_ASSERT_NOT_NULL(test, s = kunit_kcalloc(test, dwords, sizeof(u32), GFP_KERNEL));
> +	KUNIT_ASSERT_NOT_NULL(test, d = kunit_kcalloc(test, dwords, sizeof(u32), GFP_KERNEL));
> +
> +	for (n = 0; n < dwords; n++)
> +		s[n] = n;
> +
> +	buf = xe_guc_buf_reserve(cache, dwords);
> +	KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +	KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf));
> +	KUNIT_EXPECT_PTR_NE(test, p, s);
> +	KUNIT_EXPECT_PTR_NE(test, p, d);
> +
> +	memcpy(p, s, bytes);
> +	KUNIT_EXPECT_NE(test, 0, xe_guc_buf_flush(buf));
> +
> +	iosys_map_memcpy_from(d, &cache->sam->bo->vmap, 0, bytes);
> +	KUNIT_EXPECT_MEMEQ(test, s, d, bytes);
> +
> +	xe_guc_buf_release(buf);
> +}
> +
> +static void test_lookup(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf buf;
> +	u32 dwords;
> +	u64 addr;
> +	u32 *p;
> +	int n;
> +
> +	dwords = xe_guc_buf_cache_dwords(cache);
> +	buf = xe_guc_buf_reserve(cache, dwords);
> +	KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +	KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf));
> +	KUNIT_ASSERT_NE(test, 0, addr = xe_guc_buf_gpu_addr(buf));
> +
> +	KUNIT_EXPECT_EQ(test, 0, xe_guc_cache_gpu_addr_from_ptr(cache, p - 1, sizeof(u32)));
> +	KUNIT_EXPECT_EQ(test, 0, xe_guc_cache_gpu_addr_from_ptr(cache, p + dwords, sizeof(u32)));
> +
> +	for (n = 0; n < dwords; n++)
> +		KUNIT_EXPECT_EQ_MSG(test, xe_guc_cache_gpu_addr_from_ptr(cache, p + n, sizeof(u32)),
> +				    addr + n * sizeof(u32), "n=%d", n);
> +
> +	xe_guc_buf_release(buf);
> +}
> +
> +static void test_data(struct kunit *test)
> +{
> +	static const u32 data[] = { 1, 2, 3, 4, 5, 6 };
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	struct xe_guc_buf buf;
> +	void *p;
> +
> +	buf = xe_guc_buf_from_data(cache, data, sizeof(data));
> +	KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +	KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf));
> +	KUNIT_EXPECT_MEMEQ(test, p, data, sizeof(data));
> +
> +	xe_guc_buf_release(buf);
> +}
> +
> +static void test_class(struct kunit *test)
> +{
> +	struct xe_guc_buf_cache *cache = test->priv;
> +	u32 dwords = xe_guc_buf_cache_dwords(cache);
> +
> +	{
> +		CLASS(xe_guc_buf, buf)(cache, dwords);
> +		KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +		KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
> +		KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
> +		KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
> +		KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
> +	}
> +
> +	{
> +		CLASS(xe_guc_buf, buf)(cache, dwords);
> +		KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
> +		KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
> +		KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
> +		KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
> +		KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
> +	}
> +}
> +
> +static struct kunit_case guc_buf_test_cases[] = {
> +	KUNIT_CASE(test_smallest),
> +	KUNIT_CASE(test_largest),
> +	KUNIT_CASE(test_granular),
> +	KUNIT_CASE(test_unique),
> +	KUNIT_CASE(test_overlap),
> +	KUNIT_CASE(test_reusable),
> +	KUNIT_CASE(test_too_big),
> +	KUNIT_CASE(test_flush),
> +	KUNIT_CASE(test_lookup),
> +	KUNIT_CASE(test_data),
> +	KUNIT_CASE(test_class),
> +	{}
> +};
> +
> +static struct kunit_suite guc_buf_suite = {
> +	.name = "guc_buf",
> +	.test_cases = guc_buf_test_cases,
> +	.init = guc_buf_test_init,
> +};
> +
> +kunit_test_suites(&guc_buf_suite);
> diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c
> index 261c7c74417f..ce6d9830e13b 100644
> --- a/drivers/gpu/drm/xe/xe_guc_buf.c
> +++ b/drivers/gpu/drm/xe/xe_guc_buf.c
> @@ -170,3 +170,7 @@ u64 xe_guc_cache_gpu_addr_from_ptr(struct xe_guc_buf_cache *cache, const void *p
>  
>  	return cache->sam->gpu_addr + offset;
>  }
> +
> +#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST)
> +#include "tests/xe_guc_buf_kunit.c"
> +#endif
> -- 
> 2.47.1
> 

  reply	other threads:[~2024-12-12  3:35 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-12  1:01 [PATCH 00/13] The xe_sa_manager based GuC Buffer Cache Michal Wajdeczko
2024-12-12  1:01 ` [PATCH 01/13] drm/xe/sa: Always call drm_suballoc_manager_fini() Michal Wajdeczko
2024-12-12  3:03   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 02/13] drm/xe/sa: Drop redundant NULL assignments Michal Wajdeczko
2024-12-12  3:03   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 03/13] drm/xe/sa: Cleanup internal BO data at device removal Michal Wajdeczko
2024-12-12  3:07   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 04/13] drm/xe/sa: Drop useless is_iomem member Michal Wajdeczko
2024-12-12  3:09   ` Matthew Brost
2024-12-18 20:53     ` Michal Wajdeczko
2024-12-12  1:01 ` [PATCH 05/13] drm/xe/sa: Improve error message on init failure Michal Wajdeczko
2024-12-12  3:10   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 06/13] drm/xe/sa: Tidy up coding style in init() Michal Wajdeczko
2024-12-12  3:11   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 07/13] drm/xe/sa: Allow making suballocations using custom gfp flags Michal Wajdeczko
2024-12-12  3:12   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 08/13] drm/xe/sa: Allow creating suballocator with custom guard size Michal Wajdeczko
2024-12-12  3:23   ` Matthew Brost
2024-12-12 21:57     ` Michal Wajdeczko
2024-12-12 22:48       ` Matthew Brost
2024-12-12  1:01 ` [PATCH 09/13] drm/xe/sa: Minor header cleanups Michal Wajdeczko
2024-12-12  3:14   ` Matthew Brost
2024-12-12  1:01 ` [PATCH 10/13] drm/xe/guc: Introduce the GuC Buffer Cache Michal Wajdeczko
2024-12-12  3:30   ` Matthew Brost
2024-12-12 21:48     ` Michal Wajdeczko
2024-12-13 18:38       ` Matthew Brost
2024-12-13 20:13         ` Rodrigo Vivi
2024-12-18 21:03           ` Michal Wajdeczko
2024-12-19 20:28             ` Rodrigo Vivi
2024-12-12  1:01 ` [PATCH 11/13] drm/xe/pf: Use GuC Buffer Cache during VFs provisioning Michal Wajdeczko
2024-12-12  3:34   ` Matthew Brost
2024-12-12 22:02     ` Michal Wajdeczko
2024-12-12  1:01 ` [PATCH 12/13] drm/xe/kunit: Allow to replace xe_managed_bo_create_pin_map() Michal Wajdeczko
2024-12-12  1:01 ` [PATCH 13/13] drm/xe/kunit: Add KUnit tests for GuC Buffer Cache Michal Wajdeczko
2024-12-12  3:36   ` Matthew Brost [this message]
2024-12-18 21:06     ` Michal Wajdeczko
2024-12-12  2:20 ` ✓ CI.Patch_applied: success for The xe_sa_manager based " Patchwork
2024-12-12  2:20 ` ✗ CI.checkpatch: warning " Patchwork
2024-12-12  2:21 ` ✓ CI.KUnit: success " Patchwork
2024-12-12  2:41 ` ✓ CI.Build: " Patchwork
2024-12-12  2:45 ` ✓ CI.Hooks: " Patchwork
2024-12-12  2:48 ` ✓ CI.checksparse: " Patchwork
2024-12-12  3:14 ` ✗ Xe.CI.BAT: failure " Patchwork
2024-12-12  8:50 ` ✗ Xe.CI.Full: " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Z1paN30DT2nu4glj@lstrano-desk.jf.intel.com \
    --to=matthew.brost@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=michal.wajdeczko@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox