X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Ftest%2Ftest_hash_scaling.c;fp=test%2Ftest%2Ftest_hash_scaling.c;h=46c48e549b00b9897daeb08bbb1ca0d44cc61175;hb=7595afa4d30097c1177b69257118d8ad89a539be;hp=0000000000000000000000000000000000000000;hpb=ce3d555e43e3795b5d9507fcfc76b7a0a92fd0d6;p=deb_dpdk.git diff --git a/test/test/test_hash_scaling.c b/test/test/test_hash_scaling.c new file mode 100644 index 00000000..46c48e54 --- /dev/null +++ b/test/test/test_hash_scaling.c @@ -0,0 +1,220 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 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 + * are met: + * + * * 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 + * distribution. + * * 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include + +#include "test.h" + +/* + * 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) + +enum locking_mode_t { + NORMAL_LOCK, + LOCK_ELISION, + NULL_LOCK +}; + +struct { + uint32_t num_iterations; + struct rte_hash *h; + rte_spinlock_t *lock; + int locking_mode; +} tbl_scaling_test_params; + +static rte_atomic64_t gcycles; + +static int test_hash_scaling_worker(__attribute__((unused)) void *arg) +{ + uint64_t i, key; + uint32_t thr_id = rte_sys_gettid(); + uint64_t begin, cycles = 0; + + switch (tbl_scaling_test_params.locking_mode) { + + case NORMAL_LOCK: + + for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) { + /* different threads get different keys because + we use the thread-id in the key computation + */ + key = rte_hash_crc(&i, sizeof(i), thr_id); + begin = rte_rdtsc_precise(); + rte_spinlock_lock(tbl_scaling_test_params.lock); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + rte_spinlock_unlock(tbl_scaling_test_params.lock); + cycles += rte_rdtsc_precise() - begin; + } + break; + + case LOCK_ELISION: + + for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) { + key = rte_hash_crc(&i, sizeof(i), thr_id); + begin = rte_rdtsc_precise(); + rte_spinlock_lock_tm(tbl_scaling_test_params.lock); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + rte_spinlock_unlock_tm(tbl_scaling_test_params.lock); + cycles += rte_rdtsc_precise() - begin; + } + break; + + default: + + for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) { + key = rte_hash_crc(&i, sizeof(i), thr_id); + begin = rte_rdtsc_precise(); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + cycles += rte_rdtsc_precise() - begin; + } + } + + rte_atomic64_add(&gcycles, cycles); + + return 0; +} + +/* + * Do scalability perf tests. + */ +static int +test_hash_scaling(int locking_mode) +{ + static unsigned calledCount = 1; + uint32_t num_iterations = 1024*1024; + uint64_t i, key; + struct rte_hash_parameters hash_params = { + .entries = num_iterations*2, + .key_len = sizeof(key), + .hash_func = rte_hash_crc, + .hash_func_init_val = 0, + .socket_id = rte_socket_id(), + .extra_flag = RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT + }; + struct rte_hash *handle; + char name[RTE_HASH_NAMESIZE]; + rte_spinlock_t lock; + + rte_spinlock_init(&lock); + + snprintf(name, 32, "test%u", calledCount++); + hash_params.name = name; + + handle = rte_hash_create(&hash_params); + RETURN_IF_ERROR(handle == NULL, "hash creation failed"); + + tbl_scaling_test_params.num_iterations = + num_iterations/rte_lcore_count(); + tbl_scaling_test_params.h = handle; + tbl_scaling_test_params.lock = &lock; + tbl_scaling_test_params.locking_mode = locking_mode; + + rte_atomic64_init(&gcycles); + rte_atomic64_clear(&gcycles); + + /* fill up to initial size */ + for (i = 0; i < num_iterations; i++) { + key = rte_hash_crc(&i, sizeof(i), 0xabcdabcd); + rte_hash_add_key(tbl_scaling_test_params.h, &key); + } + + rte_eal_mp_remote_launch(test_hash_scaling_worker, NULL, CALL_MASTER); + rte_eal_mp_wait_lcore(); + + unsigned long long int cycles_per_operation = + rte_atomic64_read(&gcycles)/ + (tbl_scaling_test_params.num_iterations*rte_lcore_count()); + const char *lock_name; + + switch (locking_mode) { + case NORMAL_LOCK: + lock_name = "normal spinlock"; + break; + case LOCK_ELISION: + lock_name = "lock elision"; + break; + default: + lock_name = "null lock"; + } + printf("--------------------------------------------------------\n"); + printf("Cores: %d; %s mode -> cycles per operation: %llu\n", + rte_lcore_count(), lock_name, cycles_per_operation); + printf("--------------------------------------------------------\n"); + /* CSV output */ + printf(">>>%d,%s,%llu\n", rte_lcore_count(), lock_name, + cycles_per_operation); + + rte_hash_free(handle); + return 0; +} + +static int +test_hash_scaling_main(void) +{ + int r = 0; + + if (rte_lcore_count() == 1) + r = test_hash_scaling(NULL_LOCK); + + if (r == 0) + r = test_hash_scaling(NORMAL_LOCK); + + if (!rte_tm_supported()) { + printf("Hardware transactional memory (lock elision) is NOT supported\n"); + return r; + } + printf("Hardware transactional memory (lock elision) is supported\n"); + + if (r == 0) + r = test_hash_scaling(LOCK_ELISION); + + return r; +} + +REGISTER_TEST_COMMAND(hash_scaling_autotest, test_hash_scaling_main);