xref: /dpdk/app/test/test_trace_perf.c (revision 0efea35a2bb0ae9df6e204151c7f96b5eb93e130)
116a277a2SJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause
216a277a2SJerin Jacob  * Copyright(C) 2020 Marvell International Ltd.
316a277a2SJerin Jacob  */
416a277a2SJerin Jacob 
516a277a2SJerin Jacob #include <rte_cycles.h>
616a277a2SJerin Jacob #include <rte_debug.h>
716a277a2SJerin Jacob #include <rte_eal.h>
816a277a2SJerin Jacob #include <rte_eal_trace.h>
916a277a2SJerin Jacob #include <rte_malloc.h>
1016a277a2SJerin Jacob #include <rte_lcore.h>
1116a277a2SJerin Jacob 
1216a277a2SJerin Jacob #include "test.h"
1316a277a2SJerin Jacob #include "test_trace.h"
1416a277a2SJerin Jacob 
1516a277a2SJerin Jacob struct test_data;
1616a277a2SJerin Jacob 
17*0efea35aSTyler Retzlaff struct __rte_cache_aligned lcore_data {
1816a277a2SJerin Jacob 	volatile bool done;
1916a277a2SJerin Jacob 	volatile bool started;
2016a277a2SJerin Jacob 	uint64_t total_cycles;
2116a277a2SJerin Jacob 	uint64_t total_calls;
22*0efea35aSTyler Retzlaff };
2316a277a2SJerin Jacob 
24*0efea35aSTyler Retzlaff struct __rte_cache_aligned test_data {
2516a277a2SJerin Jacob 	unsigned int nb_workers;
2616a277a2SJerin Jacob 	struct lcore_data ldata[];
27*0efea35aSTyler Retzlaff };
2816a277a2SJerin Jacob 
2916a277a2SJerin Jacob #define STEP 100
3016a277a2SJerin Jacob #define CENT_OPS(OP) do {     \
3116a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3216a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3316a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3416a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3516a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3616a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3716a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3816a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
3916a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
4016a277a2SJerin Jacob OP; OP; OP; OP; OP; OP; OP; OP; OP; OP; \
4116a277a2SJerin Jacob } while (0)
4216a277a2SJerin Jacob 
4316a277a2SJerin Jacob static void
measure_perf(const char * str,struct test_data * data)4416a277a2SJerin Jacob measure_perf(const char *str, struct test_data *data)
4516a277a2SJerin Jacob {
4616a277a2SJerin Jacob 	uint64_t hz = rte_get_timer_hz();
4716a277a2SJerin Jacob 	uint64_t total_cycles = 0;
4816a277a2SJerin Jacob 	uint64_t total_calls = 0;
4916a277a2SJerin Jacob 	double cycles, ns;
5016a277a2SJerin Jacob 	unsigned int workers;
5116a277a2SJerin Jacob 
5216a277a2SJerin Jacob 	for (workers = 0; workers < data->nb_workers; workers++) {
5316a277a2SJerin Jacob 		total_cycles += data->ldata[workers].total_cycles;
5416a277a2SJerin Jacob 		total_calls += data->ldata[workers].total_calls;
5516a277a2SJerin Jacob 	}
5616a277a2SJerin Jacob 
5716a277a2SJerin Jacob 	cycles = total_calls ? (double)total_cycles / (double)total_calls : 0;
5816a277a2SJerin Jacob 	cycles /= STEP;
5916a277a2SJerin Jacob 	cycles /= 100; /* CENT_OPS */
6016a277a2SJerin Jacob 
6116a277a2SJerin Jacob 	ns = (cycles / (double)hz) * 1E9;
6216a277a2SJerin Jacob 	printf("%16s: cycles=%f ns=%f\n", str, cycles, ns);
6316a277a2SJerin Jacob }
6416a277a2SJerin Jacob 
6516a277a2SJerin Jacob static void
wait_till_workers_are_ready(struct test_data * data)6616a277a2SJerin Jacob wait_till_workers_are_ready(struct test_data *data)
6716a277a2SJerin Jacob {
6816a277a2SJerin Jacob 	unsigned int workers;
6916a277a2SJerin Jacob 
7016a277a2SJerin Jacob 	for (workers = 0; workers < data->nb_workers; workers++)
7116a277a2SJerin Jacob 		while (!data->ldata[workers].started)
7216a277a2SJerin Jacob 			rte_pause();
7316a277a2SJerin Jacob }
7416a277a2SJerin Jacob 
7516a277a2SJerin Jacob static void
signal_workers_to_finish(struct test_data * data)7616a277a2SJerin Jacob signal_workers_to_finish(struct test_data *data)
7716a277a2SJerin Jacob {
7816a277a2SJerin Jacob 	unsigned int workers;
7916a277a2SJerin Jacob 
8016a277a2SJerin Jacob 	for (workers = 0; workers < data->nb_workers; workers++) {
8116a277a2SJerin Jacob 		data->ldata[workers].done = 1;
8216a277a2SJerin Jacob 	}
8316a277a2SJerin Jacob }
8416a277a2SJerin Jacob 
8516a277a2SJerin Jacob #define WORKER_DEFINE(func) \
8616a277a2SJerin Jacob static void __rte_noinline \
8716a277a2SJerin Jacob __worker_##func(struct lcore_data *ldata) \
8816a277a2SJerin Jacob { \
8916a277a2SJerin Jacob 	uint64_t start; \
9016a277a2SJerin Jacob 	int i; \
9116a277a2SJerin Jacob 	while (!ldata->done) { \
9216a277a2SJerin Jacob 		start = rte_get_timer_cycles(); \
9316a277a2SJerin Jacob 		for (i = 0; i < STEP; i++) \
9416a277a2SJerin Jacob 			CENT_OPS(func); \
9516a277a2SJerin Jacob 		ldata->total_cycles += rte_get_timer_cycles() - start; \
9616a277a2SJerin Jacob 		ldata->total_calls++; \
9716a277a2SJerin Jacob 	} \
9816a277a2SJerin Jacob } \
9916a277a2SJerin Jacob static int \
10016a277a2SJerin Jacob worker_fn_##func(void *arg) \
10116a277a2SJerin Jacob { \
10216a277a2SJerin Jacob 	struct lcore_data *ldata = arg; \
10316a277a2SJerin Jacob 	ldata->started = 1; \
10416a277a2SJerin Jacob 	__worker_##func(ldata); \
10516a277a2SJerin Jacob 	return 0; \
10616a277a2SJerin Jacob }
10716a277a2SJerin Jacob 
10816a277a2SJerin Jacob 
10916a277a2SJerin Jacob /* Test to find trace overhead */
11016a277a2SJerin Jacob #define GENERIC_VOID rte_eal_trace_generic_void()
11116a277a2SJerin Jacob #define GENERIC_U64 rte_eal_trace_generic_u64(0x120000)
11216a277a2SJerin Jacob #define GENERIC_INT rte_eal_trace_generic_int(-34)
11316a277a2SJerin Jacob #define GENERIC_FLOAT rte_eal_trace_generic_float(3.3f)
11416a277a2SJerin Jacob #define GENERIC_DOUBLE rte_eal_trace_generic_double(3.66666)
11516a277a2SJerin Jacob #define GENERIC_STR rte_eal_trace_generic_str("hello world")
11616a277a2SJerin Jacob #define VOID_FP app_dpdk_test_fp()
11716a277a2SJerin Jacob 
11816a277a2SJerin Jacob WORKER_DEFINE(GENERIC_VOID)
WORKER_DEFINE(GENERIC_U64)11916a277a2SJerin Jacob WORKER_DEFINE(GENERIC_U64)
12016a277a2SJerin Jacob WORKER_DEFINE(GENERIC_INT)
12116a277a2SJerin Jacob WORKER_DEFINE(GENERIC_FLOAT)
12216a277a2SJerin Jacob WORKER_DEFINE(GENERIC_DOUBLE)
12316a277a2SJerin Jacob WORKER_DEFINE(GENERIC_STR)
12416a277a2SJerin Jacob WORKER_DEFINE(VOID_FP)
12516a277a2SJerin Jacob 
12616a277a2SJerin Jacob static void
12716a277a2SJerin Jacob run_test(const char *str, lcore_function_t f, struct test_data *data, size_t sz)
12816a277a2SJerin Jacob {
12916a277a2SJerin Jacob 	unsigned int id, worker = 0;
13016a277a2SJerin Jacob 
13116a277a2SJerin Jacob 	memset(data, 0, sz);
13216a277a2SJerin Jacob 	data->nb_workers = rte_lcore_count() - 1;
133cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(id)
13416a277a2SJerin Jacob 		rte_eal_remote_launch(f, &data->ldata[worker++], id);
13516a277a2SJerin Jacob 
13616a277a2SJerin Jacob 	wait_till_workers_are_ready(data);
13716a277a2SJerin Jacob 	rte_delay_ms(100); /* Wait for some time to accumulate the stats */
13816a277a2SJerin Jacob 	signal_workers_to_finish(data);
13916a277a2SJerin Jacob 
140cb056611SStephen Hemminger 	RTE_LCORE_FOREACH_WORKER(id)
14116a277a2SJerin Jacob 		rte_eal_wait_lcore(id);
142dda66e71SFeifei Wang 
143dda66e71SFeifei Wang 	measure_perf(str, data);
14416a277a2SJerin Jacob }
14516a277a2SJerin Jacob 
14616a277a2SJerin Jacob static int
test_trace_perf(void)14716a277a2SJerin Jacob test_trace_perf(void)
14816a277a2SJerin Jacob {
14916a277a2SJerin Jacob 	unsigned int nb_cores, nb_workers;
15016a277a2SJerin Jacob 	struct test_data *data;
15116a277a2SJerin Jacob 	size_t sz;
15216a277a2SJerin Jacob 
15316a277a2SJerin Jacob 	nb_cores = rte_lcore_count();
15416a277a2SJerin Jacob 	nb_workers = nb_cores - 1;
15516a277a2SJerin Jacob 	if (nb_cores < 2) {
15616a277a2SJerin Jacob 		printf("Need minimum two cores for testing\n");
15716a277a2SJerin Jacob 		return TEST_SKIPPED;
15816a277a2SJerin Jacob 	}
15916a277a2SJerin Jacob 
16016a277a2SJerin Jacob 	printf("Timer running at %5.2fMHz\n", rte_get_timer_hz()/1E6);
16116a277a2SJerin Jacob 	sz = sizeof(struct test_data);
16216a277a2SJerin Jacob 	sz += nb_workers * sizeof(struct lcore_data);
16316a277a2SJerin Jacob 
16416a277a2SJerin Jacob 	data = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE);
16516a277a2SJerin Jacob 	if (data == NULL) {
16616a277a2SJerin Jacob 		printf("Failed to allocate memory\n");
16716a277a2SJerin Jacob 		return TEST_FAILED;
16816a277a2SJerin Jacob 	}
16916a277a2SJerin Jacob 
17016a277a2SJerin Jacob 	run_test("void", worker_fn_GENERIC_VOID, data, sz);
17116a277a2SJerin Jacob 	run_test("u64", worker_fn_GENERIC_U64, data, sz);
17216a277a2SJerin Jacob 	run_test("int", worker_fn_GENERIC_INT, data, sz);
17316a277a2SJerin Jacob 	run_test("float", worker_fn_GENERIC_FLOAT, data, sz);
17416a277a2SJerin Jacob 	run_test("double", worker_fn_GENERIC_DOUBLE, data, sz);
17516a277a2SJerin Jacob 	run_test("string", worker_fn_GENERIC_STR, data, sz);
17616a277a2SJerin Jacob 	run_test("void_fp", worker_fn_VOID_FP, data, sz);
17716a277a2SJerin Jacob 
17816a277a2SJerin Jacob 	rte_free(data);
17916a277a2SJerin Jacob 	return TEST_SUCCESS;
18016a277a2SJerin Jacob }
18116a277a2SJerin Jacob 
182e0a8442cSBruce Richardson REGISTER_PERF_TEST(trace_perf_autotest, test_trace_perf);
183