Re: [PATCH v3 1/8] drm/amd/display: Introduce KUnit tests for fixed31_32 library

From: Magali Lemes
Date: Wed Oct 19 2022 - 09:13:04 EST


Em sex., 30 de set. de 2022 às 11:14, Harry Wentland
<hwentlan@xxxxxxx> escreveu:
>
>
>
> On 9/12/22 11:59, Maíra Canal wrote:
> > From: Tales Aparecida <tales.aparecida@xxxxxxxxx>
> >
> > The fixed31_32 library performs a lot of the mathematical operations
> > involving fixed-point arithmetic and the conversion of integers to
> > fixed-point representation.
> >
> > This unit tests intend to assure the proper functioning of the basic
> > mathematical operations of fixed-point arithmetic, such as
> > multiplication, conversion from fractional to fixed-point number,
> > and more. Use kunit_tool to run:
> >
> > $ ./tools/testing/kunit/kunit.py run --arch=x86_64 \
> > --kunitconfig=drivers/gpu/drm/amd/display/tests/
> >
> > Reviewed-by: David Gow <davidgow@xxxxxxxxxx>
> > Signed-off-by: Tales Aparecida <tales.aparecida@xxxxxxxxx>
> > Signed-off-by: Maíra Canal <mairacanal@xxxxxxxxxx>
> > ---
> > drivers/gpu/drm/amd/display/Kconfig | 13 +
> > drivers/gpu/drm/amd/display/Makefile | 2 +-
> > .../gpu/drm/amd/display/tests/.kunitconfig | 6 +
> > drivers/gpu/drm/amd/display/tests/Makefile | 12 +
> > .../display/tests/dc/basics/fixpt31_32_test.c | 232 ++++++++++++++++++
> > 5 files changed, 264 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/gpu/drm/amd/display/tests/.kunitconfig
> > create mode 100644 drivers/gpu/drm/amd/display/tests/Makefile
> > create mode 100644 drivers/gpu/drm/amd/display/tests/dc/basics/fixpt31_32_test.c
> >
> > diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
> > index 96cbc87f7b6b..cc44cfe88607 100644
> > --- a/drivers/gpu/drm/amd/display/Kconfig
> > +++ b/drivers/gpu/drm/amd/display/Kconfig
> > @@ -55,4 +55,17 @@ config DRM_AMD_SECURE_DISPLAY
> > Cooperate with specific DMCU FW.
> >
> >
> > +config AMD_DC_BASICS_KUNIT_TEST
>
> I would prefer if we kept the same prefix as for other
> configs in the file: "DRM_AMD_DC". Maybe name all the
> KUNIT configs here "DRM_AMD_DC_KUNIT_XYZ".
>
>
> > + bool "Enable KUnit tests for the 'basics' sub-component of DAL" if !KUNIT_ALL_TESTS
> > + depends on DRM_AMD_DC && KUNIT
> > + default KUNIT_ALL_TESTS
> > + help
> > + Enables unit tests for the Display Core. Only useful for kernel
> > + devs running KUnit.
> > +
> > + For more information on KUnit and unit tests in general please refer to
> > + the KUnit documentation in Documentation/dev-tools/kunit/.
> > +
> > + If unsure, say N.
> > +
> > endmenu
> > diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile
> > index 2633de77de5e..0f329aab13f0 100644
> > --- a/drivers/gpu/drm/amd/display/Makefile
> > +++ b/drivers/gpu/drm/amd/display/Makefile
> > @@ -43,7 +43,7 @@ endif
> > #TODO: remove when Timing Sync feature is complete
> > subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0
> >
> > -DAL_LIBS = amdgpu_dm dc modules/freesync modules/color modules/info_packet modules/power dmub/src
> > +DAL_LIBS = amdgpu_dm dc modules/freesync modules/color modules/info_packet modules/power dmub/src tests
>
> Can we put these tests into a 'kunit' directory instead of 'tests'?
> We use the codebase on other platforms and 'tests' might be
> confusing to some AMD-internal developers, whereas 'kunit' is
> explicit and will ensure people understand where these are coming
> from and how to use them.
>
> Other than the CONFIG and directory naming these tests look really
> nice. Thanks for your contribution.
>
> Harry
>

Hi, Harry.
Thank you for your feedback and comments. We'll change the directory
and config entries' names in a new version.

Magali

> >
> > ifdef CONFIG_DRM_AMD_DC_HDCP
> > DAL_LIBS += modules/hdcp
> > diff --git a/drivers/gpu/drm/amd/display/tests/.kunitconfig b/drivers/gpu/drm/amd/display/tests/.kunitconfig
> > new file mode 100644
> > index 000000000000..60f2ff8158f5
> > --- /dev/null
> > +++ b/drivers/gpu/drm/amd/display/tests/.kunitconfig
> > @@ -0,0 +1,6 @@
> > +CONFIG_KUNIT=y
> > +CONFIG_PCI=y
> > +CONFIG_DRM=y
> > +CONFIG_DRM_AMDGPU=y
> > +CONFIG_DRM_AMD_DC=y
> > +CONFIG_AMD_DC_BASICS_KUNIT_TEST=y
> > \ No newline at end of file
> > diff --git a/drivers/gpu/drm/amd/display/tests/Makefile b/drivers/gpu/drm/amd/display/tests/Makefile
> > new file mode 100644
> > index 000000000000..ef16497318e8
> > --- /dev/null
> > +++ b/drivers/gpu/drm/amd/display/tests/Makefile
> > @@ -0,0 +1,12 @@
> > +# SPDX-License-Identifier: MIT
> > +#
> > +# Makefile for the KUnit Tests for DC
> > +#
> > +
> > +ifdef CONFIG_AMD_DC_BASICS_KUNIT_TEST
> > + DC_TESTS += dc/basics/fixpt31_32_test.o
> > +endif
> > +
> > +AMD_DAL_DC_TESTS = $(addprefix $(AMDDALPATH)/tests/,$(DC_TESTS))
> > +
> > +AMD_DISPLAY_FILES += $(AMD_DAL_DC_TESTS)
> > diff --git a/drivers/gpu/drm/amd/display/tests/dc/basics/fixpt31_32_test.c b/drivers/gpu/drm/amd/display/tests/dc/basics/fixpt31_32_test.c
> > new file mode 100644
> > index 000000000000..2fc489203499
> > --- /dev/null
> > +++ b/drivers/gpu/drm/amd/display/tests/dc/basics/fixpt31_32_test.c
> > @@ -0,0 +1,232 @@
> > +// SPDX-License-Identifier: MIT
> > +/* Unit tests for display/include/fixed31_32.h and dc/basics/fixpt31_32.c
> > + *
> > + * Copyright (C) 2022, Tales Aparecida <tales.aparecida@xxxxxxxxx>
> > + */
> > +
> > +#include <kunit/test.h>
> > +#include "os_types.h"
> > +#include "fixed31_32.h"
> > +
> > +static const struct fixed31_32 dc_fixpt_minus_one = { -0x100000000LL };
> > +
> > +/**
> > + * dc_fixpt_from_int_test - KUnit test for dc_fixpt_from_int
> > + * @test: represents a running instance of a test.
> > + */
> > +static void dc_fixpt_from_int_test(struct kunit *test)
> > +{
> > + struct fixed31_32 res;
> > +
> > + res = dc_fixpt_from_int(0);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_zero.value);
> > +
> > + res = dc_fixpt_from_int(1);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_int(-1);
> > + KUNIT_EXPECT_EQ(test, res.value, -dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_int(INT_MAX);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x7FFFFFFF00000000LL);
> > +
> > + res = dc_fixpt_from_int(INT_MIN);
> > + KUNIT_EXPECT_EQ(test, res.value,
> > + 0x8000000000000000LL); /* implicit negative signal */
> > +}
> > +
> > +/**
> > + * dc_fixpt_from_fraction_test - KUnit test for dc_fixpt_from_fraction
> > + * @test: represents a running instance of a test.
> > + */
> > +static void dc_fixpt_from_fraction_test(struct kunit *test)
> > +{
> > + struct fixed31_32 res;
> > +
> > + /* Assert signal works as expected */
> > + res = dc_fixpt_from_fraction(1LL, 1LL);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_fraction(-1LL, 1LL);
> > + KUNIT_EXPECT_EQ(test, res.value, -dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_fraction(1LL, -1LL);
> > + KUNIT_EXPECT_EQ(test, res.value, -dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_fraction(-1LL, -1LL);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + /* Assert that the greatest parameter values works as expected */
> > + res = dc_fixpt_from_fraction(LLONG_MAX, LLONG_MAX);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_fraction(LLONG_MIN, LLONG_MIN);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + /* Edge case using the smallest fraction possible without LSB rounding */
> > + res = dc_fixpt_from_fraction(1, 1LL << (FIXED31_32_BITS_PER_FRACTIONAL_PART));
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_epsilon.value);
> > +
> > + /* Edge case using the smallest fraction possible with LSB rounding */
> > + res = dc_fixpt_from_fraction(1, 1LL << (FIXED31_32_BITS_PER_FRACTIONAL_PART + 1));
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_epsilon.value);
> > +
> > + /* Assert an nil numerator is a valid input */
> > + res = dc_fixpt_from_fraction(0LL, LLONG_MAX);
> > + KUNIT_EXPECT_EQ(test, res.value, 0LL);
> > +
> > + /* Edge case using every bit of the decimal part without rounding */
> > + res = dc_fixpt_from_fraction(8589934590LL, 8589934592LL);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x0FFFFFFFFLL);
> > +
> > + res = dc_fixpt_from_fraction(-8589934590LL, 8589934592LL);
> > + KUNIT_EXPECT_EQ(test, res.value, -0x0FFFFFFFFLL);
> > +
> > + /* Edge case using every bit of the decimal part then rounding LSB */
> > + res = dc_fixpt_from_fraction(8589934591LL, 8589934592LL);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_from_fraction(-8589934591LL, 8589934592LL);
> > + KUNIT_EXPECT_EQ(test, res.value, -dc_fixpt_one.value);
> > + /* A repeating decimal in binary representation that doesn't round up the LSB */
> > + res = dc_fixpt_from_fraction(4, 3);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x0000000155555555LL);
> > +
> > + res = dc_fixpt_from_fraction(-4, 3);
> > + KUNIT_EXPECT_EQ(test, res.value, -0x0000000155555555LL);
> > +
> > + /* A repeating decimal in binary representation that rounds up the LSB */
> > + res = dc_fixpt_from_fraction(5, 3);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x00000001AAAAAAABLL);
> > +
> > + res = dc_fixpt_from_fraction(-5, 3);
> > + KUNIT_EXPECT_EQ(test, res.value, -0x00000001AAAAAAABLL);
> > +}
> > +
> > +/**
> > + * dc_fixpt_mul_test - KUnit test for dc_fixpt_mul
> > + * @test: represents a running instance of a test.
> > + */
> > +static void dc_fixpt_mul_test(struct kunit *test)
> > +{
> > + struct fixed31_32 res;
> > + struct fixed31_32 arg;
> > +
> > + /* Assert signal works as expected */
> > + res = dc_fixpt_mul(dc_fixpt_one, dc_fixpt_one);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + res = dc_fixpt_mul(dc_fixpt_minus_one, dc_fixpt_one);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_minus_one.value);
> > +
> > + res = dc_fixpt_mul(dc_fixpt_one, dc_fixpt_minus_one);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_minus_one.value);
> > +
> > + res = dc_fixpt_mul(dc_fixpt_minus_one, dc_fixpt_minus_one);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + /* Assert that the greatest parameter values works as expected */
> > + arg.value = LONG_MAX;
> > + res = dc_fixpt_mul(arg, dc_fixpt_one);
> > + KUNIT_EXPECT_EQ(test, res.value, arg.value);
> > +
> > + arg.value = LONG_MIN;
> > + res = dc_fixpt_mul(arg, dc_fixpt_one);
> > + KUNIT_EXPECT_EQ(test, res.value, arg.value);
> > +
> > + arg.value = LONG_MAX;
> > + res = dc_fixpt_mul(dc_fixpt_one, arg);
> > + KUNIT_EXPECT_EQ(test, res.value, arg.value);
> > +
> > + arg.value = LONG_MIN;
> > + res = dc_fixpt_mul(dc_fixpt_one, arg);
> > + KUNIT_EXPECT_EQ(test, res.value, arg.value);
> > +
> > + /* Assert it doesn't round LSB as expected */
> > + arg.value = 0x7FFFFFFF7fffffffLL;
> > + res = dc_fixpt_mul(arg, dc_fixpt_epsilon);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x000000007FFFFFFF);
> > +
> > + /* Assert it rounds LSB as expected */
> > + arg.value = 0x7FFFFFFF80000000LL;
> > + res = dc_fixpt_mul(arg, dc_fixpt_epsilon);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x0000000080000000);
> > +}
> > +
> > +/**
> > + * dc_fixpt_sqr_test - KUnit test for dc_fixpt_sqr
> > + * @test: represents a running instance of a test.
> > + */
> > +static void dc_fixpt_sqr_test(struct kunit *test)
> > +{
> > + struct fixed31_32 res;
> > + struct fixed31_32 arg;
> > +
> > + arg.value = dc_fixpt_one.value;
> > + res = dc_fixpt_sqr(arg);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + arg.value = dc_fixpt_minus_one.value;
> > + res = dc_fixpt_sqr(arg);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + arg.value = 0;
> > + res = dc_fixpt_sqr(arg);
> > + KUNIT_EXPECT_EQ(test, res.value, 0);
> > +
> > + /* Test some recognizable values */
> > + arg = dc_fixpt_from_int(100);
> > + res = dc_fixpt_sqr(arg);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_from_int(10000).value);
> > +
> > + arg = dc_fixpt_from_fraction(1, 100);
> > + res = dc_fixpt_sqr(arg);
> > + KUNIT_EXPECT_EQ(test, res.value,
> > + dc_fixpt_from_fraction(1, 10000).value);
> > +
> > + /* LSB rounding */
> > + arg = dc_fixpt_from_fraction(3, 2);
> > + res = dc_fixpt_sqr(arg);
> > + KUNIT_EXPECT_EQ(test, res.value,
> > + dc_fixpt_from_fraction(9, 4).value + 1LL);
> > +}
> > +
> > +/**
> > + * dc_fixpt_recip_test - KUnit test for dc_fixpt_recip
> > + * @test: represents a running instance of a test.
> > + */
> > +static void dc_fixpt_recip_test(struct kunit *test)
> > +{
> > + struct fixed31_32 res;
> > + struct fixed31_32 arg;
> > +
> > + /* Assert 1/1 works as expected */
> > + res = dc_fixpt_recip(dc_fixpt_one);
> > + KUNIT_EXPECT_EQ(test, res.value, dc_fixpt_one.value);
> > +
> > + /* Assert smallest parameters work as expected. */
> > + arg.value = 3LL;
> > + res = dc_fixpt_recip(arg);
> > + KUNIT_EXPECT_EQ(test, res.value, 0x5555555555555555LL);
> > +
> > + arg.value = -3LL;
> > + res = dc_fixpt_recip(arg);
> > + KUNIT_EXPECT_EQ(test, res.value, -0x5555555555555555LL);
> > +}
> > +
> > +static struct kunit_case dc_basics_fixpt31_32_test_cases[] = {
> > + KUNIT_CASE(dc_fixpt_from_int_test),
> > + KUNIT_CASE(dc_fixpt_from_fraction_test),
> > + KUNIT_CASE(dc_fixpt_mul_test),
> > + KUNIT_CASE(dc_fixpt_sqr_test),
> > + KUNIT_CASE(dc_fixpt_recip_test),
> > + {}
> > +};
> > +
> > +static struct kunit_suite dc_basics_fixpt31_32_test_suite = {
> > + .name = "dc_basics_fixpt31_32",
> > + .test_cases = dc_basics_fixpt31_32_test_cases,
> > +};
> > +
> > +kunit_test_suites(&dc_basics_fixpt31_32_test_suite);
> > +