API Reference Manual 1.51.0
Loading...
Searching...
No Matches
odp_crc.c
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2021 Nokia
3 */
4
13#include <stdio.h>
14#include <string.h>
15#include <stdint.h>
16#include <inttypes.h>
17#include <getopt.h>
18
19#include <odp_api.h>
20#include <odp/helper/odph_api.h>
21
22#define KB 1024ull
23#define MB (1024ull * 1024ull)
24
25/* Command line options */
26typedef struct {
27 uint32_t size;
28 uint32_t rounds;
29 uint32_t offset;
30 uint32_t test;
31} options_t;
32
33static options_t options;
34static const options_t options_def = {
35 .size = 16,
36 .rounds = 10000,
37 .offset = 0,
38 .test = 0,
39};
40
41static void print_usage(void)
42{
43 printf("\n"
44 "CRC performance test\n"
45 "\n"
46 "Usage: odp_crc_perf [options]\n"
47 "\n"
48 " -s, --size Size of buffer in KB (default %u)\n"
49 " -r, --rounds Number of test rounds (default %u)\n"
50 " Rounded down to nearest multiple of 8\n"
51 " -o, --offset Offset of data (default %u)\n"
52 " -t, --test Which API to test (default %u)\n"
53 " 0: both\n"
54 " 1: odp_hash_crc32c\n"
55 " 2: odp_hash_crc32\n"
56 " -h, --help This help\n"
57 "\n",
58 options_def.size, options_def.rounds, options_def.offset,
59 options.test);
60}
61
62static int parse_options(int argc, char *argv[])
63{
64 int opt;
65 int ret = 0;
66
67 static const struct option longopts[] = {
68 { "size", required_argument, NULL, 's' },
69 { "rounds", required_argument, NULL, 'r' },
70 { "offset", required_argument, NULL, 'o' },
71 { "test", required_argument, NULL, 't' },
72 { "help", no_argument, NULL, 'h' },
73 { NULL, 0, NULL, 0 }
74 };
75
76 static const char *shortopts = "+s:r:o:t:h";
77
78 options = options_def;
79
80 while (1) {
81 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
82
83 if (opt == -1)
84 break;
85
86 switch (opt) {
87 case 's':
88 options.size = atol(optarg);
89 break;
90 case 'r':
91 options.rounds = atol(optarg);
92 break;
93 case 'o':
94 options.offset = atol(optarg);
95 break;
96 case 't':
97 options.test = atol(optarg);
98 break;
99 case 'h':
100 /* fall through */
101 default:
102 print_usage();
103 ret = -1;
104 break;
105 }
106 }
107
108 if (options.size < 1) {
109 ODPH_ERR("Invalid size: %" PRIu32 "\n", options.size);
110 return -1;
111 }
112
113 if (options.offset > 4 * KB) {
114 ODPH_ERR("Invalid offset: %" PRIu32 "\n", options.offset);
115 return -1;
116 }
117
118 if (options.test > 2) {
119 ODPH_ERR("Invalid API to test: %" PRIu32 "\n", options.test);
120 return -1;
121 }
122
123 return ret;
124}
125
126static void report(uint64_t nsec)
127{
128 uint64_t size = (uint64_t)options.size * KB;
129 uint32_t rounds = options.rounds & ~7ul;
130 double mb, seconds;
131
132 printf("size: %d KB rounds: %d offset: %d ",
133 options.size, rounds, options.offset);
134 mb = (double)(size * (uint64_t)rounds) / (double)MB;
135 seconds = (double)nsec / (double)ODP_TIME_SEC_IN_NS;
136 printf("MB: %.3f seconds: %.3f ", mb, seconds);
137 printf("MB/s: %.3f", mb / seconds);
138 printf("\n\n");
139}
140
141static uint64_t measure_crc32c(uint8_t *data, uint32_t size)
142{
143 void *p = data + options.offset;
144 uint32_t crc = 1;
145 volatile uint32_t v;
146 odp_time_t start = odp_time_local();
147
148 for (uint32_t i = 0; i < options.rounds / 8; i++) {
149 crc ^= odp_hash_crc32c(p, size, crc);
150 crc ^= odp_hash_crc32c(p, size, crc);
151 crc ^= odp_hash_crc32c(p, size, crc);
152 crc ^= odp_hash_crc32c(p, size, crc);
153
154 crc ^= odp_hash_crc32c(p, size, crc);
155 crc ^= odp_hash_crc32c(p, size, crc);
156 crc ^= odp_hash_crc32c(p, size, crc);
157 crc ^= odp_hash_crc32c(p, size, crc);
158 }
159
160 /* Make sure that crc is not optimized out. */
161 v = crc;
162
163 /* Quell "unused" warning. */
164 (void)v;
165
166 return odp_time_diff_ns(odp_time_local(), start);
167}
168
169static void test_odp_hash_crc32c(uint8_t *data)
170{
171 uint64_t size = (uint64_t)options.size * KB;
172 uint64_t nsec;
173
174 /* Warm-up. */
175 measure_crc32c(data, size);
176
177 /* Actual measurement. */
178 nsec = measure_crc32c(data, size);
179
180 report(nsec);
181}
182
183static uint64_t measure_crc32(uint8_t *data, uint32_t size)
184{
185 void *p = data + options.offset;
186 uint32_t crc = 1;
187 volatile uint32_t v;
188 odp_time_t start = odp_time_local();
189
190 for (uint32_t i = 0; i < options.rounds / 8; i++) {
191 crc ^= odp_hash_crc32(p, size, crc);
192 crc ^= odp_hash_crc32(p, size, crc);
193 crc ^= odp_hash_crc32(p, size, crc);
194 crc ^= odp_hash_crc32(p, size, crc);
195
196 crc ^= odp_hash_crc32(p, size, crc);
197 crc ^= odp_hash_crc32(p, size, crc);
198 crc ^= odp_hash_crc32(p, size, crc);
199 crc ^= odp_hash_crc32(p, size, crc);
200 }
201
202 /* Make sure that crc is not optimized out. */
203 v = crc;
204
205 /* Quell "unused" warning. */
206 (void)v;
207
208 return odp_time_diff_ns(odp_time_local(), start);
209}
210
211static void test_odp_hash_crc32(uint8_t *data)
212{
213 uint64_t size = (uint64_t)options.size * KB;
214 uint64_t nsec;
215
216 /* Warm-up. */
217 measure_crc32(data, size);
218
219 /* Actual measurement. */
220 nsec = measure_crc32(data, size);
221
222 report(nsec);
223}
224
225int main(int argc, char **argv)
226{
227 odp_instance_t instance;
228 odp_init_t init;
229
230 if (parse_options(argc, argv))
231 exit(EXIT_FAILURE);
232
233 /* List features not to be used */
234 odp_init_param_init(&init);
235 init.not_used.feat.cls = 1;
236 init.not_used.feat.compress = 1;
237 init.not_used.feat.crypto = 1;
238 init.not_used.feat.ipsec = 1;
239 init.not_used.feat.schedule = 1;
240 init.not_used.feat.stash = 1;
241 init.not_used.feat.timer = 1;
242 init.not_used.feat.tm = 1;
243
244 /* Init ODP before calling anything else */
245 if (odp_init_global(&instance, &init, NULL)) {
246 ODPH_ERR("Global init failed.\n");
247 exit(EXIT_FAILURE);
248 }
249
250 /* Init this thread */
251 if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
252 ODPH_ERR("Local init failed.\n");
253 exit(EXIT_FAILURE);
254 }
255
257
258 uint8_t *buf, *data;
259 uint32_t size = options.size * KB;
260 uint64_t seed = 1;
261 const unsigned long page = 4 * KB;
262
263 /* One extra page for alignment, another one for offset. */
264 buf = (uint8_t *)malloc(size + page * 2);
265
266 if (!buf) {
267 ODPH_ERR("Memory allocation failed.\n");
268 exit(EXIT_FAILURE);
269 }
270
271 /* Align to start of page. */
272 data = (uint8_t *)(((uintptr_t)buf + (page - 1)) & ~(page - 1));
273
274 if (odp_random_test_data(data, size, &seed) != (int32_t)size) {
275 ODPH_ERR("odp_random_test_data() failed.\n");
276 exit(EXIT_FAILURE);
277 }
278
279 if (options.test == 0 || options.test == 1) {
280 printf("odp_hash_crc32c\n"
281 "---------------\n");
282 test_odp_hash_crc32c(data);
283 }
284
285 if (options.test == 0 || options.test == 2) {
286 printf("odp_hash_crc32\n"
287 "--------------\n");
288 test_odp_hash_crc32(data);
289 }
290
291 free(buf);
292
293 if (odp_term_local()) {
294 ODPH_ERR("Local terminate failed.\n");
295 exit(EXIT_FAILURE);
296 }
297
298 if (odp_term_global(instance)) {
299 ODPH_ERR("Global terminate failed.\n");
300 exit(EXIT_FAILURE);
301 }
302
303 return 0;
304}
uint32_t odp_hash_crc32(const void *data, uint32_t data_len, uint32_t init_val)
Calculate CRC-32.
uint32_t odp_hash_crc32c(const void *data, uint32_t data_len, uint32_t init_val)
Calculate CRC-32C.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
Generate repeatable random data for testing purposes.
void odp_sys_info_print(void)
Print system info.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
odp_time_t odp_time_local(void)
Current local time.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
The OpenDataPlane API.
Global initialization parameters.
odp_feature_t not_used
Unused features.
uint32_t tm
Traffic Manager APIs, e.g., odp_tm_xxx()
uint32_t stash
Stash APIs, e.g., odp_stash_xxx()
uint32_t crypto
Crypto APIs, e.g., odp_crypto_xxx()
uint32_t ipsec
IPsec APIs, e.g., odp_ipsec_xxx()
uint32_t timer
Timer APIs, e.g., odp_timer_xxx(), odp_timeout_xxx()
uint32_t cls
Classifier APIs, e.g., odp_cls_xxx(), odp_cos_xxx()
struct odp_feature_t::@174 feat
Individual feature bits.
uint32_t schedule
Scheduler APIs, e.g., odp_schedule_xxx()
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()