1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Basic resctrl file system operations 4 * 5 * Copyright (C) 2018 Intel Corporation 6 * 7 * Authors: 8 * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, 9 * Fenghua Yu <fenghua.yu@intel.com> 10 */ 11 #include <fcntl.h> 12 #include <limits.h> 13 14 #include "resctrl.h" 15 16 static int find_resctrl_mount(char *buffer) 17 { 18 FILE *mounts; 19 char line[256], *fs, *mntpoint; 20 21 mounts = fopen("/proc/mounts", "r"); 22 if (!mounts) { 23 ksft_perror("/proc/mounts"); 24 return -ENXIO; 25 } 26 while (!feof(mounts)) { 27 if (!fgets(line, 256, mounts)) 28 break; 29 fs = strtok(line, " \t"); 30 if (!fs) 31 continue; 32 mntpoint = strtok(NULL, " \t"); 33 if (!mntpoint) 34 continue; 35 fs = strtok(NULL, " \t"); 36 if (!fs) 37 continue; 38 if (strcmp(fs, "resctrl")) 39 continue; 40 41 fclose(mounts); 42 if (buffer) 43 strncpy(buffer, mntpoint, 256); 44 45 return 0; 46 } 47 48 fclose(mounts); 49 50 return -ENOENT; 51 } 52 53 /* 54 * mount_resctrlfs - Mount resctrl FS at /sys/fs/resctrl 55 * 56 * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid 57 * pre-existing settings interfering with the test results. 58 * 59 * Return: 0 on success, < 0 on error. 60 */ 61 int mount_resctrlfs(void) 62 { 63 int ret; 64 65 ret = find_resctrl_mount(NULL); 66 if (ret != -ENOENT) 67 return -1; 68 69 ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH); 70 ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL); 71 if (ret) 72 ksft_perror("mount"); 73 74 return ret; 75 } 76 77 int umount_resctrlfs(void) 78 { 79 char mountpoint[256]; 80 int ret; 81 82 ret = find_resctrl_mount(mountpoint); 83 if (ret == -ENOENT) 84 return 0; 85 if (ret) 86 return ret; 87 88 if (umount(mountpoint)) { 89 ksft_perror("Unable to umount resctrl"); 90 91 return -1; 92 } 93 94 return 0; 95 } 96 97 /* 98 * get_cache_level - Convert cache level from string to integer 99 * @cache_type: Cache level as string 100 * 101 * Return: cache level as integer or -1 if @cache_type is invalid. 102 */ 103 static int get_cache_level(const char *cache_type) 104 { 105 if (!strcmp(cache_type, "L3")) 106 return 3; 107 if (!strcmp(cache_type, "L2")) 108 return 2; 109 110 ksft_print_msg("Invalid cache level\n"); 111 return -1; 112 } 113 114 /* 115 * get_resource_id - Get socket number/l3 id for a specified CPU 116 * @cpu_no: CPU number 117 * @resource_id: Socket number or l3_id 118 * 119 * Return: >= 0 on success, < 0 on failure. 120 */ 121 int get_resource_id(int cpu_no, int *resource_id) 122 { 123 char phys_pkg_path[1024]; 124 FILE *fp; 125 126 if (get_vendor() == ARCH_AMD) 127 sprintf(phys_pkg_path, "%s%d/cache/index3/id", 128 PHYS_ID_PATH, cpu_no); 129 else 130 sprintf(phys_pkg_path, "%s%d/topology/physical_package_id", 131 PHYS_ID_PATH, cpu_no); 132 133 fp = fopen(phys_pkg_path, "r"); 134 if (!fp) { 135 ksft_perror("Failed to open physical_package_id"); 136 137 return -1; 138 } 139 if (fscanf(fp, "%d", resource_id) <= 0) { 140 ksft_perror("Could not get socket number or l3 id"); 141 fclose(fp); 142 143 return -1; 144 } 145 fclose(fp); 146 147 return 0; 148 } 149 150 /* 151 * get_cache_size - Get cache size for a specified CPU 152 * @cpu_no: CPU number 153 * @cache_type: Cache level L2/L3 154 * @cache_size: pointer to cache_size 155 * 156 * Return: = 0 on success, < 0 on failure. 157 */ 158 int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size) 159 { 160 char cache_path[1024], cache_str[64]; 161 int length, i, cache_num; 162 FILE *fp; 163 164 cache_num = get_cache_level(cache_type); 165 if (cache_num < 0) 166 return cache_num; 167 168 sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size", 169 cpu_no, cache_num); 170 fp = fopen(cache_path, "r"); 171 if (!fp) { 172 ksft_perror("Failed to open cache size"); 173 174 return -1; 175 } 176 if (fscanf(fp, "%s", cache_str) <= 0) { 177 ksft_perror("Could not get cache_size"); 178 fclose(fp); 179 180 return -1; 181 } 182 fclose(fp); 183 184 length = (int)strlen(cache_str); 185 186 *cache_size = 0; 187 188 for (i = 0; i < length; i++) { 189 if ((cache_str[i] >= '0') && (cache_str[i] <= '9')) 190 191 *cache_size = *cache_size * 10 + (cache_str[i] - '0'); 192 193 else if (cache_str[i] == 'K') 194 195 *cache_size = *cache_size * 1024; 196 197 else if (cache_str[i] == 'M') 198 199 *cache_size = *cache_size * 1024 * 1024; 200 201 else 202 break; 203 } 204 205 return 0; 206 } 207 208 #define CORE_SIBLINGS_PATH "/sys/bus/cpu/devices/cpu" 209 210 /* 211 * get_bit_mask - Get bit mask from given file 212 * @filename: File containing the mask 213 * @mask: The bit mask returned as unsigned long 214 * 215 * Return: = 0 on success, < 0 on failure. 216 */ 217 static int get_bit_mask(const char *filename, unsigned long *mask) 218 { 219 FILE *fp; 220 221 if (!filename || !mask) 222 return -1; 223 224 fp = fopen(filename, "r"); 225 if (!fp) { 226 ksft_print_msg("Failed to open bit mask file '%s': %s\n", 227 filename, strerror(errno)); 228 return -1; 229 } 230 231 if (fscanf(fp, "%lx", mask) <= 0) { 232 ksft_print_msg("Could not read bit mask file '%s': %s\n", 233 filename, strerror(errno)); 234 fclose(fp); 235 236 return -1; 237 } 238 fclose(fp); 239 240 return 0; 241 } 242 243 /* 244 * create_bit_mask- Create bit mask from start, len pair 245 * @start: LSB of the mask 246 * @len Number of bits in the mask 247 */ 248 unsigned long create_bit_mask(unsigned int start, unsigned int len) 249 { 250 return ((1UL << len) - 1UL) << start; 251 } 252 253 /* 254 * count_contiguous_bits - Returns the longest train of bits in a bit mask 255 * @val A bit mask 256 * @start The location of the least-significant bit of the longest train 257 * 258 * Return: The length of the contiguous bits in the longest train of bits 259 */ 260 unsigned int count_contiguous_bits(unsigned long val, unsigned int *start) 261 { 262 unsigned long last_val; 263 unsigned int count = 0; 264 265 while (val) { 266 last_val = val; 267 val &= (val >> 1); 268 count++; 269 } 270 271 if (start) { 272 if (count) 273 *start = ffsl(last_val) - 1; 274 else 275 *start = 0; 276 } 277 278 return count; 279 } 280 281 /* 282 * get_full_cbm - Get full Cache Bit Mask (CBM) 283 * @cache_type: Cache type as "L2" or "L3" 284 * @mask: Full cache bit mask representing the maximal portion of cache 285 * available for allocation, returned as unsigned long. 286 * 287 * Return: = 0 on success, < 0 on failure. 288 */ 289 int get_full_cbm(const char *cache_type, unsigned long *mask) 290 { 291 char cbm_path[PATH_MAX]; 292 int ret; 293 294 if (!cache_type) 295 return -1; 296 297 snprintf(cbm_path, sizeof(cbm_path), "%s/%s/cbm_mask", 298 INFO_PATH, cache_type); 299 300 ret = get_bit_mask(cbm_path, mask); 301 if (ret || !*mask) 302 return -1; 303 304 return 0; 305 } 306 307 /* 308 * get_shareable_mask - Get shareable mask from shareable_bits 309 * @cache_type: Cache type as "L2" or "L3" 310 * @shareable_mask: Shareable mask returned as unsigned long 311 * 312 * Return: = 0 on success, < 0 on failure. 313 */ 314 static int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask) 315 { 316 char mask_path[PATH_MAX]; 317 318 if (!cache_type) 319 return -1; 320 321 snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits", 322 INFO_PATH, cache_type); 323 324 return get_bit_mask(mask_path, shareable_mask); 325 } 326 327 /* 328 * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits 329 * @cache_type: Cache type as "L2" or "L3" 330 * @mask: The largest exclusive portion of the cache out of the 331 * full CBM, returned as unsigned long 332 * 333 * Parts of a cache may be shared with other devices such as GPU. This function 334 * calculates the largest exclusive portion of the cache where no other devices 335 * besides CPU have access to the cache portion. 336 * 337 * Return: = 0 on success, < 0 on failure. 338 */ 339 int get_mask_no_shareable(const char *cache_type, unsigned long *mask) 340 { 341 unsigned long full_mask, shareable_mask; 342 unsigned int start, len; 343 344 if (get_full_cbm(cache_type, &full_mask) < 0) 345 return -1; 346 if (get_shareable_mask(cache_type, &shareable_mask) < 0) 347 return -1; 348 349 len = count_contiguous_bits(full_mask & ~shareable_mask, &start); 350 if (!len) 351 return -1; 352 353 *mask = create_bit_mask(start, len); 354 355 return 0; 356 } 357 358 /* 359 * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu 360 * @bm_pid: PID that should be binded 361 * @cpu_no: CPU number at which the PID would be binded 362 * @old_affinity: When not NULL, set to old CPU affinity 363 * 364 * Return: 0 on success, < 0 on error. 365 */ 366 int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity) 367 { 368 cpu_set_t my_set; 369 370 if (old_affinity) { 371 CPU_ZERO(old_affinity); 372 if (sched_getaffinity(bm_pid, sizeof(*old_affinity), 373 old_affinity)) { 374 ksft_perror("Unable to read CPU affinity"); 375 return -1; 376 } 377 } 378 379 CPU_ZERO(&my_set); 380 CPU_SET(cpu_no, &my_set); 381 382 if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) { 383 ksft_perror("Unable to taskset benchmark"); 384 385 return -1; 386 } 387 388 return 0; 389 } 390 391 /* 392 * taskset_restore - Taskset PID to the earlier CPU affinity 393 * @bm_pid: PID that should be reset 394 * @old_affinity: The old CPU affinity to restore 395 * 396 * Return: 0 on success, < 0 on error. 397 */ 398 int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity) 399 { 400 if (sched_setaffinity(bm_pid, sizeof(*old_affinity), old_affinity)) { 401 ksft_perror("Unable to restore CPU affinity"); 402 return -1; 403 } 404 405 return 0; 406 } 407 408 /* 409 * create_grp - Create a group only if one doesn't exist 410 * @grp_name: Name of the group 411 * @grp: Full path and name of the group 412 * @parent_grp: Full path and name of the parent group 413 * 414 * Return: 0 on success, < 0 on error. 415 */ 416 static int create_grp(const char *grp_name, char *grp, const char *parent_grp) 417 { 418 int found_grp = 0; 419 struct dirent *ep; 420 DIR *dp; 421 422 /* 423 * At this point, we are guaranteed to have resctrl FS mounted and if 424 * length of grp_name == 0, it means, user wants to use root con_mon 425 * grp, so do nothing 426 */ 427 if (strlen(grp_name) == 0) 428 return 0; 429 430 /* Check if requested grp exists or not */ 431 dp = opendir(parent_grp); 432 if (dp) { 433 while ((ep = readdir(dp)) != NULL) { 434 if (strcmp(ep->d_name, grp_name) == 0) 435 found_grp = 1; 436 } 437 closedir(dp); 438 } else { 439 ksft_perror("Unable to open resctrl for group"); 440 441 return -1; 442 } 443 444 /* Requested grp doesn't exist, hence create it */ 445 if (found_grp == 0) { 446 if (mkdir(grp, 0) == -1) { 447 ksft_perror("Unable to create group"); 448 449 return -1; 450 } 451 } 452 453 return 0; 454 } 455 456 static int write_pid_to_tasks(char *tasks, pid_t pid) 457 { 458 FILE *fp; 459 460 fp = fopen(tasks, "w"); 461 if (!fp) { 462 ksft_perror("Failed to open tasks file"); 463 464 return -1; 465 } 466 if (fprintf(fp, "%d\n", pid) < 0) { 467 ksft_print_msg("Failed to write pid to tasks file\n"); 468 fclose(fp); 469 470 return -1; 471 } 472 fclose(fp); 473 474 return 0; 475 } 476 477 /* 478 * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS 479 * @bm_pid: PID that should be written 480 * @ctrlgrp: Name of the control monitor group (con_mon grp) 481 * @mongrp: Name of the monitor group (mon grp) 482 * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc) 483 * 484 * If a con_mon grp is requested, create it and write pid to it, otherwise 485 * write pid to root con_mon grp. 486 * If a mon grp is requested, create it and write pid to it, otherwise 487 * pid is not written, this means that pid is in con_mon grp and hence 488 * should consult con_mon grp's mon_data directory for results. 489 * 490 * Return: 0 on success, < 0 on error. 491 */ 492 int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp, 493 char *resctrl_val) 494 { 495 char controlgroup[128], monitorgroup[512], monitorgroup_p[256]; 496 char tasks[1024]; 497 int ret = 0; 498 499 if (strlen(ctrlgrp)) 500 sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp); 501 else 502 sprintf(controlgroup, "%s", RESCTRL_PATH); 503 504 /* Create control and monitoring group and write pid into it */ 505 ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH); 506 if (ret) 507 goto out; 508 sprintf(tasks, "%s/tasks", controlgroup); 509 ret = write_pid_to_tasks(tasks, bm_pid); 510 if (ret) 511 goto out; 512 513 /* Create mon grp and write pid into it for "mbm" and "cmt" test */ 514 if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)) || 515 !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) { 516 if (strlen(mongrp)) { 517 sprintf(monitorgroup_p, "%s/mon_groups", controlgroup); 518 sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp); 519 ret = create_grp(mongrp, monitorgroup, monitorgroup_p); 520 if (ret) 521 goto out; 522 523 sprintf(tasks, "%s/mon_groups/%s/tasks", 524 controlgroup, mongrp); 525 ret = write_pid_to_tasks(tasks, bm_pid); 526 if (ret) 527 goto out; 528 } 529 } 530 531 out: 532 ksft_print_msg("Writing benchmark parameters to resctrl FS\n"); 533 if (ret) 534 ksft_print_msg("Failed writing to resctrlfs\n"); 535 536 return ret; 537 } 538 539 /* 540 * write_schemata - Update schemata of a con_mon grp 541 * @ctrlgrp: Name of the con_mon grp 542 * @schemata: Schemata that should be updated to 543 * @cpu_no: CPU number that the benchmark PID is binded to 544 * @resource: Resctrl resource (Eg: MB, L3, L2, etc.) 545 * 546 * Update schemata of a con_mon grp *only* if requested resctrl resource is 547 * allocation type 548 * 549 * Return: 0 on success, < 0 on error. 550 */ 551 int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resource) 552 { 553 char controlgroup[1024], reason[128], schema[1024] = {}; 554 int resource_id, fd, schema_len, ret = 0; 555 556 if (!schemata) { 557 ksft_print_msg("Skipping empty schemata update\n"); 558 559 return -1; 560 } 561 562 if (get_resource_id(cpu_no, &resource_id) < 0) { 563 sprintf(reason, "Failed to get resource id"); 564 ret = -1; 565 566 goto out; 567 } 568 569 if (strlen(ctrlgrp) != 0) 570 sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp); 571 else 572 sprintf(controlgroup, "%s/schemata", RESCTRL_PATH); 573 574 schema_len = snprintf(schema, sizeof(schema), "%s:%d=%s\n", 575 resource, resource_id, schemata); 576 if (schema_len < 0 || schema_len >= sizeof(schema)) { 577 snprintf(reason, sizeof(reason), 578 "snprintf() failed with return value : %d", schema_len); 579 ret = -1; 580 goto out; 581 } 582 583 fd = open(controlgroup, O_WRONLY); 584 if (fd < 0) { 585 snprintf(reason, sizeof(reason), 586 "open() failed : %s", strerror(errno)); 587 ret = -1; 588 589 goto err_schema_not_empty; 590 } 591 if (write(fd, schema, schema_len) < 0) { 592 snprintf(reason, sizeof(reason), 593 "write() failed : %s", strerror(errno)); 594 close(fd); 595 ret = -1; 596 597 goto err_schema_not_empty; 598 } 599 close(fd); 600 601 err_schema_not_empty: 602 schema[schema_len - 1] = 0; 603 out: 604 ksft_print_msg("Write schema \"%s\" to resctrl FS%s%s\n", 605 schema, ret ? " # " : "", 606 ret ? reason : ""); 607 608 return ret; 609 } 610 611 bool check_resctrlfs_support(void) 612 { 613 FILE *inf = fopen("/proc/filesystems", "r"); 614 DIR *dp; 615 char *res; 616 bool ret = false; 617 618 if (!inf) 619 return false; 620 621 res = fgrep(inf, "nodev\tresctrl\n"); 622 623 if (res) { 624 ret = true; 625 free(res); 626 } 627 628 fclose(inf); 629 630 ksft_print_msg("%s Check kernel supports resctrl filesystem\n", 631 ret ? "Pass:" : "Fail:"); 632 633 if (!ret) 634 return ret; 635 636 dp = opendir(RESCTRL_PATH); 637 ksft_print_msg("%s Check resctrl mountpoint \"%s\" exists\n", 638 dp ? "Pass:" : "Fail:", RESCTRL_PATH); 639 if (dp) 640 closedir(dp); 641 642 ksft_print_msg("resctrl filesystem %s mounted\n", 643 find_resctrl_mount(NULL) ? "not" : "is"); 644 645 return ret; 646 } 647 648 char *fgrep(FILE *inf, const char *str) 649 { 650 char line[256]; 651 int slen = strlen(str); 652 653 while (!feof(inf)) { 654 if (!fgets(line, 256, inf)) 655 break; 656 if (strncmp(line, str, slen)) 657 continue; 658 659 return strdup(line); 660 } 661 662 return NULL; 663 } 664 665 /* 666 * validate_resctrl_feature_request - Check if requested feature is valid. 667 * @resource: Required resource (e.g., MB, L3, L2, L3_MON, etc.) 668 * @feature: Required monitor feature (in mon_features file). Can only be 669 * set for L3_MON. Must be NULL for all other resources. 670 * 671 * Return: True if the resource/feature is supported, else false. False is 672 * also returned if resctrl FS is not mounted. 673 */ 674 bool validate_resctrl_feature_request(const char *resource, const char *feature) 675 { 676 char res_path[PATH_MAX]; 677 struct stat statbuf; 678 char *res; 679 FILE *inf; 680 int ret; 681 682 if (!resource) 683 return false; 684 685 ret = find_resctrl_mount(NULL); 686 if (ret) 687 return false; 688 689 snprintf(res_path, sizeof(res_path), "%s/%s", INFO_PATH, resource); 690 691 if (stat(res_path, &statbuf)) 692 return false; 693 694 if (!feature) 695 return true; 696 697 snprintf(res_path, sizeof(res_path), "%s/%s/mon_features", INFO_PATH, resource); 698 inf = fopen(res_path, "r"); 699 if (!inf) 700 return false; 701 702 res = fgrep(inf, feature); 703 free(res); 704 fclose(inf); 705 706 return !!res; 707 } 708 709 bool test_resource_feature_check(const struct resctrl_test *test) 710 { 711 return validate_resctrl_feature_request(test->resource, NULL); 712 } 713 714 int filter_dmesg(void) 715 { 716 char line[1024]; 717 FILE *fp; 718 int pipefds[2]; 719 pid_t pid; 720 int ret; 721 722 ret = pipe(pipefds); 723 if (ret) { 724 ksft_perror("pipe"); 725 return ret; 726 } 727 fflush(stdout); 728 pid = fork(); 729 if (pid == 0) { 730 close(pipefds[0]); 731 dup2(pipefds[1], STDOUT_FILENO); 732 execlp("dmesg", "dmesg", NULL); 733 ksft_perror("Executing dmesg"); 734 exit(1); 735 } 736 close(pipefds[1]); 737 fp = fdopen(pipefds[0], "r"); 738 if (!fp) { 739 ksft_perror("fdopen(pipe)"); 740 kill(pid, SIGTERM); 741 742 return -1; 743 } 744 745 while (fgets(line, 1024, fp)) { 746 if (strstr(line, "intel_rdt:")) 747 ksft_print_msg("dmesg: %s", line); 748 if (strstr(line, "resctrl:")) 749 ksft_print_msg("dmesg: %s", line); 750 } 751 fclose(fp); 752 waitpid(pid, NULL, 0); 753 754 return 0; 755 } 756 757 int validate_bw_report_request(char *bw_report) 758 { 759 if (strcmp(bw_report, "reads") == 0) 760 return 0; 761 if (strcmp(bw_report, "writes") == 0) 762 return 0; 763 if (strcmp(bw_report, "nt-writes") == 0) { 764 strcpy(bw_report, "writes"); 765 return 0; 766 } 767 if (strcmp(bw_report, "total") == 0) 768 return 0; 769 770 fprintf(stderr, "Requested iMC B/W report type unavailable\n"); 771 772 return -1; 773 } 774 775 int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, 776 int group_fd, unsigned long flags) 777 { 778 int ret; 779 780 ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, 781 group_fd, flags); 782 return ret; 783 } 784 785 unsigned int count_bits(unsigned long n) 786 { 787 unsigned int count = 0; 788 789 while (n) { 790 count += n & 1; 791 n >>= 1; 792 } 793 794 return count; 795 } 796