[RFC,3/3] test/hash: add tests for integrated RCU QSBR
diff mbox series

Message ID 20190901065810.15137-4-dharmik.thakkar@arm.com
State New
Delegated to: David Marchand
Headers show
Series
  • Untitled series #6186
Related show

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/Intel-compilation success Compilation OK

Commit Message

Dharmik Thakkar Sept. 1, 2019, 6:58 a.m. UTC
Add functional and performance tests for the integrated RCU QSBR.

Suggested-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>
Signed-off-by: Dharmik Thakkar <dharmik.thakkar@arm.com>
---
 app/test/test_hash_readwrite_lf.c | 694 +++++++++++++++++++++++++++++-
 1 file changed, 693 insertions(+), 1 deletion(-)

Patch
diff mbox series

diff --git a/app/test/test_hash_readwrite_lf.c b/app/test/test_hash_readwrite_lf.c
index 1f2fba41f1b8..0846ed46ae52 100644
--- a/app/test/test_hash_readwrite_lf.c
+++ b/app/test/test_hash_readwrite_lf.c
@@ -13,6 +13,7 @@ 
 #include <rte_malloc.h>
 #include <rte_random.h>
 #include <rte_spinlock.h>
+#include <rte_rcu_qsbr.h>
 
 #include "test.h"
 
@@ -58,6 +59,7 @@  struct rwc_perf {
 	uint32_t w_ks_r_miss[2][NUM_TEST];
 	uint32_t multi_rw[NUM_TEST - 1][2][NUM_TEST];
 	uint32_t w_ks_r_hit_extbkt[2][NUM_TEST];
+	uint32_t writer_add_del[NUM_TEST];
 };
 
 static struct rwc_perf rwc_lf_results, rwc_non_lf_results;
@@ -84,12 +86,15 @@  struct {
 
 static rte_atomic64_t gread_cycles;
 static rte_atomic64_t greads;
+static rte_atomic64_t gwrite_cycles;
+static rte_atomic64_t gwrites;
 
 static volatile uint8_t writer_done;
 
 uint16_t enabled_core_ids[RTE_MAX_LCORE];
 
 uint8_t *scanned_bkts;
+uint8_t no_free_on_del;
 
 static inline uint16_t
 get_short_sig(const hash_sig_t hash)
@@ -173,6 +178,9 @@  init_params(int rwc_lf, int use_jhash, int htm, int ext_bkt)
 	if (ext_bkt)
 		hash_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
 
+	if (no_free_on_del)
+		hash_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
+
 	hash_params.name = "tests";
 
 	handle = rte_hash_create(&hash_params);
@@ -1240,6 +1248,666 @@  test_hash_add_ks_lookup_hit_extbkt(struct rwc_perf *rwc_perf_results,
 	return -1;
 }
 
+static uint32_t *hash_data[TOTAL_ENTRY];
+static struct rte_rcu_qsbr *t;
+#define COUNTER_VALUE 4096
+#define TEST_RCU_MAX_LCORE 128
+static int
+test_rwc_rcu_reader(__attribute__((unused))void *arg)
+{
+	struct rte_rcu_qsbr *temp;
+	unsigned int i;
+	uint32_t lcore_id = rte_lcore_id();
+	uint32_t *pdata;
+	temp = t;
+
+	rte_rcu_qsbr_thread_register(temp, lcore_id);
+	do {
+		rte_rcu_qsbr_thread_online(temp, lcore_id);
+		for (i = 0; i < tbl_rwc_test_param.count_keys_no_ks; i++) {
+			rte_rcu_qsbr_lock(temp, lcore_id);
+			if (rte_hash_lookup_data(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i,
+					(void **)&pdata) != -ENOENT) {
+				if (pdata != NULL) {
+					pdata[lcore_id] = 0;
+					while (pdata[lcore_id] < COUNTER_VALUE)
+						pdata[lcore_id]++;
+				}
+			}
+			rte_rcu_qsbr_unlock(temp, lcore_id);
+		}
+		/* Update quiescent state counter */
+		rte_rcu_qsbr_quiescent(temp, lcore_id);
+		rte_rcu_qsbr_thread_offline(temp, lcore_id);
+	} while (!writer_done);
+	rte_rcu_qsbr_thread_unregister(temp, lcore_id);
+
+	return 0;
+}
+
+static int
+test_rwc_rcu_multi_writer(void *arg)
+{
+	int32_t pos;
+
+	uint32_t i, offset;
+	uint8_t pos_core = (uint32_t)((uintptr_t)arg);
+	offset = pos_core * tbl_rwc_test_param.single_insert;
+
+	for (i = offset; i < offset + tbl_rwc_test_param.single_insert; i++) {
+		/* Delete element from the shared data structure */
+		pos = rte_hash_del_key(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i);
+		if (no_free_on_del) {
+			if (rte_hash_free_key_with_position(tbl_rwc_test_param.h,
+								pos) < 0)
+				return -1;
+		}
+		if (pos < 0) {
+			printf("Delete key failed #%u at #%d\n",
+				tbl_rwc_test_param.keys_no_ks[i], i);
+			return -1;
+		}
+		rte_hash_add_key(tbl_rwc_test_param.h,
+				tbl_rwc_test_param.keys_no_ks + i);
+	}
+	return 0;
+}
+
+uint8_t error_state;
+static void
+free_hash_data(void *pdata)
+{
+	uint32_t i;
+	uint32_t *h_data = pdata;
+	if (h_data == NULL)
+		return;
+	for (i = 0; i < rwc_core_cnt[NUM_TEST - 1]; i++) {
+		if (h_data[i] != COUNTER_VALUE && h_data[i] != 0) {
+			printf("Reader did not complete\n");
+			__atomic_store_n(&error_state, 1, __ATOMIC_RELAXED);
+			return;
+		}
+	}
+	rte_free(pdata);
+	return;
+}
+
+/*
+ * Test integrated RCU with 'free' on hash_delete
+ * and with extended bkt feature disabled
+ */
+static int
+test_hash_rcu_free_on_del(__attribute__((unused))struct rwc_perf
+				*rwc_perf_results, int rwc_lf, int htm,
+				int ext_bkt)
+{
+	unsigned int n, m;
+	uint64_t i;
+	uint8_t write_type;
+	int use_jhash = 0;
+	no_free_on_del = 0;
+
+	if (init_params(rwc_lf, use_jhash, htm, ext_bkt) != 0)
+		goto err;
+
+	uint32_t sz;
+	sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
+	t = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
+	if (rte_hash_rcu_qsbr_add(tbl_rwc_test_param.h, t,
+				free_hash_data) < 0) {
+		printf("RCU init in hash failed\n");
+		return -1;
+	}
+	printf("\nTest: RCU - free on hash del - ext bkt disabled\n");
+	uint8_t pos_core;
+
+	for (m = 1; m < NUM_TEST; m++) {
+		/* Calculate keys added by each writer */
+		tbl_rwc_test_param.single_insert =
+			tbl_rwc_test_param.count_keys_no_ks / rwc_core_cnt[m];
+		for (n = 0; n < NUM_TEST; n++) {
+			unsigned int tot_lcore = rte_lcore_count();
+			if (tot_lcore < (rwc_core_cnt[n] +
+			     rwc_core_cnt[m] + 1))
+				goto finish;
+
+			printf("\nNumber of writers: %u", rwc_core_cnt[m]);
+			printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
+
+			rte_hash_reset(tbl_rwc_test_param.h);
+			writer_done = 0;
+			write_type = WRITE_NO_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			write_type = WRITE_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			for (i = 0; i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				hash_data[i] =
+					rte_zmalloc(NULL, sizeof(uint32_t)
+						* rwc_core_cnt[NUM_TEST - 1],
+						0);
+				if (hash_data[i] == NULL) {
+					printf("No memory\n");
+					return -1;
+				}
+			}
+			for (i = 0;
+				i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				if (rte_hash_add_key_data(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i,
+					(void *)((uintptr_t)hash_data[i]))
+					< 0) {
+					printf("Hash key add Failed #%d\n",
+						tbl_rwc_test_param.keys_no_ks[i]);
+					return -1;
+				}
+			}
+
+			rte_rcu_qsbr_init(t, TEST_RCU_MAX_LCORE);
+			/* Launch reader(s) */
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				rte_eal_remote_launch(test_rwc_rcu_reader,
+					(void *)(uintptr_t)rwc_core_cnt[m],
+					enabled_core_ids[i]);
+			pos_core = 0;
+			/* Launch writers */
+			for (; i <= rwc_core_cnt[m]
+			     + rwc_core_cnt[n];	i++) {
+				rte_eal_remote_launch
+					(test_rwc_rcu_multi_writer,
+					(void *)(uintptr_t)pos_core,
+					enabled_core_ids[i]);
+				pos_core++;
+			}
+
+			/* Wait for writers to complete */
+			for (i = rwc_core_cnt[n] + 1;
+			     i <= rwc_core_cnt[m] + rwc_core_cnt[n];
+			     i++)
+				rte_eal_wait_lcore(enabled_core_ids[i]);
+
+			writer_done = 1;
+
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
+					goto err;
+
+		}
+	}
+
+finish:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return 0;
+
+err:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return -1;
+}
+
+/*
+ * Test integrated RCU with NO 'free' on hash_delete
+ * and with extended bkt feature disabled
+ */
+static int
+test_hash_rcu_no_free_on_del(__attribute__((unused))struct rwc_perf
+				*rwc_perf_results, int rwc_lf, int htm,
+				int ext_bkt)
+{
+	unsigned int n, m;
+	uint64_t i;
+	uint8_t write_type;
+	int use_jhash = 0;
+	no_free_on_del = 1;
+
+	if (init_params(rwc_lf, use_jhash, htm, ext_bkt) != 0)
+		goto err;
+
+	uint32_t sz;
+	sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
+	t = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
+	if (rte_hash_rcu_qsbr_add(tbl_rwc_test_param.h, t,
+				free_hash_data) < 0) {
+		printf("RCU init in hash failed\n");
+		return -1;
+	}
+
+	printf("\nTest: RCU - no free on hash del - ext bkt disabled\n");
+	uint8_t pos_core;
+
+	for (m = 1; m < NUM_TEST; m++) {
+		/* Calculate keys added by each writer */
+		tbl_rwc_test_param.single_insert =
+			tbl_rwc_test_param.count_keys_no_ks / rwc_core_cnt[m];
+		for (n = 0; n < NUM_TEST; n++) {
+			unsigned int tot_lcore = rte_lcore_count();
+			if (tot_lcore < (rwc_core_cnt[n] +
+			     rwc_core_cnt[m] + 1))
+				goto finish;
+
+			printf("\nNumber of writers: %u", rwc_core_cnt[m]);
+			printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
+
+			rte_hash_reset(tbl_rwc_test_param.h);
+			writer_done = 0;
+			write_type = WRITE_NO_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			write_type = WRITE_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			for (i = 0; i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				hash_data[i] =
+					rte_zmalloc(NULL, sizeof(uint32_t)
+						* rwc_core_cnt[NUM_TEST - 1],
+						0);
+				if (hash_data[i] == NULL) {
+					printf("No memory\n");
+					return -1;
+				}
+			}
+			for (i = 0;
+				i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				if (rte_hash_add_key_data(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i,
+					(void *)((uintptr_t)hash_data[i]))
+					< 0) {
+					printf("Hash key add Failed #%d\n",
+						tbl_rwc_test_param.keys_no_ks[i]);
+					return -1;
+				}
+			}
+
+			rte_rcu_qsbr_init(t, TEST_RCU_MAX_LCORE);
+			/* Launch reader(s) */
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				rte_eal_remote_launch(test_rwc_rcu_reader,
+					(void *)(uintptr_t)rwc_core_cnt[m],
+					enabled_core_ids[i]);
+			pos_core = 0;
+			/* Launch writers */
+			for (; i <= rwc_core_cnt[m]
+			     + rwc_core_cnt[n];	i++) {
+				rte_eal_remote_launch
+					(test_rwc_rcu_multi_writer,
+					(void *)(uintptr_t)pos_core,
+					enabled_core_ids[i]);
+				pos_core++;
+			}
+			/* Wait for writers to complete */
+			for (i = rwc_core_cnt[n] + 1;
+			     i <= rwc_core_cnt[m] + rwc_core_cnt[n];
+			     i++)
+				rte_eal_wait_lcore(enabled_core_ids[i]);
+
+			writer_done = 1;
+
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
+					goto err;
+		}
+	}
+
+finish:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return 0;
+
+err:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return -1;
+}
+
+/*
+ * Test integrated RCU with 'free' on hash_delete
+ * and with extended bkt feature enabled
+ */
+static int
+test_hash_rcu_ext_bkt_free_on_del(__attribute__((unused))struct rwc_perf
+					*rwc_perf_results, int rwc_lf, int htm,
+					int ext_bkt)
+{
+	unsigned int n, m;
+	uint64_t i;
+	uint8_t write_type;
+	int use_jhash = 0;
+	no_free_on_del = 0;
+
+	if (init_params(rwc_lf, use_jhash, htm, ext_bkt) != 0)
+		goto err;
+
+	uint32_t sz;
+	sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
+	t = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
+	if (rte_hash_rcu_qsbr_add(tbl_rwc_test_param.h, t,
+				free_hash_data) < 0) {
+		printf("RCU init in hash failed\n");
+		return -1;
+	}
+
+	printf("\nTest: RCU - free on hash del - ext bkt enabled\n");
+	uint8_t pos_core;
+
+	for (m = 1; m < NUM_TEST; m++) {
+		/* Calculate keys added by each writer */
+		tbl_rwc_test_param.single_insert =
+			tbl_rwc_test_param.count_keys_no_ks / rwc_core_cnt[m];
+		for (n = 0; n < NUM_TEST; n++) {
+			unsigned int tot_lcore = rte_lcore_count();
+			if (tot_lcore < (rwc_core_cnt[n] +
+			     rwc_core_cnt[m] + 1))
+				goto finish;
+
+			printf("\nNumber of writers: %u", rwc_core_cnt[m]);
+			printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
+
+			rte_hash_reset(tbl_rwc_test_param.h);
+			writer_done = 0;
+			write_type = WRITE_NO_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			write_type = WRITE_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			for (i = 0; i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				hash_data[i] =
+					rte_zmalloc(NULL, sizeof(uint32_t)
+						* rwc_core_cnt[NUM_TEST - 1],
+						0);
+				if (hash_data[i] == NULL) {
+					printf("No memory\n");
+					return -1;
+				}
+			}
+			for (i = 0;
+				i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				if (rte_hash_add_key_data(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i,
+					(void *)((uintptr_t)hash_data[i]))
+					< 0) {
+					printf("Hash key add Failed #%d\n",
+						tbl_rwc_test_param.keys_no_ks[i]);
+					return -1;
+				}
+			}
+
+			rte_rcu_qsbr_init(t, TEST_RCU_MAX_LCORE);
+			/* Launch reader(s) */
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				rte_eal_remote_launch(test_rwc_rcu_reader,
+					(void *)(uintptr_t)rwc_core_cnt[m],
+					enabled_core_ids[i]);
+			pos_core = 0;
+			/* Launch writers */
+			for (; i <= rwc_core_cnt[m]
+			     + rwc_core_cnt[n];	i++) {
+				rte_eal_remote_launch
+					(test_rwc_rcu_multi_writer,
+					(void *)(uintptr_t)pos_core,
+					enabled_core_ids[i]);
+				pos_core++;
+			}
+			/* Wait for writers to complete */
+			for (i = rwc_core_cnt[n] + 1;
+			     i <= rwc_core_cnt[m] + rwc_core_cnt[n];
+			     i++)
+				rte_eal_wait_lcore(enabled_core_ids[i]);
+
+			writer_done = 1;
+
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
+					goto err;
+		}
+	}
+
+finish:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return 0;
+
+err:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return -1;
+}
+
+/*
+ * Test integrated RCU with NO 'free' on hash_delete
+ * and with extended bkt feature enabled
+ */
+static int
+test_hash_rcu_ext_bkt_no_free_on_del(__attribute__((unused))struct rwc_perf
+					*rwc_perf_results, int rwc_lf, int htm,
+					int ext_bkt)
+{
+	unsigned int n, m;
+	uint64_t i;
+	uint8_t write_type;
+	int use_jhash = 0;
+	no_free_on_del = 1;
+
+	if (init_params(rwc_lf, use_jhash, htm, ext_bkt) != 0)
+		goto err;
+
+	uint32_t sz;
+	sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
+	t = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
+	if (rte_hash_rcu_qsbr_add(tbl_rwc_test_param.h, t,
+				free_hash_data) < 0) {
+		printf("RCU init in hash failed\n");
+		return -1;
+	}
+
+	printf("\nTest: RCU - no free on hash del - ext bkt enabled\n");
+	uint8_t pos_core;
+
+	for (m = 1; m < NUM_TEST; m++) {
+		/* Calculate keys added by each writer */
+		tbl_rwc_test_param.single_insert =
+			tbl_rwc_test_param.count_keys_no_ks / rwc_core_cnt[m];
+		for (n = 0; n < NUM_TEST; n++) {
+			unsigned int tot_lcore = rte_lcore_count();
+			if (tot_lcore < (rwc_core_cnt[n] +
+			     rwc_core_cnt[m] + 1))
+				goto finish;
+
+			printf("\nNumber of writers: %u", rwc_core_cnt[m]);
+			printf("\nNumber of readers: %u\n", rwc_core_cnt[n]);
+
+			rte_hash_reset(tbl_rwc_test_param.h);
+			writer_done = 0;
+			write_type = WRITE_NO_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			write_type = WRITE_KEY_SHIFT;
+			if (write_keys(write_type) < 0)
+				goto err;
+			for (i = 0; i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				hash_data[i] =
+					rte_zmalloc(NULL, sizeof(uint32_t)
+						* rwc_core_cnt[NUM_TEST - 1],
+						0);
+				if (hash_data[i] == NULL) {
+					printf("No memory\n");
+					return -1;
+				}
+			}
+			for (i = 0;
+				i < tbl_rwc_test_param.count_keys_no_ks;
+				i++) {
+				if (rte_hash_add_key_data(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i,
+					(void *)((uintptr_t)hash_data[i]))
+					< 0) {
+					printf("Hash key add Failed #%d\n",
+						tbl_rwc_test_param.keys_no_ks[i]);
+					return -1;
+				}
+			}
+
+			rte_rcu_qsbr_init(t, TEST_RCU_MAX_LCORE);
+			/* Launch reader(s) */
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				rte_eal_remote_launch(test_rwc_rcu_reader,
+					(void *)(uintptr_t)rwc_core_cnt[m],
+					enabled_core_ids[i]);
+			pos_core = 0;
+			/* Launch writers */
+			for (; i <= rwc_core_cnt[m]
+			     + rwc_core_cnt[n];	i++) {
+				rte_eal_remote_launch
+					(test_rwc_rcu_multi_writer,
+					(void *)(uintptr_t)pos_core,
+					enabled_core_ids[i]);
+				pos_core++;
+			}
+			/* Wait for writers to complete */
+			for (i = rwc_core_cnt[n] + 1;
+			     i <= rwc_core_cnt[m] + rwc_core_cnt[n];
+			     i++)
+				rte_eal_wait_lcore(enabled_core_ids[i]);
+
+			writer_done = 1;
+
+			for (i = 1; i <= rwc_core_cnt[n]; i++)
+				if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
+					goto err;
+		}
+	}
+
+finish:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return 0;
+
+err:
+	rte_hash_free(tbl_rwc_test_param.h);
+	rte_free(t);
+	return -1;
+}
+
+static int
+test_multiwriter_perf(void *arg)
+{
+	uint32_t i, offset;
+	uint64_t begin, cycles;
+	uint8_t pos_core = (uint32_t)((uintptr_t)arg);
+	offset = pos_core * tbl_rwc_test_param.single_insert;
+
+	begin = rte_rdtsc_precise();
+	for (i = offset; i < offset + tbl_rwc_test_param.single_insert; i++) {
+		/* Delete element from the shared data structure */
+		rte_hash_del_key(tbl_rwc_test_param.h,
+					tbl_rwc_test_param.keys_no_ks + i);
+		rte_hash_add_key(tbl_rwc_test_param.h,
+				tbl_rwc_test_param.keys_no_ks + i);
+	}
+	cycles = rte_rdtsc_precise() - begin;
+	rte_atomic64_add(&gwrite_cycles, cycles);
+	rte_atomic64_add(&gwrites, tbl_rwc_test_param.single_insert);
+	return 0;
+}
+
+/*
+ * Test RCU perf:
+ * Writer(s) delete and add keys in the table.
+ */
+static int
+test_hash_writer_perf(struct rwc_perf *rwc_perf_results, int rwc_lf,
+				int htm, int ext_bkt)
+{
+	unsigned int n;
+	uint64_t i;
+	int use_jhash = 0;
+	uint8_t write_type;
+
+	no_free_on_del = 0;
+
+	rte_atomic64_init(&gwrites);
+	rte_atomic64_init(&gwrite_cycles);
+
+	if (init_params(rwc_lf, use_jhash, htm, ext_bkt) != 0)
+		goto err;
+
+	if (rwc_lf) {
+		uint32_t sz;
+		sz = rte_rcu_qsbr_get_memsize(TEST_RCU_MAX_LCORE);
+		t = (struct rte_rcu_qsbr *)rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
+		if (rte_hash_rcu_qsbr_add(tbl_rwc_test_param.h, t,
+					free_hash_data) < 0) {
+			printf("RCU init in hash failed\n");
+			return -1;
+		}
+		printf("\nTest: Writer perf with integrated RCU\n");
+	} else
+		printf("\nTest: Writer perf without integrated RCU\n");
+
+	for (n = 0; n < NUM_TEST; n++) {
+		unsigned int tot_lcore = rte_lcore_count();
+		if (tot_lcore < rwc_core_cnt[n] + 1)
+			goto finish;
+
+		/* Calculate keys added by each writer */
+		tbl_rwc_test_param.single_insert =
+			tbl_rwc_test_param.count_keys_no_ks /
+				rwc_core_cnt[n];
+		printf("\nNumber of writers: %u\n", rwc_core_cnt[n]);
+
+		rte_atomic64_clear(&gwrites);
+		rte_atomic64_clear(&gwrite_cycles);
+
+		rte_hash_reset(tbl_rwc_test_param.h);
+		if (rwc_lf)
+			rte_rcu_qsbr_init(t, TEST_RCU_MAX_LCORE);
+		write_type = WRITE_NO_KEY_SHIFT;
+		if (write_keys(write_type) < 0)
+			goto err;
+		write_type = WRITE_KEY_SHIFT;
+		if (write_keys(write_type) < 0)
+			goto err;
+		for (i = 1; i <= rwc_core_cnt[n]; i++)
+			rte_eal_remote_launch(test_multiwriter_perf,
+					(void *)(uintptr_t)(i - 1),
+						enabled_core_ids[i]);
+
+		rte_eal_mp_wait_lcore();
+
+		unsigned long long cycles_per_write_operation =
+			rte_atomic64_read(&gwrite_cycles) /
+			rte_atomic64_read(&gwrites);
+		rwc_perf_results->writer_add_del[n]
+					= cycles_per_write_operation;
+		printf("Cycles per write operation: %llu\n",
+				cycles_per_write_operation);
+	}
+
+finish:
+	rte_hash_free(tbl_rwc_test_param.h);
+	if (rwc_lf)
+		rte_free(t);
+	return 0;
+
+err:
+	rte_eal_mp_wait_lcore();
+	rte_hash_free(tbl_rwc_test_param.h);
+	if (rwc_lf)
+		rte_free(t);
+	return -1;
+}
+
 static int
 test_hash_readwrite_lf_main(void)
 {
@@ -1272,7 +1940,6 @@  test_hash_readwrite_lf_main(void)
 		return -1;
 	if (get_enabled_cores_list() != 0)
 		return -1;
-
 	if (RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF) {
 		rwc_lf = 1;
 		ext_bkt = 1;
@@ -1299,6 +1966,23 @@  test_hash_readwrite_lf_main(void)
 		if (test_hash_add_ks_lookup_hit_extbkt(&rwc_lf_results, rwc_lf,
 							htm, ext_bkt) < 0)
 			return -1;
+		ext_bkt = 0;
+		if (test_hash_rcu_free_on_del(&rwc_lf_results, rwc_lf, htm,
+						ext_bkt) < 0)
+			return -1;
+		if (test_hash_rcu_no_free_on_del(&rwc_lf_results, rwc_lf, htm,
+						ext_bkt) < 0)
+			return -1;
+		ext_bkt = 1;
+		if (test_hash_rcu_ext_bkt_free_on_del(&rwc_lf_results, rwc_lf,
+							htm, ext_bkt) < 0)
+			return -1;
+		if (test_hash_rcu_ext_bkt_no_free_on_del(&rwc_lf_results, rwc_lf
+							, htm, ext_bkt) < 0)
+			return -1;
+		if (test_hash_writer_perf(&rwc_lf_results, rwc_lf
+							, htm, ext_bkt) < 0)
+			return -1;
 	}
 	printf("\nTest lookup with read-write concurrency lock free support"
 	       " disabled\n");
@@ -1330,9 +2014,17 @@  test_hash_readwrite_lf_main(void)
 	if (test_hash_multi_add_lookup(&rwc_non_lf_results, rwc_lf, htm,
 							ext_bkt) < 0)
 		return -1;
+	no_free_on_del = 0;
 	if (test_hash_add_ks_lookup_hit_extbkt(&rwc_non_lf_results, rwc_lf,
 						htm, ext_bkt) < 0)
 		return -1;
+	if (test_hash_writer_perf(&rwc_non_lf_results, rwc_lf,
+						htm, ext_bkt) < 0)
+		return -1;
+
+	if (error_state != 0)
+		return -1;
+
 results:
 	printf("\n\t\t\t\t\t\t********** Results summary **********\n\n");
 	int i, j, k;