1c62b318aSDmitry Kozlyuk /* SPDX-License-Identifier: BSD-3-Clause
2c62b318aSDmitry Kozlyuk * Copyright (c) 2021 NVIDIA Corporation & Affiliates
3c62b318aSDmitry Kozlyuk */
4c62b318aSDmitry Kozlyuk
5c62b318aSDmitry Kozlyuk #include <inttypes.h>
6c62b318aSDmitry Kozlyuk #include <string.h>
7c62b318aSDmitry Kozlyuk #include <rte_cycles.h>
8c62b318aSDmitry Kozlyuk #include <rte_errno.h>
9c62b318aSDmitry Kozlyuk #include <rte_malloc.h>
10c62b318aSDmitry Kozlyuk #include <rte_memzone.h>
11c62b318aSDmitry Kozlyuk
12c62b318aSDmitry Kozlyuk #include "test.h"
13c62b318aSDmitry Kozlyuk
14c62b318aSDmitry Kozlyuk #define TEST_LOG(level, ...) RTE_LOG(level, USER1, __VA_ARGS__)
15c62b318aSDmitry Kozlyuk
16c62b318aSDmitry Kozlyuk typedef void * (alloc_t)(const char *name, size_t size, unsigned int align);
17c62b318aSDmitry Kozlyuk typedef void (free_t)(void *addr);
18c62b318aSDmitry Kozlyuk typedef void * (memset_t)(void *addr, int value, size_t size);
19c62b318aSDmitry Kozlyuk
20c62b318aSDmitry Kozlyuk static const uint64_t KB = 1 << 10;
21c62b318aSDmitry Kozlyuk static const uint64_t GB = 1 << 30;
22c62b318aSDmitry Kozlyuk
23c62b318aSDmitry Kozlyuk static double
tsc_to_us(uint64_t tsc,size_t runs)24c62b318aSDmitry Kozlyuk tsc_to_us(uint64_t tsc, size_t runs)
25c62b318aSDmitry Kozlyuk {
26c62b318aSDmitry Kozlyuk return (double)tsc / rte_get_tsc_hz() * US_PER_S / runs;
27c62b318aSDmitry Kozlyuk }
28c62b318aSDmitry Kozlyuk
29c62b318aSDmitry Kozlyuk static int
test_memset_perf(double * us_per_gb)30c62b318aSDmitry Kozlyuk test_memset_perf(double *us_per_gb)
31c62b318aSDmitry Kozlyuk {
32c62b318aSDmitry Kozlyuk static const size_t RUNS = 20;
33c62b318aSDmitry Kozlyuk
34c62b318aSDmitry Kozlyuk void *ptr;
35c62b318aSDmitry Kozlyuk size_t i;
36c62b318aSDmitry Kozlyuk uint64_t tsc;
37c62b318aSDmitry Kozlyuk
38c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "Reference: memset\n");
39c62b318aSDmitry Kozlyuk
40c62b318aSDmitry Kozlyuk ptr = rte_malloc(NULL, GB, 0);
41c62b318aSDmitry Kozlyuk if (ptr == NULL) {
42c62b318aSDmitry Kozlyuk TEST_LOG(ERR, "rte_malloc(size=%"PRIx64") failed\n", GB);
43c62b318aSDmitry Kozlyuk return -1;
44c62b318aSDmitry Kozlyuk }
45c62b318aSDmitry Kozlyuk
46c62b318aSDmitry Kozlyuk tsc = rte_rdtsc_precise();
47c62b318aSDmitry Kozlyuk for (i = 0; i < RUNS; i++)
48c62b318aSDmitry Kozlyuk memset(ptr, 0, GB);
49c62b318aSDmitry Kozlyuk tsc = rte_rdtsc_precise() - tsc;
50c62b318aSDmitry Kozlyuk
51c62b318aSDmitry Kozlyuk *us_per_gb = tsc_to_us(tsc, RUNS);
52c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "Result: %f.3 GiB/s <=> %.2f us/MiB\n",
53c62b318aSDmitry Kozlyuk US_PER_S / *us_per_gb, *us_per_gb / KB);
54c62b318aSDmitry Kozlyuk
55c62b318aSDmitry Kozlyuk rte_free(ptr);
56c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "\n");
57c62b318aSDmitry Kozlyuk return 0;
58c62b318aSDmitry Kozlyuk }
59c62b318aSDmitry Kozlyuk
60c62b318aSDmitry Kozlyuk static int
test_alloc_perf(const char * name,alloc_t * alloc_fn,free_t * free_fn,memset_t * memset_fn,double memset_gb_us,size_t max_runs)61c62b318aSDmitry Kozlyuk test_alloc_perf(const char *name, alloc_t *alloc_fn, free_t *free_fn,
62c62b318aSDmitry Kozlyuk memset_t *memset_fn, double memset_gb_us, size_t max_runs)
63c62b318aSDmitry Kozlyuk {
64c62b318aSDmitry Kozlyuk static const size_t SIZES[] = {
65c62b318aSDmitry Kozlyuk 1 << 6, 1 << 7, 1 << 10, 1 << 12, 1 << 16, 1 << 20,
66c62b318aSDmitry Kozlyuk 1 << 21, 1 << 22, 1 << 24, 1 << 30 };
67c62b318aSDmitry Kozlyuk
68c62b318aSDmitry Kozlyuk size_t i, j;
69c62b318aSDmitry Kozlyuk void **ptrs;
70c62b318aSDmitry Kozlyuk
71c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "Performance: %s\n", name);
72c62b318aSDmitry Kozlyuk
73c62b318aSDmitry Kozlyuk ptrs = calloc(max_runs, sizeof(ptrs[0]));
74c62b318aSDmitry Kozlyuk if (ptrs == NULL) {
75c62b318aSDmitry Kozlyuk TEST_LOG(ERR, "Cannot allocate memory for pointers");
76c62b318aSDmitry Kozlyuk return -1;
77c62b318aSDmitry Kozlyuk }
78c62b318aSDmitry Kozlyuk
79c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "%12s%8s%12s%12s%12s%17s\n", "Size (B)", "Runs",
80c62b318aSDmitry Kozlyuk "Alloc (us)", "Free (us)", "Total (us)",
81c62b318aSDmitry Kozlyuk memset_fn != NULL ? "memset (us)" : "est.memset (us)");
82c62b318aSDmitry Kozlyuk for (i = 0; i < RTE_DIM(SIZES); i++) {
83c62b318aSDmitry Kozlyuk size_t size = SIZES[i];
84c62b318aSDmitry Kozlyuk size_t runs_done;
85c62b318aSDmitry Kozlyuk uint64_t tsc_start, tsc_alloc, tsc_memset = 0, tsc_free;
86c62b318aSDmitry Kozlyuk double alloc_time, free_time, memset_time;
87c62b318aSDmitry Kozlyuk
88c62b318aSDmitry Kozlyuk tsc_start = rte_rdtsc_precise();
89c62b318aSDmitry Kozlyuk for (j = 0; j < max_runs; j++) {
90c62b318aSDmitry Kozlyuk ptrs[j] = alloc_fn(NULL, size, 0);
91c62b318aSDmitry Kozlyuk if (ptrs[j] == NULL)
92c62b318aSDmitry Kozlyuk break;
93c62b318aSDmitry Kozlyuk }
94c62b318aSDmitry Kozlyuk tsc_alloc = rte_rdtsc_precise() - tsc_start;
95c62b318aSDmitry Kozlyuk
96c62b318aSDmitry Kozlyuk if (j == 0) {
97c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "%12zu Interrupted: out of memory.\n",
98c62b318aSDmitry Kozlyuk size);
99c62b318aSDmitry Kozlyuk break;
100c62b318aSDmitry Kozlyuk }
101c62b318aSDmitry Kozlyuk runs_done = j;
102c62b318aSDmitry Kozlyuk
103c62b318aSDmitry Kozlyuk if (memset_fn != NULL) {
104c62b318aSDmitry Kozlyuk tsc_start = rte_rdtsc_precise();
105c62b318aSDmitry Kozlyuk for (j = 0; j < runs_done && ptrs[j] != NULL; j++)
106c62b318aSDmitry Kozlyuk memset_fn(ptrs[j], 0, size);
107c62b318aSDmitry Kozlyuk tsc_memset = rte_rdtsc_precise() - tsc_start;
108c62b318aSDmitry Kozlyuk }
109c62b318aSDmitry Kozlyuk
110c62b318aSDmitry Kozlyuk tsc_start = rte_rdtsc_precise();
111c62b318aSDmitry Kozlyuk for (j = 0; j < runs_done && ptrs[j] != NULL; j++)
112c62b318aSDmitry Kozlyuk free_fn(ptrs[j]);
113c62b318aSDmitry Kozlyuk tsc_free = rte_rdtsc_precise() - tsc_start;
114c62b318aSDmitry Kozlyuk
115c62b318aSDmitry Kozlyuk alloc_time = tsc_to_us(tsc_alloc, runs_done);
116c62b318aSDmitry Kozlyuk free_time = tsc_to_us(tsc_free, runs_done);
117c62b318aSDmitry Kozlyuk memset_time = memset_fn != NULL ?
118c62b318aSDmitry Kozlyuk tsc_to_us(tsc_memset, runs_done) :
119c62b318aSDmitry Kozlyuk memset_gb_us * size / GB;
120c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "%12zu%8zu%12.2f%12.2f%12.2f%17.2f\n",
121c62b318aSDmitry Kozlyuk size, runs_done, alloc_time, free_time,
122c62b318aSDmitry Kozlyuk alloc_time + free_time, memset_time);
123c62b318aSDmitry Kozlyuk
124c62b318aSDmitry Kozlyuk memset(ptrs, 0, max_runs * sizeof(ptrs[0]));
125c62b318aSDmitry Kozlyuk }
126c62b318aSDmitry Kozlyuk
127c62b318aSDmitry Kozlyuk free(ptrs);
128c62b318aSDmitry Kozlyuk TEST_LOG(INFO, "\n");
129c62b318aSDmitry Kozlyuk return 0;
130c62b318aSDmitry Kozlyuk }
131c62b318aSDmitry Kozlyuk
132c62b318aSDmitry Kozlyuk static void *
memzone_alloc(const char * name __rte_unused,size_t size,unsigned int align)133c62b318aSDmitry Kozlyuk memzone_alloc(const char *name __rte_unused, size_t size, unsigned int align)
134c62b318aSDmitry Kozlyuk {
135c62b318aSDmitry Kozlyuk const struct rte_memzone *mz;
136c62b318aSDmitry Kozlyuk char gen_name[RTE_MEMZONE_NAMESIZE];
137c62b318aSDmitry Kozlyuk
138c62b318aSDmitry Kozlyuk snprintf(gen_name, sizeof(gen_name), "test-mz-%"PRIx64, rte_rdtsc());
139c62b318aSDmitry Kozlyuk mz = rte_memzone_reserve_aligned(gen_name, size, SOCKET_ID_ANY,
140c62b318aSDmitry Kozlyuk RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY, align);
141c62b318aSDmitry Kozlyuk return (void *)(uintptr_t)mz;
142c62b318aSDmitry Kozlyuk }
143c62b318aSDmitry Kozlyuk
144c62b318aSDmitry Kozlyuk static void
memzone_free(void * addr)145c62b318aSDmitry Kozlyuk memzone_free(void *addr)
146c62b318aSDmitry Kozlyuk {
147c62b318aSDmitry Kozlyuk rte_memzone_free((struct rte_memzone *)addr);
148c62b318aSDmitry Kozlyuk }
149c62b318aSDmitry Kozlyuk
150c62b318aSDmitry Kozlyuk static int
test_malloc_perf(void)151c62b318aSDmitry Kozlyuk test_malloc_perf(void)
152c62b318aSDmitry Kozlyuk {
153c62b318aSDmitry Kozlyuk static const size_t MAX_RUNS = 10000;
154c62b318aSDmitry Kozlyuk
155c62b318aSDmitry Kozlyuk double memset_us_gb = 0;
156c62b318aSDmitry Kozlyuk
157c62b318aSDmitry Kozlyuk if (test_memset_perf(&memset_us_gb) < 0)
158c62b318aSDmitry Kozlyuk return -1;
159c62b318aSDmitry Kozlyuk
160c62b318aSDmitry Kozlyuk if (test_alloc_perf("rte_malloc", rte_malloc, rte_free, memset,
161c62b318aSDmitry Kozlyuk memset_us_gb, MAX_RUNS) < 0)
162c62b318aSDmitry Kozlyuk return -1;
163c62b318aSDmitry Kozlyuk if (test_alloc_perf("rte_zmalloc", rte_zmalloc, rte_free, memset,
164c62b318aSDmitry Kozlyuk memset_us_gb, MAX_RUNS) < 0)
165c62b318aSDmitry Kozlyuk return -1;
166c62b318aSDmitry Kozlyuk
167c62b318aSDmitry Kozlyuk if (test_alloc_perf("rte_memzone_reserve", memzone_alloc, memzone_free,
16838689022SOphir Munk NULL, memset_us_gb, rte_memzone_max_get() - 1) < 0)
169c62b318aSDmitry Kozlyuk return -1;
170c62b318aSDmitry Kozlyuk
171c62b318aSDmitry Kozlyuk return 0;
172c62b318aSDmitry Kozlyuk }
173c62b318aSDmitry Kozlyuk
174*e0a8442cSBruce Richardson REGISTER_PERF_TEST(malloc_perf_autotest, test_malloc_perf);
175