test/lpm: avoid code duplication in RCU perf tests
Avoid code duplication by combining single and multi threaded tests Also, enable support for more than 2 writers Signed-off-by: Dharmik Thakkar <dharmik.thakkar@arm.com> Reviewed-by: Ruifeng Wang <ruifeng.wang@arm.com> Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com> Acked-by: Vladimir Medvedkin <vladimir.medvedkin@intel.com>
This commit is contained in:
parent
f02383671a
commit
924e8e1a29
@ -23,6 +23,7 @@ static struct rte_rcu_qsbr *rv;
|
|||||||
static volatile uint8_t writer_done;
|
static volatile uint8_t writer_done;
|
||||||
static volatile uint32_t thr_id;
|
static volatile uint32_t thr_id;
|
||||||
static uint64_t gwrite_cycles;
|
static uint64_t gwrite_cycles;
|
||||||
|
static uint32_t num_writers;
|
||||||
/* LPM APIs are not thread safe, use mutex to provide thread safety */
|
/* LPM APIs are not thread safe, use mutex to provide thread safety */
|
||||||
static pthread_mutex_t lpm_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t lpm_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
@ -430,23 +431,18 @@ test_lpm_rcu_qsbr_writer(void *arg)
|
|||||||
{
|
{
|
||||||
unsigned int i, j, si, ei;
|
unsigned int i, j, si, ei;
|
||||||
uint64_t begin, total_cycles;
|
uint64_t begin, total_cycles;
|
||||||
uint8_t core_id = (uint8_t)((uintptr_t)arg);
|
|
||||||
uint32_t next_hop_add = 0xAA;
|
uint32_t next_hop_add = 0xAA;
|
||||||
|
uint8_t pos_core = (uint8_t)((uintptr_t)arg);
|
||||||
|
|
||||||
/* 2 writer threads are used */
|
si = (pos_core * NUM_LDEPTH_ROUTE_ENTRIES) / num_writers;
|
||||||
if (core_id % 2 == 0) {
|
ei = ((pos_core + 1) * NUM_LDEPTH_ROUTE_ENTRIES) / num_writers;
|
||||||
si = 0;
|
|
||||||
ei = NUM_LDEPTH_ROUTE_ENTRIES / 2;
|
|
||||||
} else {
|
|
||||||
si = NUM_LDEPTH_ROUTE_ENTRIES / 2;
|
|
||||||
ei = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Measure add/delete. */
|
/* Measure add/delete. */
|
||||||
begin = rte_rdtsc_precise();
|
begin = rte_rdtsc_precise();
|
||||||
for (i = 0; i < RCU_ITERATIONS; i++) {
|
for (i = 0; i < RCU_ITERATIONS; i++) {
|
||||||
/* Add all the entries */
|
/* Add all the entries */
|
||||||
for (j = si; j < ei; j++) {
|
for (j = si; j < ei; j++) {
|
||||||
|
if (num_writers > 1)
|
||||||
pthread_mutex_lock(&lpm_mutex);
|
pthread_mutex_lock(&lpm_mutex);
|
||||||
if (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,
|
if (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,
|
||||||
large_ldepth_route_table[j].depth,
|
large_ldepth_route_table[j].depth,
|
||||||
@ -455,11 +451,13 @@ test_lpm_rcu_qsbr_writer(void *arg)
|
|||||||
i, j);
|
i, j);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (num_writers > 1)
|
||||||
pthread_mutex_unlock(&lpm_mutex);
|
pthread_mutex_unlock(&lpm_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete all the entries */
|
/* Delete all the entries */
|
||||||
for (j = si; j < ei; j++) {
|
for (j = si; j < ei; j++) {
|
||||||
|
if (num_writers > 1)
|
||||||
pthread_mutex_lock(&lpm_mutex);
|
pthread_mutex_lock(&lpm_mutex);
|
||||||
if (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,
|
if (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,
|
||||||
large_ldepth_route_table[j].depth) != 0) {
|
large_ldepth_route_table[j].depth) != 0) {
|
||||||
@ -467,6 +465,7 @@ test_lpm_rcu_qsbr_writer(void *arg)
|
|||||||
i, j);
|
i, j);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (num_writers > 1)
|
||||||
pthread_mutex_unlock(&lpm_mutex);
|
pthread_mutex_unlock(&lpm_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -478,22 +477,24 @@ test_lpm_rcu_qsbr_writer(void *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
if (num_writers > 1)
|
||||||
pthread_mutex_unlock(&lpm_mutex);
|
pthread_mutex_unlock(&lpm_mutex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functional test:
|
* Functional test:
|
||||||
* 2 writers, rest are readers
|
* 1/2 writers, rest are readers
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
test_lpm_rcu_perf_multi_writer(void)
|
test_lpm_rcu_perf_multi_writer(uint8_t use_rcu)
|
||||||
{
|
{
|
||||||
struct rte_lpm_config config;
|
struct rte_lpm_config config;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
unsigned int i;
|
unsigned int i, j;
|
||||||
uint16_t core_id;
|
uint16_t core_id;
|
||||||
struct rte_lpm_rcu_config rcu_cfg = {0};
|
struct rte_lpm_rcu_config rcu_cfg = {0};
|
||||||
|
int (*reader_f)(void *arg) = NULL;
|
||||||
|
|
||||||
if (rte_lcore_count() < 3) {
|
if (rte_lcore_count() < 3) {
|
||||||
printf("Not enough cores for lpm_rcu_perf_autotest, expecting at least 3\n");
|
printf("Not enough cores for lpm_rcu_perf_autotest, expecting at least 3\n");
|
||||||
@ -506,8 +507,15 @@ test_lpm_rcu_perf_multi_writer(void)
|
|||||||
num_cores++;
|
num_cores++;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nPerf test: 2 writers, %d readers, RCU integration enabled\n",
|
for (j = 1; j < 3; j++) {
|
||||||
num_cores - 2);
|
if (use_rcu)
|
||||||
|
printf("\nPerf test: %d writer(s), %d reader(s),"
|
||||||
|
" RCU integration enabled\n", j, num_cores - j);
|
||||||
|
else
|
||||||
|
printf("\nPerf test: %d writer(s), %d reader(s),"
|
||||||
|
" RCU integration disabled\n", j, num_cores - j);
|
||||||
|
|
||||||
|
num_writers = j;
|
||||||
|
|
||||||
/* Create LPM table */
|
/* Create LPM table */
|
||||||
config.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;
|
config.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;
|
||||||
@ -517,6 +525,7 @@ test_lpm_rcu_perf_multi_writer(void)
|
|||||||
TEST_LPM_ASSERT(lpm != NULL);
|
TEST_LPM_ASSERT(lpm != NULL);
|
||||||
|
|
||||||
/* Init RCU variable */
|
/* Init RCU variable */
|
||||||
|
if (use_rcu) {
|
||||||
sz = rte_rcu_qsbr_get_memsize(num_cores);
|
sz = rte_rcu_qsbr_get_memsize(num_cores);
|
||||||
rv = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
|
rv = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
|
||||||
RTE_CACHE_LINE_SIZE);
|
RTE_CACHE_LINE_SIZE);
|
||||||
@ -529,24 +538,28 @@ test_lpm_rcu_perf_multi_writer(void)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader_f = test_lpm_rcu_qsbr_reader;
|
||||||
|
} else
|
||||||
|
reader_f = test_lpm_reader;
|
||||||
|
|
||||||
writer_done = 0;
|
writer_done = 0;
|
||||||
__atomic_store_n(&gwrite_cycles, 0, __ATOMIC_RELAXED);
|
__atomic_store_n(&gwrite_cycles, 0, __ATOMIC_RELAXED);
|
||||||
|
|
||||||
__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);
|
||||||
|
|
||||||
/* Launch reader threads */
|
/* Launch reader threads */
|
||||||
for (i = 2; i < num_cores; i++)
|
for (i = j; i < num_cores; i++)
|
||||||
rte_eal_remote_launch(test_lpm_rcu_qsbr_reader, NULL,
|
rte_eal_remote_launch(reader_f, NULL,
|
||||||
enabled_core_ids[i]);
|
enabled_core_ids[i]);
|
||||||
|
|
||||||
/* Launch writer threads */
|
/* Launch writer threads */
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < j; i++)
|
||||||
rte_eal_remote_launch(test_lpm_rcu_qsbr_writer,
|
rte_eal_remote_launch(test_lpm_rcu_qsbr_writer,
|
||||||
(void *)(uintptr_t)i,
|
(void *)(uintptr_t)i,
|
||||||
enabled_core_ids[i]);
|
enabled_core_ids[i]);
|
||||||
|
|
||||||
/* Wait for writer threads */
|
/* Wait for writer threads */
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < j; i++)
|
||||||
if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
|
if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -558,222 +571,15 @@ test_lpm_rcu_perf_multi_writer(void)
|
|||||||
|
|
||||||
writer_done = 1;
|
writer_done = 1;
|
||||||
/* Wait until all readers have exited */
|
/* Wait until all readers have exited */
|
||||||
for (i = 2; i < num_cores; i++)
|
for (i = j; i < num_cores; i++)
|
||||||
rte_eal_wait_lcore(enabled_core_ids[i]);
|
rte_eal_wait_lcore(enabled_core_ids[i]);
|
||||||
|
|
||||||
rte_lpm_free(lpm);
|
rte_lpm_free(lpm);
|
||||||
rte_free(rv);
|
rte_free(rv);
|
||||||
lpm = NULL;
|
lpm = NULL;
|
||||||
rv = NULL;
|
rv = NULL;
|
||||||
|
|
||||||
/* Test without RCU integration */
|
|
||||||
printf("\nPerf test: 2 writers, %d readers, RCU integration disabled\n",
|
|
||||||
num_cores - 2);
|
|
||||||
|
|
||||||
/* Create LPM table */
|
|
||||||
config.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
config.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
config.flags = 0;
|
|
||||||
lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
|
|
||||||
TEST_LPM_ASSERT(lpm != NULL);
|
|
||||||
|
|
||||||
writer_done = 0;
|
|
||||||
__atomic_store_n(&gwrite_cycles, 0, __ATOMIC_RELAXED);
|
|
||||||
__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);
|
|
||||||
|
|
||||||
/* Launch reader threads */
|
|
||||||
for (i = 2; i < num_cores; i++)
|
|
||||||
rte_eal_remote_launch(test_lpm_reader, NULL,
|
|
||||||
enabled_core_ids[i]);
|
|
||||||
|
|
||||||
/* Launch writer threads */
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
rte_eal_remote_launch(test_lpm_rcu_qsbr_writer,
|
|
||||||
(void *)(uintptr_t)i,
|
|
||||||
enabled_core_ids[i]);
|
|
||||||
|
|
||||||
/* Wait for writer threads */
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
if (rte_eal_wait_lcore(enabled_core_ids[i]) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
printf("Total LPM Adds: %d\n", TOTAL_WRITES);
|
|
||||||
printf("Total LPM Deletes: %d\n", TOTAL_WRITES);
|
|
||||||
printf("Average LPM Add/Del: %"PRIu64" cycles\n",
|
|
||||||
__atomic_load_n(&gwrite_cycles, __ATOMIC_RELAXED)
|
|
||||||
/ TOTAL_WRITES);
|
|
||||||
|
|
||||||
writer_done = 1;
|
|
||||||
/* Wait until all readers have exited */
|
|
||||||
for (i = 2; i < num_cores; i++)
|
|
||||||
rte_eal_wait_lcore(enabled_core_ids[i]);
|
|
||||||
|
|
||||||
rte_lpm_free(lpm);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
writer_done = 1;
|
|
||||||
/* Wait until all readers have exited */
|
|
||||||
rte_eal_mp_wait_lcore();
|
|
||||||
|
|
||||||
rte_lpm_free(lpm);
|
|
||||||
rte_free(rv);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Functional test:
|
|
||||||
* Single writer, rest are readers
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
test_lpm_rcu_perf(void)
|
|
||||||
{
|
|
||||||
struct rte_lpm_config config;
|
|
||||||
uint64_t begin, total_cycles;
|
|
||||||
size_t sz;
|
|
||||||
unsigned int i, j;
|
|
||||||
uint16_t core_id;
|
|
||||||
uint32_t next_hop_add = 0xAA;
|
|
||||||
struct rte_lpm_rcu_config rcu_cfg = {0};
|
|
||||||
|
|
||||||
if (rte_lcore_count() < 2) {
|
|
||||||
printf("Not enough cores for lpm_rcu_perf_autotest, expecting at least 2\n");
|
|
||||||
return TEST_SKIPPED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
num_cores = 0;
|
|
||||||
RTE_LCORE_FOREACH_WORKER(core_id) {
|
|
||||||
enabled_core_ids[num_cores] = core_id;
|
|
||||||
num_cores++;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nPerf test: 1 writer, %d readers, RCU integration enabled\n",
|
|
||||||
num_cores);
|
|
||||||
|
|
||||||
/* Create LPM table */
|
|
||||||
config.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
config.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
config.flags = 0;
|
|
||||||
lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
|
|
||||||
TEST_LPM_ASSERT(lpm != NULL);
|
|
||||||
|
|
||||||
/* Init RCU variable */
|
|
||||||
sz = rte_rcu_qsbr_get_memsize(num_cores);
|
|
||||||
rv = (struct rte_rcu_qsbr *)rte_zmalloc("rcu0", sz,
|
|
||||||
RTE_CACHE_LINE_SIZE);
|
|
||||||
rte_rcu_qsbr_init(rv, num_cores);
|
|
||||||
|
|
||||||
rcu_cfg.v = rv;
|
|
||||||
/* Assign the RCU variable to LPM */
|
|
||||||
if (rte_lpm_rcu_qsbr_add(lpm, &rcu_cfg) != 0) {
|
|
||||||
printf("RCU variable assignment failed\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
writer_done = 0;
|
|
||||||
__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);
|
|
||||||
|
|
||||||
/* Launch reader threads */
|
|
||||||
for (i = 0; i < num_cores; i++)
|
|
||||||
rte_eal_remote_launch(test_lpm_rcu_qsbr_reader, NULL,
|
|
||||||
enabled_core_ids[i]);
|
|
||||||
|
|
||||||
/* Measure add/delete. */
|
|
||||||
begin = rte_rdtsc_precise();
|
|
||||||
for (i = 0; i < RCU_ITERATIONS; i++) {
|
|
||||||
/* Add all the entries */
|
|
||||||
for (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)
|
|
||||||
if (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,
|
|
||||||
large_ldepth_route_table[j].depth,
|
|
||||||
next_hop_add) != 0) {
|
|
||||||
printf("Failed to add iteration %d, route# %d\n",
|
|
||||||
i, j);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete all the entries */
|
|
||||||
for (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)
|
|
||||||
if (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,
|
|
||||||
large_ldepth_route_table[j].depth) != 0) {
|
|
||||||
printf("Failed to delete iteration %d, route# %d\n",
|
|
||||||
i, j);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total_cycles = rte_rdtsc_precise() - begin;
|
|
||||||
|
|
||||||
printf("Total LPM Adds: %d\n", TOTAL_WRITES);
|
|
||||||
printf("Total LPM Deletes: %d\n", TOTAL_WRITES);
|
|
||||||
printf("Average LPM Add/Del: %g cycles\n",
|
|
||||||
(double)total_cycles / TOTAL_WRITES);
|
|
||||||
|
|
||||||
writer_done = 1;
|
|
||||||
/* Wait until all readers have exited */
|
|
||||||
for (i = 0; i < num_cores; i++)
|
|
||||||
rte_eal_wait_lcore(enabled_core_ids[i]);
|
|
||||||
|
|
||||||
rte_lpm_free(lpm);
|
|
||||||
rte_free(rv);
|
|
||||||
lpm = NULL;
|
|
||||||
rv = NULL;
|
|
||||||
|
|
||||||
/* Test without RCU integration */
|
|
||||||
printf("\nPerf test: 1 writer, %d readers, RCU integration disabled\n",
|
|
||||||
num_cores);
|
|
||||||
|
|
||||||
/* Create LPM table */
|
|
||||||
config.max_rules = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
config.number_tbl8s = NUM_LDEPTH_ROUTE_ENTRIES;
|
|
||||||
config.flags = 0;
|
|
||||||
lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
|
|
||||||
TEST_LPM_ASSERT(lpm != NULL);
|
|
||||||
|
|
||||||
writer_done = 0;
|
|
||||||
__atomic_store_n(&thr_id, 0, __ATOMIC_SEQ_CST);
|
|
||||||
|
|
||||||
/* Launch reader threads */
|
|
||||||
for (i = 0; i < num_cores; i++)
|
|
||||||
rte_eal_remote_launch(test_lpm_reader, NULL,
|
|
||||||
enabled_core_ids[i]);
|
|
||||||
|
|
||||||
/* Measure add/delete. */
|
|
||||||
begin = rte_rdtsc_precise();
|
|
||||||
for (i = 0; i < RCU_ITERATIONS; i++) {
|
|
||||||
/* Add all the entries */
|
|
||||||
for (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)
|
|
||||||
if (rte_lpm_add(lpm, large_ldepth_route_table[j].ip,
|
|
||||||
large_ldepth_route_table[j].depth,
|
|
||||||
next_hop_add) != 0) {
|
|
||||||
printf("Failed to add iteration %d, route# %d\n",
|
|
||||||
i, j);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete all the entries */
|
|
||||||
for (j = 0; j < NUM_LDEPTH_ROUTE_ENTRIES; j++)
|
|
||||||
if (rte_lpm_delete(lpm, large_ldepth_route_table[j].ip,
|
|
||||||
large_ldepth_route_table[j].depth) != 0) {
|
|
||||||
printf("Failed to delete iteration %d, route# %d\n",
|
|
||||||
i, j);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
total_cycles = rte_rdtsc_precise() - begin;
|
|
||||||
|
|
||||||
printf("Total LPM Adds: %d\n", TOTAL_WRITES);
|
|
||||||
printf("Total LPM Deletes: %d\n", TOTAL_WRITES);
|
|
||||||
printf("Average LPM Add/Del: %g cycles\n",
|
|
||||||
(double)total_cycles / TOTAL_WRITES);
|
|
||||||
|
|
||||||
writer_done = 1;
|
|
||||||
/* Wait until all readers have exited */
|
|
||||||
for (i = 0; i < num_cores; i++)
|
|
||||||
rte_eal_wait_lcore(enabled_core_ids[i]);
|
|
||||||
|
|
||||||
rte_lpm_free(lpm);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -948,10 +754,10 @@ test_lpm_perf(void)
|
|||||||
rte_lpm_delete_all(lpm);
|
rte_lpm_delete_all(lpm);
|
||||||
rte_lpm_free(lpm);
|
rte_lpm_free(lpm);
|
||||||
|
|
||||||
if (test_lpm_rcu_perf() < 0)
|
if (test_lpm_rcu_perf_multi_writer(0) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (test_lpm_rcu_perf_multi_writer() < 0)
|
if (test_lpm_rcu_perf_multi_writer(1) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user