app/test: improve hash unit tests
authorPablo de Lara <pablo.de.lara.guarch@intel.com>
Thu, 9 Jul 2015 16:54:30 +0000 (17:54 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Fri, 10 Jul 2015 10:34:13 +0000 (12:34 +0200)
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 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.

Note that performance numbers include time to take a random key
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>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
app/test/test_hash.c
app/test/test_hash_perf.c

index 4300de9..7c71ed6 100644 (file)
@@ -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();
 
index d0e5ce0..a3876c1 100644 (file)
  */
 
 #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);