1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016 Intel Corporation 3 */ 4 5 #include <ctype.h> 6 #include <errno.h> 7 #include <getopt.h> 8 #include <inttypes.h> 9 #include <limits.h> 10 #include <sched.h> 11 #include <signal.h> 12 #include <stdio.h> 13 14 #include <rte_common.h> 15 #include <rte_memcpy.h> 16 17 #include <pqos.h> 18 19 #include "cat.h" 20 21 #define BITS_PER_HEX 4 22 #define PQOS_MAX_SOCKETS 8 23 #define PQOS_MAX_SOCKET_CORES 64 24 #define PQOS_MAX_CORES (PQOS_MAX_SOCKET_CORES * PQOS_MAX_SOCKETS) 25 26 static const struct pqos_cap *m_cap; 27 static const struct pqos_cpuinfo *m_cpu; 28 static const struct pqos_capability *m_cap_l3ca; 29 #if PQOS_VERSION <= 103 30 static unsigned m_sockets[PQOS_MAX_SOCKETS]; 31 #else 32 static unsigned int *m_sockets; 33 #endif 34 static unsigned m_sock_count; 35 static struct cat_config m_config[PQOS_MAX_CORES]; 36 static unsigned m_config_count; 37 38 static unsigned 39 bits_count(uint64_t bitmask) 40 { 41 unsigned count = 0; 42 43 for (; bitmask != 0; count++) 44 bitmask &= bitmask - 1; 45 46 return count; 47 } 48 49 /* 50 * Parse elem, the elem could be single number/range or '(' ')' group 51 * 1) A single number elem, it's just a simple digit. e.g. 9 52 * 2) A single range elem, two digits with a '-' between. e.g. 2-6 53 * 3) A group elem, combines multiple 1) or 2) with '( )'. e.g (0,2-4,6) 54 * Within group elem, '-' used for a range separator; 55 * ',' used for a single number. 56 */ 57 static int 58 parse_set(const char *input, rte_cpuset_t *cpusetp) 59 { 60 unsigned idx; 61 const char *str = input; 62 char *end = NULL; 63 unsigned min, max; 64 const unsigned num = PQOS_MAX_CORES; 65 66 CPU_ZERO(cpusetp); 67 68 while (isblank(*str)) 69 str++; 70 71 /* only digit or left bracket is qualify for start point */ 72 if ((!isdigit(*str) && *str != '(') || *str == '\0') 73 return -1; 74 75 /* process single number or single range of number */ 76 if (*str != '(') { 77 errno = 0; 78 idx = strtoul(str, &end, 10); 79 80 if (errno || end == NULL || idx >= num) 81 return -1; 82 83 while (isblank(*end)) 84 end++; 85 86 min = idx; 87 max = idx; 88 if (*end == '-') { 89 /* process single <number>-<number> */ 90 end++; 91 while (isblank(*end)) 92 end++; 93 if (!isdigit(*end)) 94 return -1; 95 96 errno = 0; 97 idx = strtoul(end, &end, 10); 98 if (errno || end == NULL || idx >= num) 99 return -1; 100 max = idx; 101 while (isblank(*end)) 102 end++; 103 if (*end != ',' && *end != '\0') 104 return -1; 105 } 106 107 if (*end != ',' && *end != '\0' && *end != '@') 108 return -1; 109 110 for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max); 111 idx++) 112 CPU_SET(idx, cpusetp); 113 114 return end - input; 115 } 116 117 /* process set within bracket */ 118 str++; 119 while (isblank(*str)) 120 str++; 121 if (*str == '\0') 122 return -1; 123 124 min = PQOS_MAX_CORES; 125 do { 126 127 /* go ahead to the first digit */ 128 while (isblank(*str)) 129 str++; 130 if (!isdigit(*str)) 131 return -1; 132 133 /* get the digit value */ 134 errno = 0; 135 idx = strtoul(str, &end, 10); 136 if (errno || end == NULL || idx >= num) 137 return -1; 138 139 /* go ahead to separator '-',',' and ')' */ 140 while (isblank(*end)) 141 end++; 142 if (*end == '-') { 143 if (min == PQOS_MAX_CORES) 144 min = idx; 145 else /* avoid continuous '-' */ 146 return -1; 147 } else if ((*end == ',') || (*end == ')')) { 148 max = idx; 149 if (min == PQOS_MAX_CORES) 150 min = idx; 151 for (idx = RTE_MIN(min, max); idx <= RTE_MAX(min, max); 152 idx++) 153 CPU_SET(idx, cpusetp); 154 155 min = PQOS_MAX_CORES; 156 } else 157 return -1; 158 159 str = end + 1; 160 } while (*end != '\0' && *end != ')'); 161 162 return str - input; 163 } 164 165 /* Test if bitmask is contiguous */ 166 static int 167 is_contiguous(uint64_t bitmask) 168 { 169 /* check if bitmask is contiguous */ 170 unsigned i = 0; 171 unsigned j = 0; 172 const unsigned max_idx = (sizeof(bitmask) * CHAR_BIT); 173 174 if (bitmask == 0) 175 return 0; 176 177 for (i = 0; i < max_idx; i++) { 178 if (((1ULL << i) & bitmask) != 0) 179 j++; 180 else if (j > 0) 181 break; 182 } 183 184 if (bits_count(bitmask) != j) { 185 printf("PQOS: mask 0x%llx is not contiguous.\n", 186 (unsigned long long)bitmask); 187 return 0; 188 } 189 190 return 1; 191 } 192 193 /* 194 * The format pattern: --l3ca='<cbm@cpus>[,<(ccbm,dcbm)@cpus>...]' 195 * cbm could be a single mask or for a CDP enabled system, a group of two masks 196 * ("code cbm" and "data cbm") 197 * '(' and ')' are necessary if it's a group. 198 * cpus could be a single digit/range or a group. 199 * '(' and ')' are necessary if it's a group. 200 * 201 * e.g. '0x00F00@(1,3), 0x0FF00@(4-6), 0xF0000@7' 202 * - CPUs 1 and 3 share its 4 ways with CPUs 4, 5 and 6; 203 * - CPUs 4,5 and 6 share half (4 out of 8 ways) of its L3 with 1 and 3; 204 * - CPUs 4,5 and 6 have exclusive access to 4 out of 8 ways; 205 * - CPU 7 has exclusive access to all of its 4 ways; 206 * 207 * e.g. '(0x00C00,0x00300)@(1,3)' for a CDP enabled system 208 * - cpus 1 and 3 have access to 2 ways for code and 2 ways for data, 209 * code and data ways are not overlapping.; 210 */ 211 static int 212 parse_l3ca(const char *l3ca) 213 { 214 unsigned idx = 0; 215 const char *cbm_start = NULL; 216 char *cbm_end = NULL; 217 const char *end = NULL; 218 int offset; 219 rte_cpuset_t cpuset; 220 uint64_t mask = 0; 221 uint64_t cmask = 0; 222 223 if (l3ca == NULL) 224 goto err; 225 226 /* Get cbm */ 227 do { 228 CPU_ZERO(&cpuset); 229 mask = 0; 230 cmask = 0; 231 232 while (isblank(*l3ca)) 233 l3ca++; 234 235 if (*l3ca == '\0') 236 goto err; 237 238 /* record mask_set start point */ 239 cbm_start = l3ca; 240 241 /* go across a complete bracket */ 242 if (*cbm_start == '(') { 243 l3ca += strcspn(l3ca, ")"); 244 if (*l3ca++ == '\0') 245 goto err; 246 } 247 248 /* scan the separator '@', ','(next) or '\0'(finish) */ 249 l3ca += strcspn(l3ca, "@,"); 250 251 if (*l3ca != '@') 252 goto err; 253 254 /* explicit assign cpu_set */ 255 offset = parse_set(l3ca + 1, &cpuset); 256 if (offset < 0 || CPU_COUNT(&cpuset) == 0) 257 goto err; 258 259 end = l3ca + 1 + offset; 260 261 if (*end != ',' && *end != '\0') 262 goto err; 263 264 /* parse mask_set from start point */ 265 if (*cbm_start == '(') { 266 cbm_start++; 267 268 while (isblank(*cbm_start)) 269 cbm_start++; 270 271 if (!isxdigit(*cbm_start)) 272 goto err; 273 274 errno = 0; 275 cmask = strtoul(cbm_start, &cbm_end, 16); 276 if (errno != 0 || cbm_end == NULL || cmask == 0) 277 goto err; 278 279 while (isblank(*cbm_end)) 280 cbm_end++; 281 282 if (*cbm_end != ',') 283 goto err; 284 285 cbm_end++; 286 287 while (isblank(*cbm_end)) 288 cbm_end++; 289 290 if (!isxdigit(*cbm_end)) 291 goto err; 292 293 errno = 0; 294 mask = strtoul(cbm_end, &cbm_end, 16); 295 if (errno != 0 || cbm_end == NULL || mask == 0) 296 goto err; 297 } else { 298 while (isblank(*cbm_start)) 299 cbm_start++; 300 301 if (!isxdigit(*cbm_start)) 302 goto err; 303 304 errno = 0; 305 mask = strtoul(cbm_start, &cbm_end, 16); 306 if (errno != 0 || cbm_end == NULL || mask == 0) 307 goto err; 308 309 } 310 311 if (mask == 0 || is_contiguous(mask) == 0) 312 goto err; 313 314 if (cmask != 0 && is_contiguous(cmask) == 0) 315 goto err; 316 317 rte_memcpy(&m_config[idx].cpumask, 318 &cpuset, sizeof(rte_cpuset_t)); 319 320 if (cmask != 0) { 321 m_config[idx].cdp = 1; 322 m_config[idx].code_mask = cmask; 323 m_config[idx].data_mask = mask; 324 } else 325 m_config[idx].mask = mask; 326 327 m_config_count++; 328 329 l3ca = end + 1; 330 idx++; 331 } while (*end != '\0' && idx < PQOS_MAX_CORES); 332 333 return 0; 334 335 err: 336 return -EINVAL; 337 } 338 339 static int 340 check_cpus_overlapping(void) 341 { 342 unsigned i = 0; 343 unsigned j = 0; 344 rte_cpuset_t mask; 345 346 CPU_ZERO(&mask); 347 348 for (i = 0; i < m_config_count; i++) { 349 for (j = i + 1; j < m_config_count; j++) { 350 RTE_CPU_AND(&mask, 351 &m_config[i].cpumask, 352 &m_config[j].cpumask); 353 354 if (CPU_COUNT(&mask) != 0) { 355 printf("PQOS: Requested CPUs sets are " 356 "overlapping.\n"); 357 return -EINVAL; 358 } 359 } 360 } 361 362 return 0; 363 } 364 365 static int 366 check_cpus(void) 367 { 368 unsigned i = 0; 369 unsigned cpu_id = 0; 370 unsigned cos_id = 0; 371 int ret = 0; 372 373 for (i = 0; i < m_config_count; i++) { 374 for (cpu_id = 0; cpu_id < PQOS_MAX_CORES; cpu_id++) { 375 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) != 0) { 376 377 ret = pqos_cpu_check_core(m_cpu, cpu_id); 378 if (ret != PQOS_RETVAL_OK) { 379 printf("PQOS: %u is not a valid " 380 "logical core id.\n", cpu_id); 381 ret = -ENODEV; 382 goto exit; 383 } 384 385 #if PQOS_VERSION <= 103 386 ret = pqos_l3ca_assoc_get(cpu_id, &cos_id); 387 #else 388 ret = pqos_alloc_assoc_get(cpu_id, &cos_id); 389 #endif 390 if (ret != PQOS_RETVAL_OK) { 391 printf("PQOS: Failed to read COS " 392 "associated to cpu %u.\n", 393 cpu_id); 394 ret = -EFAULT; 395 goto exit; 396 } 397 398 /* 399 * Check if COS assigned to lcore is different 400 * then default one (#0) 401 */ 402 if (cos_id != 0) { 403 printf("PQOS: cpu %u has already " 404 "associated COS#%u. " 405 "Please reset L3CA.\n", 406 cpu_id, cos_id); 407 ret = -EBUSY; 408 goto exit; 409 } 410 } 411 } 412 } 413 414 exit: 415 return ret; 416 } 417 418 static int 419 check_cdp(void) 420 { 421 unsigned i = 0; 422 423 for (i = 0; i < m_config_count; i++) { 424 if (m_config[i].cdp == 1 && m_cap_l3ca->u.l3ca->cdp_on == 0) { 425 if (m_cap_l3ca->u.l3ca->cdp == 0) { 426 printf("PQOS: CDP requested but not " 427 "supported.\n"); 428 } else { 429 printf("PQOS: CDP requested but not enabled. " 430 "Please enable CDP.\n"); 431 } 432 return -ENOTSUP; 433 } 434 } 435 436 return 0; 437 } 438 439 static int 440 check_cbm_len_and_contention(void) 441 { 442 unsigned i = 0; 443 uint64_t mask = 0; 444 const uint64_t not_cbm = (UINT64_MAX << (m_cap_l3ca->u.l3ca->num_ways)); 445 const uint64_t cbm_contention_mask = m_cap_l3ca->u.l3ca->way_contention; 446 int ret = 0; 447 448 for (i = 0; i < m_config_count; i++) { 449 if (m_config[i].cdp == 1) 450 mask = m_config[i].code_mask | m_config[i].data_mask; 451 else 452 mask = m_config[i].mask; 453 454 if ((mask & not_cbm) != 0) { 455 printf("PQOS: One or more of requested CBM masks not " 456 "supported by system (too long).\n"); 457 ret = -ENOTSUP; 458 break; 459 } 460 461 /* Just a warning */ 462 if ((mask & cbm_contention_mask) != 0) { 463 printf("PQOS: One or more of requested CBM masks " 464 "overlap CBM contention mask.\n"); 465 break; 466 } 467 468 } 469 470 return ret; 471 } 472 473 static int 474 check_and_select_classes(unsigned cos_id_map[][PQOS_MAX_SOCKETS]) 475 { 476 unsigned i = 0; 477 unsigned j = 0; 478 unsigned phy_pkg_id = 0; 479 unsigned cos_id = 0; 480 unsigned cpu_id = 0; 481 unsigned phy_pkg_lcores[PQOS_MAX_SOCKETS][m_config_count]; 482 const unsigned cos_num = m_cap_l3ca->u.l3ca->num_classes; 483 unsigned used_cos_table[PQOS_MAX_SOCKETS][cos_num]; 484 int ret = 0; 485 486 memset(phy_pkg_lcores, 0, sizeof(phy_pkg_lcores)); 487 memset(used_cos_table, 0, sizeof(used_cos_table)); 488 489 /* detect currently used COS */ 490 for (j = 0; j < m_cpu->num_cores; j++) { 491 cpu_id = m_cpu->cores[j].lcore; 492 493 #if PQOS_VERSION <= 103 494 ret = pqos_l3ca_assoc_get(cpu_id, &cos_id); 495 #else 496 ret = pqos_alloc_assoc_get(cpu_id, &cos_id); 497 #endif 498 if (ret != PQOS_RETVAL_OK) { 499 printf("PQOS: Failed to read COS associated to " 500 "cpu %u on phy_pkg %u.\n", cpu_id, phy_pkg_id); 501 ret = -EFAULT; 502 goto exit; 503 } 504 505 ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id); 506 if (ret != PQOS_RETVAL_OK) { 507 printf("PQOS: Failed to get socket for cpu %u\n", 508 cpu_id); 509 ret = -EFAULT; 510 goto exit; 511 } 512 513 /* Mark COS as used */ 514 if (used_cos_table[phy_pkg_id][cos_id] == 0) 515 used_cos_table[phy_pkg_id][cos_id]++; 516 } 517 518 /* look for avail. COS to fulfill requested config */ 519 for (i = 0; i < m_config_count; i++) { 520 for (j = 0; j < m_cpu->num_cores; j++) { 521 cpu_id = m_cpu->cores[j].lcore; 522 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0) 523 continue; 524 525 ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id); 526 if (ret != PQOS_RETVAL_OK) { 527 printf("PQOS: Failed to get socket for " 528 "cpu %u\n", cpu_id); 529 ret = -EFAULT; 530 goto exit; 531 } 532 533 /* 534 * Check if we already have COS selected 535 * to be used for that group on that socket 536 */ 537 if (phy_pkg_lcores[phy_pkg_id][i] != 0) 538 continue; 539 540 phy_pkg_lcores[phy_pkg_id][i]++; 541 542 /* Search for avail. COS to be used on that socket */ 543 for (cos_id = 0; cos_id < cos_num; cos_id++) { 544 if (used_cos_table[phy_pkg_id][cos_id] == 0) { 545 used_cos_table[phy_pkg_id][cos_id]++; 546 cos_id_map[i][phy_pkg_id] = cos_id; 547 break; 548 } 549 } 550 551 /* If there is no COS available ...*/ 552 if (cos_id == cos_num) { 553 ret = -E2BIG; 554 goto exit; 555 } 556 } 557 } 558 559 exit: 560 if (ret != 0) 561 printf("PQOS: Not enough available COS to configure " 562 "requested configuration.\n"); 563 564 return ret; 565 } 566 567 static int 568 configure_cat(unsigned cos_id_map[][PQOS_MAX_SOCKETS]) 569 { 570 unsigned phy_pkg_id = 0; 571 unsigned cpu_id = 0; 572 unsigned cos_id = 0; 573 unsigned i = 0; 574 unsigned j = 0; 575 struct pqos_l3ca l3ca = {0}; 576 int ret = 0; 577 578 for (i = 0; i < m_config_count; i++) { 579 memset(&l3ca, 0, sizeof(l3ca)); 580 581 l3ca.cdp = m_config[i].cdp; 582 if (m_config[i].cdp == 1) { 583 #if PQOS_VERSION <= 103 584 l3ca.code_mask = m_config[i].code_mask; 585 l3ca.data_mask = m_config[i].data_mask; 586 #else 587 l3ca.u.s.code_mask = m_config[i].code_mask; 588 l3ca.u.s.data_mask = m_config[i].data_mask; 589 #endif 590 } else 591 #if PQOS_VERSION <= 103 592 l3ca.ways_mask = m_config[i].mask; 593 #else 594 l3ca.u.ways_mask = m_config[i].mask; 595 #endif 596 597 for (j = 0; j < m_sock_count; j++) { 598 phy_pkg_id = m_sockets[j]; 599 if (cos_id_map[i][phy_pkg_id] == 0) 600 continue; 601 602 l3ca.class_id = cos_id_map[i][phy_pkg_id]; 603 604 ret = pqos_l3ca_set(phy_pkg_id, 1, &l3ca); 605 if (ret != PQOS_RETVAL_OK) { 606 printf("PQOS: Failed to set COS %u on " 607 "phy_pkg %u.\n", l3ca.class_id, 608 phy_pkg_id); 609 ret = -EFAULT; 610 goto exit; 611 } 612 } 613 } 614 615 for (i = 0; i < m_config_count; i++) { 616 for (j = 0; j < m_cpu->num_cores; j++) { 617 cpu_id = m_cpu->cores[j].lcore; 618 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0) 619 continue; 620 621 ret = pqos_cpu_get_socketid(m_cpu, cpu_id, &phy_pkg_id); 622 if (ret != PQOS_RETVAL_OK) { 623 printf("PQOS: Failed to get socket for " 624 "cpu %u\n", cpu_id); 625 ret = -EFAULT; 626 goto exit; 627 } 628 629 cos_id = cos_id_map[i][phy_pkg_id]; 630 631 #if PQOS_VERSION <= 103 632 ret = pqos_l3ca_assoc_set(cpu_id, cos_id); 633 #else 634 ret = pqos_alloc_assoc_set(cpu_id, cos_id); 635 #endif 636 if (ret != PQOS_RETVAL_OK) { 637 printf("PQOS: Failed to associate COS %u to " 638 "cpu %u\n", cos_id, cpu_id); 639 ret = -EFAULT; 640 goto exit; 641 } 642 } 643 } 644 645 exit: 646 return ret; 647 } 648 649 650 /* Parse the argument given in the command line of the application */ 651 static int 652 parse_args(int argc, char **argv) 653 { 654 int opt = 0; 655 int retval = 0; 656 int oldopterr = 0; 657 char **argvopt = argv; 658 char *prgname = argv[0]; 659 660 static struct option lgopts[] = { 661 { "l3ca", required_argument, 0, 0 }, 662 { NULL, 0, 0, 0 } 663 }; 664 665 /* Disable printing messages within getopt() */ 666 oldopterr = opterr; 667 opterr = 0; 668 669 opt = getopt_long(argc, argvopt, "", lgopts, NULL); 670 if (opt == 0) { 671 retval = parse_l3ca(optarg); 672 if (retval != 0) { 673 printf("PQOS: Invalid L3CA parameters!\n"); 674 goto exit; 675 } 676 677 argv[optind - 1] = prgname; 678 retval = optind - 1; 679 } else 680 retval = 0; 681 682 exit: 683 /* reset getopt lib */ 684 optind = 1; 685 686 /* Restore opterr value */ 687 opterr = oldopterr; 688 689 return retval; 690 } 691 692 static void 693 print_cmd_line_config(void) 694 { 695 char cpustr[PQOS_MAX_CORES * 3] = {0}; 696 unsigned i = 0; 697 unsigned j = 0; 698 699 for (i = 0; i < m_config_count; i++) { 700 unsigned len = 0; 701 memset(cpustr, 0, sizeof(cpustr)); 702 703 /* Generate CPU list */ 704 for (j = 0; j < PQOS_MAX_CORES; j++) { 705 if (CPU_ISSET(j, &m_config[i].cpumask) != 1) 706 continue; 707 708 len += snprintf(cpustr + len, sizeof(cpustr) - len - 1, 709 "%u,", j); 710 711 if (len >= sizeof(cpustr) - 1) 712 break; 713 } 714 715 if (m_config[i].cdp == 1) { 716 printf("PQOS: CPUs: %s cMASK: 0x%llx, dMASK: " 717 "0x%llx\n", cpustr, 718 (unsigned long long)m_config[i].code_mask, 719 (unsigned long long)m_config[i].data_mask); 720 } else { 721 printf("PQOS: CPUs: %s MASK: 0x%llx\n", cpustr, 722 (unsigned long long)m_config[i].mask); 723 } 724 } 725 } 726 727 /** 728 * @brief Prints CAT configuration 729 */ 730 static void 731 print_cat_config(void) 732 { 733 int ret = PQOS_RETVAL_OK; 734 unsigned i = 0; 735 736 for (i = 0; i < m_sock_count; i++) { 737 struct pqos_l3ca tab[PQOS_MAX_L3CA_COS] = {{0} }; 738 unsigned num = 0; 739 unsigned n = 0; 740 741 ret = pqos_l3ca_get(m_sockets[i], PQOS_MAX_L3CA_COS, &num, tab); 742 if (ret != PQOS_RETVAL_OK) { 743 printf("PQOS: Error retrieving COS!\n"); 744 return; 745 } 746 747 printf("PQOS: COS definitions for Socket %u:\n", m_sockets[i]); 748 for (n = 0; n < num; n++) { 749 if (tab[n].cdp == 1) { 750 printf("PQOS: COS: %u, cMASK: 0x%llx, " 751 "dMASK: 0x%llx\n", tab[n].class_id, 752 #if PQOS_VERSION <= 103 753 (unsigned long long)tab[n].code_mask, 754 (unsigned long long)tab[n].data_mask); 755 #else 756 (unsigned long long)tab[n].u.s.code_mask, 757 (unsigned long long)tab[n].u.s.data_mask); 758 #endif 759 } else { 760 printf("PQOS: COS: %u, MASK: 0x%llx\n", 761 tab[n].class_id, 762 #if PQOS_VERSION <= 103 763 (unsigned long long)tab[n].ways_mask); 764 #else 765 (unsigned long long)tab[n].u.ways_mask); 766 #endif 767 } 768 } 769 } 770 771 for (i = 0; i < m_sock_count; i++) { 772 #if PQOS_VERSION <= 103 773 unsigned lcores[PQOS_MAX_SOCKET_CORES] = {0}; 774 #else 775 unsigned int *lcores = NULL; 776 #endif 777 unsigned lcount = 0; 778 unsigned n = 0; 779 780 #if PQOS_VERSION <= 103 781 ret = pqos_cpu_get_cores(m_cpu, m_sockets[i], 782 PQOS_MAX_SOCKET_CORES, &lcount, &lcores[0]); 783 if (ret != PQOS_RETVAL_OK) { 784 #else 785 lcores = pqos_cpu_get_cores(m_cpu, m_sockets[i], 786 &lcount); 787 if (lcores == NULL || lcount == 0) { 788 #endif 789 printf("PQOS: Error retrieving core information!\n"); 790 return; 791 } 792 793 printf("PQOS: CPU information for socket %u:\n", m_sockets[i]); 794 for (n = 0; n < lcount; n++) { 795 unsigned class_id = 0; 796 797 #if PQOS_VERSION <= 103 798 ret = pqos_l3ca_assoc_get(lcores[n], &class_id); 799 #else 800 ret = pqos_alloc_assoc_get(lcores[n], &class_id); 801 #endif 802 if (ret == PQOS_RETVAL_OK) 803 printf("PQOS: CPU: %u, COS: %u\n", lcores[n], 804 class_id); 805 else 806 printf("PQOS: CPU: %u, ERROR\n", lcores[n]); 807 } 808 809 #if PQOS_VERSION > 103 810 free(lcores); 811 #endif 812 } 813 814 } 815 816 static int 817 cat_validate(void) 818 { 819 int ret = 0; 820 821 ret = check_cpus(); 822 if (ret != 0) 823 return ret; 824 825 ret = check_cdp(); 826 if (ret != 0) 827 return ret; 828 829 ret = check_cbm_len_and_contention(); 830 if (ret != 0) 831 return ret; 832 833 ret = check_cpus_overlapping(); 834 if (ret != 0) 835 return ret; 836 837 return 0; 838 } 839 840 static int 841 cat_set(void) 842 { 843 int ret = 0; 844 unsigned cos_id_map[m_config_count][PQOS_MAX_SOCKETS]; 845 846 memset(cos_id_map, 0, sizeof(cos_id_map)); 847 848 ret = check_and_select_classes(cos_id_map); 849 if (ret != 0) 850 return ret; 851 852 ret = configure_cat(cos_id_map); 853 if (ret != 0) 854 return ret; 855 856 return 0; 857 } 858 859 static void 860 cat_fini(void) 861 { 862 int ret = 0; 863 864 printf("PQOS: Shutting down PQoS library...\n"); 865 866 /* deallocate all the resources */ 867 ret = pqos_fini(); 868 if (ret != PQOS_RETVAL_OK && ret != PQOS_RETVAL_INIT) 869 printf("PQOS: Error shutting down PQoS library!\n"); 870 871 m_cap = NULL; 872 m_cpu = NULL; 873 m_cap_l3ca = NULL; 874 #if PQOS_VERSION <= 103 875 memset(m_sockets, 0, sizeof(m_sockets)); 876 #else 877 free(m_sockets); 878 #endif 879 m_sock_count = 0; 880 memset(m_config, 0, sizeof(m_config)); 881 m_config_count = 0; 882 } 883 884 void 885 cat_exit(void) 886 { 887 unsigned i = 0; 888 unsigned j = 0; 889 unsigned cpu_id = 0; 890 int ret = 0; 891 892 /* if lib is not initialized, do nothing */ 893 if (m_cap == NULL && m_cpu == NULL) 894 return; 895 896 printf("PQOS: Reverting CAT configuration...\n"); 897 898 for (i = 0; i < m_config_count; i++) { 899 for (j = 0; j < m_cpu->num_cores; j++) { 900 cpu_id = m_cpu->cores[j].lcore; 901 if (CPU_ISSET(cpu_id, &m_config[i].cpumask) == 0) 902 continue; 903 904 #if PQOS_VERSION <= 103 905 ret = pqos_l3ca_assoc_set(cpu_id, 0); 906 #else 907 ret = pqos_alloc_assoc_set(cpu_id, 0); 908 #endif 909 if (ret != PQOS_RETVAL_OK) { 910 printf("PQOS: Failed to associate COS 0 to " 911 "cpu %u\n", cpu_id); 912 } 913 } 914 } 915 916 cat_fini(); 917 } 918 919 static void 920 signal_handler(int signum) 921 { 922 if (signum == SIGINT || signum == SIGTERM) { 923 printf("\nPQOS: Signal %d received, preparing to exit...\n", 924 signum); 925 926 cat_exit(); 927 928 /* exit with the expected status */ 929 signal(signum, SIG_DFL); 930 kill(getpid(), signum); 931 } 932 } 933 934 int 935 cat_init(int argc, char **argv) 936 { 937 int ret = 0; 938 int args_num = 0; 939 struct pqos_config cfg = {0}; 940 941 if (m_cap != NULL || m_cpu != NULL) { 942 printf("PQOS: CAT module already initialized!\n"); 943 return -EEXIST; 944 } 945 946 /* Parse cmd line args */ 947 ret = parse_args(argc, argv); 948 949 if (ret <= 0) 950 goto err; 951 952 args_num = ret; 953 954 /* Print cmd line configuration */ 955 print_cmd_line_config(); 956 957 /* PQoS Initialization - Check and initialize CAT capability */ 958 cfg.fd_log = STDOUT_FILENO; 959 cfg.verbose = 0; 960 #if PQOS_VERSION <= 103 961 cfg.cdp_cfg = PQOS_REQUIRE_CDP_ANY; 962 #endif 963 ret = pqos_init(&cfg); 964 if (ret != PQOS_RETVAL_OK) { 965 printf("PQOS: Error initializing PQoS library!\n"); 966 ret = -EFAULT; 967 goto err; 968 } 969 970 /* Get capability and CPU info pointer */ 971 ret = pqos_cap_get(&m_cap, &m_cpu); 972 if (ret != PQOS_RETVAL_OK || m_cap == NULL || m_cpu == NULL) { 973 printf("PQOS: Error retrieving PQoS capabilities!\n"); 974 ret = -EFAULT; 975 goto err; 976 } 977 978 /* Get L3CA capabilities */ 979 ret = pqos_cap_get_type(m_cap, PQOS_CAP_TYPE_L3CA, &m_cap_l3ca); 980 if (ret != PQOS_RETVAL_OK || m_cap_l3ca == NULL) { 981 printf("PQOS: Error retrieving PQOS_CAP_TYPE_L3CA " 982 "capabilities!\n"); 983 ret = -EFAULT; 984 goto err; 985 } 986 987 /* Get CPU socket information */ 988 #if PQOS_VERSION <= 103 989 ret = pqos_cpu_get_sockets(m_cpu, PQOS_MAX_SOCKETS, &m_sock_count, 990 m_sockets); 991 if (ret != PQOS_RETVAL_OK) { 992 #else 993 m_sockets = pqos_cpu_get_sockets(m_cpu, &m_sock_count); 994 if (m_sockets == NULL) { 995 #endif 996 printf("PQOS: Error retrieving CPU socket information!\n"); 997 ret = -EFAULT; 998 goto err; 999 } 1000 1001 /* Validate cmd line configuration */ 1002 ret = cat_validate(); 1003 if (ret != 0) { 1004 printf("PQOS: Requested CAT configuration is not valid!\n"); 1005 goto err; 1006 } 1007 1008 /* configure system */ 1009 ret = cat_set(); 1010 if (ret != 0) { 1011 printf("PQOS: Failed to configure CAT!\n"); 1012 goto err; 1013 } 1014 1015 signal(SIGINT, signal_handler); 1016 signal(SIGTERM, signal_handler); 1017 1018 ret = atexit(cat_exit); 1019 if (ret != 0) { 1020 printf("PQOS: Cannot set exit function\n"); 1021 goto err; 1022 } 1023 1024 /* Print CAT configuration */ 1025 print_cat_config(); 1026 1027 return args_num; 1028 1029 err: 1030 /* deallocate all the resources */ 1031 cat_fini(); 1032 return ret; 1033 } 1034