[RFC 3/3] drm/amd/display: Introduce KUnit tests to the bw_fixed library
Maíra Canal
maira.canal at usp.br
Wed Jun 8 01:07:11 UTC 2022
From: Magali Lemes <magalilemes00 at gmail.com>
The bw_fixed library performs a lot of the mathematical operations
involving fixed-point arithmetic and the conversion of integers to
fixed-point representation.
As fixed-point representation is the base foundation of the DML calcs
operations, 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.
Co-developed-by: Tales Aparecida <tales.aparecida at gmail.com>
Signed-off-by: Tales Aparecida <tales.aparecida at gmail.com>
Signed-off-by: Magali Lemes <magalilemes00 at gmail.com>
Co-developed-by: Maíra Canal <maira.canal at usp.br>
Signed-off-by: Maíra Canal <maira.canal at usp.br>
---
.../drm/amd/display/amdgpu_dm/tests/Kconfig | 12 +
.../drm/amd/display/amdgpu_dm/tests/Makefile | 4 +
.../amdgpu_dm/tests/calcs/bw_fixed_test.c | 322 ++++++++++++++++++
.../amd/display/amdgpu_dm/tests/dml_test.c | 3 +
.../amd/display/amdgpu_dm/tests/dml_test.h | 8 +
5 files changed, 349 insertions(+)
create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/calcs/bw_fixed_test.c
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Kconfig b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Kconfig
index bd1d971d4452..540b2f79f971 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Kconfig
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Kconfig
@@ -2,6 +2,18 @@
menu "DML Unit Tests"
depends on DRM_AMD_DC && KUNIT=m
+config BW_FIXED_KUNIT_TEST
+ bool "Enable unit tests for dml/calcs/bw_fixed" if !DML_KUNIT_TEST
+ default y if DML_KUNIT_TEST
+ help
+ Enables unit tests for the dml/calcs/bw_fixed. 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.
+
config DISPLAY_MODE_LIB_KUNIT_TEST
bool "Enable unit tests for dml/display_mode_lib" if !DML_KUNIT_TEST
default y if DML_KUNIT_TEST
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
index 53b38e340564..23109e51cf32 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile
@@ -5,6 +5,10 @@
DML_TESTS = dml_test.o
+ifdef CONFIG_BW_FIXED_KUNIT_TEST
+DML_TESTS += calcs/bw_fixed_test.o
+endif
+
ifdef CONFIG_DISPLAY_MODE_LIB_KUNIT_TEST
DML_TESTS += display_mode_lib_test.o
endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/calcs/bw_fixed_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/calcs/bw_fixed_test.c
new file mode 100644
index 000000000000..344c1517745e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/calcs/bw_fixed_test.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: MIT
+/*
+ * KUnit tests for dml/calcs/bw_fixed.h
+ *
+ * Copyright (C) 2022, Magali Lemes <magalilemes00 at gmail.com>
+ * Copyright (C) 2022, Maíra Canal <mairacanal at riseup.net>
+ * Copyright (C) 2022, Tales Aparecida <tales.aparecida at gmail.com>
+ */
+
+#include <kunit/test.h>
+#include "../../../dc/inc/bw_fixed.h"
+#include "../dml_test.h"
+
+/**
+ * DOC: Unit tests for AMDGPU DML calcs/bw_fixed.h
+ *
+ * bw_fixed.h performs a lot of the mathematical operations involving
+ * fixed-point arithmetic and the conversion of integers to fixed-point
+ * representation.
+ *
+ * As fixed-point representation is the base foundation of the DML calcs
+ * operations, these 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.
+ *
+ */
+
+static void abs_i64_test(struct kunit *test)
+{
+ KUNIT_EXPECT_EQ(test, 0ULL, abs_i64(0LL));
+
+ /* Argument type limits */
+ KUNIT_EXPECT_EQ(test, (uint64_t)MAX_I64, abs_i64(MAX_I64));
+ KUNIT_EXPECT_EQ(test, (uint64_t)MAX_I64 + 1, abs_i64(MIN_I64));
+}
+
+static void bw_int_to_fixed_nonconst_test(struct kunit *test)
+{
+ struct bw_fixed res;
+
+ /* Add BW_FIXED_BITS_PER_FRACTIONAL_PART trailing 0s to binary number */
+ res = bw_int_to_fixed_nonconst(1000); /* 0x3E8 */
+ KUNIT_EXPECT_EQ(test, 16777216000, res.value); /* 0x3E8000000 */
+
+ res = bw_int_to_fixed_nonconst(-1000); /* -0x3E8 */
+ KUNIT_EXPECT_EQ(test, -16777216000, res.value); /* -0x3E8000000 */
+
+ res = bw_int_to_fixed_nonconst(0LL);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+
+ /**
+ * Test corner cases, as the function's argument has to be an int64_t
+ * between BW_FIXED_MIN_I32 and BW_FIXED_MAX_I32.
+ */
+ res = bw_int_to_fixed_nonconst(BW_FIXED_MAX_I32 - 1); /* 0x7FFFFFFFFE */
+ KUNIT_EXPECT_EQ(test, 9223372036821221376, res.value); /* 0x7FFFFFFFFE000000 */
+
+ res = bw_int_to_fixed_nonconst(BW_FIXED_MIN_I32 + 1); /* -0x7FFFFFFFFF */
+ KUNIT_EXPECT_EQ(test, -9223372036837998592, res.value); /* -0x7FFFFFFFFF000000 */
+}
+
+static void bw_frc_to_fixed_test(struct kunit *test)
+{
+ struct bw_fixed res;
+
+ /* Extreme scenarios */
+
+ /* A fraction of N/N should result in "1.0" */
+ res = bw_frc_to_fixed(MAX_I64, MAX_I64);
+ KUNIT_EXPECT_EQ(test, 1LL << BW_FIXED_BITS_PER_FRACTIONAL_PART, res.value);
+
+ res = bw_frc_to_fixed(1, MAX_I64);
+ KUNIT_EXPECT_EQ(test, 0LL, res.value);
+
+ res = bw_frc_to_fixed(0, MAX_I64);
+ KUNIT_EXPECT_EQ(test, 0LL, res.value);
+
+ /* Turn a repeating decimal to the fixed-point representation */
+
+ /* A repeating decimal that doesn't round up the LSB */
+ res = bw_frc_to_fixed(4, 3);
+ KUNIT_EXPECT_EQ(test, 22369621LL, res.value); /* 0x1555555 */
+
+ res = bw_frc_to_fixed(-4, 3);
+ KUNIT_EXPECT_EQ(test, -22369621LL, res.value); /* -0x1555555 */
+
+ res = bw_frc_to_fixed(99999997, 100000000);
+ KUNIT_EXPECT_EQ(test, 16777215LL, res.value); /* 0x0FFFFFF */
+
+ /* A repeating decimal that rounds up the MSB */
+ res = bw_frc_to_fixed(5, 3);
+ KUNIT_EXPECT_EQ(test, 27962027LL, res.value); /* 0x1AAAAAB */
+
+ res = bw_frc_to_fixed(-5, 3);
+ KUNIT_EXPECT_EQ(test, -27962027LL, res.value); /* -0x1AAAAAB */
+
+ res = bw_frc_to_fixed(99999998, 100000000);
+ KUNIT_EXPECT_EQ(test, 1LL << BW_FIXED_BITS_PER_FRACTIONAL_PART, res.value);
+
+ /* Turn a terminating decimal to the fixed-point representation */
+ res = bw_frc_to_fixed(62609, 100);
+ KUNIT_EXPECT_EQ(test, 10504047165LL, res.value); /* 0X272170A3D */
+
+ res = bw_frc_to_fixed(-62609, 100);
+ KUNIT_EXPECT_EQ(test, -10504047165LL, res.value); /* -0X272170A3D */
+}
+
+static void bw_floor2_test(struct kunit *test)
+{
+ struct bw_fixed arg;
+ struct bw_fixed significance;
+ struct bw_fixed res;
+
+ /* Round 10 down to the nearest multiple of 3 */
+ arg.value = 10;
+ significance.value = 3;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 9, res.value);
+
+ /* Round 10 down to the nearest multiple of 5 */
+ arg.value = 10;
+ significance.value = 5;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 10, res.value);
+
+ /* Round 100 down to the nearest multiple of 7 */
+ arg.value = 100;
+ significance.value = 7;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 98, res.value);
+
+ /* Round an integer down to its nearest multiple should return itself */
+ arg.value = MAX_I64;
+ significance.value = MAX_I64;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, MAX_I64, res.value);
+
+ arg.value = MIN_I64;
+ significance.value = MIN_I64;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, MIN_I64, res.value);
+
+ /* Value is a multiple of significance, result should be value */
+ arg.value = MAX_I64;
+ significance.value = MIN_I64 + 1;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, MAX_I64, res.value);
+
+ /* Round 0 down to the nearest multiple of any number should return 0 */
+ arg.value = 0;
+ significance.value = MAX_I64;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+
+ arg.value = 0;
+ significance.value = MIN_I64;
+ res = bw_floor2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+}
+
+static void bw_ceil2_test(struct kunit *test)
+{
+ struct bw_fixed arg;
+ struct bw_fixed significance;
+ struct bw_fixed res;
+
+ /* Round 10 up to the nearest multiple of 3 */
+ arg.value = 10;
+ significance.value = 3;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 12, res.value);
+
+ /* Round 10 up to the nearest multiple of 5 */
+ arg.value = 10;
+ significance.value = 5;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 10, res.value);
+
+ /* Round 100 up to the nearest multiple of 7 */
+ arg.value = 100;
+ significance.value = 7;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 105, res.value);
+
+ /* Round an integer up to its nearest multiple should return itself */
+ arg.value = MAX_I64;
+ significance.value = MAX_I64;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, MAX_I64, res.value);
+
+ arg.value = MIN_I64 + 1;
+ significance.value = MIN_I64 + 1;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, MIN_I64 + 1, res.value);
+
+ /* Value is a multiple of significance, result should be value */
+ arg.value = MAX_I64;
+ significance.value = MIN_I64 + 1;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, MAX_I64, res.value);
+
+ /* Round 0 up to the nearest multiple of any number should return 0 */
+ arg.value = 0;
+ significance.value = MAX_I64;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+
+ arg.value = 0;
+ significance.value = MIN_I64;
+ res = bw_ceil2(arg, significance);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+}
+
+static void bw_mul_test(struct kunit *test)
+{
+ struct bw_fixed arg1;
+ struct bw_fixed arg2;
+ struct bw_fixed res;
+ struct bw_fixed ans;
+
+ /* Extreme scenario */
+ arg1.value = MAX_I64;
+ arg2.value = MIN_I64;
+ res = bw_mul(arg1, arg2);
+ KUNIT_EXPECT_EQ(test, BW_FIXED_MAX_I32 + 1, res.value);
+
+ /* Testing multiplication property: x * 1 = x */
+ arg1.value = 1;
+ arg2.value = MAX_I64;
+ res = bw_mul(arg1, arg2);
+ KUNIT_EXPECT_EQ(test, BW_FIXED_MAX_I32 + 1, res.value);
+
+ arg1.value = 1;
+ arg2.value = MIN_I64;
+ res = bw_mul(arg1, arg2);
+ KUNIT_EXPECT_EQ(test, BW_FIXED_MIN_I32, res.value);
+
+ /* Testing multiplication property: x * 0 = 0 */
+ arg1.value = 0;
+ arg2.value = 0;
+ res = bw_mul(arg1, arg2);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+
+ arg1.value = 0;
+ arg2.value = MAX_I64;
+ res = bw_mul(arg1, arg2);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+
+ arg1.value = 0;
+ arg2.value = MIN_I64;
+ res = bw_mul(arg1, arg2);
+ KUNIT_EXPECT_EQ(test, 0, res.value);
+
+ /* Testing multiplication between integers */
+ res = bw_mul(bw_int_to_fixed(8), bw_int_to_fixed(10));
+ KUNIT_EXPECT_EQ(test, 1342177280LL, res.value); /* 0x50000000 */
+
+ res = bw_mul(bw_int_to_fixed(10), bw_int_to_fixed(5));
+ KUNIT_EXPECT_EQ(test, 838860800LL, res.value); /* 0x32000000 */
+
+ res = bw_mul(bw_int_to_fixed(-10), bw_int_to_fixed(7));
+ KUNIT_EXPECT_EQ(test, -1174405120LL, res.value); /* -0x46000000 */
+
+ /* Testing multiplication between fractions and integers */
+ res = bw_mul(bw_frc_to_fixed(4, 3), bw_int_to_fixed(3));
+ ans = bw_int_to_fixed(4);
+
+ /**
+ * As bw_frc_to_fixed(4, 3) didn't round up the fixed-point representation,
+ * the ans must be subtrated by 1.
+ */
+ KUNIT_EXPECT_EQ(test, ans.value - 1, res.value);
+
+ res = bw_mul(bw_frc_to_fixed(5, 3), bw_int_to_fixed(3));
+ ans = bw_int_to_fixed(5);
+
+ /**
+ * As bw_frc_to_fixed(5, 3) rounds up the fixed-point representation,
+ * the ans must be added by 1.
+ */
+ KUNIT_EXPECT_EQ(test, ans.value + 1, res.value);
+}
+
+static struct kunit_case bw_fixed_test_cases[] = {
+ KUNIT_CASE(abs_i64_test),
+ KUNIT_CASE(bw_int_to_fixed_nonconst_test),
+ KUNIT_CASE(bw_frc_to_fixed_test),
+ KUNIT_CASE(bw_floor2_test),
+ KUNIT_CASE(bw_ceil2_test),
+ KUNIT_CASE(bw_mul_test),
+ { }
+};
+
+static struct kunit_suite bw_fixed_test_suite = {
+ .name = "dml-calcs-bw-fixed",
+ .test_cases = bw_fixed_test_cases,
+};
+
+static struct kunit_suite *bw_fixed_test_suites[] = { &bw_fixed_test_suite, NULL };
+
+int bw_fixed_test_init(void)
+{
+ pr_info("===> Running calcs/bw_fixed KUnit Tests");
+ pr_info("**********************************************************");
+ pr_info("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
+ pr_info("** **");
+ pr_info("** calcs/bw_fixed KUnit Tests are being run. This means **");
+ pr_info("** that this is a TEST kernel and should not be used **");
+ pr_info("** for production. **");
+ pr_info("** **");
+ pr_info("** If you see this message and you are not debugging **");
+ pr_info("** the kernel, report this immediately to your vendor! **");
+ pr_info("** **");
+ pr_info("**********************************************************");
+
+ return __kunit_test_suites_init(bw_fixed_test_suites);
+}
+
+void bw_fixed_test_exit(void)
+{
+ return __kunit_test_suites_exit(bw_fixed_test_suites);
+}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.c
index 9a5d47597c10..98ae4e8cd952 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.c
@@ -13,11 +13,14 @@
*/
int amdgpu_dml_test_init(void)
{
+ bw_fixed_test_init();
display_mode_lib_test_init();
+
return 0;
}
void amdgpu_dml_test_exit(void)
{
display_mode_lib_test_exit();
+ bw_fixed_test_exit();
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.h b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.h
index 2786db9d0e87..d8fe38abd9bc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/dml_test.h
@@ -2,6 +2,14 @@
#ifndef DML_TEST_H_
#define DML_TEST_H_
+#if defined (CONFIG_BW_FIXED_KUNIT_TEST)
+int bw_fixed_test_init(void);
+void bw_fixed_test_exit(void);
+#else
+static inline int bw_fixed_test_init(void) { return 0; }
+static inline void bw_fixed_test_exit(void) { }
+#endif
+
#if defined (CONFIG_DISPLAY_MODE_LIB_KUNIT_TEST)
int display_mode_lib_test_init(void);
void display_mode_lib_test_exit(void);
--
2.36.1
More information about the dri-devel
mailing list