]>
git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/dpdk/examples/l2fwd-cat/cat.c
4 * Copyright(c) 2016 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 #include <rte_common.h>
42 #include <rte_memcpy.h>
48 #define BITS_PER_HEX 4
49 #define PQOS_MAX_SOCKETS 8
50 #define PQOS_MAX_SOCKET_CORES 64
51 #define PQOS_MAX_CORES (PQOS_MAX_SOCKET_CORES * PQOS_MAX_SOCKETS)
53 static const struct pqos_cap
*m_cap
;
54 static const struct pqos_cpuinfo
*m_cpu
;
55 static const struct pqos_capability
*m_cap_l3ca
;
56 static unsigned m_sockets
[PQOS_MAX_SOCKETS
];
57 static unsigned m_sock_count
;
58 static struct cat_config m_config
[PQOS_MAX_CORES
];
59 static unsigned m_config_count
;
62 bits_count(uint64_t bitmask
)
66 for (; bitmask
!= 0; count
++)
67 bitmask
&= bitmask
- 1;
73 * Parse elem, the elem could be single number/range or '(' ')' group
74 * 1) A single number elem, it's just a simple digit. e.g. 9
75 * 2) A single range elem, two digits with a '-' between. e.g. 2-6
76 * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6)
77 * Within group elem, '-' used for a range separator;
78 * ',' used for a single number.
81 parse_set(const char *input
, rte_cpuset_t
*cpusetp
)
84 const char *str
= input
;
87 const unsigned num
= PQOS_MAX_CORES
;
94 /* only digit or left bracket is qualify for start point */
95 if ((!isdigit(*str
) && *str
!= '(') || *str
== '\0')
98 /* process single number or single range of number */
101 idx
= strtoul(str
, &end
, 10);
103 if (errno
|| end
== NULL
|| idx
>= num
)
106 while (isblank(*end
))
112 /* process single <number>-<number> */
114 while (isblank(*end
))
120 idx
= strtoul(end
, &end
, 10);
121 if (errno
|| end
== NULL
|| idx
>= num
)
124 while (isblank(*end
))
126 if (*end
!= ',' && *end
!= '\0')
130 if (*end
!= ',' && *end
!= '\0' && *end
!= '@')
133 for (idx
= RTE_MIN(min
, max
); idx
<= RTE_MAX(min
, max
);
135 CPU_SET(idx
, cpusetp
);
140 /* process set within bracket */
142 while (isblank(*str
))
147 min
= PQOS_MAX_CORES
;
150 /* go ahead to the first digit */
151 while (isblank(*str
))
156 /* get the digit value */
158 idx
= strtoul(str
, &end
, 10);
159 if (errno
|| end
== NULL
|| idx
>= num
)
162 /* go ahead to separator '-',',' and ')' */
163 while (isblank(*end
))
166 if (min
== PQOS_MAX_CORES
)
168 else /* avoid continuous '-' */
170 } else if ((*end
== ',') || (*end
== ')')) {
172 if (min
== PQOS_MAX_CORES
)
174 for (idx
= RTE_MIN(min
, max
); idx
<= RTE_MAX(min
, max
);
176 CPU_SET(idx
, cpusetp
);
178 min
= PQOS_MAX_CORES
;
183 } while (*end
!= '\0' && *end
!= ')');
188 /* Test if bitmask is contiguous */
190 is_contiguous(uint64_t bitmask
)
192 /* check if bitmask is contiguous */
195 const unsigned max_idx
= (sizeof(bitmask
) * CHAR_BIT
);
200 for (i
= 0; i
< max_idx
; i
++) {
201 if (((1ULL << i
) & bitmask
) != 0)
207 if (bits_count(bitmask
) != j
) {
208 printf("PQOS: mask 0x%llx is not contiguous.\n",
209 (unsigned long long)bitmask
);
217 * The format pattern: --l3ca='<cbm@cpus>[,<(ccbm,dcbm)@cpus>...]'
218 * cbm could be a single mask or for a CDP enabled system, a group of two masks
219 * ("code cbm" and "data cbm")
220 * '(' and ')' are necessary if it's a group.
221 * cpus could be a single digit/range or a group.
222 * '(' and ')' are necessary if it's a group.
224 * e.g. '0x00F00@(1,3), 0x0FF00@(4-6), 0xF0000@7'
225 * - CPUs 1 and 3 share its 4 ways with CPUs 4, 5 and 6;
226 * - CPUs 4,5 and 6 share half (4 out of 8 ways) of its L3 with 1 and 3;
227 * - CPUs 4,5 and 6 have exclusive access to 4 out of 8 ways;
228 * - CPU 7 has exclusive access to all of its 4 ways;
230 * e.g. '(0x00C00,0x00300)@(1,3)' for a CDP enabled system
231 * - cpus 1 and 3 have access to 2 ways for code and 2 ways for data,
232 * code and data ways are not overlapping.;
235 parse_l3ca(const char *l3ca
)
238 const char *cbm_start
= NULL
;
239 char *cbm_end
= NULL
;
240 const char *end
= NULL
;
255 while (isblank(*l3ca
))
261 /* record mask_set start point */
264 /* go across a complete bracket */
265 if (*cbm_start
== '(') {
266 l3ca
+= strcspn(l3ca
, ")");
271 /* scan the separator '@', ','(next) or '\0'(finish) */
272 l3ca
+= strcspn(l3ca
, "@,");
275 /* explicit assign cpu_set */
276 offset
= parse_set(l3ca
+ 1, &cpuset
);
277 if (offset
< 0 || CPU_COUNT(&cpuset
) == 0)
280 end
= l3ca
+ 1 + offset
;
284 if (*end
!= ',' && *end
!= '\0')
287 /* parse mask_set from start point */
288 if (*cbm_start
== '(') {
291 while (isblank(*cbm_start
))
294 if (!isxdigit(*cbm_start
))
298 cmask
= strtoul(cbm_start
, &cbm_end
, 16);
299 if (errno
!= 0 || cbm_end
== NULL
|| cmask
== 0)
302 while (isblank(*cbm_end
))
310 while (isblank(*cbm_end
))
313 if (!isxdigit(*cbm_end
))
317 mask
= strtoul(cbm_end
, &cbm_end
, 16);
318 if (errno
!= 0 || cbm_end
== NULL
|| mask
== 0)
321 while (isblank(*cbm_start
))
324 if (!isxdigit(*cbm_start
))
328 mask
= strtoul(cbm_start
, &cbm_end
, 16);
329 if (errno
!= 0 || cbm_end
== NULL
|| mask
== 0)
334 if (mask
== 0 || is_contiguous(mask
) == 0)
337 if (cmask
!= 0 && is_contiguous(cmask
) == 0)
340 rte_memcpy(&m_config
[idx
].cpumask
,
341 &cpuset
, sizeof(rte_cpuset_t
));
344 m_config
[idx
].cdp
= 1;
345 m_config
[idx
].code_mask
= cmask
;
346 m_config
[idx
].data_mask
= mask
;
348 m_config
[idx
].mask
= mask
;
354 } while (*end
!= '\0' && idx
< PQOS_MAX_CORES
);
356 if (m_config_count
== 0)
366 check_cpus_overlapping(void)
374 for (i
= 0; i
< m_config_count
; i
++) {
375 for (j
= i
+ 1; j
< m_config_count
; j
++) {
377 &m_config
[i
].cpumask
,
378 &m_config
[j
].cpumask
);
380 if (CPU_COUNT(&mask
) != 0) {
381 printf("PQOS: Requested CPUs sets are "
399 for (i
= 0; i
< m_config_count
; i
++) {
400 for (cpu_id
= 0; cpu_id
< PQOS_MAX_CORES
; cpu_id
++) {
401 if (CPU_ISSET(cpu_id
, &m_config
[i
].cpumask
) != 0) {
403 ret
= pqos_cpu_check_core(m_cpu
, cpu_id
);
404 if (ret
!= PQOS_RETVAL_OK
) {
405 printf("PQOS: %u is not a valid "
406 "logical core id.\n", cpu_id
);
411 ret
= pqos_l3ca_assoc_get(cpu_id
, &cos_id
);
412 if (ret
!= PQOS_RETVAL_OK
) {
413 printf("PQOS: Failed to read COS "
414 "associated to cpu %u.\n",
421 * Check if COS assigned to lcore is different
422 * then default one (#0)
425 printf("PQOS: cpu %u has already "
426 "associated COS#%u. "
427 "Please reset L3CA.\n",
445 for (i
= 0; i
< m_config_count
; i
++) {
446 if (m_config
[i
].cdp
== 1 && m_cap_l3ca
->u
.l3ca
->cdp_on
== 0) {
447 if (m_cap_l3ca
->u
.l3ca
->cdp
== 0) {
448 printf("PQOS: CDP requested but not "
451 printf("PQOS: CDP requested but not enabled. "
452 "Please enable CDP.\n");
462 check_cbm_len_and_contention(void)
466 const uint64_t not_cbm
= (UINT64_MAX
<< (m_cap_l3ca
->u
.l3ca
->num_ways
));
467 const uint64_t cbm_contention_mask
= m_cap_l3ca
->u
.l3ca
->way_contention
;
470 for (i
= 0; i
< m_config_count
; i
++) {
471 if (m_config
[i
].cdp
== 1)
472 mask
= m_config
[i
].code_mask
| m_config
[i
].data_mask
;
474 mask
= m_config
[i
].mask
;
476 if ((mask
& not_cbm
) != 0) {
477 printf("PQOS: One or more of requested CBM masks not "
478 "supported by system (too long).\n");
484 if ((mask
& cbm_contention_mask
) != 0) {
485 printf("PQOS: One or more of requested CBM masks "
486 "overlap CBM contention mask.\n");
496 check_and_select_classes(unsigned cos_id_map
[][PQOS_MAX_SOCKETS
])
500 unsigned phy_pkg_id
= 0;
503 unsigned phy_pkg_lcores
[PQOS_MAX_SOCKETS
][m_config_count
];
504 const unsigned cos_num
= m_cap_l3ca
->u
.l3ca
->num_classes
;
505 unsigned used_cos_table
[PQOS_MAX_SOCKETS
][cos_num
];
508 memset(phy_pkg_lcores
, 0, sizeof(phy_pkg_lcores
));
509 memset(used_cos_table
, 0, sizeof(used_cos_table
));
511 /* detect currently used COS */
512 for (j
= 0; j
< m_cpu
->num_cores
; j
++) {
513 cpu_id
= m_cpu
->cores
[j
].lcore
;
515 ret
= pqos_l3ca_assoc_get(cpu_id
, &cos_id
);
516 if (ret
!= PQOS_RETVAL_OK
) {
517 printf("PQOS: Failed to read COS associated to "
518 "cpu %u on phy_pkg %u.\n", cpu_id
, phy_pkg_id
);
523 ret
= pqos_cpu_get_socketid(m_cpu
, cpu_id
, &phy_pkg_id
);
524 if (ret
!= PQOS_RETVAL_OK
) {
525 printf("PQOS: Failed to get socket for cpu %u\n",
531 /* Mark COS as used */
532 if (used_cos_table
[phy_pkg_id
][cos_id
] == 0)
533 used_cos_table
[phy_pkg_id
][cos_id
]++;
536 /* look for avail. COS to fulfill requested config */
537 for (i
= 0; i
< m_config_count
; i
++) {
538 for (j
= 0; j
< m_cpu
->num_cores
; j
++) {
539 cpu_id
= m_cpu
->cores
[j
].lcore
;
540 if (CPU_ISSET(cpu_id
, &m_config
[i
].cpumask
) == 0)
543 ret
= pqos_cpu_get_socketid(m_cpu
, cpu_id
, &phy_pkg_id
);
544 if (ret
!= PQOS_RETVAL_OK
) {
545 printf("PQOS: Failed to get socket for "
552 * Check if we already have COS selected
553 * to be used for that group on that socket
555 if (phy_pkg_lcores
[phy_pkg_id
][i
] != 0)
558 phy_pkg_lcores
[phy_pkg_id
][i
]++;
560 /* Search for avail. COS to be used on that socket */
561 for (cos_id
= 0; cos_id
< cos_num
; cos_id
++) {
562 if (used_cos_table
[phy_pkg_id
][cos_id
] == 0) {
563 used_cos_table
[phy_pkg_id
][cos_id
]++;
564 cos_id_map
[i
][phy_pkg_id
] = cos_id
;
569 /* If there is no COS available ...*/
570 if (cos_id
== cos_num
) {
579 printf("PQOS: Not enough available COS to configure "
580 "requested configuration.\n");
586 configure_cat(unsigned cos_id_map
[][PQOS_MAX_SOCKETS
])
588 unsigned phy_pkg_id
= 0;
593 struct pqos_l3ca l3ca
= {0};
596 for (i
= 0; i
< m_config_count
; i
++) {
597 memset(&l3ca
, 0, sizeof(l3ca
));
599 l3ca
.cdp
= m_config
[i
].cdp
;
600 if (m_config
[i
].cdp
== 1) {
601 l3ca
.code_mask
= m_config
[i
].code_mask
;
602 l3ca
.data_mask
= m_config
[i
].data_mask
;
604 l3ca
.ways_mask
= m_config
[i
].mask
;
606 for (j
= 0; j
< m_sock_count
; j
++) {
607 phy_pkg_id
= m_sockets
[j
];
608 if (cos_id_map
[i
][phy_pkg_id
] == 0)
611 l3ca
.class_id
= cos_id_map
[i
][phy_pkg_id
];
613 ret
= pqos_l3ca_set(phy_pkg_id
, 1, &l3ca
);
614 if (ret
!= PQOS_RETVAL_OK
) {
615 printf("PQOS: Failed to set COS %u on "
616 "phy_pkg %u.\n", l3ca
.class_id
,
624 for (i
= 0; i
< m_config_count
; i
++) {
625 for (j
= 0; j
< m_cpu
->num_cores
; j
++) {
626 cpu_id
= m_cpu
->cores
[j
].lcore
;
627 if (CPU_ISSET(cpu_id
, &m_config
[i
].cpumask
) == 0)
630 ret
= pqos_cpu_get_socketid(m_cpu
, cpu_id
, &phy_pkg_id
);
631 if (ret
!= PQOS_RETVAL_OK
) {
632 printf("PQOS: Failed to get socket for "
638 cos_id
= cos_id_map
[i
][phy_pkg_id
];
640 ret
= pqos_l3ca_assoc_set(cpu_id
, cos_id
);
641 if (ret
!= PQOS_RETVAL_OK
) {
642 printf("PQOS: Failed to associate COS %u to "
643 "cpu %u\n", cos_id
, cpu_id
);
655 /* Parse the argument given in the command line of the application */
657 parse_args(int argc
, char **argv
)
662 char **argvopt
= argv
;
663 char *prgname
= argv
[0];
665 static struct option lgopts
[] = {
666 { "l3ca", required_argument
, 0, 0 },
670 /* Disable printing messages within getopt() */
674 opt
= getopt_long(argc
, argvopt
, "", lgopts
, NULL
);
676 retval
= parse_l3ca(optarg
);
678 printf("PQOS: Invalid L3CA parameters!\n");
682 argv
[optind
- 1] = prgname
;
688 /* reset getopt lib */
691 /* Restore opterr value */
698 print_cmd_line_config(void)
700 char cpustr
[PQOS_MAX_CORES
* 3] = {0};
704 for (i
= 0; i
< m_config_count
; i
++) {
706 memset(cpustr
, 0, sizeof(cpustr
));
708 /* Generate CPU list */
709 for (j
= 0; j
< PQOS_MAX_CORES
; j
++) {
710 if (CPU_ISSET(j
, &m_config
[i
].cpumask
) != 1)
713 len
+= snprintf(cpustr
+ len
, sizeof(cpustr
) - len
- 1,
716 if (len
>= sizeof(cpustr
) - 1)
720 if (m_config
[i
].cdp
== 1) {
721 printf("PQOS: CPUs: %s cMASK: 0x%llx, dMASK: "
723 (unsigned long long)m_config
[i
].code_mask
,
724 (unsigned long long)m_config
[i
].data_mask
);
726 printf("PQOS: CPUs: %s MASK: 0x%llx\n", cpustr
,
727 (unsigned long long)m_config
[i
].mask
);
733 * @brief Prints CAT configuration
736 print_cat_config(void)
738 int ret
= PQOS_RETVAL_OK
;
741 for (i
= 0; i
< m_sock_count
; i
++) {
742 struct pqos_l3ca tab
[PQOS_MAX_L3CA_COS
] = {{0} };
746 ret
= pqos_l3ca_get(m_sockets
[i
], PQOS_MAX_L3CA_COS
, &num
, tab
);
747 if (ret
!= PQOS_RETVAL_OK
) {
748 printf("PQOS: Error retrieving COS!\n");
752 printf("PQOS: COS definitions for Socket %u:\n", m_sockets
[i
]);
753 for (n
= 0; n
< num
; n
++) {
754 if (tab
[n
].cdp
== 1) {
755 printf("PQOS: COS: %u, cMASK: 0x%llx, "
756 "dMASK: 0x%llx\n", tab
[n
].class_id
,
757 (unsigned long long)tab
[n
].code_mask
,
758 (unsigned long long)tab
[n
].data_mask
);
760 printf("PQOS: COS: %u, MASK: 0x%llx\n",
762 (unsigned long long)tab
[n
].ways_mask
);
767 for (i
= 0; i
< m_sock_count
; i
++) {
768 unsigned lcores
[PQOS_MAX_SOCKET_CORES
] = {0};
772 ret
= pqos_cpu_get_cores(m_cpu
, m_sockets
[i
],
773 PQOS_MAX_SOCKET_CORES
, &lcount
, &lcores
[0]);
774 if (ret
!= PQOS_RETVAL_OK
) {
775 printf("PQOS: Error retrieving core information!\n");
779 printf("PQOS: CPU information for socket %u:\n", m_sockets
[i
]);
780 for (n
= 0; n
< lcount
; n
++) {
781 unsigned class_id
= 0;
783 ret
= pqos_l3ca_assoc_get(lcores
[n
], &class_id
);
784 if (ret
== PQOS_RETVAL_OK
)
785 printf("PQOS: CPU: %u, COS: %u\n", lcores
[n
],
788 printf("PQOS: CPU: %u, ERROR\n", lcores
[n
]);
807 ret
= check_cbm_len_and_contention();
811 ret
= check_cpus_overlapping();
822 unsigned cos_id_map
[m_config_count
][PQOS_MAX_SOCKETS
];
824 memset(cos_id_map
, 0, sizeof(cos_id_map
));
826 ret
= check_and_select_classes(cos_id_map
);
830 ret
= configure_cat(cos_id_map
);
842 printf("PQOS: Shutting down PQoS library...\n");
844 /* deallocate all the resources */
846 if (ret
!= PQOS_RETVAL_OK
&& ret
!= PQOS_RETVAL_INIT
)
847 printf("PQOS: Error shutting down PQoS library!\n");
852 memset(m_sockets
, 0, sizeof(m_sockets
));
854 memset(m_config
, 0, sizeof(m_config
));
866 /* if lib is not initialized, do nothing */
867 if (m_cap
== NULL
&& m_cpu
== NULL
)
870 printf("PQOS: Reverting CAT configuration...\n");
872 for (i
= 0; i
< m_config_count
; i
++) {
873 for (j
= 0; j
< m_cpu
->num_cores
; j
++) {
874 cpu_id
= m_cpu
->cores
[j
].lcore
;
875 if (CPU_ISSET(cpu_id
, &m_config
[i
].cpumask
) == 0)
878 ret
= pqos_l3ca_assoc_set(cpu_id
, 0);
879 if (ret
!= PQOS_RETVAL_OK
) {
880 printf("PQOS: Failed to associate COS 0 to "
890 signal_handler(int signum
)
892 if (signum
== SIGINT
|| signum
== SIGTERM
) {
893 printf("\nPQOS: Signal %d received, preparing to exit...\n",
898 /* exit with the expected status */
899 signal(signum
, SIG_DFL
);
900 kill(getpid(), signum
);
905 cat_init(int argc
, char **argv
)
909 struct pqos_config cfg
= {0};
911 if (m_cap
!= NULL
|| m_cpu
!= NULL
) {
912 printf("PQOS: CAT module already initialized!\n");
916 /* Parse cmd line args */
917 ret
= parse_args(argc
, argv
);
924 /* Print cmd line configuration */
925 print_cmd_line_config();
927 /* PQoS Initialization - Check and initialize CAT capability */
928 cfg
.fd_log
= STDOUT_FILENO
;
930 cfg
.cdp_cfg
= PQOS_REQUIRE_CDP_ANY
;
931 ret
= pqos_init(&cfg
);
932 if (ret
!= PQOS_RETVAL_OK
) {
933 printf("PQOS: Error initializing PQoS library!\n");
938 /* Get capability and CPU info pointer */
939 ret
= pqos_cap_get(&m_cap
, &m_cpu
);
940 if (ret
!= PQOS_RETVAL_OK
|| m_cap
== NULL
|| m_cpu
== NULL
) {
941 printf("PQOS: Error retrieving PQoS capabilities!\n");
946 /* Get L3CA capabilities */
947 ret
= pqos_cap_get_type(m_cap
, PQOS_CAP_TYPE_L3CA
, &m_cap_l3ca
);
948 if (ret
!= PQOS_RETVAL_OK
|| m_cap_l3ca
== NULL
) {
949 printf("PQOS: Error retrieving PQOS_CAP_TYPE_L3CA "
955 /* Get CPU socket information */
956 ret
= pqos_cpu_get_sockets(m_cpu
, PQOS_MAX_SOCKETS
, &m_sock_count
,
958 if (ret
!= PQOS_RETVAL_OK
) {
959 printf("PQOS: Error retrieving CPU socket information!\n");
964 /* Validate cmd line configuration */
965 ret
= cat_validate();
967 printf("PQOS: Requested CAT configuration is not valid!\n");
971 /* configure system */
974 printf("PQOS: Failed to configure CAT!\n");
978 signal(SIGINT
, signal_handler
);
979 signal(SIGTERM
, signal_handler
);
981 ret
= atexit(cat_exit
);
983 printf("PQOS: Cannot set exit function\n");
987 /* Print CAT configuration */
993 /* deallocate all the resources */