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