API Reference Manual  1.46.0
odp_cpu_bench.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2018 Linaro Limited
3  */
4 
13 #include <odp_api.h>
14 #include <odp/helper/odph_api.h>
15 
16 #include <getopt.h>
17 #include <inttypes.h>
18 #include <signal.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 
22 /* Queues are divided into groups and tests packets are passed only between
23  * queues which belong to the same group. */
24 #define MAX_GROUPS 64
25 #define QUEUES_PER_GROUP 4
26 #define PKTS_PER_QUEUE 256
27 
28 #define MAX_EVENT_BURST 32
29 #define CRC_INIT_VAL 123456789
30 #define PASS_PACKETS 10000
31 
32 /* Default number of entries in the test lookup table */
33 #define DEF_LOOKUP_TBL_SIZE (1024 * 1024)
34 
35 #define MAX_WORKERS \
36  (((ODP_THREAD_COUNT_MAX - 1) > (MAX_GROUPS * QUEUES_PER_GROUP)) ? \
37  (MAX_GROUPS * QUEUES_PER_GROUP) : \
38  (ODP_THREAD_COUNT_MAX - 1))
39 
40 ODP_STATIC_ASSERT(MAX_WORKERS <= MAX_GROUPS * QUEUES_PER_GROUP,
41  "Not enough queues for all workers");
42 
43 /* Get rid of path in filename - only for unix-type paths using '/' */
44 #define NO_PATH(file_name) (strrchr((file_name), '/') ? \
45  strrchr((file_name), '/') + 1 : (file_name))
46 
47 /* Test dummy lookup table entry */
48 typedef struct {
49  uint64_t idx;
50  uint32_t val0;
51  uint32_t val1;
52 } lookup_entry_t;
53 
54 /* Test packet */
55 typedef struct {
56  uint32_t seq;
57  uint32_t crc;
58  uint16_t group;
59 } test_hdr_t;
60 
61 /* Parsed application arguments */
62 typedef struct {
63  uint64_t lookup_tbl_size; /* Lookup table size */
64  int accuracy; /* Number of seconds between stats prints */
65  unsigned int cpu_count; /* CPU count */
66  int time; /* Time in seconds to run */
67 } appl_args_t;
68 
69 /* Statistics */
70 typedef union ODP_ALIGNED_CACHE {
71  struct {
72  /* Number of processed packets */
73  uint64_t pkts;
74  /* Number of dropped packets */
75  uint64_t dropped_pkts;
76  /* Time spent processing packets */
77  uint64_t nsec;
78  /* Cycles spent processing packets */
79  uint64_t cycles;
80  } s;
81 
82  uint8_t padding[ODP_CACHE_LINE_SIZE];
83 } stats_t;
84 
85 /* Thread specific data */
86 typedef struct thread_args_t {
87  stats_t stats;
88  uint16_t idx;
89 } thread_args_t;
90 
91 /* Grouping of all global data */
92 typedef struct {
93  /* Thread specific arguments */
94  thread_args_t thread[MAX_WORKERS];
95  /* Barriers to synchronize main and workers */
96  odp_barrier_t init_barrier;
97  odp_barrier_t term_barrier;
98  /* Application (parsed) arguments */
99  appl_args_t appl;
100  /* Test queues */
101  odp_queue_t queue[MAX_GROUPS][QUEUES_PER_GROUP];
102  /* Test lookup table */
103  lookup_entry_t *lookup_tbl;
104  /* Break workers loop if set to 1 */
105  odp_atomic_u32_t exit_threads;
106 } args_t;
107 
108 /* Global pointer to args */
109 static args_t *gbl_args;
110 
111 static const uint8_t test_udp_packet[] = {
112  0x00, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00, 0x01,
113  0x02, 0x03, 0x04, 0x05, 0x08, 0x00, 0x45, 0x00,
114  0x02, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
115  0xF7, 0x7C, 0xC0, 0xA8, 0x00, 0x01, 0xC0, 0xA8,
116  0x00, 0x02, 0x04, 0xD2, 0x1A, 0x82, 0x02, 0x08,
117  0x24, 0x1E, 0xC9, 0x56, 0xB4, 0xD6, 0x4B, 0x64,
118  0xB3, 0x01, 0xA1, 0x97, 0x4D, 0xD1, 0xA4, 0x76,
119  0xF5, 0x7B, 0x27, 0x22, 0x6C, 0xA9, 0xED, 0x29,
120  0x6E, 0x02, 0x80, 0xF7, 0xC4, 0x2D, 0x2A, 0x96,
121  0x2D, 0xF6, 0x02, 0x8E, 0x89, 0x9F, 0x8C, 0xF4,
122  0x0D, 0xC5, 0xE5, 0x1F, 0xA1, 0x52, 0xC3, 0x4B,
123  0x5C, 0x4C, 0xDF, 0x14, 0x05, 0x6A, 0xA8, 0xD7,
124  0xAD, 0x4F, 0x22, 0xA6, 0xB8, 0xF9, 0x52, 0x5A,
125  0xB8, 0xF9, 0xE2, 0x2C, 0x05, 0x2A, 0x6F, 0xF2,
126  0xCA, 0xA1, 0xA7, 0xC3, 0x56, 0xE1, 0xDB, 0xC1,
127  0xDB, 0x86, 0x26, 0x55, 0xAC, 0xBE, 0xE1, 0x3D,
128  0x82, 0x86, 0xB9, 0xDE, 0x3E, 0xD3, 0x11, 0xAB,
129  0x65, 0x6A, 0xED, 0x1B, 0x60, 0xBE, 0x69, 0x71,
130  0xB2, 0xA8, 0x5B, 0xB1, 0x06, 0xE3, 0x48, 0x14,
131  0xC9, 0x13, 0x73, 0xDA, 0xBE, 0xE4, 0x7A, 0x5F,
132  0xC0, 0xE0, 0xCA, 0xF3, 0x7A, 0xCA, 0x3F, 0xC9,
133  0x4A, 0xEE, 0x47, 0x76, 0x67, 0xF0, 0x0D, 0x3F,
134  0x7F, 0x3D, 0x69, 0xEA, 0x39, 0x53, 0x7C, 0xE3,
135  0xED, 0x78, 0x79, 0x47, 0x60, 0x95, 0xCB, 0xDC,
136  0x26, 0x60, 0x46, 0xAC, 0x47, 0xDA, 0x4C, 0x4D,
137  0x0F, 0xE1, 0x68, 0x43, 0xBC, 0xCD, 0x4E, 0xFE,
138  0x2E, 0xD6, 0xC2, 0x6E, 0x63, 0xEA, 0xB3, 0x98,
139  0xCA, 0x8F, 0x7F, 0x05, 0xDF, 0x72, 0x8F, 0x6E,
140  0x3E, 0x6D, 0xC7, 0x94, 0x59, 0x9D, 0x15, 0x5B,
141  0xB8, 0x02, 0x52, 0x4F, 0x68, 0x3A, 0xF1, 0xFF,
142  0xA9, 0xA4, 0x30, 0x29, 0xE0, 0x1C, 0xA0, 0x1B,
143  0x50, 0xAB, 0xFD, 0x06, 0x84, 0xD4, 0x33, 0x51,
144  0x01, 0xB3, 0x5F, 0x49, 0x5F, 0x21, 0xA0, 0xA1,
145  0xC9, 0x08, 0xB3, 0xDF, 0x72, 0x9B, 0x5B, 0x70,
146  0x89, 0x96, 0x08, 0x25, 0x88, 0x1E, 0xED, 0x52,
147  0xDC, 0x98, 0xA0, 0xB8, 0x83, 0x2A, 0xA0, 0x90,
148  0x45, 0xC9, 0x77, 0xD2, 0x19, 0xD7, 0x6B, 0xAB,
149  0x49, 0x67, 0x7C, 0xD1, 0xE0, 0x23, 0xA2, 0x36,
150  0xB2, 0x91, 0x3B, 0x23, 0x3B, 0x03, 0x36, 0xAF,
151  0xAD, 0x81, 0xFA, 0x6F, 0x68, 0xD5, 0xBE, 0x73,
152  0x1D, 0x56, 0x8A, 0xE8, 0x1A, 0xB4, 0xA8, 0x7C,
153  0xF3, 0x82, 0x10, 0xD0, 0xF2, 0x1D, 0x9C, 0xEA,
154  0xAB, 0xE7, 0xEC, 0x53, 0x6D, 0x52, 0xBD, 0x29,
155  0x86, 0x21, 0xCE, 0xAA, 0xF3, 0x68, 0xA6, 0xEC,
156  0x7E, 0xCA, 0x6F, 0xEB, 0xE1, 0x81, 0x80, 0x7C,
157  0xF3, 0xE5, 0x22, 0xA0, 0x91, 0x08, 0xB7, 0x35,
158  0x15, 0x87, 0x0C, 0x77, 0x31, 0x9C, 0x2F, 0x73,
159  0xCE, 0x29, 0x6F, 0xC6, 0xAC, 0x9F, 0x68, 0xB8,
160  0x6A, 0xFC, 0xD3, 0xB5, 0x08, 0x98, 0xAE, 0xE4,
161  0x20, 0x84, 0x24, 0x69, 0xA5, 0xF5, 0x4A, 0x9D,
162  0x44, 0x26, 0x5A, 0xF9, 0x6B, 0x5E, 0x5D, 0xC8,
163  0x6F, 0xD4, 0x62, 0x91, 0xE5, 0x8E, 0x80, 0x05,
164  0xA1, 0x95, 0x09, 0xEA, 0xFE, 0x84, 0x6D, 0xC3,
165  0x0D, 0xD4, 0x32, 0xA4, 0x38, 0xB2, 0xF7, 0x9D,
166  0x58, 0xD3, 0x5D, 0x93, 0x5F, 0x67, 0x86, 0xE1,
167  0xAF, 0xFF, 0xE9, 0xFE, 0xF4, 0x71, 0x63, 0xE3,
168  0x3E, 0xE1, 0x7A, 0x80, 0x5A, 0x23, 0x4F, 0x5B,
169  0x54, 0x21, 0x0E, 0xE2, 0xAF, 0x01, 0x2E, 0xA4,
170  0xF5, 0x1F, 0x59, 0x96, 0x3E, 0x82, 0xF3, 0x44,
171  0xDF, 0xA6, 0x7C, 0x64, 0x5D, 0xC7, 0x79, 0xA1,
172  0x17, 0xE1, 0x06, 0x14, 0x3E, 0x1B, 0x46, 0xCA,
173  0x71, 0xC8, 0x05, 0x62, 0xD0, 0x56, 0x23, 0x9B,
174  0xBA, 0xFE, 0x6D, 0xA8, 0x03, 0x4C, 0x23, 0xD8,
175  0x98, 0x8A, 0xE8, 0x9C, 0x93, 0x8E, 0xB7, 0x24,
176  0x31, 0x2A, 0x81, 0x72, 0x8F, 0x13, 0xD4, 0x7E,
177  0xEB, 0xB1, 0xEE, 0x33, 0xD9, 0xF4, 0x96, 0x5E,
178  0x6C, 0x3D, 0x45, 0x9C, 0xE0, 0x71, 0xA3, 0xFA,
179  0x17, 0x2B, 0xC3, 0x07, 0xD6, 0x86, 0xA2, 0x06,
180  0xC5, 0x33, 0xF0, 0xEA, 0x25, 0x70, 0x68, 0x56,
181  0xD5, 0xB0
182 };
183 
184 static void sig_handler(int signo ODP_UNUSED)
185 {
186  if (gbl_args == NULL)
187  return;
188  odp_atomic_store_u32(&gbl_args->exit_threads, 1);
189 }
190 
191 static inline void init_packet(odp_packet_t pkt, uint32_t seq, uint16_t group)
192 {
193  odp_una_u32_t *payload;
194  test_hdr_t *hdr;
196 
197  param.proto = ODP_PROTO_ETH;
199  param.chksums.all_chksum = 0;
200  if (odp_packet_parse(pkt, 0, &param))
201  ODPH_ABORT("odp_packet_parse() failed\n");
202 
203  /* Modify UDP payload and update checksum */
204  payload = odp_packet_offset(pkt, odp_packet_l4_offset(pkt) +
205  ODPH_UDPHDR_LEN, NULL, NULL);
206  *payload = seq;
207  if (odph_udp_chksum_set(pkt))
208  ODPH_ABORT("odph_udp_chksum_set() failed\n");
209 
210  /* Test header is stored in user area */
211  hdr = odp_packet_user_area(pkt);
212  hdr->seq = seq;
213  hdr->group = group;
214  hdr->crc = odp_hash_crc32c(odp_packet_data(pkt), odp_packet_len(pkt),
215  CRC_INIT_VAL);
216 }
217 
218 static inline odp_queue_t work_on_event(odp_event_t event)
219 {
220  odp_packet_t pkt;
222  odph_udphdr_t *udp_hdr;
223  test_hdr_t *hdr;
224  lookup_entry_t *lookup_entry;
225  odp_una_u32_t *payload;
226  uint32_t crc;
227  uint32_t pkt_len;
228  uint8_t *data;
229  uint32_t new_val;
230  uint32_t old_val;
231 
232  if (odp_event_type(event) != ODP_EVENT_PACKET)
233  return ODP_QUEUE_INVALID;
234 
235  pkt = odp_packet_from_event(event);
236  hdr = odp_packet_user_area(pkt);
237  pkt_len = odp_packet_len(pkt);
238  data = odp_packet_data(pkt);
239 
240  crc = odp_hash_crc32c(data, pkt_len, CRC_INIT_VAL);
241  if (crc != hdr->crc)
242  ODPH_ERR("Error: Invalid packet crc\n");
243 
244  param.proto = ODP_PROTO_ETH;
246  param.chksums.all_chksum = 1;
247  if (odp_packet_parse(pkt, 0, &param)) {
248  ODPH_ERR("Error: odp_packet_parse() failed\n");
249  return ODP_QUEUE_INVALID;
250  }
251 
252  /* Modify packet data using lookup table value and sequence number, and
253  * update UDP checksum accordingly. */
254  lookup_entry = &gbl_args->lookup_tbl[(crc + hdr->seq) %
255  gbl_args->appl.lookup_tbl_size];
256  udp_hdr = odp_packet_l4_ptr(pkt, NULL);
257  payload = odp_packet_offset(pkt, odp_packet_l4_offset(pkt) +
258  ODPH_UDPHDR_LEN, NULL, NULL);
259  old_val = *payload;
260  *payload += lookup_entry->idx % 2 ? lookup_entry->val1 :
261  lookup_entry->val0;
262  new_val = *payload;
263  udp_hdr->chksum = ~(~udp_hdr->chksum + (-old_val) + new_val);
264 
265  payload++;
266  old_val = *payload;
267  *payload += hdr->seq;
268  new_val = *payload;
269  udp_hdr->chksum = ~(~udp_hdr->chksum + (-old_val) + new_val);
270 
271  hdr->crc = odp_hash_crc32c(data, pkt_len, CRC_INIT_VAL);
272 
273  return gbl_args->queue[hdr->group][hdr->seq++ % QUEUES_PER_GROUP];
274 }
275 
279 static int run_thread(void *arg)
280 {
281  thread_args_t *thr_args = arg;
282  stats_t *stats = &thr_args->stats;
283  odp_time_t t1, t2;
284  uint64_t c1, c2;
285 
286  odp_barrier_wait(&gbl_args->init_barrier);
287 
288  c1 = odp_cpu_cycles();
289  t1 = odp_time_local();
290 
291  while (!odp_atomic_load_u32(&gbl_args->exit_threads)) {
292  odp_event_t event_tbl[MAX_EVENT_BURST];
293  odp_queue_t dst_queue;
294  int num_events;
295  int i;
296 
297  num_events = odp_schedule_multi(NULL, ODP_SCHED_NO_WAIT,
298  event_tbl, MAX_EVENT_BURST);
299  if (num_events <= 0)
300  continue;
301 
302  for (i = 0; i < num_events; i++) {
303  odp_event_t event = event_tbl[i];
304 
305  dst_queue = work_on_event(event);
306  if (odp_unlikely(dst_queue == ODP_QUEUE_INVALID)) {
307  stats->s.dropped_pkts++;
308  odp_event_free(event);
309  continue;
310  }
311 
312  if (odp_unlikely(odp_queue_enq(dst_queue, event))) {
313  ODPH_ERR("Error: odp_queue_enq() failed\n");
314  stats->s.dropped_pkts++;
315  odp_event_free(event);
316  break;
317  }
318 
319  stats->s.pkts++;
320  }
321  }
322 
323  c2 = odp_cpu_cycles();
324  t2 = odp_time_local();
325 
326  stats->s.cycles = c2 - c1;
327  stats->s.nsec = odp_time_diff_ns(t2, t1);
328 
329  odp_barrier_wait(&gbl_args->term_barrier);
330 
331  /* Free remaining events in queues */
332  while (1) {
333  odp_event_t ev;
334 
335  ev = odp_schedule(NULL,
337 
338  if (ev == ODP_EVENT_INVALID)
339  break;
340 
341  odp_event_free(ev);
342  }
343 
344  return 0;
345 }
346 
347 /*
348  * Print usage information
349  */
350 static void usage(char *progname)
351 {
352  printf("\n"
353  "OpenDataPlane CPU benchmarking application.\n"
354  "\n"
355  "Usage: %s [options]\n"
356  "\n"
357  " E.g. %s -c 4 -t 30\n"
358  "Options:\n"
359  " -c, --count <number> CPU count, 0=all available, default=1\n"
360  " -t, --time <sec> Time in seconds to run\n"
361  " (default is 10 second).\n"
362  " -a, --accuracy <sec> Time in seconds get print statistics\n"
363  " (default is 1 second).\n"
364  " -l, --lookup_tbl <num> Number of entries in dummy lookup table\n"
365  " (default is %d).\n"
366  " -h, --help Display help and exit.\n\n"
367  "\n", NO_PATH(progname), NO_PATH(progname), DEF_LOOKUP_TBL_SIZE);
368 }
369 
377 static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
378 {
379  int opt;
380 
381  static const struct option longopts[] = {
382  {"accuracy", required_argument, NULL, 'a'},
383  {"cpu", required_argument, NULL, 'c'},
384  {"lookup_tbl", required_argument, NULL, 'l'},
385  {"time", required_argument, NULL, 't'},
386  {"help", no_argument, NULL, 'h'},
387  {NULL, 0, NULL, 0}
388  };
389 
390  static const char *shortopts = "+a:c:l:t:h";
391 
392  appl_args->accuracy = 1; /* Get and print pps stats second */
393  appl_args->cpu_count = 1;
394  appl_args->lookup_tbl_size = DEF_LOOKUP_TBL_SIZE;
395  appl_args->time = 10; /* Loop forever if time to run is 0 */
396 
397  while (1) {
398  opt = getopt_long(argc, argv, shortopts, longopts, NULL);
399 
400  if (opt == -1)
401  break; /* No more options */
402 
403  switch (opt) {
404  case 'a':
405  appl_args->accuracy = atoi(optarg);
406  break;
407  case 'c':
408  appl_args->cpu_count = atoi(optarg);
409  break;
410  case 'l':
411  appl_args->lookup_tbl_size = atoi(optarg);
412  break;
413  case 't':
414  appl_args->time = atoi(optarg);
415  break;
416  case 'h':
417  usage(argv[0]);
418  exit(EXIT_SUCCESS);
419  break;
420 
421  default:
422  break;
423  }
424  }
425 
426  if (appl_args->lookup_tbl_size < 1) {
427  printf("At least one lookup table entry required.\n");
428  exit(EXIT_FAILURE);
429  }
430 }
431 
432 /*
433  * Print statistics
434  *
435  * num_workers Number of worker threads
436  * thr_stats Pointers to stats storage
437  * duration Number of seconds to loop
438  */
439 static int print_stats(int num_workers, stats_t **thr_stats, int duration,
440  int accuracy)
441 {
442  uint64_t pkts;
443  uint64_t dropped;
444  uint64_t pkts_prev = 0;
445  uint64_t nsec = 0;
446  uint64_t cycles = 0;
447  int i;
448  int elapsed = 0;
449  int stats_enabled = 1;
450  int loop_forever = (duration == 0);
451 
452  if (accuracy <= 0) {
453  stats_enabled = 0;
454  accuracy = 1;
455  }
456  /* Wait for all threads to be ready*/
457  odp_barrier_wait(&gbl_args->init_barrier);
458 
459  do {
460  uint64_t pps;
461 
462  sleep(accuracy);
463 
464  pkts = 0;
465  dropped = 0;
466  for (i = 0; i < num_workers; i++) {
467  pkts += thr_stats[i]->s.pkts;
468  dropped += thr_stats[i]->s.dropped_pkts;
469  }
470 
471  pps = (pkts - pkts_prev) / accuracy;
472 
473  if (stats_enabled) {
474  printf("%.2f Mpps, ", pps / 1000000.0);
475 
476  printf("%" PRIu64 " dropped\n", dropped);
477  }
478 
479  pkts_prev = pkts;
480  elapsed += accuracy;
481  } while (!odp_atomic_load_u32(&gbl_args->exit_threads) &&
482  (loop_forever || (elapsed < duration)));
483 
484  odp_atomic_store_u32(&gbl_args->exit_threads, 1);
485  odp_barrier_wait(&gbl_args->term_barrier);
486 
487  pkts = 0;
488  dropped = 0;
489  for (i = 0; i < num_workers; i++) {
490  pkts += thr_stats[i]->s.pkts;
491  dropped += thr_stats[i]->s.dropped_pkts;
492  nsec += thr_stats[i]->s.nsec;
493  cycles += thr_stats[i]->s.cycles;
494  }
495 
496  printf("\nRESULTS - per thread (Million packets per sec):\n");
497  printf("-----------------------------------------------\n");
498  printf(" avg 1 2 3 4 5 6 7 8 9 10\n");
499  printf("%6.2f ", pkts / (nsec / 1000.0));
500 
501  for (i = 0; i < num_workers; i++) {
502  if (i != 0 && (i % 10) == 0)
503  printf("\n ");
504 
505  printf("%6.2f ", thr_stats[i]->s.pkts /
506  (thr_stats[i]->s.nsec / 1000.0));
507  }
508  printf("\n\n");
509 
510  nsec /= num_workers;
511  printf("RESULTS - total over %i threads:\n", num_workers);
512  printf("----------------------------------\n");
513  printf(" avg packets per sec: %.3f M\n", pkts / (nsec / 1000.0));
514  printf(" avg cycles per packet: %" PRIu64 "\n", cycles / pkts);
515  printf(" dropped packets: %" PRIu64 "\n\n", dropped);
516 
517  return pkts > PASS_PACKETS ? 0 : -1;
518 }
519 
520 static void gbl_args_init(args_t *args)
521 {
522  memset(args, 0, sizeof(args_t));
523  odp_atomic_init_u32(&args->exit_threads, 0);
524 }
525 
529 int main(int argc, char *argv[])
530 {
531  stats_t *stats[MAX_WORKERS];
532  odph_helper_options_t helper_options;
533  odph_thread_t thread_tbl[MAX_WORKERS];
534  odph_thread_common_param_t thr_common;
535  odph_thread_param_t thr_param[MAX_WORKERS];
536  odp_cpumask_t cpumask;
537  odp_pool_capability_t pool_capa;
538  odp_pool_t pool;
539  odp_schedule_config_t schedule_config;
540  odp_shm_t shm;
541  odp_shm_t lookup_tbl_shm;
542  odp_pool_param_t params;
543  odp_instance_t instance;
544  odp_init_t init;
545  char cpumaskstr[ODP_CPUMASK_STR_SIZE];
546  uint32_t num_pkts;
547  uint32_t num_groups;
548  uint32_t num_queues;
549  uint32_t pkts_per_group;
550  uint32_t pkt_len;
551  uint32_t init_val;
552  unsigned int num_workers;
553  unsigned int i, j;
554  int ret = 0;
555 
556  /* Let helper collect its own arguments (e.g. --odph_proc) */
557  argc = odph_parse_options(argc, argv);
558  if (odph_options(&helper_options)) {
559  ODPH_ERR("Error: reading ODP helper options failed.\n");
560  exit(EXIT_FAILURE);
561  }
562 
563  odp_init_param_init(&init);
564 
565  /* List features not to be used (may optimize performance) */
566  init.not_used.feat.cls = 1;
567  init.not_used.feat.compress = 1;
568  init.not_used.feat.crypto = 1;
569  init.not_used.feat.ipsec = 1;
570  init.not_used.feat.timer = 1;
571  init.not_used.feat.tm = 1;
572 
573  init.mem_model = helper_options.mem_model;
574 
575  /* Signal handler has to be registered before global init in case ODP
576  * implementation creates internal threads/processes. */
577  signal(SIGINT, sig_handler);
578 
579  if (odp_init_global(&instance, &init, NULL)) {
580  ODPH_ERR("Error: ODP global init failed\n");
581  return -1;
582  }
583 
584  if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
585  ODPH_ERR("Error: ODP local init failed\n");
586  exit(EXIT_FAILURE);
587  }
588 
589  shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE,
590  0);
591  if (shm == ODP_SHM_INVALID) {
592  ODPH_ERR("Error: shared mem reserve failed.\n");
593  exit(EXIT_FAILURE);
594  }
595 
596  gbl_args = odp_shm_addr(shm);
597  if (gbl_args == NULL) {
598  ODPH_ERR("Error: shared mem alloc failed\n");
599  exit(EXIT_FAILURE);
600  }
601  gbl_args_init(gbl_args);
602 
603  /* Parse and store the application arguments */
604  parse_args(argc, argv, &gbl_args->appl);
605 
606  lookup_tbl_shm = odp_shm_reserve("lookup_tbl_shm",
607  sizeof(lookup_entry_t) *
608  gbl_args->appl.lookup_tbl_size,
609  ODP_CACHE_LINE_SIZE, 0);
610  if (lookup_tbl_shm == ODP_SHM_INVALID) {
611  ODPH_ERR("Error: shared mem reserve failed.\n");
612  exit(EXIT_FAILURE);
613  }
614 
615  gbl_args->lookup_tbl = odp_shm_addr(lookup_tbl_shm);
616  if (gbl_args->lookup_tbl == NULL) {
617  ODPH_ERR("Error: lookup table mem alloc failed\n");
618  exit(EXIT_FAILURE);
619  }
620 
621  printf("\n");
623 
624  /* Default to system CPU count unless user specified */
625  num_workers = MAX_WORKERS;
626  if (gbl_args->appl.cpu_count && gbl_args->appl.cpu_count < MAX_WORKERS)
627  num_workers = gbl_args->appl.cpu_count;
628 
629  /* Get default worker cpumask */
630  num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
631  (void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
632 
633  printf("num worker threads: %i\n", num_workers);
634  printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
635  printf("cpu mask: %s\n", cpumaskstr);
636 
637  odp_schedule_config_init(&schedule_config);
638  odp_schedule_config(&schedule_config);
639 
640  /* Make sure a single queue can store all the packets in a group */
641  pkts_per_group = QUEUES_PER_GROUP * PKTS_PER_QUEUE;
642  if (schedule_config.queue_size &&
643  schedule_config.queue_size < pkts_per_group)
644  pkts_per_group = schedule_config.queue_size;
645 
646  /* Divide queues evenly into groups */
647  if (schedule_config.num_queues < QUEUES_PER_GROUP) {
648  ODPH_ERR("Error: min %d queues required\n", QUEUES_PER_GROUP);
649  return -1;
650  }
651  num_queues = num_workers > schedule_config.num_queues ?
652  schedule_config.num_queues : num_workers;
653  num_groups = (num_queues + QUEUES_PER_GROUP - 1) / QUEUES_PER_GROUP;
654  if (num_groups * QUEUES_PER_GROUP > schedule_config.num_queues)
655  num_groups--;
656  num_queues = num_groups * QUEUES_PER_GROUP;
657 
658  for (i = 0; i < num_groups; i++) {
659  for (j = 0; j < QUEUES_PER_GROUP; j++) {
660  odp_queue_t queue;
661  odp_queue_param_t param;
662 
663  odp_queue_param_init(&param);
664  param.type = ODP_QUEUE_TYPE_SCHED;
668  param.size = pkts_per_group;
669 
670  queue = odp_queue_create(NULL, &param);
671  if (queue == ODP_QUEUE_INVALID) {
672  ODPH_ERR("Error: odp_queue_create() failed\n");
673  return -1;
674  }
675  gbl_args->queue[i][j] = queue;
676  }
677  }
678 
679  /* Create packet pool */
680  if (odp_pool_capability(&pool_capa)) {
681  ODPH_ERR("Error: odp_pool_capability() failed\n");
682  exit(EXIT_FAILURE);
683  }
684  num_pkts = pkts_per_group * num_groups;
685  if (num_pkts > pool_capa.pkt.max_num)
686  num_pkts = pool_capa.pkt.max_num;
687 
688  pkt_len = sizeof(test_udp_packet);
689  if (pool_capa.pkt.max_len && pkt_len > pool_capa.pkt.max_len)
690  pkt_len = pool_capa.pkt.max_len;
691 
692  if (pool_capa.pkt.max_seg_len && pkt_len > pool_capa.pkt.max_seg_len)
693  pkt_len = pool_capa.pkt.max_seg_len;
694 
695  if (pkt_len < sizeof(test_udp_packet)) {
696  ODPH_ERR("Error: min %dB single segment packets required\n",
697  (int)sizeof(test_udp_packet));
698  exit(EXIT_FAILURE);
699  }
700 
701  if (pool_capa.pkt.max_uarea_size &&
702  pool_capa.pkt.max_uarea_size < sizeof(test_hdr_t)) {
703  ODPH_ERR("Error: min %dB of packet user area required\n",
704  (int)sizeof(test_hdr_t));
705  exit(EXIT_FAILURE);
706  }
707 
708  odp_pool_param_init(&params);
709  params.pkt.len = pkt_len;
710  params.pkt.max_len = pkt_len;
711  params.pkt.seg_len = pkt_len;
712  params.pkt.num = num_pkts;
713  params.pkt.max_num = num_pkts;
714  params.pkt.uarea_size = sizeof(test_hdr_t);
715  params.type = ODP_POOL_PACKET;
716  pool = odp_pool_create("pkt_pool", &params);
717  if (pool == ODP_POOL_INVALID) {
718  ODPH_ERR("Error: packet pool create failed\n");
719  exit(EXIT_FAILURE);
720  }
721  odp_pool_print(pool);
722 
723  printf("CPU bench args\n--------------\n");
724  printf(" workers: %u\n", num_workers);
725  printf(" queues: %" PRIu32 "\n", num_queues);
726  printf(" pkts: %" PRIu32 "\n", num_pkts);
727  printf(" pkt size: %" PRIu32 " B\n", pkt_len);
728  printf(" lookup entries: %" PRIu64 "\n\n",
729  gbl_args->appl.lookup_tbl_size);
730 
731  /* Spread test packets into queues */
732  for (i = 0; i < num_pkts; i++) {
733  odp_packet_t pkt = odp_packet_alloc(pool, pkt_len);
734  odp_event_t ev;
735  odp_queue_t queue;
736  uint16_t group = i % num_groups;
737 
738  if (pkt == ODP_PACKET_INVALID) {
739  ODPH_ERR("Error: odp_packet_alloc() failed\n");
740  return -1;
741  }
742 
743  odp_packet_copy_from_mem(pkt, 0, pkt_len, test_udp_packet);
744 
745  init_packet(pkt, i, group);
746 
747  queue = gbl_args->queue[group][i % QUEUES_PER_GROUP];
748 
749  ev = odp_packet_to_event(pkt);
750  if (odp_queue_enq(queue, ev)) {
751  ODPH_ERR("Error: odp_queue_enq() failed\n");
752  return -1;
753  }
754  }
755 
756  odp_barrier_init(&gbl_args->init_barrier, num_workers + 1);
757  odp_barrier_init(&gbl_args->term_barrier, num_workers + 1);
758 
759  /* Initialize lookup table */
760  init_val = CRC_INIT_VAL;
761  for (i = 0; i < gbl_args->appl.lookup_tbl_size; i++) {
762  uint32_t *val0 = &gbl_args->lookup_tbl[i].val0;
763  uint32_t *val1 = &gbl_args->lookup_tbl[i].val1;
764 
765  gbl_args->lookup_tbl[i].idx = i;
766 
767  *val0 = i;
768  *val0 = odp_hash_crc32c(val0, sizeof(uint32_t), init_val);
769  *val1 = odp_hash_crc32c(val0, sizeof(uint32_t), init_val);
770  init_val = *val1;
771  }
772 
773  /* Create worker threads */
774  odph_thread_common_param_init(&thr_common);
775  thr_common.instance = instance;
776  thr_common.cpumask = &cpumask;
777 
778  for (i = 0; i < num_workers; i++) {
779  gbl_args->thread[i].idx = i;
780  stats[i] = &gbl_args->thread[i].stats;
781 
782  odph_thread_param_init(&thr_param[i]);
783  thr_param[i].start = run_thread;
784  thr_param[i].arg = &gbl_args->thread[i];
785  thr_param[i].thr_type = ODP_THREAD_WORKER;
786  }
787 
788  memset(thread_tbl, 0, sizeof(thread_tbl));
789  odph_thread_create(thread_tbl, &thr_common, thr_param, num_workers);
790 
791  ret = print_stats(num_workers, stats, gbl_args->appl.time,
792  gbl_args->appl.accuracy);
793 
794  /* Master thread waits for other threads to exit */
795  odph_thread_join(thread_tbl, num_workers);
796 
797  for (i = 0; i < num_groups; i++) {
798  for (j = 0; j < QUEUES_PER_GROUP; j++) {
799  if (odp_queue_destroy(gbl_args->queue[i][j])) {
800  ODPH_ERR("Error: queue destroy\n");
801  exit(EXIT_FAILURE);
802  }
803  }
804  }
805  gbl_args = NULL;
806  odp_mb_full();
807 
808  if (odp_pool_destroy(pool)) {
809  ODPH_ERR("Error: pool destroy\n");
810  exit(EXIT_FAILURE);
811  }
812 
813  if (odp_shm_free(shm)) {
814  ODPH_ERR("Error: shm free\n");
815  exit(EXIT_FAILURE);
816  }
817 
818  if (odp_shm_free(lookup_tbl_shm)) {
819  ODPH_ERR("Error: shm free\n");
820  exit(EXIT_FAILURE);
821  }
822 
823  if (odp_term_local()) {
824  ODPH_ERR("Error: term local\n");
825  exit(EXIT_FAILURE);
826  }
827 
828  if (odp_term_global(instance)) {
829  ODPH_ERR("Error: term global\n");
830  exit(EXIT_FAILURE);
831  }
832 
833  return ret;
834 }
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_mb_full(void)
Full memory barrier.
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_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition: spec/hints.h:54
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.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
#define ODP_EVENT_INVALID
Invalid event.
uint32_t odp_hash_crc32c(const void *data, uint32_t data_len, uint32_t init_val)
Calculate CRC-32C.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
#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.
odp_event_t odp_packet_to_event(odp_packet_t pkt)
Convert packet handle to event.
uint32_t odp_packet_l4_offset(odp_packet_t pkt)
Layer 4 start offset.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
void * odp_packet_user_area(odp_packet_t pkt)
User area address.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
odp_packet_t odp_packet_alloc(odp_pool_t pool, uint32_t len)
Allocate a packet from a packet pool.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
int odp_packet_parse(odp_packet_t pkt, uint32_t offset, const odp_packet_parse_param_t *param)
Parse packet.
int odp_packet_copy_from_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, const void *src)
Copy data from memory to packet.
void * odp_packet_l4_ptr(odp_packet_t pkt, uint32_t *len)
Layer 4 start pointer.
#define ODP_PACKET_INVALID
Invalid packet.
void * odp_packet_offset(odp_packet_t pkt, uint32_t offset, uint32_t *len, odp_packet_seg_t *seg)
Packet offset pointer.
@ ODP_PROTO_ETH
Ethernet (including VLAN)
@ ODP_PROTO_LAYER_ALL
All layers.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
void odp_pool_print(odp_pool_t pool)
Print pool info.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
int odp_queue_enq(odp_queue_t queue, odp_event_t ev)
Enqueue an event to a queue.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
void odp_schedule_config_init(odp_schedule_config_t *config)
Initialize schedule configuration options.
#define ODP_SCHED_NO_WAIT
Do not wait.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
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.
uint32_t odp_una_u32_t
Unaligned uint32_t type.
void odp_sys_info_print(void)
Print system info.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
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.
Packet parse parameters.
odp_proto_chksums_t chksums
Flags to control payload data checksums checks up to the selected parse layer.
odp_proto_layer_t last_layer
Continue parsing until this layer.
odp_proto_t proto
Protocol header at parse starting point.
struct odp_pool_capability_t::@122 pkt
Packet pool capabilities
uint32_t max_num
Maximum number of buffers of any size.
uint32_t max_uarea_size
Maximum user area size in bytes.
uint32_t max_seg_len
Maximum packet segment data length in bytes.
uint32_t max_len
Maximum packet data length in bytes.
Pool parameters.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
uint32_t max_len
Maximum packet length that will be allocated from the pool.
uint32_t max_num
Maximum number of packets.
odp_pool_type_t type
Pool type.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
struct odp_pool_param_t::@126 pkt
Parameters for packet pools.
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
uint32_t size
Queue size.
odp_queue_type_t type
Queue type.
Schedule configuration.
uint32_t num_queues
Maximum number of scheduled queues to be supported.
uint32_t queue_size
Maximum number of events required to be stored simultaneously in scheduled queue.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
uint32_t tm
Traffic Manager APIs, e.g., odp_tm_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::@148 feat
Individual feature bits.
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()
uint32_t all_chksum
All checksum bits.