API Reference Manual 1.51.0
Loading...
Searching...
No Matches
odp_atomic_perf.c
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (c) 2021-2024 Nokia
3 */
4
13#include <stdio.h>
14#include <string.h>
15#include <stdint.h>
16#include <inttypes.h>
17#include <stdlib.h>
18#include <getopt.h>
19
20#include <odp_api.h>
21#include <odp/helper/odph_api.h>
22
23#include <export_results.h>
24
25/* Default number of test rounds */
26#define NUM_ROUNDS 100000u
27
28/* Initial value for atomic variables. Supports up to 2 billion
29 * rounds of 32-bit min and max tests. */
30#define INIT_VAL 0x80000000
31
32/* Max number of workers if num_cpu=0 */
33#define DEFAULT_MAX_WORKERS 10
34
35/* Maximum number of results to be held */
36#define TEST_MAX_BENCH 70
37
38#define TEST_INFO(name, test, validate, op_type) \
39 {name, test, validate, op_type}
40
41/* Test function template */
42typedef void (*test_fn_t)(void *val, void *out, uint32_t num_round);
43/* Test result validation function template */
44typedef int (*validate_fn_t)(void *val, void *out, uint32_t num_round,
45 uint32_t num_worker, int private);
46
47typedef enum {
48 OP_32BIT,
49 OP_64BIT,
50 OP_128BIT
51} op_bit_t;
52
53/* Command line options */
54typedef struct test_options_t {
55 uint32_t num_cpu;
56 uint32_t num_round;
57 int private;
58
59} test_options_t;
60
61/* Cache aligned atomics for private mode operation */
62typedef struct ODP_ALIGNED_CACHE test_atomic_t {
63 union {
67 };
68} test_atomic_t;
69
70typedef struct test_global_t test_global_t;
71
72/* Worker thread context */
73typedef struct test_thread_ctx_t {
74 test_global_t *global;
75 test_fn_t func;
76 uint64_t nsec;
77 uint64_t cycles;
78 uint32_t idx;
79 op_bit_t type;
80
81} test_thread_ctx_t;
82
83typedef struct results_t {
84 const char *test_name;
85 double cycles_per_op;
86 double nsec_per_op;
87 double operations_per_cpu;
88 double total_operations;
89} results_t;
90
91/* Global data */
92struct test_global_t {
93 test_options_t test_options;
94 odp_barrier_t barrier;
95 union {
96 odp_atomic_u32_t atomic_u32;
97 odp_atomic_u64_t atomic_u64;
98 odp_atomic_u128_t atomic_u128;
99 };
100 odp_cpumask_t cpumask;
101 odph_thread_t thread_tbl[ODP_THREAD_COUNT_MAX];
102 test_thread_ctx_t thread_ctx[ODP_THREAD_COUNT_MAX];
103 test_atomic_t atomic_private[ODP_THREAD_COUNT_MAX];
104 union {
105 uint32_t u32;
106 uint64_t u64;
107 odp_u128_t u128;
108 } output[ODP_THREAD_COUNT_MAX];
109 test_common_options_t common_options;
110 results_t results[TEST_MAX_BENCH];
111};
112
113typedef struct {
114 const char *name;
115 test_fn_t test_fn;
116 validate_fn_t validate_fn;
117 op_bit_t type;
118} test_case_t;
119
120static test_global_t *test_global;
121
122static inline void test_atomic_load_u32(void *val, void *out, uint32_t num_round)
123{
124 odp_atomic_u32_t *atomic_val = val;
125 uint32_t *result = out;
126 uint32_t ret = 0;
127
128 for (uint32_t i = 0; i < num_round; i++)
129 ret += odp_atomic_load_u32(atomic_val);
130
131 *result = ret;
132}
133
134static inline void test_atomic_load_u64(void *val, void *out, uint32_t num_round)
135{
136 odp_atomic_u64_t *atomic_val = val;
137 uint64_t *result = out;
138 uint64_t ret = 0;
139
140 for (uint32_t i = 0; i < num_round; i++)
141 ret += odp_atomic_load_u64(atomic_val);
142
143 *result = ret;
144}
145
146static inline void test_atomic_load_u128(void *val, void *out, uint32_t num_round)
147{
148 odp_atomic_u128_t *atomic_val = val;
149 odp_u128_t *result = out;
150 odp_u128_t ret;
151
152 ret.u64[0] = 0;
153 ret.u64[1] = 0;
154
155 for (uint32_t i = 0; i < num_round; i++) {
156 odp_u128_t cur_val = odp_atomic_load_u128(atomic_val);
157
158 ret.u64[0] += cur_val.u64[0];
159 ret.u64[1] += cur_val.u64[1];
160 }
161
162 *result = ret;
163}
164
165static inline int validate_atomic_init_val_u32(void *val, void *out, uint32_t num_round,
166 uint32_t num_worker ODP_UNUSED,
167 int private ODP_UNUSED)
168{
169 odp_atomic_u32_t *atomic_val = val;
170 uint32_t *result = out;
171
172 return (odp_atomic_load_u32(atomic_val) != INIT_VAL) ||
173 (*result != (uint32_t)INIT_VAL * num_round);
174}
175
176static inline int validate_atomic_init_val_u64(void *val, void *out, uint32_t num_round,
177 uint32_t worker ODP_UNUSED, int private ODP_UNUSED)
178{
179 odp_atomic_u64_t *atomic_val = val;
180 uint64_t *result = out;
181
182 return (odp_atomic_load_u64(atomic_val) != INIT_VAL) ||
183 (*result != (uint64_t)INIT_VAL * num_round);
184}
185
186static inline int validate_atomic_init_val_u128(void *val, void *out, uint32_t num_round,
187 uint32_t worker ODP_UNUSED, int private ODP_UNUSED)
188{
190 odp_u128_t *result = out;
191
192 if (atomic_val.u64[0] != INIT_VAL || atomic_val.u64[1] != INIT_VAL)
193 return -1;
194
195 if (result->u64[0] != (uint64_t)INIT_VAL * num_round ||
196 result->u64[1] != (uint64_t)INIT_VAL * num_round)
197 return -1;
198
199 return 0;
200}
201
202static inline void test_atomic_store_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
203{
204 odp_atomic_u32_t *atomic_val = val;
205 uint32_t new_val = INIT_VAL + 1;
206
207 for (uint32_t i = 0; i < num_round; i++)
208 odp_atomic_store_u32(atomic_val, new_val++);
209}
210
211static inline void test_atomic_store_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
212{
213 odp_atomic_u64_t *atomic_val = val;
214 uint64_t new_val = INIT_VAL + 1;
215
216 for (uint32_t i = 0; i < num_round; i++)
217 odp_atomic_store_u64(atomic_val, new_val++);
218}
219
220static inline void test_atomic_store_u128(void *val, void *out ODP_UNUSED, uint32_t num_round)
221{
222 odp_atomic_u128_t *atomic_val = val;
223 odp_u128_t new_val;
224
225 new_val.u64[0] = INIT_VAL + 1;
226 new_val.u64[1] = INIT_VAL + 1;
227
228 for (uint32_t i = 0; i < num_round; i++) {
229 odp_atomic_store_u128(atomic_val, new_val);
230 new_val.u64[0]++;
231 new_val.u64[1]++;
232 }
233}
234
235static inline int validate_atomic_num_round_u32(void *val, void *out ODP_UNUSED, uint32_t num_round,
236 uint32_t worker ODP_UNUSED, int private ODP_UNUSED)
237{
238 odp_atomic_u32_t *atomic_val = val;
239
240 return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL + num_round);
241}
242
243static inline int validate_atomic_num_round_u64(void *val, void *out ODP_UNUSED, uint32_t num_round,
244 uint32_t worker ODP_UNUSED, int private ODP_UNUSED)
245{
246 odp_atomic_u64_t *atomic_val = val;
247
248 return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL + num_round);
249}
250
251static inline int validate_atomic_num_round_u128(void *val, void *out ODP_UNUSED,
252 uint32_t num_round, uint32_t worker ODP_UNUSED,
253 int private ODP_UNUSED)
254{
256
257 return (atomic_val.u64[0] != ((uint64_t)INIT_VAL + num_round) ||
258 atomic_val.u64[1] != ((uint64_t)INIT_VAL + num_round));
259}
260
261static inline void test_atomic_fetch_add_u32(void *val, void *out, uint32_t num_round)
262{
263 odp_atomic_u32_t *atomic_val = val;
264 uint32_t *result = out;
265 uint32_t ret = 0;
266
267 for (uint32_t i = 0; i < num_round; i++)
268 ret += odp_atomic_fetch_add_u32(atomic_val, 1);
269
270 *result = ret;
271}
272
273static inline void test_atomic_fetch_add_u64(void *val, void *out, uint32_t num_round)
274{
275 odp_atomic_u64_t *atomic_val = val;
276 uint64_t *result = out;
277 uint64_t ret = 0;
278
279 for (uint32_t i = 0; i < num_round; i++)
280 ret += odp_atomic_fetch_add_u64(atomic_val, 1);
281
282 *result = ret;
283}
284
285static inline int validate_atomic_add_round_u32(void *val, void *out ODP_UNUSED, uint32_t num_round,
286 uint32_t num_worker, int private)
287{
288 odp_atomic_u32_t *atomic_val = val;
289
290 if (private)
291 return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL + num_round);
292
293 return odp_atomic_load_u32(atomic_val) != (INIT_VAL + (num_worker * num_round));
294}
295
296static inline int validate_atomic_add_round_u64(void *val, void *out ODP_UNUSED, uint32_t num_round,
297 uint32_t num_worker, int private)
298{
299 odp_atomic_u64_t *atomic_val = val;
300
301 if (private)
302 return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL + num_round);
303
304 return odp_atomic_load_u64(atomic_val) != (INIT_VAL + ((uint64_t)num_worker * num_round));
305}
306
307static inline void test_atomic_add_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
308{
309 odp_atomic_u32_t *atomic_val = val;
310
311 for (uint32_t i = 0; i < num_round; i++)
312 odp_atomic_add_u32(atomic_val, 1);
313}
314
315static inline void test_atomic_add_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
316{
317 odp_atomic_u64_t *atomic_val = val;
318
319 for (uint32_t i = 0; i < num_round; i++)
320 odp_atomic_add_u64(atomic_val, 1);
321}
322
323static inline void test_atomic_fetch_sub_u32(void *val, void *out, uint32_t num_round)
324{
325 odp_atomic_u32_t *atomic_val = val;
326 uint32_t *result = out;
327 uint32_t ret = 0;
328
329 for (uint32_t i = 0; i < num_round; i++)
330 ret += odp_atomic_fetch_sub_u32(atomic_val, 1);
331
332 *result = ret;
333}
334
335static inline void test_atomic_fetch_sub_u64(void *val, void *out, uint32_t num_round)
336{
337 odp_atomic_u64_t *atomic_val = val;
338 uint64_t *result = out;
339 uint64_t ret = 0;
340
341 for (uint32_t i = 0; i < num_round; i++)
342 ret += odp_atomic_fetch_sub_u64(atomic_val, 1);
343
344 *result = ret;
345}
346
347static inline int validate_atomic_sub_round_u32(void *val, void *out ODP_UNUSED, uint32_t num_round,
348 uint32_t num_worker, int private)
349{
350 odp_atomic_u32_t *atomic_val = val;
351
352 if (private)
353 return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL - num_round);
354
355 return odp_atomic_load_u32(atomic_val) != ((uint32_t)INIT_VAL - (num_worker * num_round));
356}
357
358static inline int validate_atomic_sub_round_u64(void *val, void *out ODP_UNUSED, uint32_t num_round,
359 uint32_t num_worker, int private)
360{
361 odp_atomic_u64_t *atomic_val = val;
362
363 if (private)
364 return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL - num_round);
365
366 return odp_atomic_load_u64(atomic_val) != ((uint64_t)INIT_VAL -
367 ((uint64_t)num_worker * num_round));
368}
369
370static inline void test_atomic_sub_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
371{
372 odp_atomic_u32_t *atomic_val = val;
373
374 for (uint32_t i = 0; i < num_round; i++)
375 odp_atomic_sub_u32(atomic_val, 1);
376}
377
378static inline void test_atomic_sub_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
379{
380 odp_atomic_u64_t *atomic_val = val;
381
382 for (uint32_t i = 0; i < num_round; i++)
383 odp_atomic_sub_u64(atomic_val, 1);
384}
385
386static inline void test_atomic_fetch_inc_u32(void *val, void *out, uint32_t num_round)
387{
388 odp_atomic_u32_t *atomic_val = val;
389 uint32_t *result = out;
390 uint32_t ret = 0;
391
392 for (uint32_t i = 0; i < num_round; i++)
393 ret += odp_atomic_fetch_inc_u32(atomic_val);
394
395 *result = ret;
396}
397
398static inline void test_atomic_fetch_inc_u64(void *val, void *out, uint32_t num_round)
399{
400 odp_atomic_u64_t *atomic_val = val;
401 uint64_t *result = out;
402 uint64_t ret = 0;
403
404 for (uint32_t i = 0; i < num_round; i++)
405 ret += odp_atomic_fetch_inc_u64(atomic_val);
406
407 *result = ret;
408}
409
410static inline void test_atomic_inc_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
411{
412 odp_atomic_u32_t *atomic_val = val;
413
414 for (uint32_t i = 0; i < num_round; i++)
415 odp_atomic_inc_u32(atomic_val);
416}
417
418static inline void test_atomic_inc_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
419{
420 odp_atomic_u64_t *atomic_val = val;
421
422 for (uint32_t i = 0; i < num_round; i++)
423 odp_atomic_inc_u64(atomic_val);
424}
425
426static inline void test_atomic_fetch_dec_u32(void *val, void *out, uint32_t num_round)
427{
428 odp_atomic_u32_t *atomic_val = val;
429 uint32_t *result = out;
430 uint32_t ret = 0;
431
432 for (uint32_t i = 0; i < num_round; i++)
433 ret += odp_atomic_fetch_dec_u32(atomic_val);
434
435 *result = ret;
436}
437
438static inline void test_atomic_fetch_dec_u64(void *val, void *out, uint32_t num_round)
439{
440 odp_atomic_u64_t *atomic_val = val;
441 uint64_t *result = out;
442 uint64_t ret = 0;
443
444 for (uint32_t i = 0; i < num_round; i++)
445 ret += odp_atomic_fetch_dec_u64(atomic_val);
446
447 *result = ret;
448}
449
450static inline void test_atomic_dec_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
451{
452 odp_atomic_u32_t *atomic_val = val;
453
454 for (uint32_t i = 0; i < num_round; i++)
455 odp_atomic_dec_u32(atomic_val);
456}
457
458static inline void test_atomic_dec_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
459{
460 odp_atomic_u64_t *atomic_val = val;
461
462 for (uint32_t i = 0; i < num_round; i++)
463 odp_atomic_dec_u64(atomic_val);
464}
465
466static inline void test_atomic_max_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
467{
468 odp_atomic_u32_t *atomic_val = val;
469 uint32_t new_max = INIT_VAL + 1;
470
471 for (uint32_t i = 0; i < num_round; i++)
472 odp_atomic_max_u32(atomic_val, new_max++);
473}
474
475static inline void test_atomic_max_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
476{
477 odp_atomic_u64_t *atomic_val = val;
478 uint64_t new_max = INIT_VAL + 1;
479
480 for (uint32_t i = 0; i < num_round; i++)
481 odp_atomic_max_u64(atomic_val, new_max++);
482}
483
484static inline int validate_atomic_max_u32(void *val, void *out ODP_UNUSED, uint32_t num_round,
485 uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED)
486{
487 uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val);
488
489 return (result != ((uint32_t)INIT_VAL + num_round)) && (result != UINT32_MAX);
490}
491
492static inline int validate_atomic_max_u64(void *val, void *out ODP_UNUSED, uint32_t num_round,
493 uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED)
494{
495 uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val);
496
497 return (result != ((uint64_t)INIT_VAL + num_round)) && (result != UINT64_MAX);
498}
499
500static inline void test_atomic_fetch_max_u32(void *val, void *out, uint32_t num_round)
501{
502 odp_atomic_u32_t *atomic_val = val;
503 uint32_t *result = out;
504 uint32_t new_max = INIT_VAL + 1, old_max = INIT_VAL;
505
506 for (uint32_t i = 0; i < num_round; i++)
507 old_max = odp_atomic_fetch_max_u32(atomic_val, new_max++);
508
509 *result = old_max;
510}
511
512static inline void test_atomic_fetch_max_u64(void *val, void *out, uint32_t num_round)
513{
514 odp_atomic_u64_t *atomic_val = val;
515 uint64_t *result = out;
516 uint64_t new_max = INIT_VAL + 1, old_max = INIT_VAL;
517
518 for (uint32_t i = 0; i < num_round; i++)
519 old_max = odp_atomic_fetch_max_u64(atomic_val, new_max++);
520
521 *result = old_max;
522}
523
524static inline int validate_atomic_fetch_max_u32(void *val, void *out, uint32_t num_round,
525 uint32_t num_worker ODP_UNUSED,
526 int private ODP_UNUSED)
527{
528 uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val);
529 uint32_t *output = out;
530
531 return (result != ((uint32_t)INIT_VAL + num_round) && result != UINT32_MAX) ||
532 (*output != result - 1 && *output != result);
533}
534
535static inline int validate_atomic_fetch_max_u64(void *val, void *out, uint32_t num_round,
536 uint32_t num_worker ODP_UNUSED,
537 int private ODP_UNUSED)
538{
539 uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val);
540 uint64_t *output = out;
541
542 return (result != ((uint64_t)INIT_VAL + num_round) && result != UINT64_MAX) ||
543 (*output != result - 1 && *output != result);
544}
545
546static inline void test_atomic_min_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
547{
548 odp_atomic_u32_t *atomic_val = val;
549 uint32_t new_min = INIT_VAL - 1;
550
551 for (uint32_t i = 0; i < num_round; i++)
552 odp_atomic_min_u32(atomic_val, new_min--);
553}
554
555static inline void test_atomic_min_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
556{
557 odp_atomic_u64_t *atomic_val = val;
558 uint64_t new_min = INIT_VAL - 1;
559
560 for (uint32_t i = 0; i < num_round; i++)
561 odp_atomic_min_u64(atomic_val, new_min--);
562}
563
564static inline int validate_atomic_min_u32(void *val, void *out ODP_UNUSED, uint32_t num_round,
565 uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED)
566{
567 uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val);
568
569 return result != ((uint32_t)INIT_VAL - num_round) && result != 0;
570}
571
572static inline int validate_atomic_min_u64(void *val, void *out ODP_UNUSED, uint32_t num_round,
573 uint32_t num_worker ODP_UNUSED, int private ODP_UNUSED)
574{
575 uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val);
576
577 return result != ((uint64_t)INIT_VAL - num_round) && result != 0;
578}
579
580static inline void test_atomic_fetch_min_u32(void *val, void *out, uint32_t num_round)
581{
582 odp_atomic_u32_t *atomic_val = val;
583 uint32_t *result = out;
584 uint32_t new_min = INIT_VAL - 1, old_min = INIT_VAL;
585
586 for (uint32_t i = 0; i < num_round; i++)
587 old_min = odp_atomic_fetch_min_u32(atomic_val, new_min--);
588
589 *result = old_min;
590}
591
592static inline void test_atomic_fetch_min_u64(void *val, void *out, uint32_t num_round)
593{
594 odp_atomic_u64_t *atomic_val = val;
595 uint64_t *result = out;
596 uint64_t new_min = INIT_VAL - 1, old_min = INIT_VAL;
597
598 for (uint32_t i = 0; i < num_round; i++)
599 old_min = odp_atomic_fetch_min_u64(atomic_val, new_min--);
600
601 *result = old_min;
602}
603
604static inline int validate_atomic_fetch_min_u32(void *val, void *out, uint32_t num_round,
605 uint32_t num_worker ODP_UNUSED,
606 int private ODP_UNUSED)
607{
608 uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val);
609 uint32_t *output = out;
610
611 return (result != ((uint32_t)INIT_VAL - num_round) && result != 0) ||
612 (*output != result + 1 && *output != result);
613}
614
615static inline int validate_atomic_fetch_min_u64(void *val, void *out, uint32_t num_round,
616 uint32_t num_worker ODP_UNUSED,
617 int private ODP_UNUSED)
618{
619 uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val);
620 uint64_t *output = out;
621
622 return (result != ((uint64_t)INIT_VAL - num_round) && result != 0) ||
623 (*output != result + 1 && *output != result);
624}
625
626static inline void test_atomic_cas_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
627{
628 odp_atomic_u32_t *atomic_val = val;
629 uint32_t new_val = INIT_VAL + 1;
630 uint32_t old_val = INIT_VAL;
631
632 for (uint32_t i = 0; i < num_round; i++) {
633 if (odp_atomic_cas_u32(atomic_val, &old_val, new_val))
634 old_val = new_val++;
635 }
636}
637
638static inline void test_atomic_cas_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
639{
640 odp_atomic_u64_t *atomic_val = val;
641 uint64_t new_val = INIT_VAL + 1;
642 uint64_t old_val = INIT_VAL;
643
644 for (uint32_t i = 0; i < num_round; i++) {
645 if (odp_atomic_cas_u64(atomic_val, &old_val, new_val))
646 old_val = new_val++;
647 }
648}
649
650static inline void test_atomic_cas_u128(void *val, void *out ODP_UNUSED, uint32_t num_round)
651{
652 odp_atomic_u128_t *atomic_val = val;
653 odp_u128_t new_val;
654 odp_u128_t old_val;
655
656 new_val.u64[0] = INIT_VAL + 1;
657 new_val.u64[1] = INIT_VAL + 1;
658 old_val.u64[0] = INIT_VAL;
659 old_val.u64[1] = INIT_VAL;
660
661 for (uint32_t i = 0; i < num_round; i++) {
662 if (odp_atomic_cas_u128(atomic_val, &old_val, new_val)) {
663 old_val = new_val;
664 new_val.u64[0]++;
665 new_val.u64[1]++;
666 }
667 }
668}
669
670static inline int validate_atomic_cas_u32(void *val, void *out ODP_UNUSED, uint32_t num_round,
671 uint32_t num_worker ODP_UNUSED, int private)
672{
673 uint32_t result = odp_atomic_load_u32((odp_atomic_u32_t *)val);
674
675 if (private)
676 return result != ((uint32_t)INIT_VAL + num_round);
677
678 return result > ((uint32_t)INIT_VAL + num_round);
679}
680
681static inline int validate_atomic_cas_u64(void *val, void *out ODP_UNUSED, uint32_t num_round,
682 uint32_t num_worker ODP_UNUSED, int private)
683{
684 uint64_t result = odp_atomic_load_u64((odp_atomic_u64_t *)val);
685
686 if (private)
687 return result != ((uint64_t)INIT_VAL + num_round);
688
689 return result > ((uint64_t)INIT_VAL + num_round);
690}
691
692static inline int validate_atomic_cas_u128(void *val, void *out ODP_UNUSED, uint32_t num_round,
693 uint32_t num_worker ODP_UNUSED, int private)
694{
696
697 if (private)
698 return (result.u64[0] != ((uint64_t)INIT_VAL + num_round) ||
699 result.u64[1] != ((uint64_t)INIT_VAL + num_round));
700
701 return (result.u64[0] > ((uint64_t)INIT_VAL + num_round) ||
702 result.u64[1] > ((uint64_t)INIT_VAL + num_round));
703}
704
705static inline void test_atomic_xchg_u32(void *val, void *out, uint32_t num_round)
706{
707 odp_atomic_u32_t *atomic_val = val;
708 uint32_t new_val = INIT_VAL + 1;
709 uint32_t *result = out;
710 uint32_t ret = 0;
711
712 for (uint32_t i = 0; i < num_round; i++)
713 ret += odp_atomic_xchg_u32(atomic_val, new_val++);
714
715 *result = ret;
716}
717
718static inline void test_atomic_xchg_u64(void *val, void *out, uint32_t num_round)
719{
720 odp_atomic_u64_t *atomic_val = val;
721 uint64_t new_val = INIT_VAL + 1;
722 uint64_t *result = out;
723 uint64_t ret = 0;
724
725 for (uint32_t i = 0; i < num_round; i++)
726 ret += odp_atomic_xchg_u64(atomic_val, new_val++);
727
728 *result = ret;
729}
730
731static inline void test_atomic_bit_set_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
732{
733 odp_atomic_u32_t *atomic_val = val;
734
735 for (uint32_t i = 0; i < num_round; i++)
736 odp_atomic_bit_set_u32(atomic_val, 0x1);
737}
738
739static inline void test_atomic_bit_fetch_set_u32(void *val, void *out, uint32_t num_round)
740{
741 odp_atomic_u32_t *atomic_val = val;
742 uint32_t *result = out;
743 uint32_t ret = 0;
744
745 for (uint32_t i = 0; i < num_round; i++)
746 ret += odp_atomic_bit_fetch_set_u32(atomic_val, 0x1);
747
748 *result = ret;
749}
750
751static inline void test_atomic_bit_clr_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
752{
753 odp_atomic_u32_t *atomic_val = val;
754
755 for (uint32_t i = 0; i < num_round; i++)
756 odp_atomic_bit_clr_u32(atomic_val, 0x1);
757}
758
759static inline void test_atomic_bit_fetch_clr_u32(void *val, void *out, uint32_t num_round)
760{
761 odp_atomic_u32_t *atomic_val = val;
762 uint32_t *result = out;
763 uint32_t ret = 0;
764
765 for (uint32_t i = 0; i < num_round; i++)
766 ret += odp_atomic_bit_fetch_clr_u32(atomic_val, 0x1);
767
768 *result = ret;
769}
770
771static inline void test_atomic_bit_set_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
772{
773 odp_atomic_u64_t *atomic_val = val;
774
775 for (uint32_t i = 0; i < num_round; i++)
776 odp_atomic_bit_set_u64(atomic_val, 0x1);
777}
778
779static inline void test_atomic_bit_fetch_set_u64(void *val, void *out, uint32_t num_round)
780{
781 odp_atomic_u64_t *atomic_val = val;
782 uint64_t *result = out;
783 uint64_t ret = 0;
784
785 for (uint32_t i = 0; i < num_round; i++)
786 ret += odp_atomic_bit_fetch_set_u64(atomic_val, 0x1);
787
788 *result = ret;
789}
790
791static inline void test_atomic_bit_clr_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
792{
793 odp_atomic_u64_t *atomic_val = val;
794
795 for (uint32_t i = 0; i < num_round; i++)
796 odp_atomic_bit_clr_u64(atomic_val, 0x1);
797}
798
799static inline void test_atomic_bit_fetch_clr_u64(void *val, void *out, uint32_t num_round)
800{
801 odp_atomic_u64_t *atomic_val = val;
802 uint64_t *result = out;
803 uint64_t ret = 0;
804
805 for (uint32_t i = 0; i < num_round; i++)
806 ret += odp_atomic_bit_fetch_clr_u64(atomic_val, 0x1);
807
808 *result = ret;
809}
810
811static inline void test_atomic_load_acq_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
812{
813 odp_atomic_u32_t *atomic_val = val;
814 uint32_t *result = out;
815 uint32_t ret = 0;
816
817 for (uint32_t i = 0; i < num_round; i++)
818 ret += odp_atomic_load_acq_u32(atomic_val);
819
820 *result = ret;
821}
822
823static inline void test_atomic_load_acq_u64(void *val, void *out, uint32_t num_round)
824{
825 odp_atomic_u64_t *atomic_val = val;
826 uint64_t *result = out;
827 uint64_t ret = 0;
828
829 for (uint32_t i = 0; i < num_round; i++)
830 ret += odp_atomic_load_acq_u64(atomic_val);
831
832 *result = ret;
833}
834
835static inline void test_atomic_store_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
836{
837 odp_atomic_u32_t *atomic_val = val;
838 uint32_t new_val = INIT_VAL + 1;
839
840 for (uint32_t i = 0; i < num_round; i++)
841 odp_atomic_store_rel_u32(atomic_val, new_val++);
842}
843
844static inline void test_atomic_store_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
845{
846 odp_atomic_u64_t *atomic_val = val;
847 uint64_t new_val = INIT_VAL + 1;
848
849 for (uint32_t i = 0; i < num_round; i++)
850 odp_atomic_store_rel_u64(atomic_val, new_val++);
851}
852
853static inline void test_atomic_add_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
854{
855 odp_atomic_u32_t *atomic_val = val;
856
857 for (uint32_t i = 0; i < num_round; i++)
858 odp_atomic_add_rel_u32(atomic_val, 1);
859}
860
861static inline void test_atomic_add_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
862{
863 odp_atomic_u64_t *atomic_val = val;
864
865 for (uint32_t i = 0; i < num_round; i++)
866 odp_atomic_add_rel_u64(atomic_val, 1);
867}
868
869static inline void test_atomic_sub_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
870{
871 odp_atomic_u32_t *atomic_val = val;
872
873 for (uint32_t i = 0; i < num_round; i++)
874 odp_atomic_sub_rel_u32(atomic_val, 1);
875}
876
877static inline void test_atomic_sub_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
878{
879 odp_atomic_u64_t *atomic_val = val;
880
881 for (uint32_t i = 0; i < num_round; i++)
882 odp_atomic_sub_rel_u64(atomic_val, 1);
883}
884
885static inline void test_atomic_cas_acq_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
886{
887 odp_atomic_u32_t *atomic_val = val;
888 uint32_t new_val = INIT_VAL + 1;
889 uint32_t old_val = INIT_VAL;
890
891 for (uint32_t i = 0; i < num_round; i++) {
892 if (odp_atomic_cas_acq_u32(atomic_val, &old_val, new_val))
893 old_val = new_val++;
894 }
895}
896
897static inline void test_atomic_cas_acq_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
898{
899 odp_atomic_u64_t *atomic_val = val;
900 uint64_t new_val = INIT_VAL + 1;
901 uint64_t old_val = INIT_VAL;
902
903 for (uint32_t i = 0; i < num_round; i++) {
904 if (odp_atomic_cas_acq_u64(atomic_val, &old_val, new_val))
905 old_val = new_val++;
906 }
907}
908
909static inline void test_atomic_cas_acq_u128(void *val, void *out ODP_UNUSED, uint32_t num_round)
910{
911 odp_atomic_u128_t *atomic_val = val;
912 odp_u128_t new_val;
913 odp_u128_t old_val;
914
915 new_val.u64[0] = INIT_VAL + 1;
916 new_val.u64[1] = INIT_VAL + 1;
917 old_val.u64[0] = INIT_VAL;
918 old_val.u64[1] = INIT_VAL;
919
920 for (uint32_t i = 0; i < num_round; i++) {
921 if (odp_atomic_cas_acq_u128(atomic_val, &old_val, new_val)) {
922 old_val = new_val;
923 new_val.u64[0]++;
924 new_val.u64[1]++;
925 }
926 }
927}
928
929static inline void test_atomic_cas_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
930{
931 odp_atomic_u32_t *atomic_val = val;
932 uint32_t new_val = INIT_VAL + 1;
933 uint32_t old_val = INIT_VAL;
934
935 for (uint32_t i = 0; i < num_round; i++) {
936 if (odp_atomic_cas_rel_u32(atomic_val, &old_val, new_val))
937 old_val = new_val++;
938 }
939}
940
941static inline void test_atomic_cas_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
942{
943 odp_atomic_u64_t *atomic_val = val;
944 uint64_t new_val = INIT_VAL + 1;
945 uint64_t old_val = INIT_VAL;
946
947 for (uint32_t i = 0; i < num_round; i++) {
948 if (odp_atomic_cas_rel_u64(atomic_val, &old_val, new_val))
949 old_val = new_val++;
950 }
951}
952
953static inline void test_atomic_cas_rel_u128(void *val, void *out ODP_UNUSED, uint32_t num_round)
954{
955 odp_atomic_u128_t *atomic_val = val;
956 odp_u128_t new_val;
957 odp_u128_t old_val;
958
959 new_val.u64[0] = INIT_VAL + 1;
960 new_val.u64[1] = INIT_VAL + 1;
961 old_val.u64[0] = INIT_VAL;
962 old_val.u64[1] = INIT_VAL;
963
964 for (uint32_t i = 0; i < num_round; i++) {
965 if (odp_atomic_cas_rel_u128(atomic_val, &old_val, new_val)) {
966 old_val = new_val;
967 new_val.u64[0]++;
968 new_val.u64[1]++;
969 }
970 }
971}
972
973static inline void test_atomic_cas_acq_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
974{
975 odp_atomic_u32_t *atomic_val = val;
976 uint32_t new_val = INIT_VAL + 1;
977 uint32_t old_val = INIT_VAL;
978
979 for (uint32_t i = 0; i < num_round; i++) {
980 if (odp_atomic_cas_acq_rel_u32(atomic_val, &old_val, new_val))
981 old_val = new_val++;
982 }
983}
984
985static inline void test_atomic_cas_acq_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
986{
987 odp_atomic_u64_t *atomic_val = val;
988 uint64_t new_val = INIT_VAL + 1;
989 uint64_t old_val = INIT_VAL;
990
991 for (uint32_t i = 0; i < num_round; i++) {
992 if (odp_atomic_cas_acq_rel_u64(atomic_val, &old_val, new_val))
993 old_val = new_val++;
994 }
995}
996
997static inline void test_atomic_cas_acq_rel_u128(void *val, void *out ODP_UNUSED, uint32_t num_round)
998{
999 odp_atomic_u128_t *atomic_val = val;
1000 odp_u128_t new_val;
1001 odp_u128_t old_val;
1002
1003 new_val.u64[0] = INIT_VAL + 1;
1004 new_val.u64[1] = INIT_VAL + 1;
1005 old_val.u64[0] = INIT_VAL;
1006 old_val.u64[1] = INIT_VAL;
1007
1008 for (uint32_t i = 0; i < num_round; i++) {
1009 if (odp_atomic_cas_acq_rel_u128(atomic_val, &old_val, new_val)) {
1010 old_val = new_val;
1011 new_val.u64[0]++;
1012 new_val.u64[1]++;
1013 }
1014 }
1015}
1016
1017static inline void test_atomic_bit_set_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
1018{
1019 odp_atomic_u32_t *atomic_val = val;
1020
1021 for (uint32_t i = 0; i < num_round; i++)
1022 odp_atomic_bit_set_rel_u32(atomic_val, 0x1);
1023}
1024
1025static inline void test_atomic_bit_clr_rel_u32(void *val, void *out ODP_UNUSED, uint32_t num_round)
1026{
1027 odp_atomic_u32_t *atomic_val = val;
1028
1029 for (uint32_t i = 0; i < num_round; i++)
1030 odp_atomic_bit_clr_rel_u32(atomic_val, 0x1);
1031}
1032
1033static inline void test_atomic_bit_set_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
1034{
1035 odp_atomic_u64_t *atomic_val = val;
1036
1037 for (uint32_t i = 0; i < num_round; i++)
1038 odp_atomic_bit_set_rel_u64(atomic_val, 0x1);
1039}
1040
1041static inline void test_atomic_bit_clr_rel_u64(void *val, void *out ODP_UNUSED, uint32_t num_round)
1042{
1043 odp_atomic_u64_t *atomic_val = val;
1044
1045 for (uint32_t i = 0; i < num_round; i++)
1046 odp_atomic_bit_clr_rel_u64(atomic_val, 0x1);
1047}
1048
1049static void print_usage(void)
1050{
1051 printf("\n"
1052 "Atomic operations performance test\n"
1053 "\n"
1054 "Usage: odp_atomic_perf [options]\n"
1055 "\n"
1056 " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs (or max %d) (default)\n"
1057 " -r, --num_round Number of rounds (default %u)\n"
1058 " -p, --private 0: The same atomic variable is shared between threads (default)\n"
1059 " 1: Atomic variables are private to each thread\n"
1060 " -h, --help This help\n"
1061 "\n", DEFAULT_MAX_WORKERS, NUM_ROUNDS);
1062}
1063
1064static void print_info(test_options_t *test_options)
1065{
1066 odp_atomic_op_t atomic_ops;
1067
1068 printf("\nAtomic operations performance test configuration:\n");
1069 printf(" num cpu %u\n", test_options->num_cpu);
1070 printf(" num rounds %u\n", test_options->num_round);
1071 printf(" private %i\n", test_options->private);
1072 printf("\n");
1073
1074 atomic_ops.all_bits = 0;
1075 odp_atomic_lock_free_u64(&atomic_ops);
1076
1077 printf("\nAtomic operations lock-free:\n");
1078 printf(" odp_atomic_load_u64: %" PRIu32 "\n", atomic_ops.op.load);
1079 printf(" odp_atomic_store_u64: %" PRIu32 "\n", atomic_ops.op.store);
1080 printf(" odp_atomic_fetch_add_u64: %" PRIu32 "\n", atomic_ops.op.fetch_add);
1081 printf(" odp_atomic_add_u64: %" PRIu32 "\n", atomic_ops.op.add);
1082 printf(" odp_atomic_fetch_sub_u64: %" PRIu32 "\n", atomic_ops.op.fetch_sub);
1083 printf(" odp_atomic_sub_u64: %" PRIu32 "\n", atomic_ops.op.sub);
1084 printf(" odp_atomic_fetch_inc_u64: %" PRIu32 "\n", atomic_ops.op.fetch_inc);
1085 printf(" odp_atomic_inc_u64: %" PRIu32 "\n", atomic_ops.op.inc);
1086 printf(" odp_atomic_fetch_dec_u64: %" PRIu32 "\n", atomic_ops.op.fetch_dec);
1087 printf(" odp_atomic_dec_u64: %" PRIu32 "\n", atomic_ops.op.dec);
1088 printf(" odp_atomic_min_u64: %" PRIu32 "\n", atomic_ops.op.min);
1089 printf(" odp_atomic_fetch_min_u64: %" PRIu32 "\n", atomic_ops.op.fetch_min);
1090 printf(" odp_atomic_max_u64: %" PRIu32 "\n", atomic_ops.op.max);
1091 printf(" odp_atomic_fetch_max_u64: %" PRIu32 "\n", atomic_ops.op.fetch_max);
1092 printf(" odp_atomic_cas_u64: %" PRIu32 "\n", atomic_ops.op.cas);
1093 printf(" odp_atomic_xchg_u64: %" PRIu32 "\n", atomic_ops.op.xchg);
1094 printf(" odp_atomic_bit_fetch_set_u64: %" PRIu32 "\n", atomic_ops.op.bit_fetch_set);
1095 printf(" odp_atomic_bit_set_u64: %" PRIu32 "\n", atomic_ops.op.bit_set);
1096 printf(" odp_atomic_bit_fetch_clr_u64: %" PRIu32 "\n", atomic_ops.op.bit_fetch_clr);
1097 printf(" odp_atomic_bit_clr_u64: %" PRIu32 "\n", atomic_ops.op.bit_clr);
1098
1099 atomic_ops.all_bits = 0;
1100 odp_atomic_lock_free_u128(&atomic_ops);
1101
1102 printf(" odp_atomic_load_u128: %" PRIu32 "\n", atomic_ops.op.load);
1103 printf(" odp_atomic_store_u128: %" PRIu32 "\n", atomic_ops.op.store);
1104 printf(" odp_atomic_cas_u128: %" PRIu32 "\n", atomic_ops.op.cas);
1105
1106 printf("\n\n");
1107}
1108
1109static int output_summary(test_global_t *global)
1110{
1111 int results_size = ODPH_ARRAY_SIZE(global->results);
1112 results_t res;
1113
1114 if (global->common_options.is_export) {
1115 if (test_common_write("function name,ops/cpu (M/s),total ops (M/s),"
1116 "cycles/op,nsec/op\n")) {
1117 test_common_write_term();
1118 return -1;
1119 }
1120 }
1121
1122 printf("Average results over %i threads:\n", global->test_options.num_cpu);
1123 printf("%-33s %-15s %-17s %-11s %-11s\n", "function name", "ops/cpu (M/s)",
1124 "total ops (M/s)", "cycles/op", "nsec/op");
1125 printf("-----------------------------------------------------------------------------"
1126 "-----------------------\n");
1127 for (int i = 0; i < results_size && global->results[i].test_name; i++) {
1128 res = global->results[i];
1129 printf("[%02d] %-28s %-15.2f %-17.2f %-11.2f %-11.2f\n", i + 1,
1130 res.test_name, res.operations_per_cpu, res.total_operations,
1131 res.cycles_per_op, res.nsec_per_op);
1132 if (global->common_options.is_export) {
1133 if (test_common_write("%s,%f,%f,%f,%f\n", res.test_name,
1134 res.operations_per_cpu, res.total_operations,
1135 res.cycles_per_op, res.nsec_per_op)) {
1136 test_common_write_term();
1137 return -1;
1138 }
1139 }
1140 }
1141
1142 if (global->common_options.is_export)
1143 test_common_write_term();
1144
1145 return 0;
1146}
1147
1148static int parse_options(int argc, char *argv[], test_options_t *test_options)
1149{
1150 int opt;
1151 int ret = 0;
1152
1153 static const struct option longopts[] = {
1154 {"num_cpu", required_argument, NULL, 'c'},
1155 {"num_round", required_argument, NULL, 'r'},
1156 {"private", required_argument, NULL, 'p'},
1157 {"help", no_argument, NULL, 'h'},
1158 {NULL, 0, NULL, 0}
1159 };
1160
1161 static const char *shortopts = "+c:r:p:h";
1162
1163 memset(test_options, 0, sizeof(test_options_t));
1164 test_options->num_cpu = 0;
1165 test_options->num_round = NUM_ROUNDS;
1166 test_options->private = 0;
1167
1168 while (1) {
1169 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
1170
1171 if (opt == -1)
1172 break;
1173
1174 switch (opt) {
1175 case 'c':
1176 test_options->num_cpu = atoi(optarg);
1177 break;
1178 case 'r':
1179 test_options->num_round = atol(optarg);
1180 break;
1181 case 'p':
1182 test_options->private = atoi(optarg);
1183 break;
1184 case 'h':
1185 /* fall through */
1186 default:
1187 print_usage();
1188 ret = -1;
1189 break;
1190 }
1191 }
1192
1193 if (test_options->num_round < 1) {
1194 ODPH_ERR("Invalid number of test rounds: %" PRIu32 "\n", test_options->num_round);
1195 return -1;
1196 }
1197
1198 return ret;
1199}
1200
1201static int set_num_cpu(test_global_t *global)
1202{
1203 int ret, max_num;
1204 test_options_t *test_options = &global->test_options;
1205 int num_cpu = test_options->num_cpu;
1206
1207 /* One thread used for the main thread */
1208 if (num_cpu > ODP_THREAD_COUNT_MAX - 1) {
1209 ODPH_ERR("Too many workers. Maximum is %i.\n", ODP_THREAD_COUNT_MAX - 1);
1210 return -1;
1211 }
1212
1213 max_num = num_cpu;
1214 if (num_cpu == 0) {
1215 max_num = ODP_THREAD_COUNT_MAX - 1;
1216 if (max_num > DEFAULT_MAX_WORKERS)
1217 max_num = DEFAULT_MAX_WORKERS;
1218 }
1219
1220 ret = odp_cpumask_default_worker(&global->cpumask, max_num);
1221
1222 if (num_cpu && ret != num_cpu) {
1223 ODPH_ERR("Too many workers. Max supported %i.\n", ret);
1224 return -1;
1225 }
1226
1227 /* Zero: all available workers */
1228 if (num_cpu == 0) {
1229 if (ret > max_num) {
1230 ODPH_ERR("Too many cpus from odp_cpumask_default_worker(): %i\n", ret);
1231 return -1;
1232 }
1233
1234 num_cpu = ret;
1235 test_options->num_cpu = num_cpu;
1236 }
1237
1238 odp_barrier_init(&global->barrier, num_cpu);
1239
1240 return 0;
1241}
1242
1243static int init_test(test_global_t *global, const char *name, op_bit_t type)
1244{
1245 odp_u128_t init_val;
1246
1247 init_val.u64[0] = INIT_VAL;
1248 init_val.u64[1] = INIT_VAL;
1249
1250 printf("TEST: %s\n", name);
1251
1252 if (type == OP_32BIT)
1253 odp_atomic_init_u32(&global->atomic_u32, INIT_VAL);
1254 else if (type == OP_64BIT)
1255 odp_atomic_init_u64(&global->atomic_u64, INIT_VAL);
1256 else if (type == OP_128BIT)
1257 odp_atomic_init_u128(&global->atomic_u128, init_val);
1258 else
1259 return -1;
1260
1261 for (int i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1262 if (type == OP_32BIT) {
1263 global->output[i].u32 = 0;
1264 odp_atomic_init_u32(&global->atomic_private[i].u32, INIT_VAL);
1265 } else if (type == OP_64BIT) {
1266 global->output[i].u64 = 0;
1267 odp_atomic_init_u64(&global->atomic_private[i].u64, INIT_VAL);
1268 } else {
1269 global->output[i].u128.u64[0] = 0;
1270 global->output[i].u128.u64[1] = 0;
1271 odp_atomic_init_u128(&global->atomic_private[i].u128, init_val);
1272 }
1273 }
1274 return 0;
1275}
1276
1277static int run_test(void *arg)
1278{
1279 uint64_t nsec;
1280 odp_time_t t1, t2;
1281 uint64_t cycles;
1282 uint64_t c1, c2;
1283 test_thread_ctx_t *thread_ctx = arg;
1284 test_global_t *global = thread_ctx->global;
1285 test_options_t *test_options = &global->test_options;
1286 uint32_t num_round = test_options->num_round;
1287 uint32_t idx = thread_ctx->idx;
1288 test_fn_t test_func = thread_ctx->func;
1289 op_bit_t type = thread_ctx->type;
1290 void *val;
1291 void *out;
1292 uint32_t out_u32 = 0;
1293 uint64_t out_u64 = 0;
1294 odp_u128_t out_u128;
1295
1296 out_u128.u64[0] = 0;
1297 out_u128.u64[1] = 0;
1298
1299 if (type == OP_32BIT) {
1300 val = &global->atomic_u32;
1301 out = &out_u32;
1302 } else if (type == OP_64BIT) {
1303 val = &global->atomic_u64;
1304 out = &out_u64;
1305 } else {
1306 val = &global->atomic_u128;
1307 out = &out_u128;
1308 }
1309
1310 if (global->test_options.private) {
1311 if (type == OP_32BIT)
1312 val = &global->atomic_private[idx].u32;
1313 else if (type == OP_64BIT)
1314 val = &global->atomic_private[idx].u64;
1315 else
1316 val = &global->atomic_private[idx].u128;
1317 }
1318
1319 /* Start all workers at the same time */
1320 odp_barrier_wait(&global->barrier);
1321
1322 t1 = odp_time_local_strict();
1323 c1 = odp_cpu_cycles();
1324
1325 test_func(val, out, num_round);
1326
1327 c2 = odp_cpu_cycles();
1328 t2 = odp_time_local_strict();
1329
1330 nsec = odp_time_diff_ns(t2, t1);
1331 cycles = odp_cpu_cycles_diff(c2, c1);
1332
1333 /* Update stats */
1334 thread_ctx->nsec = nsec;
1335 thread_ctx->cycles = cycles;
1336 if (type == OP_32BIT)
1337 global->output[idx].u32 = out_u32;
1338 else if (type == OP_64BIT)
1339 global->output[idx].u64 = out_u64;
1340 else
1341 global->output[idx].u128 = out_u128;
1342
1343 return 0;
1344}
1345
1346static int start_workers(test_global_t *global, odp_instance_t instance,
1347 test_fn_t func, op_bit_t type)
1348{
1349 odph_thread_common_param_t param;
1350 int i, ret;
1351 test_options_t *test_options = &global->test_options;
1352 int num_cpu = test_options->num_cpu;
1353 odph_thread_param_t thr_param[num_cpu];
1354
1355 odph_thread_common_param_init(&param);
1356 param.instance = instance;
1357 param.cpumask = &global->cpumask;
1358
1359 for (i = 0; i < num_cpu; i++) {
1360 test_thread_ctx_t *thread_ctx = &global->thread_ctx[i];
1361
1362 thread_ctx->global = global;
1363 thread_ctx->idx = i;
1364 thread_ctx->func = func;
1365 thread_ctx->type = type;
1366
1367 odph_thread_param_init(&thr_param[i]);
1368 thr_param[i].thr_type = ODP_THREAD_WORKER;
1369 thr_param[i].start = run_test;
1370 thr_param[i].arg = thread_ctx;
1371 }
1372
1373 ret = odph_thread_create(global->thread_tbl, &param, thr_param, num_cpu);
1374 if (ret != num_cpu) {
1375 ODPH_ERR("Failed to create all threads %i\n", ret);
1376 return -1;
1377 }
1378
1379 return 0;
1380}
1381
1382static int validate_results(test_global_t *global, validate_fn_t validate, op_bit_t type)
1383{
1384 int i;
1385 test_options_t *test_options = &global->test_options;
1386 uint32_t num_round = test_options->num_round;
1387 int num_cpu = test_options->num_cpu;
1388 int private = global->test_options.private;
1389 void *val;
1390 void *out;
1391
1392 for (i = 0; i < num_cpu; i++) {
1393 if (type == OP_32BIT) {
1394 out = &global->output[i].u32;
1395 val = &global->atomic_u32;
1396 if (private)
1397 val = &global->atomic_private[i].u32;
1398 } else if (type == OP_64BIT) {
1399 out = &global->output[i].u64;
1400 val = &global->atomic_u64;
1401 if (private)
1402 val = &global->atomic_private[i].u64;
1403 } else {
1404 out = &global->output[i].u128;
1405 val = &global->atomic_u128;
1406 if (private)
1407 val = &global->atomic_private[i].u128;
1408 }
1409
1410 if (validate != NULL && validate(val, out, num_round, num_cpu, private))
1411 return -1;
1412 }
1413 return 0;
1414}
1415
1419static test_case_t test_suite[] = {
1420 TEST_INFO("odp_atomic_load_u32", test_atomic_load_u32,
1421 validate_atomic_init_val_u32, OP_32BIT),
1422 TEST_INFO("odp_atomic_store_u32", test_atomic_store_u32,
1423 validate_atomic_num_round_u32, OP_32BIT),
1424 TEST_INFO("odp_atomic_fetch_add_u32", test_atomic_fetch_add_u32,
1425 validate_atomic_add_round_u32, OP_32BIT),
1426 TEST_INFO("odp_atomic_add_u32", test_atomic_add_u32,
1427 validate_atomic_add_round_u32, OP_32BIT),
1428 TEST_INFO("odp_atomic_fetch_sub_u32", test_atomic_fetch_sub_u32,
1429 validate_atomic_sub_round_u32, OP_32BIT),
1430 TEST_INFO("odp_atomic_sub_u32", test_atomic_sub_u32,
1431 validate_atomic_sub_round_u32, OP_32BIT),
1432 TEST_INFO("odp_atomic_fetch_inc_u32", test_atomic_fetch_inc_u32,
1433 validate_atomic_add_round_u32, OP_32BIT),
1434 TEST_INFO("odp_atomic_inc_u32", test_atomic_inc_u32,
1435 validate_atomic_add_round_u32, OP_32BIT),
1436 TEST_INFO("odp_atomic_fetch_dec_u32", test_atomic_fetch_dec_u32,
1437 validate_atomic_sub_round_u32, OP_32BIT),
1438 TEST_INFO("odp_atomic_dec_u32", test_atomic_dec_u32,
1439 validate_atomic_sub_round_u32, OP_32BIT),
1440 TEST_INFO("odp_atomic_max_u32", test_atomic_max_u32,
1441 validate_atomic_max_u32, OP_32BIT),
1442 TEST_INFO("odp_atomic_fetch_max_u32", test_atomic_fetch_max_u32,
1443 validate_atomic_fetch_max_u32, OP_32BIT),
1444 TEST_INFO("odp_atomic_min_u32", test_atomic_min_u32,
1445 validate_atomic_min_u32, OP_32BIT),
1446 TEST_INFO("odp_atomic_fetch_min_u32", test_atomic_fetch_min_u32,
1447 validate_atomic_fetch_min_u32, OP_32BIT),
1448 TEST_INFO("odp_atomic_cas_u32", test_atomic_cas_u32,
1449 validate_atomic_cas_u32, OP_32BIT),
1450 TEST_INFO("odp_atomic_xchg_u32", test_atomic_xchg_u32,
1451 validate_atomic_num_round_u32, OP_32BIT),
1452 TEST_INFO("odp_atomic_bit_set_u32", test_atomic_bit_set_u32,
1453 NULL, OP_32BIT),
1454 TEST_INFO("odp_atomic_bit_fetch_set_u32", test_atomic_bit_fetch_set_u32,
1455 NULL, OP_32BIT),
1456 TEST_INFO("odp_atomic_bit_clr_u32", test_atomic_bit_clr_u32,
1457 NULL, OP_32BIT),
1458 TEST_INFO("odp_atomic_bit_fetch_clr_u32", test_atomic_bit_fetch_clr_u32,
1459 NULL, OP_32BIT),
1460 TEST_INFO("odp_atomic_load_acq_u32", test_atomic_load_acq_u32,
1461 validate_atomic_init_val_u32, OP_32BIT),
1462 TEST_INFO("odp_atomic_store_rel_u32", test_atomic_store_rel_u32,
1463 validate_atomic_num_round_u32, OP_32BIT),
1464 TEST_INFO("odp_atomic_add_rel_u32", test_atomic_add_rel_u32,
1465 validate_atomic_add_round_u32, OP_32BIT),
1466 TEST_INFO("odp_atomic_sub_rel_u32", test_atomic_sub_rel_u32,
1467 validate_atomic_sub_round_u32, OP_32BIT),
1468 TEST_INFO("odp_atomic_cas_acq_u32", test_atomic_cas_acq_u32,
1469 validate_atomic_cas_u32, OP_32BIT),
1470 TEST_INFO("odp_atomic_cas_rel_u32", test_atomic_cas_rel_u32,
1471 validate_atomic_cas_u32, OP_32BIT),
1472 TEST_INFO("odp_atomic_cas_acq_rel_u32", test_atomic_cas_acq_rel_u32,
1473 validate_atomic_cas_u32, OP_32BIT),
1474 TEST_INFO("odp_atomic_bit_set_rel_u32", test_atomic_bit_set_rel_u32,
1475 NULL, OP_32BIT),
1476 TEST_INFO("odp_atomic_bit_clr_rel_u32", test_atomic_bit_clr_rel_u32,
1477 NULL, OP_32BIT),
1478 TEST_INFO("odp_atomic_load_u64", test_atomic_load_u64,
1479 validate_atomic_init_val_u64, OP_64BIT),
1480 TEST_INFO("odp_atomic_store_u64", test_atomic_store_u64,
1481 validate_atomic_num_round_u64, OP_64BIT),
1482 TEST_INFO("odp_atomic_fetch_add_u64", test_atomic_fetch_add_u64,
1483 validate_atomic_add_round_u64, OP_64BIT),
1484 TEST_INFO("odp_atomic_add_u64", test_atomic_add_u64,
1485 validate_atomic_add_round_u64, OP_64BIT),
1486 TEST_INFO("odp_atomic_fetch_sub_u64", test_atomic_fetch_sub_u64,
1487 validate_atomic_sub_round_u64, OP_64BIT),
1488 TEST_INFO("odp_atomic_sub_u64", test_atomic_sub_u64,
1489 validate_atomic_sub_round_u64, OP_64BIT),
1490 TEST_INFO("odp_atomic_fetch_inc_u64", test_atomic_fetch_inc_u64,
1491 validate_atomic_add_round_u64, OP_64BIT),
1492 TEST_INFO("odp_atomic_inc_u64", test_atomic_inc_u64,
1493 validate_atomic_add_round_u64, OP_64BIT),
1494 TEST_INFO("odp_atomic_fetch_dec_u64", test_atomic_fetch_dec_u64,
1495 validate_atomic_sub_round_u64, OP_64BIT),
1496 TEST_INFO("odp_atomic_dec_u64", test_atomic_dec_u64,
1497 validate_atomic_sub_round_u64, OP_64BIT),
1498 TEST_INFO("odp_atomic_max_u64", test_atomic_max_u64,
1499 validate_atomic_max_u64, OP_64BIT),
1500 TEST_INFO("odp_atomic_fetch_max_u64", test_atomic_fetch_max_u64,
1501 validate_atomic_fetch_max_u64, OP_64BIT),
1502 TEST_INFO("odp_atomic_min_u64", test_atomic_min_u64,
1503 validate_atomic_min_u64, OP_64BIT),
1504 TEST_INFO("odp_atomic_fetch_min_u64", test_atomic_fetch_min_u64,
1505 validate_atomic_fetch_min_u64, OP_64BIT),
1506 TEST_INFO("odp_atomic_cas_u64", test_atomic_cas_u64,
1507 validate_atomic_cas_u64, OP_64BIT),
1508 TEST_INFO("odp_atomic_xchg_u64", test_atomic_xchg_u64,
1509 validate_atomic_num_round_u64, OP_64BIT),
1510 TEST_INFO("odp_atomic_bit_set_u64", test_atomic_bit_set_u64,
1511 NULL, OP_64BIT),
1512 TEST_INFO("odp_atomic_bit_fetch_set_u64", test_atomic_bit_fetch_set_u64,
1513 NULL, OP_64BIT),
1514 TEST_INFO("odp_atomic_bit_clr_u64", test_atomic_bit_clr_u64,
1515 NULL, OP_64BIT),
1516 TEST_INFO("odp_atomic_bit_fetch_clr_u64", test_atomic_bit_fetch_clr_u64,
1517 NULL, OP_64BIT),
1518 TEST_INFO("odp_atomic_load_acq_u64", test_atomic_load_acq_u64,
1519 validate_atomic_init_val_u64, OP_64BIT),
1520 TEST_INFO("odp_atomic_store_rel_u64", test_atomic_store_rel_u64,
1521 validate_atomic_num_round_u64, OP_64BIT),
1522 TEST_INFO("odp_atomic_add_rel_u64", test_atomic_add_rel_u64,
1523 validate_atomic_add_round_u64, OP_64BIT),
1524 TEST_INFO("odp_atomic_sub_rel_u64", test_atomic_sub_rel_u64,
1525 validate_atomic_sub_round_u64, OP_64BIT),
1526 TEST_INFO("odp_atomic_cas_acq_u64", test_atomic_cas_acq_u64,
1527 validate_atomic_cas_u64, OP_64BIT),
1528 TEST_INFO("odp_atomic_cas_rel_u64", test_atomic_cas_rel_u64,
1529 validate_atomic_cas_u64, OP_64BIT),
1530 TEST_INFO("odp_atomic_cas_acq_rel_u64", test_atomic_cas_acq_rel_u64,
1531 validate_atomic_cas_u64, OP_64BIT),
1532 TEST_INFO("odp_atomic_bit_set_rel_u64", test_atomic_bit_set_rel_u64,
1533 NULL, OP_64BIT),
1534 TEST_INFO("odp_atomic_bit_clr_rel_u64", test_atomic_bit_clr_rel_u64,
1535 NULL, OP_64BIT),
1536 TEST_INFO("odp_atomic_load_u128", test_atomic_load_u128,
1537 validate_atomic_init_val_u128, OP_128BIT),
1538 TEST_INFO("odp_atomic_store_u128", test_atomic_store_u128,
1539 validate_atomic_num_round_u128, OP_128BIT),
1540 TEST_INFO("odp_atomic_cas_u128", test_atomic_cas_u128,
1541 validate_atomic_cas_u128, OP_128BIT),
1542 TEST_INFO("odp_atomic_cas_acq_u128", test_atomic_cas_acq_u128,
1543 validate_atomic_cas_u128, OP_128BIT),
1544 TEST_INFO("odp_atomic_cas_rel_u128", test_atomic_cas_rel_u128,
1545 validate_atomic_cas_u128, OP_128BIT),
1546 TEST_INFO("odp_atomic_cas_acq_rel_u128", test_atomic_cas_acq_rel_u128,
1547 validate_atomic_cas_u128, OP_128BIT),
1548};
1549
1550ODP_STATIC_ASSERT(ODPH_ARRAY_SIZE(test_suite) < TEST_MAX_BENCH,
1551 "Result array is too small to hold all the results");
1552
1553static void output_results(test_global_t *global, int idx)
1554{
1555 int i, num;
1556 double nsec_ave, nsec_per_op, cycles_per_op, operations_per_cpu, total_operations;
1557 test_options_t *test_options = &global->test_options;
1558 int num_cpu = test_options->num_cpu;
1559 uint32_t num_round = test_options->num_round;
1560 uint64_t nsec_sum = 0;
1561 uint64_t cycles_sum = 0;
1562
1563 global->results[idx].test_name = test_suite[idx].name;
1564
1565 for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1566 nsec_sum += global->thread_ctx[i].nsec;
1567 cycles_sum += global->thread_ctx[i].cycles;
1568 }
1569
1570 if (nsec_sum == 0 || cycles_sum == 0) {
1571 printf("No results.\n");
1572 return;
1573 }
1574
1575 nsec_ave = (double)nsec_sum / num_cpu;
1576 nsec_per_op = (double)nsec_sum / (num_cpu * num_round);
1577 cycles_per_op = (double)cycles_sum / (num_cpu * num_round);
1578 num = 0;
1579
1580 operations_per_cpu = num_round / (nsec_ave / 1000.0);
1581 total_operations = (num_cpu * num_round) / (nsec_ave / 1000.0);
1582
1583 global->results[idx].cycles_per_op = cycles_per_op;
1584 global->results[idx].operations_per_cpu = operations_per_cpu;
1585 global->results[idx].nsec_per_op = nsec_per_op;
1586 global->results[idx].total_operations = total_operations;
1587
1588 printf("---------------------------------------------\n");
1589 printf("Per thread results (Millions of ops per sec):\n");
1590 printf("---------------------------------------------\n");
1591 printf(" 1 2 3 4 5 6 7 8 9 10");
1592
1593 for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
1594 if (global->thread_ctx[i].nsec) {
1595 if ((num % 10) == 0)
1596 printf("\n ");
1597
1598 printf("%8.2f ", num_round / (global->thread_ctx[i].nsec / 1000.0));
1599 num++;
1600 }
1601 }
1602 printf("\n\n");
1603
1604 printf("Average results over %i threads:\n", num_cpu);
1605 printf("---------------------------------------\n");
1606 printf(" duration: %8.4f sec\n", nsec_ave / ODP_TIME_SEC_IN_NS);
1607 printf(" cycles per op: %8.2f\n", cycles_per_op);
1608 printf(" nsec per op: %8.2f\n", nsec_per_op);
1609 printf(" ops per cpu: %8.2fM ops/sec\n", operations_per_cpu);
1610 printf(" total ops: %8.2fM ops/sec\n", total_operations);
1611 printf("\n\n");
1612}
1613
1614int main(int argc, char **argv)
1615{
1616 odph_helper_options_t helper_options;
1617 odp_instance_t instance;
1618 odp_init_t init;
1619 odp_shm_t shm;
1620 test_options_t test_options;
1621 int num_tests, i;
1622 test_common_options_t common_options;
1623
1624 /* Let helper collect its own arguments (e.g. --odph_proc) */
1625 argc = odph_parse_options(argc, argv);
1626 if (odph_options(&helper_options)) {
1627 ODPH_ERR("Error: reading ODP helper options failed.\n");
1628 exit(EXIT_FAILURE);
1629 }
1630
1631 argc = test_common_parse_options(argc, argv);
1632 if (test_common_options(&common_options)) {
1633 ODPH_ERR("Error while reading test options, exiting\n");
1634 exit(EXIT_FAILURE);
1635 }
1636
1637 if (parse_options(argc, argv, &test_options))
1638 exit(EXIT_FAILURE);
1639
1640 /* List features not to be used */
1641 odp_init_param_init(&init);
1642 init.not_used.feat.cls = 1;
1643 init.not_used.feat.compress = 1;
1644 init.not_used.feat.crypto = 1;
1645 init.not_used.feat.ipsec = 1;
1646 init.not_used.feat.schedule = 1;
1647 init.not_used.feat.stash = 1;
1648 init.not_used.feat.timer = 1;
1649 init.not_used.feat.tm = 1;
1650
1651 init.mem_model = helper_options.mem_model;
1652
1653 /* Init ODP before calling anything else */
1654 if (odp_init_global(&instance, &init, NULL)) {
1655 ODPH_ERR("Global init failed.\n");
1656 exit(EXIT_FAILURE);
1657 }
1658
1659 /* Init this thread */
1660 if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
1661 ODPH_ERR("Local init failed.\n");
1662 exit(EXIT_FAILURE);
1663 }
1664
1665 /* Reserve memory for global data from shared mem */
1666 shm = odp_shm_reserve("test_global", sizeof(test_global_t),
1667 ODP_CACHE_LINE_SIZE, 0);
1668
1669 if (shm == ODP_SHM_INVALID) {
1670 ODPH_ERR("Shared memory reserve failed.\n");
1671 exit(EXIT_FAILURE);
1672 }
1673
1674 test_global = odp_shm_addr(shm);
1675 if (test_global == NULL) {
1676 ODPH_ERR("Shared memory alloc failed.\n");
1677 exit(EXIT_FAILURE);
1678 }
1679 memset(test_global, 0, sizeof(test_global_t));
1680 test_global->test_options = test_options;
1681 test_global->common_options = common_options;
1682
1684
1685 if (set_num_cpu(test_global))
1686 exit(EXIT_FAILURE);
1687
1688 print_info(&test_global->test_options);
1689
1690 /* Loop all test cases */
1691 num_tests = ODPH_ARRAY_SIZE(test_suite);
1692
1693 for (i = 0; i < num_tests; i++) {
1694 /* Initialize test variables */
1695 if (init_test(test_global, test_suite[i].name, test_suite[i].type)) {
1696 ODPH_ERR("Failed to initialize atomics.\n");
1697 exit(EXIT_FAILURE);
1698 }
1699
1700 /* Start workers */
1701 if (start_workers(test_global, instance, test_suite[i].test_fn, test_suite[i].type))
1702 exit(EXIT_FAILURE);
1703
1704 /* Wait workers to exit */
1705 odph_thread_join(test_global->thread_tbl, test_global->test_options.num_cpu);
1706
1707 output_results(test_global, i);
1708
1709 /* Validate test results */
1710 if (validate_results(test_global, test_suite[i].validate_fn, test_suite[i].type)) {
1711 ODPH_ERR("Test %s result validation failed.\n", test_suite[i].name);
1712 exit(EXIT_FAILURE);
1713 }
1714 }
1715
1716 if (output_summary(test_global)) {
1717 ODPH_ERR("Outputting summary failed.\n");
1718 exit(EXIT_FAILURE);
1719 }
1720
1721 if (odp_shm_free(shm)) {
1722 ODPH_ERR("Shm free failed.\n");
1723 exit(EXIT_FAILURE);
1724 }
1725
1726 if (odp_term_local()) {
1727 ODPH_ERR("Local terminate failed.\n");
1728 exit(EXIT_FAILURE);
1729 }
1730
1731 if (odp_term_global(instance)) {
1732 ODPH_ERR("Global terminate failed.\n");
1733 exit(EXIT_FAILURE);
1734 }
1735
1736 return 0;
1737}
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
void odp_atomic_store_rel_u64(odp_atomic_u64_t *atom, uint64_t val)
Store value to atomic uint64 variable using RELEASE memory ordering.
int odp_atomic_cas_rel_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t new_val)
Compare and swap atomic uint64 variable using RELEASE memory ordering.
uint32_t odp_atomic_fetch_max_u32(odp_atomic_u32_t *atom, uint32_t new_max)
Fetch and update maximum value of atomic uint32 variable.
void odp_atomic_max_u64(odp_atomic_u64_t *atom, uint64_t new_max)
Update maximum value of atomic uint64 variable.
void odp_atomic_bit_set_u32(odp_atomic_u32_t *atom, uint32_t bits)
Set bits in atomic uint32 variable.
int odp_atomic_cas_acq_u32(odp_atomic_u32_t *atom, uint32_t *old_val, uint32_t new_val)
Compare and swap atomic uint32 variable using ACQUIRE memory ordering.
int odp_atomic_cas_acq_rel_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t new_val)
Compare and swap atomic uint64 variable using ACQUIRE-and-RELEASE memory ordering.
void odp_atomic_add_u32(odp_atomic_u32_t *atom, uint32_t val)
Add to atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_inc_u32(odp_atomic_u32_t *atom)
Increment atomic uint32 variable.
void odp_atomic_dec_u64(odp_atomic_u64_t *atom)
Decrement atomic uint64 variable.
void odp_atomic_bit_set_u64(odp_atomic_u64_t *atom, uint64_t bits)
Set bits in atomic uint64 variable.
void odp_atomic_bit_clr_rel_u64(odp_atomic_u64_t *atom, uint64_t bits)
Clear bits in atomic uint64 variable using RELEASE memory ordering.
void odp_atomic_init_u64(odp_atomic_u64_t *atom, uint64_t val)
Initialize atomic uint64 variable.
void odp_atomic_max_u32(odp_atomic_u32_t *atom, uint32_t new_max)
Update maximum value of atomic uint32 variable.
uint32_t odp_atomic_fetch_sub_u32(odp_atomic_u32_t *atom, uint32_t val)
Fetch and subtract from atomic uint32 variable.
uint64_t odp_atomic_fetch_max_u64(odp_atomic_u64_t *atom, uint64_t new_max)
Fetch and update maximum value of atomic uint64 variable.
int odp_atomic_cas_acq_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val)
Compare and swap atomic odp_u128_t variable using ACQUIRE-and-RELEASE memory ordering.
uint64_t odp_atomic_load_acq_u64(odp_atomic_u64_t *atom)
Load value of atomic uint64 variable using ACQUIRE memory ordering.
uint64_t odp_atomic_xchg_u64(odp_atomic_u64_t *atom, uint64_t new_val)
Exchange value of atomic uint64 variable.
int odp_atomic_lock_free_u64(odp_atomic_op_t *atomic_op)
Query which atomic uint64 operations are lock-free.
uint64_t odp_atomic_fetch_min_u64(odp_atomic_u64_t *atom, uint64_t new_min)
Fetch and update minimum value of atomic uint64_t variable.
uint32_t odp_atomic_fetch_min_u32(odp_atomic_u32_t *atom, uint32_t new_min)
Fetch and update minimum value of atomic uint32 variable.
void odp_atomic_dec_u32(odp_atomic_u32_t *atom)
Decrement atomic uint32 variable.
void odp_atomic_min_u32(odp_atomic_u32_t *atom, uint32_t new_min)
Update minimum value of atomic uint32 variable.
uint32_t odp_atomic_fetch_inc_u32(odp_atomic_u32_t *atom)
Fetch and increment atomic uint32 variable.
uint32_t odp_atomic_fetch_add_u32(odp_atomic_u32_t *atom, uint32_t val)
Fetch and add to atomic uint32 variable.
uint64_t odp_atomic_bit_fetch_clr_u64(odp_atomic_u64_t *atom, uint64_t bits)
Fetch value and clear bits in atomic uint64 variable.
uint32_t odp_atomic_load_acq_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable using ACQUIRE memory ordering.
uint32_t odp_atomic_bit_fetch_set_u32(odp_atomic_u32_t *atom, uint32_t bits)
Fetch value and set bits in atomic uint32 variable.
void odp_atomic_bit_set_rel_u64(odp_atomic_u64_t *atom, uint64_t bits)
Set bits in atomic uint64 variable using RELEASE memory ordering.
uint64_t odp_atomic_fetch_dec_u64(odp_atomic_u64_t *atom)
Fetch and decrement atomic uint64 variable.
int odp_atomic_cas_u32(odp_atomic_u32_t *atom, uint32_t *old_val, uint32_t new_val)
Compare and swap atomic uint32 variable.
void odp_atomic_add_rel_u32(odp_atomic_u32_t *atom, uint32_t val)
Add to atomic uint32 variable using RELEASE memory ordering.
int odp_atomic_cas_rel_u32(odp_atomic_u32_t *atom, uint32_t *old_val, uint32_t new_val)
Compare and swap atomic uint32 variable using RELEASE memory ordering.
void odp_atomic_bit_set_rel_u32(odp_atomic_u32_t *atom, uint32_t bits)
Set bits in atomic uint32 variable using RELEASE memory ordering.
void odp_atomic_bit_clr_u32(odp_atomic_u32_t *atom, uint32_t bits)
Clear bits in atomic uint32 variable.
int odp_atomic_cas_acq_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val)
Compare and swap atomic odp_u128_t variable using ACQUIRE memory ordering.
void odp_atomic_inc_u64(odp_atomic_u64_t *atom)
Increment atomic uint64 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
uint64_t odp_atomic_fetch_sub_u64(odp_atomic_u64_t *atom, uint64_t val)
Fetch and subtract from atomic uint64 variable.
int odp_atomic_cas_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val)
Compare and swap atomic odp_u128_t variable.
int odp_atomic_cas_rel_u128(odp_atomic_u128_t *atom, odp_u128_t *old_val, odp_u128_t new_val)
Compare and swap atomic odp_u128_t variable using RELEASE memory ordering.
int odp_atomic_lock_free_u128(odp_atomic_op_t *atomic_op)
Query which atomic odp_atomic_u128_t operations are lock-free.
void odp_atomic_sub_rel_u32(odp_atomic_u32_t *atom, uint32_t val)
Subtract from atomic uint32 variable using RELEASE memory ordering.
uint32_t odp_atomic_bit_fetch_clr_u32(odp_atomic_u32_t *atom, uint32_t bits)
Fetch value and clear bits in atomic uint32 variable.
void odp_atomic_sub_u64(odp_atomic_u64_t *atom, uint64_t val)
Subtract from atomic uint64 variable.
odp_u128_t odp_atomic_load_u128(odp_atomic_u128_t *atom)
Load value of atomic odp_u128_t variable.
uint32_t odp_atomic_fetch_dec_u32(odp_atomic_u32_t *atom)
Fetch and decrement atomic uint32 variable.
void odp_atomic_store_u64(odp_atomic_u64_t *atom, uint64_t val)
Store value to atomic uint64 variable.
void odp_atomic_add_u64(odp_atomic_u64_t *atom, uint64_t val)
Add to atomic uint64 variable.
int odp_atomic_cas_acq_rel_u32(odp_atomic_u32_t *atom, uint32_t *old_val, uint32_t new_val)
Compare and swap atomic uint32 variable using ACQUIRE-and-RELEASE memory ordering.
int odp_atomic_cas_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t new_val)
Compare and swap atomic uint64 variable.
void odp_atomic_add_rel_u64(odp_atomic_u64_t *atom, uint64_t val)
Add to atomic uint64 variable using RELEASE memory ordering.
uint64_t odp_atomic_fetch_inc_u64(odp_atomic_u64_t *atom)
Fetch and increment atomic uint64 variable.
uint32_t odp_atomic_xchg_u32(odp_atomic_u32_t *atom, uint32_t new_val)
Exchange value of atomic uint32 variable.
uint64_t odp_atomic_bit_fetch_set_u64(odp_atomic_u64_t *atom, uint64_t bits)
Fetch value and set bits in atomic uint64 variable.
void odp_atomic_min_u64(odp_atomic_u64_t *atom, uint64_t new_min)
Update minimum value of atomic uint64 variable.
void odp_atomic_sub_u32(odp_atomic_u32_t *atom, uint32_t val)
Subtract from atomic uint32 variable.
int odp_atomic_cas_acq_u64(odp_atomic_u64_t *atom, uint64_t *old_val, uint64_t new_val)
Compare and swap atomic uint64 variable using ACQUIRE memory ordering.
void odp_atomic_init_u128(odp_atomic_u128_t *atom, odp_u128_t val)
Initialize atomic odp_u128_t variable.
void odp_atomic_sub_rel_u64(odp_atomic_u64_t *atom, uint64_t val)
Subtract from atomic uint64 variable using RELEASE memory ordering.
void odp_atomic_store_u128(odp_atomic_u128_t *atom, odp_u128_t val)
Store value to atomic odp_u128_t variable.
void odp_atomic_bit_clr_u64(odp_atomic_u64_t *atom, uint64_t bits)
Clear bits in atomic uint64 variable.
void odp_atomic_bit_clr_rel_u32(odp_atomic_u32_t *atom, uint32_t bits)
Clear bits in atomic uint32 variable using RELEASE memory ordering.
uint64_t odp_atomic_fetch_add_u64(odp_atomic_u64_t *atom, uint64_t val)
Fetch and add to atomic uint64 variable.
uint64_t odp_atomic_load_u64(odp_atomic_u64_t *atom)
Load value of atomic uint64 variable.
void odp_atomic_store_rel_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable using RELEASE memory ordering.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
#define ODP_ALIGNED_CACHE
Defines type/struct/variable to be cache line size aligned.
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition spec/hints.h:54
uint64_t odp_cpu_cycles_diff(uint64_t c2, uint64_t c1)
CPU cycle count difference.
uint64_t odp_cpu_cycles(void)
Current CPU cycle count.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
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.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
#define ODP_SHM_INVALID
Invalid shared memory block.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
void odp_sys_info_print(void)
Print system info.
#define ODP_THREAD_COUNT_MAX
Maximum number of threads supported in build time.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
odp_time_t odp_time_local_strict(void)
Current local time (strict)
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_mem_model_t mem_model
Application memory model.
odp_feature_t not_used
Unused features.
128-bit unsigned integer structure
uint64_t u64[2]
128 bits as uint64_t words
Atomic operations.
uint32_t fetch_max
Atomic fetch and maximum.
struct odp_atomic_op_t::@2 op
Operation flags.
uint32_t bit_clr
Atomic bit clear.
uint32_t fetch_add
Atomic fetch and add.
uint32_t fetch_sub
Atomic fetch and subtract.
uint32_t xchg
Atomic exchange.
uint32_t bit_set
Atomic bit set.
uint32_t sub
Atomic subtract.
uint32_t load
Atomic load.
uint32_t fetch_dec
Atomic fetch and decrement.
uint32_t fetch_inc
Atomic fetch and increment.
uint32_t inc
Atomic increment.
uint32_t bit_fetch_set
Atomic bit fetch and set.
uint32_t min
Atomic minimum.
uint32_t max
Atomic maximum.
uint32_t all_bits
All bits of the bit field structure.
uint32_t cas
Atomic compare and swap.
uint32_t store
Atomic store.
uint32_t fetch_min
Atomic fetch and minimum.
uint32_t dec
Atomic decrement.
uint32_t add
Atomic add.
uint32_t bit_fetch_clr
Atomic bit fetch and clear.
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()