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