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 at 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 at 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(&params);
> -     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
> 

Reply via email to