API Reference Manual  1.46.0
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 */
42 typedef void (*test_fn_t)(void *val, void *out, uint32_t num_round);
43 /* Test result validation function template */
44 typedef int (*validate_fn_t)(void *val, void *out, uint32_t num_round,
45  uint32_t num_worker, int private);
46 
47 typedef enum {
48  OP_32BIT,
49  OP_64BIT,
50  OP_128BIT
51 } op_bit_t;
52 
53 /* Command line options */
54 typedef 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 */
62 typedef struct ODP_ALIGNED_CACHE test_atomic_t {
63  union {
64  odp_atomic_u32_t u32;
65  odp_atomic_u64_t u64;
66  odp_atomic_u128_t u128;
67  };
68 } test_atomic_t;
69 
70 typedef struct test_global_t test_global_t;
71 
72 /* Worker thread context */
73 typedef 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 
83 typedef 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 */
92 struct 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 
113 typedef 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 
120 static test_global_t *test_global;
121 
122 static 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 
134 static 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 
146 static 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 
165 static 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 
176 static 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 
186 static 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 
202 static 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 
211 static 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 
220 static 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 
235 static 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 
243 static 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 
251 static 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 
261 static 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 
273 static 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 
285 static 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 
296 static 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 
307 static 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 
315 static 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 
323 static 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 
335 static 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 
347 static 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 
358 static 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 
370 static 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 
378 static 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 
386 static 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 
398 static 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 
410 static 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 
418 static 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 
426 static 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 
438 static 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 
450 static 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 
458 static 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 
466 static 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 
475 static 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 
484 static 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 
492 static 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 
500 static 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 
512 static 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 
524 static 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 
535 static 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 
546 static 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 
555 static 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 
564 static 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 
572 static 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 
580 static 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 
592 static 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 
604 static 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 
615 static 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 
626 static 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 
638 static 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 
650 static 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 
670 static 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 
681 static 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 
692 static 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 
705 static 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 
718 static 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 
731 static 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 
739 static 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 
751 static 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 
759 static 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 
771 static 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 
779 static 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 
791 static 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 
799 static 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 
811 static 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 
823 static 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 
835 static 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 
844 static 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 
853 static 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 
861 static 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 
869 static 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 
877 static 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 
885 static 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 
897 static 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 
909 static 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 
929 static 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 
941 static 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 
953 static 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 
973 static 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 
985 static 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 
997 static 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 
1017 static 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 
1025 static 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 
1033 static 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 
1041 static 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 
1049 static 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 
1064 static 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 
1109 static 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 
1148 static 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 
1201 static 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 
1243 static 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 
1277 static 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 
1346 static 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 
1382 static 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 
1419 static 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 
1550 ODP_STATIC_ASSERT(ODPH_ARRAY_SIZE(test_suite) < TEST_MAX_BENCH,
1551  "Result array is too small to hold all the results");
1552 
1553 static 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 
1614 int 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.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
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
uint32_t u32[4]
128 bits as uint32_t words
uint64_t u64[2]
128 bits as uint64_t words
Atomic operations.
uint32_t fetch_max
Atomic fetch and maximum.
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.
struct odp_atomic_op_t::@6 op
Operation flags.
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()
uint32_t schedule
Scheduler APIs, e.g., odp_schedule_xxx()
struct odp_feature_t::@148 feat
Individual feature bits.
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()