X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest%2Ftest_hash.c;h=2c87efe692dedc54f9e3ccf318a67c04ea63462a;hb=dd0eedb1cfcf0cb7423d859177c5bc6f931eaf8a;hp=b54fc95f96410317025d01bbd5e0794f0b715c89;hpb=18d5e8d78c25c74da0af78465d2853b20ed4ca82;p=dpdk.git diff --git a/app/test/test_hash.c b/app/test/test_hash.c index b54fc95f96..2c87efe692 100644 --- a/app/test/test_hash.c +++ b/app/test/test_hash.c @@ -1,35 +1,34 @@ /*- * BSD LICENSE - * - * Copyright(c) 2010-2012 Intel Corporation. All rights reserved. + * + * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions * are met: - * - * * Redistributions of source code must retain the above copyright + * + * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ #include @@ -46,324 +45,16 @@ #include #include #include -#include #include #include #include +#include "test.h" + #include #include #include - -#ifdef RTE_MACHINE_CPUFLAG_SSE4_2 #include -#endif -#include - -#include "test.h" - -#ifdef RTE_LIBRTE_HASH - -/* 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 */ -}; - -/* 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; -}; - -#define ITERATIONS 10000 -#define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15) - -/******************************************************************************* - * 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}, -}; - -/******************************************************************************/ /******************************************************************************* * Hash function performance test configuration section. Each performance test @@ -372,16 +63,12 @@ struct tbl_perf_test_params tbl_perf_params[] = * The five arrays below control what tests are performed. Every combination * from the array entries is tested. */ -#define HASHTEST_ITERATIONS 1000000 - -#ifdef RTE_MACHINE_CPUFLAG_SSE4_2 static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc}; -#else -static rte_hash_function hashtest_funcs[] = {rte_jhash}; -#endif static uint32_t hashtest_initvals[] = {0}; -static uint32_t hashtest_key_lens[] = {2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64}; +static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64}; +#define MAX_KEYSIZE 64 /******************************************************************************/ +#define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15) /* * Check condition and return an error if true. Assumes that "handle" is the @@ -483,13 +170,120 @@ static struct flow_key keys[5] = { { /* Parameters used for hash table in unit test functions. Name set later. */ static struct rte_hash_parameters ut_params = { .entries = 64, - .bucket_entries = 4, .key_len = sizeof(struct flow_key), /* 13 */ .hash_func = rte_jhash, .hash_func_init_val = 0, .socket_id = 0, }; +#define CRC32_ITERATIONS (1U << 10) +#define CRC32_DWORDS (1U << 6) +/* + * Test if all CRC32 implementations yield the same hash value + */ +static int +test_crc32_hash_alg_equiv(void) +{ + uint32_t hash_val; + uint32_t init_val; + uint64_t data64[CRC32_DWORDS]; + unsigned i, j; + size_t data_len; + + 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); + init_val = (uint32_t) rte_rand(); + + /* Fill the data set */ + for (j = 0; j < CRC32_DWORDS; j++) + data64[j] = rte_rand(); + + /* Calculate software CRC32 */ + rte_hash_crc_set_alg(CRC32_SW); + hash_val = rte_hash_crc(data64, data_len, init_val); + + /* Check against 4-byte-operand sse4.2 CRC32 if available */ + rte_hash_crc_set_alg(CRC32_SSE42); + if (hash_val != rte_hash_crc(data64, data_len, init_val)) { + printf("Failed checking CRC32_SW against CRC32_SSE42\n"); + break; + } + + /* Check against 8-byte-operand sse4.2 CRC32 if available */ + rte_hash_crc_set_alg(CRC32_SSE42_x64); + if (hash_val != rte_hash_crc(data64, data_len, init_val)) { + printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n"); + break; + } + + /* Check against 8-byte-operand ARM64 CRC32 if available */ + rte_hash_crc_set_alg(CRC32_ARM64); + if (hash_val != rte_hash_crc(data64, data_len, init_val)) { + printf("Failed checking CRC32_SW against CRC32_ARM64\n"); + break; + } + } + + /* Resetting to best available algorithm */ + rte_hash_crc_set_alg(CRC32_SSE42_x64); + + if (i == CRC32_ITERATIONS) + return 0; + + printf("Failed test data (hex, %zu bytes total):\n", data_len); + for (j = 0; j < data_len; j++) + printf("%02X%c", ((uint8_t *)data64)[j], + ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' '); + + return -1; +} + +/* + * Test a hash function. + */ +static void run_hash_func_test(rte_hash_function f, uint32_t init_val, + uint32_t key_len) +{ + static uint8_t key[MAX_KEYSIZE]; + unsigned i; + + + for (i = 0; i < key_len; i++) + key[i] = (uint8_t) rte_rand(); + + /* just to be on the safe side */ + if (!f) + return; + + f(key, key_len, init_val); +} + +/* + * Test all hash functions. + */ +static void run_hash_func_tests(void) +{ + unsigned i, j, k; + + for (i = 0; + i < sizeof(hashtest_funcs) / sizeof(rte_hash_function); + i++) { + for (j = 0; + j < sizeof(hashtest_initvals) / sizeof(uint32_t); + j++) { + for (k = 0; + k < sizeof(hashtest_key_lens) / sizeof(uint32_t); + k++) { + run_hash_func_test(hashtest_funcs[i], + hashtest_initvals[j], + hashtest_key_lens[k]); + } + } + } +} + /* * Basic sequence of operations for a single key: * - add @@ -500,6 +294,7 @@ static struct rte_hash_parameters ut_params = { static int test_add_delete(void) { struct rte_hash *handle; + /* test with standard add/lookup/delete functions */ int pos0, expectedPos0; ut_params.name = "test1"; @@ -527,19 +322,50 @@ static int test_add_delete(void) "fail: found key after deleting! (pos0=%d)", pos0); rte_hash_free(handle); + + /* repeat test with precomputed hash functions */ + hash_sig_t hash_value; + int pos1, expectedPos1; + + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + hash_value = rte_hash_hash(handle, &keys[0]); + pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value); + print_key_info("Add", &keys[0], pos1); + RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1); + expectedPos1 = pos1; + + pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); + print_key_info("Lkp", &keys[0], pos1); + RETURN_IF_ERROR(pos1 != expectedPos1, + "failed to find key (pos1=%d)", pos1); + + pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value); + print_key_info("Del", &keys[0], pos1); + RETURN_IF_ERROR(pos1 != expectedPos1, + "failed to delete key (pos1=%d)", pos1); + + pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value); + print_key_info("Lkp", &keys[0], pos1); + RETURN_IF_ERROR(pos1 != -ENOENT, + "fail: found key after deleting! (pos1=%d)", pos1); + + rte_hash_free(handle); + return 0; } /* * Sequence of operations for a single key: - * - delete: miss - * - add - * - lookup: hit - * - add: update - * - lookup: hit (updated data) - * - delete: hit - * - delete: miss - * - lookup: miss + * - delete: miss + * - add + * - lookup: hit + * - add: update + * - lookup: hit (updated data) + * - delete: hit + * - delete: miss + * - lookup: miss */ static int test_add_update_delete(void) { @@ -594,6 +420,46 @@ static int test_add_update_delete(void) return 0; } +/* + * Sequence of operations for retrieving a key with its position + * + * - create table + * - add key + * - get the key with its position: hit + * - delete key + * - try to get the deleted key: miss + * + */ +static int test_hash_get_key_with_position(void) +{ + struct rte_hash *handle = NULL; + int pos, expectedPos, result; + void *key; + + ut_params.name = "hash_get_key_w_pos"; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + pos = rte_hash_add_key(handle, &keys[0]); + print_key_info("Add", &keys[0], pos); + RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos); + expectedPos = pos; + + result = rte_hash_get_key_with_position(handle, pos, &key); + RETURN_IF_ERROR(result != 0, "error retrieving a key"); + + pos = rte_hash_del_key(handle, &keys[0]); + print_key_info("Del", &keys[0], pos); + RETURN_IF_ERROR(pos != expectedPos, + "failed to delete key (pos0=%d)", pos); + + result = rte_hash_get_key_with_position(handle, pos, &key); + RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved"); + + rte_hash_free(handle); + return 0; +} + /* * Sequence of operations for find existing hash table * @@ -660,7 +526,7 @@ static int test_five_keys(void) for(i = 0; i < 5; i++) key_array[i] = &keys[i]; - ret = rte_hash_lookup_multi(handle, &key_array[0], 5, (int32_t *)pos); + ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); if(ret == 0) for(i = 0; i < 5; i++) { print_key_info("Lkp", key_array[i], pos[i]); @@ -697,9 +563,18 @@ static int test_five_keys(void) pos[i] = rte_hash_lookup(handle, &keys[i]); print_key_info("Lkp", &keys[i], pos[i]); RETURN_IF_ERROR(pos[i] != -ENOENT, - "failed to find key (pos[%u]=%d)", i, pos[i]); + "found non-existent key (pos[%u]=%d)", i, pos[i]); } + /* Lookup multi */ + ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos); + if (ret == 0) + for (i = 0; i < 5; i++) { + print_key_info("Lkp", key_array[i], pos[i]); + RETURN_IF_ERROR(pos[i] != -ENOENT, + "found not-existent key (pos[%u]=%d)", i, pos[i]); + } + rte_hash_free(handle); return 0; @@ -707,22 +582,19 @@ static int test_five_keys(void) /* * Add keys to the same bucket until bucket full. - * - add 5 keys to the same bucket (hash created with 4 keys per bucket): - * first 4 successful, 5th unsuccessful - * - lookup the 5 keys: 4 hits, 1 miss - * - add the 5 keys again: 4 OK, one error as bucket is full - * - lookup the 5 keys: 4 hits (updated data), 1 miss - * - delete the 5 keys: 5 OK (even if the 5th is not in the table) - * - lookup the 5 keys: 5 misses - * - add the 5th key: OK - * - lookup the 5th key: hit + * - add 5 keys to the same bucket (hash created with 4 keys per bucket): + * first 4 successful, 5th successful, pushing existing item in bucket + * - lookup the 5 keys: 5 hits + * - add the 5 keys again: 5 OK + * - lookup the 5 keys: 5 hits (updated data) + * - delete the 5 keys: 5 OK + * - lookup the 5 keys: 5 misses */ static int test_full_bucket(void) { struct rte_hash_parameters params_pseudo_hash = { .name = "test4", .entries = 64, - .bucket_entries = 4, .key_len = sizeof(struct flow_key), /* 13 */ .hash_func = pseudo_hash, .hash_func_init_val = 0, @@ -736,7 +608,7 @@ static int test_full_bucket(void) handle = rte_hash_create(¶ms_pseudo_hash); RETURN_IF_ERROR(handle == NULL, "hash creation failed"); - /* Fill bucket*/ + /* Fill bucket */ for (i = 0; i < 4; i++) { pos[i] = rte_hash_add_key(handle, &keys[i]); print_key_info("Add", &keys[i], pos[i]); @@ -744,47 +616,39 @@ static int test_full_bucket(void) "failed to add key (pos[%u]=%d)", i, pos[i]); expected_pos[i] = pos[i]; } - /* This shouldn't work because the bucket is full */ + /* + * This should work and will push one of the items + * in the bucket because it is full + */ pos[4] = rte_hash_add_key(handle, &keys[4]); print_key_info("Add", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] != -ENOSPC, - "fail: added key to full bucket (pos[4]=%d)", pos[4]); + RETURN_IF_ERROR(pos[4] < 0, + "failed to add key (pos[4]=%d)", pos[4]); + expected_pos[4] = pos[4]; /* Lookup */ - for (i = 0; i < 4; i++) { + for (i = 0; i < 5; i++) { pos[i] = rte_hash_lookup(handle, &keys[i]); print_key_info("Lkp", &keys[i], pos[i]); RETURN_IF_ERROR(pos[i] != expected_pos[i], "failed to find key (pos[%u]=%d)", i, pos[i]); } - pos[4] = rte_hash_lookup(handle, &keys[4]); - print_key_info("Lkp", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] != -ENOENT, - "fail: found non-existent key (pos[4]=%d)", pos[4]); /* Add - update */ - for (i = 0; i < 4; i++) { + for (i = 0; i < 5; i++) { pos[i] = rte_hash_add_key(handle, &keys[i]); print_key_info("Add", &keys[i], pos[i]); RETURN_IF_ERROR(pos[i] != expected_pos[i], "failed to add key (pos[%u]=%d)", i, pos[i]); } - pos[4] = rte_hash_add_key(handle, &keys[4]); - print_key_info("Add", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] != -ENOSPC, - "fail: added key to full bucket (pos[4]=%d)", pos[4]); /* Lookup */ - for (i = 0; i < 4; i++) { + for (i = 0; i < 5; i++) { pos[i] = rte_hash_lookup(handle, &keys[i]); print_key_info("Lkp", &keys[i], pos[i]); RETURN_IF_ERROR(pos[i] != expected_pos[i], "failed to find key (pos[%u]=%d)", i, pos[i]); } - pos[4] = rte_hash_lookup(handle, &keys[4]); - print_key_info("Lkp", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] != -ENOENT, - "fail: found non-existent key (pos[4]=%d)", pos[4]); /* Delete 1 key, check other keys are still found */ pos[1] = rte_hash_del_key(handle, &keys[1]); @@ -804,35 +668,21 @@ static int test_full_bucket(void) RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]); /* Delete */ - for (i = 0; i < 4; i++) { + for (i = 0; i < 5; i++) { pos[i] = rte_hash_del_key(handle, &keys[i]); print_key_info("Del", &keys[i], pos[i]); RETURN_IF_ERROR(pos[i] != expected_pos[i], "failed to delete key (pos[%u]=%d)", i, pos[i]); } - pos[4] = rte_hash_del_key(handle, &keys[4]); - print_key_info("Del", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] != -ENOENT, - "fail: deleted non-existent key (pos[4]=%d)", pos[4]); /* Lookup */ - for (i = 0; i < 4; i++) { + for (i = 0; i < 5; i++) { pos[i] = rte_hash_lookup(handle, &keys[i]); print_key_info("Lkp", &keys[i], pos[i]); RETURN_IF_ERROR(pos[i] != -ENOENT, "fail: found non-existent key (pos[%u]=%d)", i, pos[i]); } - /* Add and lookup the 5th key */ - pos[4] = rte_hash_add_key(handle, &keys[4]); - print_key_info("Add", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] < 0, "failed to add key (pos[4]=%d)", pos[4]); - expected_pos[4] = pos[4]; - pos[4] = rte_hash_lookup(handle, &keys[4]); - print_key_info("Lkp", &keys[4], pos[4]); - RETURN_IF_ERROR(pos[4] != expected_pos[4], - "failed to find key (pos[4]=%d)", pos[4]); - rte_hash_free(handle); /* Cover the NULL case. */ @@ -840,285 +690,6 @@ static int test_full_bucket(void) return 0; } -/* - * To help print out name of hash functions. - */ -static const char *get_hash_name(rte_hash_function f) -{ - if (f == rte_jhash) - return "jhash"; - - if (f == rte_hash_crc) - return "rte_hash_crc"; - - return "UnknownHash"; -} - -/* - * Find average of array of numbers. - */ -static double -get_avg(const uint32_t *array, uint32_t size) -{ - double sum = 0; - unsigned i; - for (i = 0; i < size; i++) - sum += array[i]; - return sum / (double)size; -} - -/* - * 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. - */ -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) -{ - 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 = (uint8_t *) rte_zmalloc("hash key", - params->key_len * sizeof(uint8_t), 16); - if (key == NULL) - return -1; - - bucket_occupancies = (uint32_t *) rte_zmalloc("bucket occupancies", - num_buckets * sizeof(uint32_t), 16); - if (bucket_occupancies == NULL) { - rte_free(key); - return -1; - } - - ticks = 0; - *invalid_pos_count = 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(); - - /* Perform operation, and measure time it takes */ - begin = rte_rdtsc(); - pos = func(h, key); - end = rte_rdtsc(); - ticks += end - begin; - - /* Other work per iteration */ - if (pos < 0) - *invalid_pos_count += 1; - else - bucket_occupancies[pos / params->bucket_entries]++; - } - *avg_occupancy = get_avg(bucket_occupancies, num_buckets); - - rte_free(bucket_occupancies); - rte_free(key); - - return (double)ticks / params->num_iterations; -} - -/* - * To help print out what tests are being done. - */ -static const char * -get_tbl_perf_test_desc(enum hash_test_t type) -{ - 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"; - } -} - -/* - * Run a hash table performance test based on params. - */ -static int -run_tbl_perf_test(struct tbl_perf_test_params *params) -{ - 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 = 0, - }; - 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]; - - rte_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; - } - - rte_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); - return 0; -} - -/* - * Run all hash table performance tests. - */ -static int run_all_tbl_perf_tests(void) -{ - unsigned i; - - 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"); - - /* Loop through every combination of test parameters */ - for (i = 0; - i < sizeof(tbl_perf_params) / sizeof(struct tbl_perf_test_params); - i++) { - - /* Perform test */ - if (run_tbl_perf_test(&tbl_perf_params[i]) < 0) - return -1; - } - return 0; -} - -/* - * Test a hash function. - */ -static void run_hash_func_test(rte_hash_function f, uint32_t init_val, - uint32_t key_len) -{ - static uint8_t key[RTE_HASH_KEY_LENGTH_MAX]; - uint64_t ticks = 0, start, end; - unsigned i, j; - - for (i = 0; i < HASHTEST_ITERATIONS; i++) { - - for (j = 0; j < key_len; j++) - key[j] = (uint8_t) rte_rand(); - - start = rte_rdtsc(); - f(key, key_len, init_val); - end = rte_rdtsc(); - ticks += end - start; - } - - printf("%-12s, %-18u, %-13u, %.02f\n", get_hash_name(f), (unsigned) key_len, - (unsigned) init_val, (double)ticks / HASHTEST_ITERATIONS); -} - -/* - * Test all hash functions. - */ -static void run_hash_func_tests(void) -{ - unsigned i, j, k; - - printf("\n\n *** Hash function performance test results ***\n"); - printf(" Number of iterations for each test = %d\n", - HASHTEST_ITERATIONS); - printf("Hash Func. , Key Length (bytes), Initial value, Ticks/Op.\n"); - - for (i = 0; - i < sizeof(hashtest_funcs) / sizeof(rte_hash_function); - i++) { - for (j = 0; - j < sizeof(hashtest_initvals) / sizeof(uint32_t); - j++) { - for (k = 0; - k < sizeof(hashtest_key_lens) / sizeof(uint32_t); - k++) { - run_hash_func_test(hashtest_funcs[i], - hashtest_initvals[j], - hashtest_key_lens[k]); - } - } - } -} - /******************************************************************************/ static int fbk_hash_unit_test(void) @@ -1138,40 +709,85 @@ fbk_hash_unit_test(void) }; struct rte_fbk_hash_params invalid_params_2 = { - .name = "invalid_4", + .name = "invalid_2", .entries = 4, .entries_per_bucket = 3, /* Not power of 2 */ .socket_id = 0, }; struct rte_fbk_hash_params invalid_params_3 = { - .name = "invalid_2", + .name = "invalid_3", .entries = 0, /* Entries is 0 */ .entries_per_bucket = 4, .socket_id = 0, }; struct rte_fbk_hash_params invalid_params_4 = { - .name = "invalid_3", + .name = "invalid_4", .entries = LOCAL_FBK_HASH_ENTRIES_MAX, .entries_per_bucket = 0, /* Entries per bucket is 0 */ .socket_id = 0, }; struct rte_fbk_hash_params invalid_params_5 = { - .name = "invalid_4", + .name = "invalid_5", .entries = 4, .entries_per_bucket = 8, /* Entries per bucket > entries */ .socket_id = 0, }; struct rte_fbk_hash_params invalid_params_6 = { - .name = "invalid_5", + .name = "invalid_6", .entries = RTE_FBK_HASH_ENTRIES_MAX * 2, /* Entries > max allowed */ .entries_per_bucket = 4, .socket_id = 0, }; + struct rte_fbk_hash_params invalid_params_7 = { + .name = "invalid_7", + .entries = RTE_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2, /* Entries > max allowed */ + .socket_id = 0, + }; + + struct rte_fbk_hash_params invalid_params_8 = { + .name = "invalid_7", + .entries = RTE_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */ + }; + + /* try to create two hashes with identical names + * in this case, trying to create a second one will not + * fail but will simply return pointer to the existing + * hash with that name. sort of like a "find hash by name" :-) + */ + struct rte_fbk_hash_params invalid_params_same_name_1 = { + .name = "same_name", /* hash with identical name */ + .entries = 4, + .entries_per_bucket = 2, + .socket_id = 0, + }; + + /* trying to create this hash should return a pointer to an existing hash */ + struct rte_fbk_hash_params invalid_params_same_name_2 = { + .name = "same_name", /* hash with identical name */ + .entries = RTE_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + }; + + /* this is a sanity check for "same name" test + * creating this hash will check if we are actually able to create + * multiple hashes with different names (instead of having just one). + */ + struct rte_fbk_hash_params different_name = { + .name = "different_name", /* different name */ + .entries = LOCAL_FBK_HASH_ENTRIES_MAX, + .entries_per_bucket = 4, + .socket_id = 0, + }; + struct rte_fbk_hash_params params_jhash = { .name = "valid", .entries = LOCAL_FBK_HASH_ENTRIES_MAX, @@ -1186,11 +802,11 @@ fbk_hash_unit_test(void) .entries = LOCAL_FBK_HASH_ENTRIES_MAX, .entries_per_bucket = 4, .socket_id = 0, - .hash_func = 0, /* Tests for null hash_func */ + .hash_func = NULL, /* Tests for null hash_func */ .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT, }; - struct rte_fbk_hash_table *handle; + struct rte_fbk_hash_table *handle, *tmp; uint32_t keys[5] = {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9}; uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571}; @@ -1199,6 +815,8 @@ fbk_hash_unit_test(void) double used_entries; /* Try creating hashes with invalid parameters */ + printf("# Testing hash creation with invalid parameters " + "- expect error msgs\n"); handle = rte_fbk_hash_create(&invalid_params_1); RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); @@ -1217,6 +835,31 @@ fbk_hash_unit_test(void) handle = rte_fbk_hash_create(&invalid_params_6); RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + handle = rte_fbk_hash_create(&invalid_params_7); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_8); + RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed"); + + handle = rte_fbk_hash_create(&invalid_params_same_name_1); + RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded"); + + tmp = rte_fbk_hash_create(&invalid_params_same_name_2); + if (tmp != NULL) + rte_fbk_hash_free(tmp); + RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed"); + + /* we are not freeing handle here because we need a hash list + * to be not empty for the next test */ + + /* create a hash in non-empty list - good for coverage */ + tmp = rte_fbk_hash_create(&different_name); + RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded"); + + /* free both hashes */ + rte_fbk_hash_free(handle); + rte_fbk_hash_free(tmp); + /* Create empty jhash hash. */ handle = rte_fbk_hash_create(¶ms_jhash); RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed"); @@ -1306,86 +949,36 @@ fbk_hash_unit_test(void) "fbk hash lookup should have failed"); } - /* Cleanup. */ - rte_fbk_hash_free(handle); - - /* Cover the NULL case. */ - rte_fbk_hash_free(0); - - return 0; -} - -/* Control operation of performance testing of fbk hash. */ -#define LOAD_FACTOR 0.667 /* How full to make the hash table. */ -#define TEST_SIZE 1000000 /* How many operations to time. */ -#define TEST_ITERATIONS 30 /* How many measurements to take. */ -#define ENTRIES (1 << 15) /* How many entries. */ - -static int -fbk_hash_perf_test(void) -{ - struct rte_fbk_hash_params params = { - .name = "fbk_hash_test", - .entries = ENTRIES, - .entries_per_bucket = 4, - .socket_id = 0, - }; - struct rte_fbk_hash_table *handle; - uint32_t keys[ENTRIES] = {0}; - unsigned indexes[TEST_SIZE]; - uint64_t lookup_time = 0; - unsigned added = 0; - unsigned value = 0; - unsigned i, j; - - handle = rte_fbk_hash_create(¶ms); - RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed"); + /* coverage */ - /* Generate random keys and values. */ - for (i = 0; i < ENTRIES; i++) { - uint32_t key = (uint32_t)rte_rand(); - key = ((uint64_t)key << 32) | (uint64_t)rte_rand(); - uint16_t val = (uint16_t)rte_rand(); + /* fill up the hash_table */ + for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++) + rte_fbk_hash_add_key(handle, i, (uint16_t) i); - if (rte_fbk_hash_add_key(handle, key, val) == 0) { - keys[added] = key; - added++; - } - if (added > (LOAD_FACTOR * ENTRIES)) { - break; - } - } + /* Find non-existent key in a full hashtable */ + status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); + RETURN_IF_ERROR_FBK(status != -ENOENT, + "fbk hash lookup succeeded"); - for (i = 0; i < TEST_ITERATIONS; i++) { - uint64_t begin; - uint64_t end; + /* Delete non-existent key in a full hashtable */ + status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1); + RETURN_IF_ERROR_FBK(status != -ENOENT, + "fbk hash delete succeeded"); - /* Generate random indexes into keys[] array. */ - for (j = 0; j < TEST_SIZE; j++) { - indexes[j] = rte_rand() % added; - } - - begin = rte_rdtsc(); - /* Do lookups */ - for (j = 0; j < TEST_SIZE; j++) { - value += rte_fbk_hash_lookup(handle, keys[indexes[j]]); - } - end = rte_rdtsc(); - lookup_time += (double)(end - begin); - } + /* Delete one key from a full hashtable */ + status = rte_fbk_hash_delete_key(handle, 1); + RETURN_IF_ERROR_FBK(status != 0, + "fbk hash delete failed"); - printf("\n\n *** FBK Hash function performance test results ***\n"); - /* - * The use of the 'value' variable ensures that the hash lookup is not - * being optimised out by the compiler. - */ - if (value != 0) - printf("Number of ticks per lookup = %g\n", - (double)lookup_time / - ((double)TEST_ITERATIONS * (double)TEST_SIZE)); + /* Clear all entries. */ + rte_fbk_hash_clear_all(handle); + /* Cleanup. */ rte_fbk_hash_free(handle); + /* Cover the NULL case. */ + rte_fbk_hash_free(0); + return 0; } @@ -1425,12 +1018,13 @@ static int test_fbk_hash_find_existing(void) return 0; } +#define BUCKET_ENTRIES 4 /* * Do tests for hash creation with bad parameters. */ static int test_hash_creation_with_bad_parameters(void) { - struct rte_hash *handle; + struct rte_hash *handle, *tmp; struct rte_hash_parameters params; handle = rte_hash_create(NULL); @@ -1450,19 +1044,9 @@ static int test_hash_creation_with_bad_parameters(void) return -1; } - memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_1"; - params.bucket_entries = RTE_HASH_BUCKET_ENTRIES_MAX + 1; - handle = rte_hash_create(¶ms); - if (handle != NULL) { - rte_hash_free(handle); - printf("Impossible creating hash sucessfully with bucket_entries in parameter exceeded\n"); - return -1; - } - memcpy(¶ms, &ut_params, sizeof(params)); params.name = "creation_with_bad_parameters_2"; - params.entries = params.bucket_entries - 1; + params.entries = BUCKET_ENTRIES - 1; handle = rte_hash_create(¶ms); if (handle != NULL) { rte_hash_free(handle); @@ -1472,45 +1056,190 @@ static int test_hash_creation_with_bad_parameters(void) memcpy(¶ms, &ut_params, sizeof(params)); params.name = "creation_with_bad_parameters_3"; - params.entries = params.entries - 1; + params.key_len = 0; handle = rte_hash_create(¶ms); if (handle != NULL) { rte_hash_free(handle); - printf("Impossible creating hash sucessfully if entries in parameter is not power of 2\n"); + printf("Impossible creating hash sucessfully if key_len in parameter is zero\n"); return -1; } memcpy(¶ms, &ut_params, sizeof(params)); params.name = "creation_with_bad_parameters_4"; - params.bucket_entries = params.bucket_entries - 1; + params.socket_id = RTE_MAX_NUMA_NODES + 1; handle = rte_hash_create(¶ms); if (handle != NULL) { rte_hash_free(handle); - printf("Impossible creating hash sucessfully if bucket_entries in parameter is not power of 2\n"); + printf("Impossible creating hash sucessfully with invalid socket\n"); return -1; } + /* test with same name should fail */ memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_5"; - params.key_len = 0; + params.name = "same_name"; handle = rte_hash_create(¶ms); - if (handle != NULL) { + if (handle == NULL) { + printf("Cannot create first hash table with 'same_name'\n"); + return -1; + } + tmp = rte_hash_create(¶ms); + if (tmp != NULL) { + printf("Creation of hash table with same name should fail\n"); rte_hash_free(handle); - printf("Impossible creating hash sucessfully if key_len in parameter is zero\n"); + rte_hash_free(tmp); return -1; } + rte_hash_free(handle); + + printf("# Test successful. No more errors expected\n"); + + return 0; +} +/* + * Do tests for hash creation with parameters that look incorrect + * but are actually valid. + */ +static int +test_hash_creation_with_good_parameters(void) +{ + struct rte_hash *handle; + struct rte_hash_parameters params; + + /* create with null hash function - should choose DEFAULT_HASH_FUNC */ memcpy(¶ms, &ut_params, sizeof(params)); - params.name = "creation_with_bad_parameters_6"; - params.key_len = RTE_HASH_KEY_LENGTH_MAX + 1; + params.name = "name"; + params.hash_func = NULL; handle = rte_hash_create(¶ms); - if (handle != NULL) { - rte_hash_free(handle); - printf("Impossible creating hash sucessfully if key_len is greater than the maximun\n"); + if (handle == NULL) { + printf("Creating hash with null hash_func failed\n"); return -1; } + rte_hash_free(handle); + + return 0; +} + +#define ITERATIONS 3 +/* + * 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[MAX_KEYSIZE]; + 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 << 16; + 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_reset(handle); + + /* 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; +} + +#define NUM_ENTRIES 256 +static int test_hash_iteration(void) +{ + struct rte_hash *handle; + unsigned i; + uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE]; + const void *next_key; + void *next_data; + void *data[NUM_ENTRIES]; + unsigned added_keys; + uint32_t iter = 0; + int ret = 0; + + ut_params.entries = NUM_ENTRIES; + ut_params.name = "test_hash_iteration"; + ut_params.hash_func = rte_jhash; + ut_params.key_len = 16; + handle = rte_hash_create(&ut_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + /* Add random entries until key cannot be added */ + for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) { + data[added_keys] = (void *) ((uintptr_t) rte_rand()); + for (i = 0; i < ut_params.key_len; i++) + keys[added_keys][i] = rte_rand() % 255; + ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]); + if (ret < 0) + break; + } + + /* Iterate through the hash table */ + while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) { + /* Search for the key in the list of keys added */ + for (i = 0; i < NUM_ENTRIES; i++) { + if (memcmp(next_key, keys[i], ut_params.key_len) == 0) { + if (next_data != data[i]) { + printf("Data found in the hash table is" + "not the data added with the key\n"); + goto err; + } + added_keys--; + break; + } + } + if (i == NUM_ENTRIES) { + printf("Key found in the hash table was not added\n"); + goto err; + } + } + + /* Check if all keys have been iterated */ + if (added_keys != 0) { + printf("There were still %u keys to iterate\n", added_keys); + goto err; + } + + rte_hash_free(handle); return 0; + +err: + rte_hash_free(handle); + return -1; } static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03, @@ -1520,7 +1249,6 @@ static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03, static struct rte_hash_parameters hash_params_ex = { .name = NULL, .entries = 64, - .bucket_entries = 4, .key_len = 0, .hash_func = NULL, .hash_func_init_val = 0, @@ -1539,7 +1267,7 @@ test_hash_add_delete_jhash2(void) hash_params_ex.name = "hash_test_jhash2"; hash_params_ex.key_len = 4; - hash_params_ex.hash_func = (rte_hash_function)rte_jhash2; + hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b; handle = rte_hash_create(&hash_params_ex); if (handle == NULL) { @@ -1578,7 +1306,7 @@ test_hash_add_delete_2_jhash2(void) hash_params_ex.name = "hash_test_2_jhash2"; hash_params_ex.key_len = 8; - hash_params_ex.hash_func = (rte_hash_function)rte_jhash2; + hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b; handle = rte_hash_create(&hash_params_ex); if (handle == NULL) @@ -1606,7 +1334,7 @@ test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval) { const uint32_t *k = key; - length =length; + RTE_SET_USED(length); return rte_jhash_1word(k[0], initval); } @@ -1616,7 +1344,7 @@ test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval) { const uint32_t *k = key; - length =length; + RTE_SET_USED(length); return rte_jhash_2words(k[0], k[1], initval); } @@ -1626,7 +1354,7 @@ test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval) { const uint32_t *k = key; - length =length; + RTE_SET_USED(length); return rte_jhash_3words(k[0], k[1], k[2], initval); } @@ -1739,7 +1467,8 @@ fail_jhash_3word: /* * Do all unit and performance tests. */ -int test_hash(void) +static int +test_hash(void) { if (test_add_delete() < 0) return -1; @@ -1753,6 +1482,8 @@ int test_hash(void) return -1; if (test_hash_add_delete_jhash_3word() < 0) return -1; + if (test_hash_get_key_with_position() < 0) + return -1; if (test_hash_find_existing() < 0) return -1; if (test_add_update_delete() < 0) @@ -1761,27 +1492,26 @@ int test_hash(void) return -1; if (test_full_bucket() < 0) return -1; - if (run_all_tbl_perf_tests() < 0) - return -1; - run_hash_func_tests(); if (test_fbk_hash_find_existing() < 0) return -1; if (fbk_hash_unit_test() < 0) return -1; - if (fbk_hash_perf_test() < 0) - return -1; if (test_hash_creation_with_bad_parameters() < 0) return -1; - return 0; -} -#else + if (test_hash_creation_with_good_parameters() < 0) + return -1; + if (test_average_table_utilization() < 0) + return -1; + if (test_hash_iteration() < 0) + return -1; + + run_hash_func_tests(); + + if (test_crc32_hash_alg_equiv() < 0) + return -1; -int -test_hash(void) -{ - printf("The Hash library is not included in this build\n"); return 0; } -#endif +REGISTER_TEST_COMMAND(hash_autotest, test_hash);