0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "resctrl.h"
0012
0013 static int find_resctrl_mount(char *buffer)
0014 {
0015 FILE *mounts;
0016 char line[256], *fs, *mntpoint;
0017
0018 mounts = fopen("/proc/mounts", "r");
0019 if (!mounts) {
0020 perror("/proc/mounts");
0021 return -ENXIO;
0022 }
0023 while (!feof(mounts)) {
0024 if (!fgets(line, 256, mounts))
0025 break;
0026 fs = strtok(line, " \t");
0027 if (!fs)
0028 continue;
0029 mntpoint = strtok(NULL, " \t");
0030 if (!mntpoint)
0031 continue;
0032 fs = strtok(NULL, " \t");
0033 if (!fs)
0034 continue;
0035 if (strcmp(fs, "resctrl"))
0036 continue;
0037
0038 fclose(mounts);
0039 if (buffer)
0040 strncpy(buffer, mntpoint, 256);
0041
0042 return 0;
0043 }
0044
0045 fclose(mounts);
0046
0047 return -ENOENT;
0048 }
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 int remount_resctrlfs(bool mum_resctrlfs)
0061 {
0062 char mountpoint[256];
0063 int ret;
0064
0065 ret = find_resctrl_mount(mountpoint);
0066 if (ret)
0067 strcpy(mountpoint, RESCTRL_PATH);
0068
0069 if (!ret && mum_resctrlfs && umount(mountpoint))
0070 ksft_print_msg("Fail: unmounting \"%s\"\n", mountpoint);
0071
0072 if (!ret && !mum_resctrlfs)
0073 return 0;
0074
0075 ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH);
0076 ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL);
0077 if (ret)
0078 perror("# mount");
0079
0080 return ret;
0081 }
0082
0083 int umount_resctrlfs(void)
0084 {
0085 if (find_resctrl_mount(NULL))
0086 return 0;
0087
0088 if (umount(RESCTRL_PATH)) {
0089 perror("# Unable to umount resctrl");
0090
0091 return errno;
0092 }
0093
0094 return 0;
0095 }
0096
0097
0098
0099
0100
0101
0102
0103
0104 int get_resource_id(int cpu_no, int *resource_id)
0105 {
0106 char phys_pkg_path[1024];
0107 FILE *fp;
0108
0109 if (get_vendor() == ARCH_AMD)
0110 sprintf(phys_pkg_path, "%s%d/cache/index3/id",
0111 PHYS_ID_PATH, cpu_no);
0112 else
0113 sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
0114 PHYS_ID_PATH, cpu_no);
0115
0116 fp = fopen(phys_pkg_path, "r");
0117 if (!fp) {
0118 perror("Failed to open physical_package_id");
0119
0120 return -1;
0121 }
0122 if (fscanf(fp, "%d", resource_id) <= 0) {
0123 perror("Could not get socket number or l3 id");
0124 fclose(fp);
0125
0126 return -1;
0127 }
0128 fclose(fp);
0129
0130 return 0;
0131 }
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size)
0142 {
0143 char cache_path[1024], cache_str[64];
0144 int length, i, cache_num;
0145 FILE *fp;
0146
0147 if (!strcmp(cache_type, "L3")) {
0148 cache_num = 3;
0149 } else if (!strcmp(cache_type, "L2")) {
0150 cache_num = 2;
0151 } else {
0152 perror("Invalid cache level");
0153 return -1;
0154 }
0155
0156 sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
0157 cpu_no, cache_num);
0158 fp = fopen(cache_path, "r");
0159 if (!fp) {
0160 perror("Failed to open cache size");
0161
0162 return -1;
0163 }
0164 if (fscanf(fp, "%s", cache_str) <= 0) {
0165 perror("Could not get cache_size");
0166 fclose(fp);
0167
0168 return -1;
0169 }
0170 fclose(fp);
0171
0172 length = (int)strlen(cache_str);
0173
0174 *cache_size = 0;
0175
0176 for (i = 0; i < length; i++) {
0177 if ((cache_str[i] >= '0') && (cache_str[i] <= '9'))
0178
0179 *cache_size = *cache_size * 10 + (cache_str[i] - '0');
0180
0181 else if (cache_str[i] == 'K')
0182
0183 *cache_size = *cache_size * 1024;
0184
0185 else if (cache_str[i] == 'M')
0186
0187 *cache_size = *cache_size * 1024 * 1024;
0188
0189 else
0190 break;
0191 }
0192
0193 return 0;
0194 }
0195
0196 #define CORE_SIBLINGS_PATH "/sys/bus/cpu/devices/cpu"
0197
0198
0199
0200
0201
0202
0203
0204
0205 int get_cbm_mask(char *cache_type, char *cbm_mask)
0206 {
0207 char cbm_mask_path[1024];
0208 FILE *fp;
0209
0210 if (!cbm_mask)
0211 return -1;
0212
0213 sprintf(cbm_mask_path, "%s/%s/cbm_mask", CBM_MASK_PATH, cache_type);
0214
0215 fp = fopen(cbm_mask_path, "r");
0216 if (!fp) {
0217 perror("Failed to open cache level");
0218
0219 return -1;
0220 }
0221 if (fscanf(fp, "%s", cbm_mask) <= 0) {
0222 perror("Could not get max cbm_mask");
0223 fclose(fp);
0224
0225 return -1;
0226 }
0227 fclose(fp);
0228
0229 return 0;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238 int get_core_sibling(int cpu_no)
0239 {
0240 char core_siblings_path[1024], cpu_list_str[64];
0241 int sibling_cpu_no = -1;
0242 FILE *fp;
0243
0244 sprintf(core_siblings_path, "%s%d/topology/core_siblings_list",
0245 CORE_SIBLINGS_PATH, cpu_no);
0246
0247 fp = fopen(core_siblings_path, "r");
0248 if (!fp) {
0249 perror("Failed to open core siblings path");
0250
0251 return -1;
0252 }
0253 if (fscanf(fp, "%s", cpu_list_str) <= 0) {
0254 perror("Could not get core_siblings list");
0255 fclose(fp);
0256
0257 return -1;
0258 }
0259 fclose(fp);
0260
0261 char *token = strtok(cpu_list_str, "-,");
0262
0263 while (token) {
0264 sibling_cpu_no = atoi(token);
0265
0266 if (sibling_cpu_no != 0 && sibling_cpu_no != cpu_no)
0267 break;
0268 token = strtok(NULL, "-,");
0269 }
0270
0271 return sibling_cpu_no;
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281 int taskset_benchmark(pid_t bm_pid, int cpu_no)
0282 {
0283 cpu_set_t my_set;
0284
0285 CPU_ZERO(&my_set);
0286 CPU_SET(cpu_no, &my_set);
0287
0288 if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
0289 perror("Unable to taskset benchmark");
0290
0291 return -1;
0292 }
0293
0294 return 0;
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306 void run_benchmark(int signum, siginfo_t *info, void *ucontext)
0307 {
0308 int operation, ret, malloc_and_init_memory, memflush;
0309 unsigned long span, buffer_span;
0310 char **benchmark_cmd;
0311 char resctrl_val[64];
0312 FILE *fp;
0313
0314 benchmark_cmd = info->si_ptr;
0315
0316
0317
0318
0319
0320 fp = freopen("/dev/null", "w", stdout);
0321 if (!fp)
0322 PARENT_EXIT("Unable to direct benchmark status to /dev/null");
0323
0324 if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
0325
0326 span = strtoul(benchmark_cmd[1], NULL, 10);
0327 malloc_and_init_memory = atoi(benchmark_cmd[2]);
0328 memflush = atoi(benchmark_cmd[3]);
0329 operation = atoi(benchmark_cmd[4]);
0330 sprintf(resctrl_val, "%s", benchmark_cmd[5]);
0331
0332 if (strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0333 buffer_span = span * MB;
0334 else
0335 buffer_span = span;
0336
0337 if (run_fill_buf(buffer_span, malloc_and_init_memory, memflush,
0338 operation, resctrl_val))
0339 fprintf(stderr, "Error in running fill buffer\n");
0340 } else {
0341
0342 ret = execvp(benchmark_cmd[0], benchmark_cmd);
0343 if (ret)
0344 perror("wrong\n");
0345 }
0346
0347 fclose(stdout);
0348 PARENT_EXIT("Unable to run specified benchmark");
0349 }
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359 static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
0360 {
0361 int found_grp = 0;
0362 struct dirent *ep;
0363 DIR *dp;
0364
0365
0366
0367
0368
0369
0370 if (strlen(grp_name) == 0)
0371 return 0;
0372
0373
0374 dp = opendir(parent_grp);
0375 if (dp) {
0376 while ((ep = readdir(dp)) != NULL) {
0377 if (strcmp(ep->d_name, grp_name) == 0)
0378 found_grp = 1;
0379 }
0380 closedir(dp);
0381 } else {
0382 perror("Unable to open resctrl for group");
0383
0384 return -1;
0385 }
0386
0387
0388 if (found_grp == 0) {
0389 if (mkdir(grp, 0) == -1) {
0390 perror("Unable to create group");
0391
0392 return -1;
0393 }
0394 }
0395
0396 return 0;
0397 }
0398
0399 static int write_pid_to_tasks(char *tasks, pid_t pid)
0400 {
0401 FILE *fp;
0402
0403 fp = fopen(tasks, "w");
0404 if (!fp) {
0405 perror("Failed to open tasks file");
0406
0407 return -1;
0408 }
0409 if (fprintf(fp, "%d\n", pid) < 0) {
0410 perror("Failed to wr pid to tasks file");
0411 fclose(fp);
0412
0413 return -1;
0414 }
0415 fclose(fp);
0416
0417 return 0;
0418 }
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
0436 char *resctrl_val)
0437 {
0438 char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
0439 char tasks[1024];
0440 int ret = 0;
0441
0442 if (strlen(ctrlgrp))
0443 sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
0444 else
0445 sprintf(controlgroup, "%s", RESCTRL_PATH);
0446
0447
0448 ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
0449 if (ret)
0450 goto out;
0451 sprintf(tasks, "%s/tasks", controlgroup);
0452 ret = write_pid_to_tasks(tasks, bm_pid);
0453 if (ret)
0454 goto out;
0455
0456
0457 if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)) ||
0458 !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
0459 if (strlen(mongrp)) {
0460 sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
0461 sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
0462 ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
0463 if (ret)
0464 goto out;
0465
0466 sprintf(tasks, "%s/mon_groups/%s/tasks",
0467 controlgroup, mongrp);
0468 ret = write_pid_to_tasks(tasks, bm_pid);
0469 if (ret)
0470 goto out;
0471 }
0472 }
0473
0474 out:
0475 ksft_print_msg("Writing benchmark parameters to resctrl FS\n");
0476 if (ret)
0477 perror("# writing to resctrlfs");
0478
0479 return ret;
0480 }
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494 int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
0495 {
0496 char controlgroup[1024], schema[1024], reason[64];
0497 int resource_id, ret = 0;
0498 FILE *fp;
0499
0500 if (strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) &&
0501 strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) &&
0502 strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0503 return -ENOENT;
0504
0505 if (!schemata) {
0506 ksft_print_msg("Skipping empty schemata update\n");
0507
0508 return -1;
0509 }
0510
0511 if (get_resource_id(cpu_no, &resource_id) < 0) {
0512 sprintf(reason, "Failed to get resource id");
0513 ret = -1;
0514
0515 goto out;
0516 }
0517
0518 if (strlen(ctrlgrp) != 0)
0519 sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp);
0520 else
0521 sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
0522
0523 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) ||
0524 !strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0525 sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=', schemata);
0526 if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)))
0527 sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata);
0528
0529 fp = fopen(controlgroup, "w");
0530 if (!fp) {
0531 sprintf(reason, "Failed to open control group");
0532 ret = -1;
0533
0534 goto out;
0535 }
0536
0537 if (fprintf(fp, "%s\n", schema) < 0) {
0538 sprintf(reason, "Failed to write schemata in control group");
0539 fclose(fp);
0540 ret = -1;
0541
0542 goto out;
0543 }
0544 fclose(fp);
0545
0546 out:
0547 ksft_print_msg("Write schema \"%s\" to resctrl FS%s%s\n",
0548 schema, ret ? " # " : "",
0549 ret ? reason : "");
0550
0551 return ret;
0552 }
0553
0554 bool check_resctrlfs_support(void)
0555 {
0556 FILE *inf = fopen("/proc/filesystems", "r");
0557 DIR *dp;
0558 char *res;
0559 bool ret = false;
0560
0561 if (!inf)
0562 return false;
0563
0564 res = fgrep(inf, "nodev\tresctrl\n");
0565
0566 if (res) {
0567 ret = true;
0568 free(res);
0569 }
0570
0571 fclose(inf);
0572
0573 ksft_print_msg("%s Check kernel supports resctrl filesystem\n",
0574 ret ? "Pass:" : "Fail:");
0575
0576 if (!ret)
0577 return ret;
0578
0579 dp = opendir(RESCTRL_PATH);
0580 ksft_print_msg("%s Check resctrl mountpoint \"%s\" exists\n",
0581 dp ? "Pass:" : "Fail:", RESCTRL_PATH);
0582 if (dp)
0583 closedir(dp);
0584
0585 ksft_print_msg("resctrl filesystem %s mounted\n",
0586 find_resctrl_mount(NULL) ? "not" : "is");
0587
0588 return ret;
0589 }
0590
0591 char *fgrep(FILE *inf, const char *str)
0592 {
0593 char line[256];
0594 int slen = strlen(str);
0595
0596 while (!feof(inf)) {
0597 if (!fgets(line, 256, inf))
0598 break;
0599 if (strncmp(line, str, slen))
0600 continue;
0601
0602 return strdup(line);
0603 }
0604
0605 return NULL;
0606 }
0607
0608
0609
0610
0611
0612
0613
0614 bool validate_resctrl_feature_request(const char *resctrl_val)
0615 {
0616 struct stat statbuf;
0617 bool found = false;
0618 char *res;
0619 FILE *inf;
0620
0621 if (!resctrl_val)
0622 return false;
0623
0624 if (remount_resctrlfs(false))
0625 return false;
0626
0627 if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR))) {
0628 if (!stat(L3_PATH, &statbuf))
0629 return true;
0630 } else if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0631 if (!stat(MB_PATH, &statbuf))
0632 return true;
0633 } else if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
0634 !strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) {
0635 if (!stat(L3_MON_PATH, &statbuf)) {
0636 inf = fopen(L3_MON_FEATURES_PATH, "r");
0637 if (!inf)
0638 return false;
0639
0640 if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) {
0641 res = fgrep(inf, "llc_occupancy");
0642 if (res) {
0643 found = true;
0644 free(res);
0645 }
0646 }
0647
0648 if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
0649 res = fgrep(inf, "mbm_total_bytes");
0650 if (res) {
0651 free(res);
0652 res = fgrep(inf, "mbm_local_bytes");
0653 if (res) {
0654 found = true;
0655 free(res);
0656 }
0657 }
0658 }
0659 fclose(inf);
0660 }
0661 }
0662
0663 return found;
0664 }
0665
0666 int filter_dmesg(void)
0667 {
0668 char line[1024];
0669 FILE *fp;
0670 int pipefds[2];
0671 pid_t pid;
0672 int ret;
0673
0674 ret = pipe(pipefds);
0675 if (ret) {
0676 perror("pipe");
0677 return ret;
0678 }
0679 pid = fork();
0680 if (pid == 0) {
0681 close(pipefds[0]);
0682 dup2(pipefds[1], STDOUT_FILENO);
0683 execlp("dmesg", "dmesg", NULL);
0684 perror("executing dmesg");
0685 exit(1);
0686 }
0687 close(pipefds[1]);
0688 fp = fdopen(pipefds[0], "r");
0689 if (!fp) {
0690 perror("fdopen(pipe)");
0691 kill(pid, SIGTERM);
0692
0693 return -1;
0694 }
0695
0696 while (fgets(line, 1024, fp)) {
0697 if (strstr(line, "intel_rdt:"))
0698 ksft_print_msg("dmesg: %s", line);
0699 if (strstr(line, "resctrl:"))
0700 ksft_print_msg("dmesg: %s", line);
0701 }
0702 fclose(fp);
0703 waitpid(pid, NULL, 0);
0704
0705 return 0;
0706 }
0707
0708 int validate_bw_report_request(char *bw_report)
0709 {
0710 if (strcmp(bw_report, "reads") == 0)
0711 return 0;
0712 if (strcmp(bw_report, "writes") == 0)
0713 return 0;
0714 if (strcmp(bw_report, "nt-writes") == 0) {
0715 strcpy(bw_report, "writes");
0716 return 0;
0717 }
0718 if (strcmp(bw_report, "total") == 0)
0719 return 0;
0720
0721 fprintf(stderr, "Requested iMC B/W report type unavailable\n");
0722
0723 return -1;
0724 }
0725
0726 int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
0727 int group_fd, unsigned long flags)
0728 {
0729 int ret;
0730
0731 ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
0732 group_fd, flags);
0733 return ret;
0734 }
0735
0736 unsigned int count_bits(unsigned long n)
0737 {
0738 unsigned int count = 0;
0739
0740 while (n) {
0741 count += n & 1;
0742 n >>= 1;
0743 }
0744
0745 return count;
0746 }