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 * resource_info_unsigned_get - Read an unsigned value from 254 * /sys/fs/resctrl/info/@resource/@filename 255 * @resource: Resource name that matches directory name in 256 * /sys/fs/resctrl/info 257 * @filename: File in /sys/fs/resctrl/info/@resource 258 * @val: Contains read value on success. 259 * 260 * Return: = 0 on success, < 0 on failure. On success the read 261 * value is saved into @val. 262 */ 263 int resource_info_unsigned_get(const char *resource, const char *filename, 264 unsigned int *val) 265 { 266 char file_path[PATH_MAX]; 267 FILE *fp; 268 269 snprintf(file_path, sizeof(file_path), "%s/%s/%s", INFO_PATH, resource, 270 filename); 271 272 fp = fopen(file_path, "r"); 273 if (!fp) { 274 ksft_print_msg("Error opening %s: %m\n", file_path); 275 return -1; 276 } 277 278 if (fscanf(fp, "%u", val) <= 0) { 279 ksft_print_msg("Could not get contents of %s: %m\n", file_path); 280 fclose(fp); 281 return -1; 282 } 283 284 fclose(fp); 285 return 0; 286 } 287 288 /* 289 * create_bit_mask- Create bit mask from start, len pair 290 * @start: LSB of the mask 291 * @len Number of bits in the mask 292 */ 293 unsigned long create_bit_mask(unsigned int start, unsigned int len) 294 { 295 return ((1UL << len) - 1UL) << start; 296 } 297 298 /* 299 * count_contiguous_bits - Returns the longest train of bits in a bit mask 300 * @val A bit mask 301 * @start The location of the least-significant bit of the longest train 302 * 303 * Return: The length of the contiguous bits in the longest train of bits 304 */ 305 unsigned int count_contiguous_bits(unsigned long val, unsigned int *start) 306 { 307 unsigned long last_val; 308 unsigned int count = 0; 309 310 while (val) { 311 last_val = val; 312 val &= (val >> 1); 313 count++; 314 } 315 316 if (start) { 317 if (count) 318 *start = ffsl(last_val) - 1; 319 else 320 *start = 0; 321 } 322 323 return count; 324 } 325 326 /* 327 * get_full_cbm - Get full Cache Bit Mask (CBM) 328 * @cache_type: Cache type as "L2" or "L3" 329 * @mask: Full cache bit mask representing the maximal portion of cache 330 * available for allocation, returned as unsigned long. 331 * 332 * Return: = 0 on success, < 0 on failure. 333 */ 334 int get_full_cbm(const char *cache_type, unsigned long *mask) 335 { 336 char cbm_path[PATH_MAX]; 337 int ret; 338 339 if (!cache_type) 340 return -1; 341 342 snprintf(cbm_path, sizeof(cbm_path), "%s/%s/cbm_mask", 343 INFO_PATH, cache_type); 344 345 ret = get_bit_mask(cbm_path, mask); 346 if (ret || !*mask) 347 return -1; 348 349 return 0; 350 } 351 352 /* 353 * get_shareable_mask - Get shareable mask from shareable_bits 354 * @cache_type: Cache type as "L2" or "L3" 355 * @shareable_mask: Shareable mask returned as unsigned long 356 * 357 * Return: = 0 on success, < 0 on failure. 358 */ 359 static int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask) 360 { 361 char mask_path[PATH_MAX]; 362 363 if (!cache_type) 364 return -1; 365 366 snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits", 367 INFO_PATH, cache_type); 368 369 return get_bit_mask(mask_path, shareable_mask); 370 } 371 372 /* 373 * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits 374 * @cache_type: Cache type as "L2" or "L3" 375 * @mask: The largest exclusive portion of the cache out of the 376 * full CBM, returned as unsigned long 377 * 378 * Parts of a cache may be shared with other devices such as GPU. This function 379 * calculates the largest exclusive portion of the cache where no other devices 380 * besides CPU have access to the cache portion. 381 * 382 * Return: = 0 on success, < 0 on failure. 383 */ 384 int get_mask_no_shareable(const char *cache_type, unsigned long *mask) 385 { 386 unsigned long full_mask, shareable_mask; 387 unsigned int start, len; 388 389 if (get_full_cbm(cache_type, &full_mask) < 0) 390 return -1; 391 if (get_shareable_mask(cache_type, &shareable_mask) < 0) 392 return -1; 393 394 len = count_contiguous_bits(full_mask & ~shareable_mask, &start); 395 if (!len) 396 return -1; 397 398 *mask = create_bit_mask(start, len); 399 400 return 0; 401 } 402 403 /* 404 * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu 405 * @bm_pid: PID that should be binded 406 * @cpu_no: CPU number at which the PID would be binded 407 * @old_affinity: When not NULL, set to old CPU affinity 408 * 409 * Return: 0 on success, < 0 on error. 410 */ 411 int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity) 412 { 413 cpu_set_t my_set; 414 415 if (old_affinity) { 416 CPU_ZERO(old_affinity); 417 if (sched_getaffinity(bm_pid, sizeof(*old_affinity), 418 old_affinity)) { 419 ksft_perror("Unable to read CPU affinity"); 420 return -1; 421 } 422 } 423 424 CPU_ZERO(&my_set); 425 CPU_SET(cpu_no, &my_set); 426 427 if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) { 428 ksft_perror("Unable to taskset benchmark"); 429 430 return -1; 431 } 432 433 return 0; 434 } 435 436 /* 437 * taskset_restore - Taskset PID to the earlier CPU affinity 438 * @bm_pid: PID that should be reset 439 * @old_affinity: The old CPU affinity to restore 440 * 441 * Return: 0 on success, < 0 on error. 442 */ 443 int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity) 444 { 445 if (sched_setaffinity(bm_pid, sizeof(*old_affinity), old_affinity)) { 446 ksft_perror("Unable to restore CPU affinity"); 447 return -1; 448 } 449 450 return 0; 451 } 452 453 /* 454 * create_grp - Create a group only if one doesn't exist 455 * @grp_name: Name of the group 456 * @grp: Full path and name of the group 457 * @parent_grp: Full path and name of the parent group 458 * 459 * Return: 0 on success, < 0 on error. 460 */ 461 static int create_grp(const char *grp_name, char *grp, const char *parent_grp) 462 { 463 int found_grp = 0; 464 struct dirent *ep; 465 DIR *dp; 466 467 /* 468 * At this point, we are guaranteed to have resctrl FS mounted and if 469 * length of grp_name == 0, it means, user wants to use root con_mon 470 * grp, so do nothing 471 */ 472 if (strlen(grp_name) == 0) 473 return 0; 474 475 /* Check if requested grp exists or not */ 476 dp = opendir(parent_grp); 477 if (dp) { 478 while ((ep = readdir(dp)) != NULL) { 479 if (strcmp(ep->d_name, grp_name) == 0) 480 found_grp = 1; 481 } 482 closedir(dp); 483 } else { 484 ksft_perror("Unable to open resctrl for group"); 485 486 return -1; 487 } 488 489 /* Requested grp doesn't exist, hence create it */ 490 if (found_grp == 0) { 491 if (mkdir(grp, 0) == -1) { 492 ksft_perror("Unable to create group"); 493 494 return -1; 495 } 496 } 497 498 return 0; 499 } 500 501 static int write_pid_to_tasks(char *tasks, pid_t pid) 502 { 503 FILE *fp; 504 505 fp = fopen(tasks, "w"); 506 if (!fp) { 507 ksft_perror("Failed to open tasks file"); 508 509 return -1; 510 } 511 if (fprintf(fp, "%d\n", pid) < 0) { 512 ksft_print_msg("Failed to write pid to tasks file\n"); 513 fclose(fp); 514 515 return -1; 516 } 517 fclose(fp); 518 519 return 0; 520 } 521 522 /* 523 * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS 524 * @bm_pid: PID that should be written 525 * @ctrlgrp: Name of the control monitor group (con_mon grp) 526 * @mongrp: Name of the monitor group (mon grp) 527 * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc) 528 * 529 * If a con_mon grp is requested, create it and write pid to it, otherwise 530 * write pid to root con_mon grp. 531 * If a mon grp is requested, create it and write pid to it, otherwise 532 * pid is not written, this means that pid is in con_mon grp and hence 533 * should consult con_mon grp's mon_data directory for results. 534 * 535 * Return: 0 on success, < 0 on error. 536 */ 537 int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp, 538 char *resctrl_val) 539 { 540 char controlgroup[128], monitorgroup[512], monitorgroup_p[256]; 541 char tasks[1024]; 542 int ret = 0; 543 544 if (strlen(ctrlgrp)) 545 sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp); 546 else 547 sprintf(controlgroup, "%s", RESCTRL_PATH); 548 549 /* Create control and monitoring group and write pid into it */ 550 ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH); 551 if (ret) 552 goto out; 553 sprintf(tasks, "%s/tasks", controlgroup); 554 ret = write_pid_to_tasks(tasks, bm_pid); 555 if (ret) 556 goto out; 557 558 /* Create mon grp and write pid into it for "mbm" and "cmt" test */ 559 if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)) || 560 !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) { 561 if (strlen(mongrp)) { 562 sprintf(monitorgroup_p, "%s/mon_groups", controlgroup); 563 sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp); 564 ret = create_grp(mongrp, monitorgroup, monitorgroup_p); 565 if (ret) 566 goto out; 567 568 sprintf(tasks, "%s/mon_groups/%s/tasks", 569 controlgroup, mongrp); 570 ret = write_pid_to_tasks(tasks, bm_pid); 571 if (ret) 572 goto out; 573 } 574 } 575 576 out: 577 ksft_print_msg("Writing benchmark parameters to resctrl FS\n"); 578 if (ret) 579 ksft_print_msg("Failed writing to resctrlfs\n"); 580 581 return ret; 582 } 583 584 /* 585 * write_schemata - Update schemata of a con_mon grp 586 * @ctrlgrp: Name of the con_mon grp 587 * @schemata: Schemata that should be updated to 588 * @cpu_no: CPU number that the benchmark PID is binded to 589 * @resource: Resctrl resource (Eg: MB, L3, L2, etc.) 590 * 591 * Update schemata of a con_mon grp *only* if requested resctrl resource is 592 * allocation type 593 * 594 * Return: 0 on success, < 0 on error. 595 */ 596 int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, const char *resource) 597 { 598 char controlgroup[1024], reason[128], schema[1024] = {}; 599 int domain_id, fd, schema_len, ret = 0; 600 601 if (!schemata) { 602 ksft_print_msg("Skipping empty schemata update\n"); 603 604 return -1; 605 } 606 607 if (get_domain_id(resource, cpu_no, &domain_id) < 0) { 608 sprintf(reason, "Failed to get domain ID"); 609 ret = -1; 610 611 goto out; 612 } 613 614 if (strlen(ctrlgrp) != 0) 615 sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp); 616 else 617 sprintf(controlgroup, "%s/schemata", RESCTRL_PATH); 618 619 schema_len = snprintf(schema, sizeof(schema), "%s:%d=%s\n", 620 resource, domain_id, schemata); 621 if (schema_len < 0 || schema_len >= sizeof(schema)) { 622 snprintf(reason, sizeof(reason), 623 "snprintf() failed with return value : %d", schema_len); 624 ret = -1; 625 goto out; 626 } 627 628 fd = open(controlgroup, O_WRONLY); 629 if (fd < 0) { 630 snprintf(reason, sizeof(reason), 631 "open() failed : %s", strerror(errno)); 632 ret = -1; 633 634 goto err_schema_not_empty; 635 } 636 if (write(fd, schema, schema_len) < 0) { 637 snprintf(reason, sizeof(reason), 638 "write() failed : %s", strerror(errno)); 639 close(fd); 640 ret = -1; 641 642 goto err_schema_not_empty; 643 } 644 close(fd); 645 646 err_schema_not_empty: 647 schema[schema_len - 1] = 0; 648 out: 649 ksft_print_msg("Write schema \"%s\" to resctrl FS%s%s\n", 650 schema, ret ? " # " : "", 651 ret ? reason : ""); 652 653 return ret; 654 } 655 656 bool check_resctrlfs_support(void) 657 { 658 FILE *inf = fopen("/proc/filesystems", "r"); 659 DIR *dp; 660 char *res; 661 bool ret = false; 662 663 if (!inf) 664 return false; 665 666 res = fgrep(inf, "nodev\tresctrl\n"); 667 668 if (res) { 669 ret = true; 670 free(res); 671 } 672 673 fclose(inf); 674 675 ksft_print_msg("%s Check kernel supports resctrl filesystem\n", 676 ret ? "Pass:" : "Fail:"); 677 678 if (!ret) 679 return ret; 680 681 dp = opendir(RESCTRL_PATH); 682 ksft_print_msg("%s Check resctrl mountpoint \"%s\" exists\n", 683 dp ? "Pass:" : "Fail:", RESCTRL_PATH); 684 if (dp) 685 closedir(dp); 686 687 ksft_print_msg("resctrl filesystem %s mounted\n", 688 find_resctrl_mount(NULL) ? "not" : "is"); 689 690 return ret; 691 } 692 693 char *fgrep(FILE *inf, const char *str) 694 { 695 char line[256]; 696 int slen = strlen(str); 697 698 while (!feof(inf)) { 699 if (!fgets(line, 256, inf)) 700 break; 701 if (strncmp(line, str, slen)) 702 continue; 703 704 return strdup(line); 705 } 706 707 return NULL; 708 } 709 710 /* 711 * resctrl_resource_exists - Check if a resource is supported. 712 * @resource: Resctrl resource (e.g., MB, L3, L2, L3_MON, etc.) 713 * 714 * Return: True if the resource is supported, else false. False is 715 * also returned if resctrl FS is not mounted. 716 */ 717 bool resctrl_resource_exists(const char *resource) 718 { 719 char res_path[PATH_MAX]; 720 struct stat statbuf; 721 int ret; 722 723 if (!resource) 724 return false; 725 726 ret = find_resctrl_mount(NULL); 727 if (ret) 728 return false; 729 730 snprintf(res_path, sizeof(res_path), "%s/%s", INFO_PATH, resource); 731 732 if (stat(res_path, &statbuf)) 733 return false; 734 735 return true; 736 } 737 738 /* 739 * resctrl_mon_feature_exists - Check if requested monitoring feature is valid. 740 * @resource: Resource that uses the mon_features file. Currently only L3_MON 741 * is valid. 742 * @feature: Required monitor feature (in mon_features file). 743 * 744 * Return: True if the feature is supported, else false. 745 */ 746 bool resctrl_mon_feature_exists(const char *resource, const char *feature) 747 { 748 char res_path[PATH_MAX]; 749 char *res; 750 FILE *inf; 751 752 if (!feature || !resource) 753 return false; 754 755 snprintf(res_path, sizeof(res_path), "%s/%s/mon_features", INFO_PATH, resource); 756 inf = fopen(res_path, "r"); 757 if (!inf) 758 return false; 759 760 res = fgrep(inf, feature); 761 free(res); 762 fclose(inf); 763 764 return !!res; 765 } 766 767 /* 768 * resource_info_file_exists - Check if a file is present inside 769 * /sys/fs/resctrl/info/@resource. 770 * @resource: Required resource (Eg: MB, L3, L2, etc.) 771 * @file: Required file. 772 * 773 * Return: True if the /sys/fs/resctrl/info/@resource/@file exists, else false. 774 */ 775 bool resource_info_file_exists(const char *resource, const char *file) 776 { 777 char res_path[PATH_MAX]; 778 struct stat statbuf; 779 780 if (!file || !resource) 781 return false; 782 783 snprintf(res_path, sizeof(res_path), "%s/%s/%s", INFO_PATH, resource, 784 file); 785 786 if (stat(res_path, &statbuf)) 787 return false; 788 789 return true; 790 } 791 792 bool test_resource_feature_check(const struct resctrl_test *test) 793 { 794 return resctrl_resource_exists(test->resource); 795 } 796 797 int filter_dmesg(void) 798 { 799 char line[1024]; 800 FILE *fp; 801 int pipefds[2]; 802 pid_t pid; 803 int ret; 804 805 ret = pipe(pipefds); 806 if (ret) { 807 ksft_perror("pipe"); 808 return ret; 809 } 810 fflush(stdout); 811 pid = fork(); 812 if (pid == 0) { 813 close(pipefds[0]); 814 dup2(pipefds[1], STDOUT_FILENO); 815 execlp("dmesg", "dmesg", NULL); 816 ksft_perror("Executing dmesg"); 817 exit(1); 818 } 819 close(pipefds[1]); 820 fp = fdopen(pipefds[0], "r"); 821 if (!fp) { 822 ksft_perror("fdopen(pipe)"); 823 kill(pid, SIGTERM); 824 825 return -1; 826 } 827 828 while (fgets(line, 1024, fp)) { 829 if (strstr(line, "intel_rdt:")) 830 ksft_print_msg("dmesg: %s", line); 831 if (strstr(line, "resctrl:")) 832 ksft_print_msg("dmesg: %s", line); 833 } 834 fclose(fp); 835 waitpid(pid, NULL, 0); 836 837 return 0; 838 } 839 840 int validate_bw_report_request(char *bw_report) 841 { 842 if (strcmp(bw_report, "reads") == 0) 843 return 0; 844 if (strcmp(bw_report, "writes") == 0) 845 return 0; 846 if (strcmp(bw_report, "nt-writes") == 0) { 847 strcpy(bw_report, "writes"); 848 return 0; 849 } 850 if (strcmp(bw_report, "total") == 0) 851 return 0; 852 853 fprintf(stderr, "Requested iMC B/W report type unavailable\n"); 854 855 return -1; 856 } 857 858 int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, 859 int group_fd, unsigned long flags) 860 { 861 int ret; 862 863 ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, 864 group_fd, flags); 865 return ret; 866 } 867 868 unsigned int count_bits(unsigned long n) 869 { 870 unsigned int count = 0; 871 872 while (n) { 873 count += n & 1; 874 n >>= 1; 875 } 876 877 return count; 878 } 879