From: Bruce Richardson <bruce.richardson@intel.com>
To: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Cc: dev@dpdk.org
Subject: Re: [dpdk-dev] [PATCH v4] test/hash: improve hash unit tests
Date: Fri, 10 Jul 2015 10:11:59 +0100 [thread overview]
Message-ID: <20150710091159.GA10556@bricha3-MOBL3> (raw)
In-Reply-To: <1436460870-30022-2-git-send-email-pablo.de.lara.guarch@intel.com>
On Thu, Jul 09, 2015 at 05:54:30PM +0100, Pablo de Lara wrote:
> Add new unit test for calculating the average table utilization,
> using random keys, based on number of entries that can be added
> until we encounter one that cannot be added (bucket if full).
>
> Also, replace current hash_perf unit test to see performance more clear.
s/clear/clearly/
> The current hash_perf unit test takes too long and add keys that
> may or may not fit in the table and look up/delete that may not be
> in the table. This new unit test gets a set of keys that we know
> that fits in the table, and then measure the time to add/look up/delete
> them.
>
> Mind that performance numbers include time to take a random key
s/Mind/Note/
> from a pre-made array of keys, plus a quick check of return value.
> Also, as stated above, expect higher numbers, as all operations
> in the new unit tests will be successful, which means that
> it will take more time, than mixing both successful and unsuccesful
> operations.
>
> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Looks good, Pablo.
Thomas, perhaps you could make the above minor changes to
the commit log when applying the patch.
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> ---
> app/test/test_hash.c | 66 +++-
> app/test/test_hash_perf.c | 923 ++++++++++++++++++++--------------------------
> 2 files changed, 458 insertions(+), 531 deletions(-)
>
> diff --git a/app/test/test_hash.c b/app/test/test_hash.c
> index 4300de9..7c71ed6 100644
> --- a/app/test/test_hash.c
> +++ b/app/test/test_hash.c
> @@ -190,7 +190,7 @@ test_crc32_hash_alg_equiv(void)
> unsigned i, j;
> size_t data_len;
>
> - printf("# CRC32 implementations equivalence test\n");
> + printf("\n# CRC32 implementations equivalence test\n");
> for (i = 0; i < CRC32_ITERATIONS; i++) {
> /* Randomizing data_len of data set */
> data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
> @@ -785,7 +785,7 @@ fbk_hash_unit_test(void)
>
> /* Try creating hashes with invalid parameters */
> printf("# Testing hash creation with invalid parameters "
> - "- expert error msgs\n");
> + "- expect error msgs\n");
> handle = rte_fbk_hash_create(&invalid_params_1);
> RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
>
> @@ -1087,6 +1087,7 @@ static int test_hash_creation_with_bad_parameters(void)
> }
>
> rte_hash_free(handle);
> + printf("# Test successful. No more errors expected\n");
>
> return 0;
> }
> @@ -1147,6 +1148,65 @@ test_hash_creation_with_good_parameters(void)
> return 0;
> }
>
> +#define ITERATIONS 50
> +/*
> + * Test to see the average table utilization (entries added/max entries)
> + * before hitting a random entry that cannot be added
> + */
> +static int test_average_table_utilization(void)
> +{
> + struct rte_hash *handle;
> + uint8_t simple_key[RTE_HASH_KEY_LENGTH_MAX];
> + unsigned i, j;
> + unsigned added_keys, average_keys_added = 0;
> + int ret;
> +
> + printf("\n# Running test to determine average utilization"
> + "\n before adding elements begins to fail\n");
> + printf("Measuring performance, please wait");
> + fflush(stdout);
> + ut_params.entries = 1 << 20;
> + ut_params.name = "test_average_utilization";
> + ut_params.hash_func = rte_jhash;
> + handle = rte_hash_create(&ut_params);
> + RETURN_IF_ERROR(handle == NULL, "hash creation failed");
> +
> + for (j = 0; j < ITERATIONS; j++) {
> + ret = 0;
> + /* Add random entries until key cannot be added */
> + for (added_keys = 0; ret >= 0; added_keys++) {
> + for (i = 0; i < ut_params.key_len; i++)
> + simple_key[i] = rte_rand() % 255;
> + ret = rte_hash_add_key(handle, simple_key);
> + }
> + if (ret != -ENOSPC) {
> + printf("Unexpected error when adding keys\n");
> + rte_hash_free(handle);
> + return -1;
> + }
> +
> + average_keys_added += added_keys;
> +
> + /* Reset the table */
> + rte_hash_free(handle);
> + handle = rte_hash_create(&ut_params);
> + RETURN_IF_ERROR(handle == NULL, "hash creation failed");
> +
> + /* Print a dot to show progress on operations */
> + printf(".");
> + fflush(stdout);
> + }
> +
> + average_keys_added /= ITERATIONS;
> +
> + printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
> + ((double) average_keys_added / ut_params.entries * 100),
> + average_keys_added, ut_params.entries);
> + rte_hash_free(handle);
> +
> + return 0;
> +}
> +
> static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
> 0x04, 0x05, 0x06, 0x07,
> 0x08, 0x09, 0x0a, 0x0b,
> @@ -1405,6 +1465,8 @@ test_hash(void)
> return -1;
> if (test_hash_creation_with_good_parameters() < 0)
> return -1;
> + if (test_average_table_utilization() < 0)
> + return -1;
>
> run_hash_func_tests();
>
> diff --git a/app/test/test_hash_perf.c b/app/test/test_hash_perf.c
> index d0e5ce0..a3876c1 100644
> --- a/app/test/test_hash_perf.c
> +++ b/app/test/test_hash_perf.c
> @@ -32,574 +32,436 @@
> */
>
> #include <stdio.h>
> -#include <stdint.h>
> -#include <string.h>
> -#include <stdlib.h>
> -#include <stdarg.h>
> -#include <errno.h>
> -#include <sys/queue.h>
> -
> -#include <rte_common.h>
> +#include <inttypes.h>
> +
> #include <rte_lcore.h>
> -#include <rte_malloc.h>
> #include <rte_cycles.h>
> +#include <rte_malloc.h>
> +#include <rte_hash.h>
> +#include <rte_hash_crc.h>
> +#include <rte_jhash.h>
> +#include <rte_fbk_hash.h>
> #include <rte_random.h>
> -#include <rte_memory.h>
> -#include <rte_memzone.h>
> -#include <rte_eal.h>
> -#include <rte_ip.h>
> #include <rte_string_fns.h>
>
> #include "test.h"
>
> -#include <rte_hash.h>
> -#include <rte_fbk_hash.h>
> -#include <rte_jhash.h>
> -#include <rte_hash_crc.h>
> -
> -/* Types of hash table performance test that can be performed */
> -enum hash_test_t {
> - ADD_ON_EMPTY, /*< Add keys to empty table */
> - DELETE_ON_EMPTY, /*< Attempt to delete keys from empty table */
> - LOOKUP_ON_EMPTY, /*< Attempt to find keys in an empty table */
> - ADD_UPDATE, /*< Add/update keys in a full table */
> - DELETE, /*< Delete keys from a full table */
> - LOOKUP /*< Find keys in a full table */
> +#define MAX_ENTRIES (1 << 19)
> +#define KEYS_TO_ADD (MAX_ENTRIES * 3 / 4) /* 75% table utilization */
> +#define NUM_LOOKUPS (KEYS_TO_ADD * 5) /* Loop among keys added, several times */
> +#define BUCKET_SIZE 4
> +#define NUM_BUCKETS (MAX_ENTRIES / BUCKET_SIZE)
> +#define MAX_KEYSIZE 64
> +#define NUM_KEYSIZES 10
> +#define NUM_SHUFFLES 10
> +#define BURST_SIZE 16
> +
> +enum operations {
> + ADD = 0,
> + LOOKUP,
> + LOOKUP_MULTI,
> + DELETE,
> + NUM_OPERATIONS
> };
>
> -/* Function type for hash table operations. */
> -typedef int32_t (*hash_operation)(const struct rte_hash *h, const void *key);
> -
> -/* Structure to hold parameters used to run a hash table performance test */
> -struct tbl_perf_test_params {
> - enum hash_test_t test_type;
> - uint32_t num_iterations;
> - uint32_t entries;
> - uint32_t bucket_entries;
> - uint32_t key_len;
> - rte_hash_function hash_func;
> - uint32_t hash_func_init_val;
> +static uint32_t hashtest_key_lens[] = {
> + /* standard key sizes */
> + 4, 8, 16, 32, 48, 64,
> + /* IPv4 SRC + DST + protocol, unpadded */
> + 9,
> + /* IPv4 5-tuple, unpadded */
> + 13,
> + /* IPv6 5-tuple, unpadded */
> + 37,
> + /* IPv6 5-tuple, padded to 8-byte boundary */
> + 40
> };
>
> -#define ITERATIONS 10000
> -#define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
> +struct rte_hash *h[NUM_KEYSIZES];
>
> -/*******************************************************************************
> - * Hash table performance test configuration section.
> - */
> -struct tbl_perf_test_params tbl_perf_params[] =
> -{
> -/* Small table, add */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 64, rte_jhash, 0},
> -/* Small table, update */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 64, rte_jhash, 0},
> -/* Small table, lookup */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ LOOKUP, ITERATIONS, 1024, 1, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 1, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 1, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 1, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 64, rte_jhash, 0},
> -/* Big table, add */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 16, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 32, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 48, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 64, rte_jhash, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 64, rte_jhash, 0},
> -/* Big table, update */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 16, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 32, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 48, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 64, rte_jhash, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 64, rte_jhash, 0},
> -/* Big table, lookup */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ LOOKUP, ITERATIONS, 1048576, 1, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 16, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 1, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 32, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 1, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 48, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 1, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 64, rte_jhash, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 64, rte_jhash, 0},
> -/* Small table, add */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 1, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 2, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 4, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 8, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1024, 1024, 16, 64, rte_hash_crc, 0},
> -/* Small table, update */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 1, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 2, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 4, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 8, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1024, 16, 64, rte_hash_crc, 0},
> -/* Small table, lookup */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ LOOKUP, ITERATIONS, 1024, 1, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 1, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 1, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 1, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 2, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 4, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 8, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1024, 16, 64, rte_hash_crc, 0},
> -/* Big table, add */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 16, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 32, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 48, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 1, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 2, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 4, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 8, 64, rte_hash_crc, 0},
> -{ ADD_ON_EMPTY, 1048576, 1048576, 16, 64, rte_hash_crc, 0},
> -/* Big table, update */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 16, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 32, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 48, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 1, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 2, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 4, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 8, 64, rte_hash_crc, 0},
> -{ ADD_UPDATE, ITERATIONS, 1048576, 16, 64, rte_hash_crc, 0},
> -/* Big table, lookup */
> -/* Test type | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
> -{ LOOKUP, ITERATIONS, 1048576, 1, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 16, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 1, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 32, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 1, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 48, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 1, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 2, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 4, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 8, 64, rte_hash_crc, 0},
> -{ LOOKUP, ITERATIONS, 1048576, 16, 64, rte_hash_crc, 0},
> -};
> +/* Array that stores if a slot is full */
> +uint8_t slot_taken[MAX_ENTRIES];
>
> -/******************************************************************************/
> +/* Array to store number of cycles per operation */
> +uint64_t cycles[NUM_KEYSIZES][NUM_OPERATIONS][2];
>
> -/*
> - * Check condition and return an error if true. Assumes that "handle" is the
> - * name of the hash structure pointer to be freed.
> - */
> -#define RETURN_IF_ERROR(cond, str, ...) do { \
> - if (cond) { \
> - printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
> - if (handle) rte_hash_free(handle); \
> - return -1; \
> - } \
> -} while(0)
> -
> -#define RETURN_IF_ERROR_FBK(cond, str, ...) do { \
> - if (cond) { \
> - printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
> - if (handle) rte_fbk_hash_free(handle); \
> - rte_free(keys); \
> - return -1; \
> - } \
> -} while(0)
> +/* Array to store all input keys */
> +uint8_t keys[KEYS_TO_ADD][MAX_KEYSIZE];
>
> -/*
> - * Find average of array of numbers.
> - */
> -static double
> -get_avg(const uint32_t *array, uint32_t size)
> +/* Array to store the precomputed hash for 'keys' */
> +hash_sig_t signatures[KEYS_TO_ADD];
> +
> +/* Array to store how many busy entries have each bucket */
> +uint8_t buckets[NUM_BUCKETS];
> +
> +/* Array to store the positions where keys are added */
> +int32_t positions[KEYS_TO_ADD];
> +
> +/* Parameters used for hash table in unit test functions. */
> +static struct rte_hash_parameters ut_params = {
> + .entries = MAX_ENTRIES,
> + .bucket_entries = BUCKET_SIZE,
> + .hash_func = rte_jhash,
> + .hash_func_init_val = 0,
> +};
> +
> +static int
> +create_table(unsigned table_index)
> {
> - double sum = 0;
> - unsigned i;
> - for (i = 0; i < size; i++)
> - sum += array[i];
> - return sum / (double)size;
> + char name[RTE_HASH_NAMESIZE];
> +
> + sprintf(name, "test_hash%d", hashtest_key_lens[table_index]);
> + ut_params.name = name;
> + ut_params.key_len = hashtest_key_lens[table_index];
> + ut_params.socket_id = rte_socket_id();
> + h[table_index] = rte_hash_find_existing(name);
> + if (h[table_index] != NULL)
> + /*
> + * If table was already created, free it to create it again,
> + * so we force it is empty
> + */
> + rte_hash_free(h[table_index]);
> + h[table_index] = rte_hash_create(&ut_params);
> + if (h[table_index] == NULL) {
> + printf("Error creating table\n");
> + return -1;
> + }
> + return 0;
> +
> }
>
> -/*
> - * To help print out name of hash functions.
> - */
> -static const char *get_hash_name(rte_hash_function f)
> +/* Shuffle the keys that have been added, so lookups will be totally random */
> +static void
> +shuffle_input_keys(unsigned table_index)
> {
> - if (f == rte_jhash)
> - return "jhash";
> + unsigned i;
> + uint32_t swap_idx;
> + uint8_t temp_key[RTE_HASH_KEY_LENGTH_MAX];
> + hash_sig_t temp_signature;
> + int32_t temp_position;
>
> - if (f == rte_hash_crc)
> - return "rte_hash_crc";
> + for (i = KEYS_TO_ADD - 1; i > 0; i--) {
> + swap_idx = rte_rand() % i;
>
> - return "UnknownHash";
> + memcpy(temp_key, keys[i], hashtest_key_lens[table_index]);
> + temp_signature = signatures[i];
> + temp_position = positions[i];
> +
> + memcpy(keys[i], keys[swap_idx], hashtest_key_lens[table_index]);
> + signatures[i] = signatures[swap_idx];
> + positions[i] = positions[swap_idx];
> +
> + memcpy(keys[swap_idx], temp_key, hashtest_key_lens[table_index]);
> + signatures[swap_idx] = temp_signature;
> + positions[swap_idx] = temp_position;
> + }
> }
>
> /*
> - * Do a single performance test, of one type of operation.
> - *
> - * @param h
> - * hash table to run test on
> - * @param func
> - * function to call (add, delete or lookup function)
> - * @param avg_occupancy
> - * The average number of entries in each bucket of the hash table
> - * @param invalid_pos_count
> - * The amount of errors (e.g. due to a full bucket).
> - * @return
> - * The average number of ticks per hash function call. A negative number
> - * signifies failure.
> + * Looks for random keys which
> + * ALL can fit in hash table (no errors)
> */
> -static double
> -run_single_tbl_perf_test(const struct rte_hash *h, hash_operation func,
> - const struct tbl_perf_test_params *params, double *avg_occupancy,
> - uint32_t *invalid_pos_count)
> +static int
> +get_input_keys(unsigned table_index)
> {
> - uint64_t begin, end, ticks = 0;
> - uint8_t *key = NULL;
> - uint32_t *bucket_occupancies = NULL;
> - uint32_t num_buckets, i, j;
> - int32_t pos;
> -
> - /* Initialise */
> - num_buckets = params->entries / params->bucket_entries;
> - key = rte_zmalloc("hash key",
> - params->key_len * sizeof(uint8_t), 16);
> - if (key == NULL)
> - return -1;
> + unsigned i, j;
> + unsigned bucket_idx, incr, success = 1;
> + uint8_t k = 0;
> + int32_t ret;
> + const uint32_t bucket_bitmask = NUM_BUCKETS - 1;
>
> - bucket_occupancies = rte_calloc("bucket occupancies",
> - num_buckets, sizeof(uint32_t), 16);
> - if (bucket_occupancies == NULL) {
> - rte_free(key);
> - return -1;
> - }
> + /* Reset all arrays */
> + for (i = 0; i < MAX_ENTRIES; i++)
> + slot_taken[i] = 0;
>
> - ticks = 0;
> - *invalid_pos_count = 0;
> + for (i = 0; i < NUM_BUCKETS; i++)
> + buckets[i] = 0;
>
> - for (i = 0; i < params->num_iterations; i++) {
> - /* Prepare inputs for the current iteration */
> - for (j = 0; j < params->key_len; j++)
> - key[j] = (uint8_t) rte_rand();
> + for (j = 0; j < hashtest_key_lens[table_index]; j++)
> + keys[0][j] = 0;
>
> - /* Perform operation, and measure time it takes */
> - begin = rte_rdtsc();
> - pos = func(h, key);
> - end = rte_rdtsc();
> - ticks += end - begin;
> + /*
> + * Add only entries that are not duplicated and that fits in the table
> + * (cannot store more than BUCKET_SIZE entries in a bucket).
> + * Regardless a key has been added correctly or not (success),
> + * the next one to try will be increased by 1.
> + */
> + for (i = 0; i < KEYS_TO_ADD;) {
> + incr = 0;
> + if (i != 0) {
> + keys[i][0] = ++k;
> + /* Overflow, need to increment the next byte */
> + if (keys[i][0] == 0)
> + incr = 1;
> + for (j = 1; j < hashtest_key_lens[table_index]; j++) {
> + /* Do not increase next byte */
> + if (incr == 0)
> + if (success == 1)
> + keys[i][j] = keys[i - 1][j];
> + else
> + keys[i][j] = keys[i][j];
> + /* Increase next byte by one */
> + else {
> + if (success == 1)
> + keys[i][j] = keys[i-1][j] + 1;
> + else
> + keys[i][j] = keys[i][j] + 1;
> + if (keys[i][j] == 0)
> + incr = 1;
> + else
> + incr = 0;
> + }
> + }
> + }
> + success = 0;
> + signatures[i] = rte_hash_hash(h[table_index], keys[i]);
> + bucket_idx = signatures[i] & bucket_bitmask;
> + /* If bucket is full, do not try to insert the key */
> + if (buckets[bucket_idx] == BUCKET_SIZE)
> + continue;
> + /* If key can be added, leave in successful key arrays "keys" */
> + ret = rte_hash_add_key_with_hash(h[table_index], keys[i],
> + signatures[i]);
> + if (ret >= 0) {
> + /* If key is already added, ignore the entry and do not store */
> + if (slot_taken[ret])
> + continue;
> + else {
> + /* Store the returned position and mark slot as taken */
> + slot_taken[ret] = 1;
> + buckets[bucket_idx]++;
> + success = 1;
> + i++;
> + }
> + }
> + }
>
> - /* Other work per iteration */
> - if (pos < 0)
> - *invalid_pos_count += 1;
> + /* Reset the table, so we can measure the time to add all the entries */
> + rte_hash_free(h[table_index]);
> + h[table_index] = rte_hash_create(&ut_params);
> +
> + return 0;
> +}
> +
> +static int
> +timed_adds(unsigned with_hash, unsigned table_index)
> +{
> + unsigned i;
> + const uint64_t start_tsc = rte_rdtsc();
> + int32_t ret;
> +
> + for (i = 0; i < KEYS_TO_ADD; i++) {
> + if (with_hash)
> + ret = rte_hash_add_key_with_hash(h[table_index],
> + (const void *) keys[i],
> + signatures[i]);
> else
> - bucket_occupancies[pos / params->bucket_entries]++;
> + ret = rte_hash_add_key(h[table_index], keys[i]);
> +
> + if (ret >= 0)
> + positions[i] = ret;
> + else {
> + printf("Failed to add key number %u\n", ret);
> + return -1;
> + }
> }
> - *avg_occupancy = get_avg(bucket_occupancies, num_buckets);
>
> - rte_free(bucket_occupancies);
> - rte_free(key);
> + const uint64_t end_tsc = rte_rdtsc();
> + const uint64_t time_taken = end_tsc - start_tsc;
>
> - return (double)ticks / params->num_iterations;
> + cycles[table_index][ADD][with_hash] = time_taken/KEYS_TO_ADD;
> + return 0;
> }
>
> -/*
> - * To help print out what tests are being done.
> - */
> -static const char *
> -get_tbl_perf_test_desc(enum hash_test_t type)
> +static int
> +timed_lookups(unsigned with_hash, unsigned table_index)
> {
> - switch (type){
> - case ADD_ON_EMPTY: return "Add on Empty";
> - case DELETE_ON_EMPTY: return "Delete on Empty";
> - case LOOKUP_ON_EMPTY: return "Lookup on Empty";
> - case ADD_UPDATE: return "Add Update";
> - case DELETE: return "Delete";
> - case LOOKUP: return "Lookup";
> - default: return "UNKNOWN";
> + unsigned i, j;
> + const uint64_t start_tsc = rte_rdtsc();
> + int32_t ret;
> +
> + for (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) {
> + for (j = 0; j < KEYS_TO_ADD; j++) {
> + if (with_hash)
> + ret = rte_hash_lookup_with_hash(h[table_index],
> + (const void *) keys[j],
> + signatures[j]);
> + else
> + ret = rte_hash_lookup(h[table_index], keys[j]);
> + if (ret < 0 || ret != positions[j]) {
> + printf("Key looked up in %d, should be in %d\n",
> + ret, positions[j]);
> + return -1;
> + }
> + }
> }
> +
> + const uint64_t end_tsc = rte_rdtsc();
> + const uint64_t time_taken = end_tsc - start_tsc;
> +
> + cycles[table_index][LOOKUP][with_hash] = time_taken/NUM_LOOKUPS;
> +
> + return 0;
> }
>
> -/*
> - * Run a hash table performance test based on params.
> - */
> static int
> -run_tbl_perf_test(struct tbl_perf_test_params *params)
> +timed_lookups_multi(unsigned table_index)
> {
> - static unsigned calledCount = 5;
> - struct rte_hash_parameters hash_params = {
> - .entries = params->entries,
> - .bucket_entries = params->bucket_entries,
> - .key_len = params->key_len,
> - .hash_func = params->hash_func,
> - .hash_func_init_val = params->hash_func_init_val,
> - .socket_id = rte_socket_id(),
> - };
> - struct rte_hash *handle;
> - double avg_occupancy = 0, ticks = 0;
> - uint32_t num_iterations, invalid_pos;
> - char name[RTE_HASH_NAMESIZE];
> - char hashname[RTE_HASH_NAMESIZE];
> -
> - snprintf(name, 32, "test%u", calledCount++);
> - hash_params.name = name;
> -
> - handle = rte_hash_create(&hash_params);
> - RETURN_IF_ERROR(handle == NULL, "hash creation failed");
> -
> - switch (params->test_type){
> - case ADD_ON_EMPTY:
> - ticks = run_single_tbl_perf_test(handle, rte_hash_add_key,
> - params, &avg_occupancy, &invalid_pos);
> - break;
> - case DELETE_ON_EMPTY:
> - ticks = run_single_tbl_perf_test(handle, rte_hash_del_key,
> - params, &avg_occupancy, &invalid_pos);
> - break;
> - case LOOKUP_ON_EMPTY:
> - ticks = run_single_tbl_perf_test(handle, rte_hash_lookup,
> - params, &avg_occupancy, &invalid_pos);
> - break;
> - case ADD_UPDATE:
> - num_iterations = params->num_iterations;
> - params->num_iterations = params->entries;
> - run_single_tbl_perf_test(handle, rte_hash_add_key, params,
> - &avg_occupancy, &invalid_pos);
> - params->num_iterations = num_iterations;
> - ticks = run_single_tbl_perf_test(handle, rte_hash_add_key,
> - params, &avg_occupancy, &invalid_pos);
> - break;
> - case DELETE:
> - num_iterations = params->num_iterations;
> - params->num_iterations = params->entries;
> - run_single_tbl_perf_test(handle, rte_hash_add_key, params,
> - &avg_occupancy, &invalid_pos);
> -
> - params->num_iterations = num_iterations;
> - ticks = run_single_tbl_perf_test(handle, rte_hash_del_key,
> - params, &avg_occupancy, &invalid_pos);
> - break;
> - case LOOKUP:
> - num_iterations = params->num_iterations;
> - params->num_iterations = params->entries;
> - run_single_tbl_perf_test(handle, rte_hash_add_key, params,
> - &avg_occupancy, &invalid_pos);
> -
> - params->num_iterations = num_iterations;
> - ticks = run_single_tbl_perf_test(handle, rte_hash_lookup,
> - params, &avg_occupancy, &invalid_pos);
> - break;
> - default: return -1;
> + unsigned i, j, k;
> + int32_t positions_burst[BURST_SIZE];
> + const void *keys_burst[BURST_SIZE];
> + const uint64_t start_tsc = rte_rdtsc();
> +
> + for (i = 0; i < NUM_LOOKUPS/KEYS_TO_ADD; i++) {
> + for (j = 0; j < KEYS_TO_ADD/BURST_SIZE; j++) {
> + for (k = 0; k < BURST_SIZE; k++)
> + keys_burst[k] = keys[j * BURST_SIZE + k];
> +
> + rte_hash_lookup_bulk(h[table_index],
> + (const void **) keys_burst,
> + BURST_SIZE,
> + positions_burst);
> + for (k = 0; k < BURST_SIZE; k++) {
> + if (positions_burst[k] != positions[j * BURST_SIZE + k]) {
> + printf("Key looked up in %d, should be in %d\n",
> + positions_burst[k],
> + positions[j * BURST_SIZE + k]);
> + return -1;
> + }
> + }
> + }
> }
>
> - snprintf(hashname, RTE_HASH_NAMESIZE, "%s", get_hash_name(params->hash_func));
> -
> - printf("%-12s, %-15s, %-16u, %-7u, %-18u, %-8u, %-19.2f, %.2f\n",
> - hashname,
> - get_tbl_perf_test_desc(params->test_type),
> - (unsigned) params->key_len,
> - (unsigned) params->entries,
> - (unsigned) params->bucket_entries,
> - (unsigned) invalid_pos,
> - avg_occupancy,
> - ticks
> - );
> -
> - /* Free */
> - rte_hash_free(handle);
> + const uint64_t end_tsc = rte_rdtsc();
> + const uint64_t time_taken = end_tsc - start_tsc;
> +
> + cycles[table_index][LOOKUP_MULTI][0] = time_taken/NUM_LOOKUPS;
> +
> return 0;
> }
>
> -/*
> - * Run all hash table performance tests.
> - */
> -static int run_all_tbl_perf_tests(void)
> +static int
> +timed_deletes(unsigned with_hash, unsigned table_index)
> {
> unsigned i;
> + const uint64_t start_tsc = rte_rdtsc();
> + int32_t ret;
> +
> + for (i = 0; i < KEYS_TO_ADD; i++) {
> + if (with_hash)
> + ret = rte_hash_del_key_with_hash(h[table_index],
> + (const void *) keys[i],
> + signatures[i]);
> + else
> + ret = rte_hash_del_key(h[table_index],
> + (const void *) keys[i]);
> + if (ret >= 0)
> + positions[i] = ret;
> + else {
> + printf("Failed to add key number %u\n", ret);
> + return -1;
> + }
> + }
> +
> + const uint64_t end_tsc = rte_rdtsc();
> + const uint64_t time_taken = end_tsc - start_tsc;
> +
> + cycles[table_index][DELETE][with_hash] = time_taken/KEYS_TO_ADD;
> +
> + return 0;
> +}
> +
> +static void
> +free_table(unsigned table_index)
> +{
> + rte_hash_free(h[table_index]);
> +}
> +
> +static int
> +reset_table(unsigned table_index)
> +{
> + free_table(table_index);
> + if (create_table(table_index) != 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +static int
> +run_all_tbl_perf_tests(void)
> +{
> + unsigned i, j;
>
> - printf(" *** Hash table performance test results ***\n");
> - printf("Hash Func. , Operation , Key size (bytes), Entries, "
> - "Entries per bucket, Errors , Avg. bucket entries, Ticks/Op.\n");
> + printf("Measuring performance, please wait");
> + fflush(stdout);
> + for (i = 0; i < NUM_KEYSIZES; i++) {
> + if (create_table(i) < 0)
> + return -1;
> +
> + if (get_input_keys(i) < 0)
> + return -1;
> +
> + if (timed_adds(0, i) < 0)
> + return -1;
> +
> + for (j = 0; j < NUM_SHUFFLES; j++)
> + shuffle_input_keys(i);
> +
> + if (timed_lookups(0, i) < 0)
> + return -1;
> +
> + if (timed_lookups_multi(i) < 0)
> + return -1;
> +
> + if (timed_deletes(0, i) < 0)
> + return -1;
>
> - /* Loop through every combination of test parameters */
> - for (i = 0;
> - i < sizeof(tbl_perf_params) / sizeof(struct tbl_perf_test_params);
> - i++) {
> + /* Print a dot to show progress on operations */
> + printf(".");
> + fflush(stdout);
> +
> + if (reset_table(i) < 0)
> + return -1;
>
> - /* Perform test */
> - if (run_tbl_perf_test(&tbl_perf_params[i]) < 0)
> + if (timed_adds(1, i) < 0)
> return -1;
> +
> + for (j = 0; j < NUM_SHUFFLES; j++)
> + shuffle_input_keys(i);
> +
> + if (timed_lookups(1, i) < 0)
> + return -1;
> +
> + if (timed_deletes(1, i) < 0)
> + return -1;
> +
> + /* Print a dot to show progress on operations */
> + printf(".");
> + fflush(stdout);
> +
> + free_table(i);
> + }
> + printf("\nResults (in CPU cycles/operation)\n");
> + printf("---------------------------------\n");
> + printf("\nWithout pre-computed hash values\n");
> + printf("\n%-18s%-18s%-18s%-18s%-18s\n",
> + "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete");
> + for (i = 0; i < NUM_KEYSIZES; i++) {
> + printf("%-18d", hashtest_key_lens[i]);
> + for (j = 0; j < NUM_OPERATIONS; j++)
> + printf("%-18"PRIu64, cycles[i][j][0]);
> + printf("\n");
> + }
> + printf("\nWith pre-computed hash values\n");
> + printf("\n%-18s%-18s%-18s%-18s%-18s\n",
> + "Keysize", "Add", "Lookup", "Lookup_bulk", "Delete");
> + for (i = 0; i < NUM_KEYSIZES; i++) {
> + printf("%-18d", hashtest_key_lens[i]);
> + for (j = 0; j < NUM_OPERATIONS; j++)
> + printf("%-18"PRIu64, cycles[i][j][1]);
> + printf("\n");
> }
> +
> return 0;
> }
>
> @@ -624,28 +486,34 @@ fbk_hash_perf_test(void)
> uint64_t lookup_time = 0;
> unsigned added = 0;
> unsigned value = 0;
> + uint32_t key;
> + uint16_t val;
> unsigned i, j;
>
> handle = rte_fbk_hash_create(¶ms);
> - RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
> + if (handle == NULL) {
> + printf("Error creating table\n");
> + return -1;
> + }
>
> keys = rte_zmalloc(NULL, ENTRIES * sizeof(*keys), 0);
> - RETURN_IF_ERROR_FBK(keys == NULL,
> - "fbk hash: memory allocation for key store failed");
> + if (keys == NULL) {
> + printf("fbk hash: memory allocation for key store failed\n");
> + return -1;
> + }
>
> /* Generate random keys and values. */
> for (i = 0; i < ENTRIES; i++) {
> - uint32_t key = (uint32_t)rte_rand();
> + key = (uint32_t)rte_rand();
> key = ((uint64_t)key << 32) | (uint64_t)rte_rand();
> - uint16_t val = (uint16_t)rte_rand();
> + val = (uint16_t)rte_rand();
>
> if (rte_fbk_hash_add_key(handle, key, val) == 0) {
> keys[added] = key;
> added++;
> }
> - if (added > (LOAD_FACTOR * ENTRIES)) {
> + if (added > (LOAD_FACTOR * ENTRIES))
> break;
> - }
> }
>
> for (i = 0; i < TEST_ITERATIONS; i++) {
> @@ -653,15 +521,14 @@ fbk_hash_perf_test(void)
> uint64_t end;
>
> /* Generate random indexes into keys[] array. */
> - for (j = 0; j < TEST_SIZE; j++) {
> + for (j = 0; j < TEST_SIZE; j++)
> indexes[j] = rte_rand() % added;
> - }
>
> begin = rte_rdtsc();
> /* Do lookups */
> - for (j = 0; j < TEST_SIZE; j++) {
> + for (j = 0; j < TEST_SIZE; j++)
> value += rte_fbk_hash_lookup(handle, keys[indexes[j]]);
> - }
> +
> end = rte_rdtsc();
> lookup_time += (double)(end - begin);
> }
> @@ -681,9 +548,6 @@ fbk_hash_perf_test(void)
> return 0;
> }
>
> -/*
> - * Do all unit and performance tests.
> - */
> static int
> test_hash_perf(void)
> {
> @@ -692,11 +556,12 @@ test_hash_perf(void)
>
> if (fbk_hash_perf_test() < 0)
> return -1;
> +
> return 0;
> }
>
> static struct test_command hash_perf_cmd = {
> - .command = "hash_perf_autotest",
> - .callback = test_hash_perf,
> + .command = "hash_perf_autotest",
> + .callback = test_hash_perf,
> };
> REGISTER_TEST_COMMAND(hash_perf_cmd);
> --
> 2.4.2
>
next prev parent reply other threads:[~2015-07-10 9:12 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-08 13:12 [dpdk-dev] [PATCH] Improve hash unit tests - Cuckoo hash part 2 Pablo de Lara
2015-07-08 13:12 ` [dpdk-dev] [PATCH] test/hash: improve hash unit tests Pablo de Lara
2015-07-08 13:39 ` Bruce Richardson
2015-07-08 15:04 ` Bruce Richardson
2015-07-08 15:14 ` De Lara Guarch, Pablo
2015-07-08 16:30 ` [dpdk-dev] [PATCH v2] Improve hash unit tests - Cuckoo hash part 2 Pablo de Lara
2015-07-08 16:30 ` [dpdk-dev] [PATCH v2] test/hash: improve hash unit tests Pablo de Lara
2015-07-09 12:19 ` [dpdk-dev] [PATCH v3] Improve hash unit tests - Cuckoo hash part 2 Pablo de Lara
2015-07-09 12:19 ` [dpdk-dev] [PATCH v3] test/hash: improve hash unit tests Pablo de Lara
2015-07-09 16:54 ` [dpdk-dev] [PATCH v4] Improve hash unit tests - Cuckoo hash part 2 Pablo de Lara
2015-07-09 16:54 ` [dpdk-dev] [PATCH v4] test/hash: improve hash unit tests Pablo de Lara
2015-07-10 9:11 ` Bruce Richardson [this message]
2015-07-10 10:35 ` Thomas Monjalon
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=20150710091159.GA10556@bricha3-MOBL3 \
--to=bruce.richardson@intel.com \
--cc=dev@dpdk.org \
--cc=pablo.de.lara.guarch@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;
as well as URLs for NNTP newsgroup(s).