From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH 1/7] app/test/reciprocal_division: make it a fast test
Date: Fri, 29 May 2026 10:10:54 -0700 [thread overview]
Message-ID: <20260529171417.526892-2-stephen@networkplumber.org> (raw)
In-Reply-To: <20260529171417.526892-1-stephen@networkplumber.org>
This test is useful to have in CI, but the iteration values
were too large to make it usable as a fast test.
Redo the test with checks around boundary values and
use unit test framework for sub tests.
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
app/test/test_reciprocal_division.c | 279 ++++++++++++++++------------
1 file changed, 157 insertions(+), 122 deletions(-)
diff --git a/app/test/test_reciprocal_division.c b/app/test/test_reciprocal_division.c
index 3d0736d8dd..80f8561523 100644
--- a/app/test/test_reciprocal_division.c
+++ b/app/test/test_reciprocal_division.c
@@ -5,162 +5,197 @@
#include "test.h"
#include <stdio.h>
-#include <unistd.h>
#include <inttypes.h>
#include <rte_common.h>
-#include <rte_cycles.h>
#include <rte_random.h>
#include <rte_reciprocal.h>
-#define MAX_ITERATIONS (1ULL << 32)
-#define DIVIDE_ITER (100)
+#define MAX_ITERATIONS (1ULL << 20)
+#define DIVISORS_RANDOM 64
static int
-test_reciprocal(void)
+test_u32_divide(uint32_t a, uint32_t d, struct rte_reciprocal r)
{
- int result = 0;
- uint32_t divisor_u32 = 0;
- uint32_t dividend_u32;
- uint32_t nresult_u32;
- uint32_t rresult_u32;
- uint64_t i, j;
- uint64_t divisor_u64 = 0;
- uint64_t dividend_u64;
- uint64_t nresult_u64;
- uint64_t rresult_u64;
- struct rte_reciprocal reci_u32 = {0};
- struct rte_reciprocal_u64 reci_u64 = {0};
-
- printf("Validating unsigned 32bit division.\n");
- for (i = 0; i < MAX_ITERATIONS; i++) {
- /* Change divisor every DIVIDE_ITER iterations. */
- if (i % DIVIDE_ITER == 0) {
- divisor_u32 = rte_rand();
- reci_u32 = rte_reciprocal_value(divisor_u32);
- }
-
- dividend_u32 = rte_rand();
- nresult_u32 = dividend_u32 / divisor_u32;
- rresult_u32 = rte_reciprocal_divide(dividend_u32,
- reci_u32);
- if (nresult_u32 != rresult_u32) {
- printf("Division failed, %"PRIu32"/%"PRIu32" = "
- "expected %"PRIu32" result %"PRIu32"\n",
- dividend_u32, divisor_u32,
- nresult_u32, rresult_u32);
- result = 1;
- break;
- }
- }
+ uint32_t expected = a / d;
+ uint32_t result = rte_reciprocal_divide(a, r);
- printf("Validating unsigned 64bit division.\n");
- for (i = 0; i < MAX_ITERATIONS; i++) {
- /* Change divisor every DIVIDE_ITER iterations. */
- if (i % DIVIDE_ITER == 0) {
- divisor_u64 = rte_rand();
- reci_u64 = rte_reciprocal_value_u64(divisor_u64);
- }
+ TEST_ASSERT_EQUAL(expected, result,
+ "%"PRIu32"/%"PRIu32" expected %"PRIu32" got %"PRIu32,
+ a, d, expected, result);
+ return 0;
+}
- dividend_u64 = rte_rand();
- nresult_u64 = dividend_u64 / divisor_u64;
- rresult_u64 = rte_reciprocal_divide_u64(dividend_u64,
- &reci_u64);
- if (nresult_u64 != rresult_u64) {
- printf("Division failed, %"PRIu64"/%"PRIu64" = "
- "expected %"PRIu64" result %"PRIu64"\n",
- dividend_u64, divisor_u64,
- nresult_u64, rresult_u64);
- result = 1;
- break;
+static int
+test_reciprocal_u32(void)
+{
+ const uint32_t edge_div_u32[] = {
+ 1, 2, 3, 7, 0x7fffffff, 0x80000000, 0xfffffffe, UINT32_MAX,
+ };
+ unsigned int n_div = RTE_DIM(edge_div_u32) + DIVISORS_RANDOM;
+
+ for (unsigned int di = 0; di < n_div; di++) {
+ uint32_t d;
+ if (di < RTE_DIM(edge_div_u32))
+ d = edge_div_u32[di]; /* Make sure and test the edge cases */
+ else
+ d = rte_rand_max(UINT32_MAX - 1) + 1;
+
+ struct rte_reciprocal r = rte_reciprocal_value(d);
+ uint32_t qmax = UINT32_MAX / d; /* largest q with q*d <= UINT32_MAX */
+ if (d != 1)
+ qmax++;
+
+ for (unsigned int k = 0; k < MAX_ITERATIONS; k++) {
+ uint32_t q = rte_rand_max(qmax);
+ uint32_t val = q * d; /* fits in u32 */
+
+ /* Check around the value.
+ * Under and overflow of 32 bit value are fine here.
+ */
+ if (test_u32_divide(val - 1, d, r) < 0 ||
+ test_u32_divide(val, d, r) < 0 ||
+ test_u32_divide(val + 1, d, r) < 0)
+ return -1;
}
}
+ return TEST_SUCCESS;
+}
- printf("Validating unsigned 64bit division with 32bit divisor.\n");
- for (i = 0; i < MAX_ITERATIONS; i++) {
- /* Change divisor every DIVIDE_ITER iterations. */
- if (i % DIVIDE_ITER == 0) {
- divisor_u64 = rte_rand() >> 32;
- reci_u64 = rte_reciprocal_value_u64(divisor_u64);
- }
+static int
+test_u64_divide(uint64_t a, uint64_t d, const struct rte_reciprocal_u64 *r)
+{
+ uint64_t expected = a / d;
+ uint64_t result = rte_reciprocal_divide_u64(a, r);
+
+ TEST_ASSERT_EQUAL(expected, result,
+ "%"PRIu64"/%"PRIu64" expected %"PRIu64" got %"PRIu64,
+ a, d, expected, result);
+ return 0;
+}
- dividend_u64 = rte_rand();
- nresult_u64 = dividend_u64 / divisor_u64;
- rresult_u64 = rte_reciprocal_divide_u64(dividend_u64,
- &reci_u64);
+static int
+test_reciprocal_u64(void)
+{
+ const uint64_t edge_div_u64[] = {
+ 1, 2, 3, 7, 0x7fffffff, 0x80000000, 0xfffffffe, UINT64_MAX,
+ };
+ unsigned int n_div = RTE_DIM(edge_div_u64) + DIVISORS_RANDOM;
+
+ for (unsigned int di = 0; di < n_div; di++) {
+ uint64_t d;
+ if (di < RTE_DIM(edge_div_u64))
+ d = edge_div_u64[di];
+ else
+ d = rte_rand_max(UINT64_MAX - 1) + 1;
+
+ struct rte_reciprocal_u64 r = rte_reciprocal_value_u64(d);
+ uint64_t qmax = UINT64_MAX / d; /* largest q with q*d <= UINT64_MAX */
+ if (d != 1)
+ ++qmax;
+
+ for (unsigned int k = 0; k < MAX_ITERATIONS; k++) {
+ uint64_t q = rte_rand_max(qmax);
+ uint64_t val = q * d;
+
+ if (test_u64_divide(val - 1, d, &r) < 0 ||
+ test_u64_divide(val, d, &r) < 0 ||
+ test_u64_divide(val + 1, d, &r) < 0)
+ return -1;
- if (nresult_u64 != rresult_u64) {
- printf("Division failed, %"PRIu64"/%"PRIu64" = "
- "expected %"PRIu64" result %"PRIu64"\n",
- dividend_u64, divisor_u64,
- nresult_u64, rresult_u64);
- result = 1;
- break;
}
}
+ return TEST_SUCCESS;
+}
- printf("Validating division by power of 2.\n");
- for (i = 0; i < 32; i++) {
- divisor_u64 = 1ull << i;
- reci_u64 = rte_reciprocal_value_u64(divisor_u64);
- reci_u32 = rte_reciprocal_value((uint32_t)divisor_u64);
+static int
+test_reciprocal_u64_small(void)
+{
+ /* 64-bit division with a 32-bit-range divisor */
+ uint64_t divisor_u64 = (rte_rand() >> 32) | 1;
+ struct rte_reciprocal_u64 reci_u64 = rte_reciprocal_value_u64(divisor_u64);
+
+ for (unsigned int i = 0; i < MAX_ITERATIONS; i++) {
+ uint64_t dividend_u64 = rte_rand();
+ uint64_t nresult_u64 = dividend_u64 / divisor_u64;
+ uint64_t rresult_u64 = rte_reciprocal_divide_u64(dividend_u64, &reci_u64);
+
+ TEST_ASSERT_EQUAL(nresult_u64, rresult_u64,
+ "%"PRIu64"/%"PRIu64" = expected %"PRIu64" got %"PRIu64,
+ dividend_u64, divisor_u64, nresult_u64, rresult_u64);
+ }
- for (j = 0; j < MAX_ITERATIONS >> 4; j++) {
- dividend_u64 = rte_rand();
+ return TEST_SUCCESS;
+}
- nresult_u64 = dividend_u64 / divisor_u64;
- rresult_u64 = rte_reciprocal_divide_u64(dividend_u64,
+static int
+test_reciprocal_pow2(void)
+{
+ for (unsigned int i = 0; i < 32; i++) {
+ uint64_t divisor_u64 = 1ULL << i;
+ struct rte_reciprocal_u64 reci_u64 = rte_reciprocal_value_u64(divisor_u64);
+ struct rte_reciprocal reci_u32 = rte_reciprocal_value((uint32_t)divisor_u64);
+
+ for (unsigned int j = 0; j < MAX_ITERATIONS >> 4; j++) {
+ uint64_t dividend_u64 = rte_rand();
+ uint64_t nresult_u64 = dividend_u64 / divisor_u64;
+ uint64_t rresult_u64 = rte_reciprocal_divide_u64(dividend_u64,
&reci_u64);
- if (nresult_u64 != rresult_u64) {
- printf(
- "Division 64 failed, %"PRIu64"/%"PRIu64" = "
- "expected %"PRIu64" result %"PRIu64"\n",
- dividend_u64, divisor_u64,
- nresult_u64, rresult_u64);
- result = 1;
- }
-
- nresult_u32 = (dividend_u64 >> 32) / divisor_u64;
- rresult_u32 = rte_reciprocal_divide(
+ TEST_ASSERT_EQUAL(nresult_u64, rresult_u64,
+ "u64 %"PRIu64"/%"PRIu64" = expected %"PRIu64" got %"PRIu64,
+ dividend_u64, divisor_u64,
+ nresult_u64, rresult_u64);
+
+ uint32_t nresult_u32 = (dividend_u64 >> 32) / divisor_u64;
+ uint32_t rresult_u32 = rte_reciprocal_divide(
(dividend_u64 >> 32), reci_u32);
- if (nresult_u32 != rresult_u32) {
- printf(
- "Division 32 failed, %"PRIu64"/%"PRIu64" = "
- "expected %"PRIu64" result %"PRIu64"\n",
- dividend_u64 >> 32, divisor_u64,
- nresult_u64, rresult_u64);
- result = 1;
- break;
- }
+ TEST_ASSERT_EQUAL(nresult_u32, rresult_u32,
+ "u32 %"PRIu64"/%"PRIu64" = expected %"PRIu32" got %"PRIu32,
+ dividend_u64 >> 32, divisor_u64,
+ nresult_u32, rresult_u32);
}
}
- for (; i < 64; i++) {
- divisor_u64 = 1ull << i;
- reci_u64 = rte_reciprocal_value_u64(divisor_u64);
+ for (unsigned int i = 32; i < 64; i++) {
+ uint64_t divisor_u64 = 1ULL << i;
+ struct rte_reciprocal_u64 reci_u64 = rte_reciprocal_value_u64(divisor_u64);
- for (j = 0; j < MAX_ITERATIONS >> 4; j++) {
- dividend_u64 = rte_rand();
-
- nresult_u64 = dividend_u64 / divisor_u64;
- rresult_u64 = rte_reciprocal_divide_u64(dividend_u64,
+ for (unsigned int j = 0; j < MAX_ITERATIONS >> 4; j++) {
+ uint64_t dividend_u64 = rte_rand();
+ uint64_t nresult_u64 = dividend_u64 / divisor_u64;
+ uint64_t rresult_u64 = rte_reciprocal_divide_u64(dividend_u64,
&reci_u64);
- if (nresult_u64 != rresult_u64) {
- printf("Division failed, %"PRIu64"/%"PRIu64" = "
- "expected %"PRIu64" result %"PRIu64"\n",
- dividend_u64, divisor_u64,
- nresult_u64, rresult_u64);
- result = 1;
- break;
- }
+ TEST_ASSERT_EQUAL(nresult_u64, rresult_u64,
+ "u64 %"PRIu64"/%"PRIu64" = expected %"PRIu64" got %"PRIu64,
+ dividend_u64, divisor_u64,
+ nresult_u64, rresult_u64);
}
}
- return result;
+ return TEST_SUCCESS;
+}
+
+static struct unit_test_suite reciprocal_tests = {
+ .suite_name = "reciprocal division autotest",
+ .setup = NULL,
+ .teardown = NULL,
+ .unit_test_cases = {
+ TEST_CASE(test_reciprocal_u32),
+ TEST_CASE(test_reciprocal_u64),
+ TEST_CASE(test_reciprocal_u64_small),
+ TEST_CASE(test_reciprocal_pow2),
+ TEST_CASES_END()
+ }
+};
+
+static int
+test_reciprocal(void)
+{
+ return unit_test_suite_runner(&reciprocal_tests);
}
-REGISTER_PERF_TEST(reciprocal_division, test_reciprocal);
+REGISTER_FAST_TEST(reciprocal_division_autotest, NOHUGE_OK, ASAN_OK, test_reciprocal);
--
2.53.0
next prev parent reply other threads:[~2026-05-29 17:14 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-29 17:10 [PATCH 0/7] app/test: make perf tests usable on wider range of systems Stephen Hemminger
2026-05-29 17:10 ` Stephen Hemminger [this message]
2026-05-29 17:10 ` [PATCH 2/7] app/test/reciprocal_division_perf: reduce test time Stephen Hemminger
2026-05-29 17:10 ` [PATCH 3/7] app/test/mempool_perf: size mempool by tested cores Stephen Hemminger
2026-06-01 8:12 ` Andrew Rybchenko
2026-06-01 12:22 ` Morten Brørup
2026-05-29 17:10 ` [PATCH 4/7] app/test/mempool_perf: drop constant-values replay Stephen Hemminger
2026-06-01 8:34 ` Andrew Rybchenko
2026-06-01 13:22 ` Morten Brørup
2026-05-29 17:10 ` [PATCH 5/7] app/test/mempool_perf: scale down for high core counts Stephen Hemminger
2026-06-01 8:42 ` Andrew Rybchenko
2026-06-01 12:58 ` Morten Brørup
2026-05-29 17:10 ` [PATCH 6/7] app/test/test_rcu_qsbr_perf: call quiescent more often Stephen Hemminger
2026-05-29 17:11 ` [PATCH 7/7] app/test/test_pmd_perf: skip if no device available Stephen Hemminger
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=20260529171417.526892-2-stephen@networkplumber.org \
--to=stephen@networkplumber.org \
--cc=dev@dpdk.org \
/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