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 <[email protected]> --- 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

