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