0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "resctrl.h"
0012
0013 #define UNCORE_IMC "uncore_imc"
0014 #define READ_FILE_NAME "events/cas_count_read"
0015 #define WRITE_FILE_NAME "events/cas_count_write"
0016 #define DYN_PMU_PATH "/sys/bus/event_source/devices"
0017 #define SCALE 0.00006103515625
0018 #define MAX_IMCS 20
0019 #define MAX_TOKENS 5
0020 #define READ 0
0021 #define WRITE 1
0022 #define CON_MON_MBM_LOCAL_BYTES_PATH \
0023 "%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0024
0025 #define CON_MBM_LOCAL_BYTES_PATH \
0026 "%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0027
0028 #define MON_MBM_LOCAL_BYTES_PATH \
0029 "%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0030
0031 #define MBM_LOCAL_BYTES_PATH \
0032 "%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0033
0034 #define CON_MON_LCC_OCCUP_PATH \
0035 "%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
0036
0037 #define CON_LCC_OCCUP_PATH \
0038 "%s/%s/mon_data/mon_L3_%02d/llc_occupancy"
0039
0040 #define MON_LCC_OCCUP_PATH \
0041 "%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
0042
0043 #define LCC_OCCUP_PATH \
0044 "%s/mon_data/mon_L3_%02d/llc_occupancy"
0045
0046 struct membw_read_format {
0047 __u64 value;
0048 __u64 time_enabled;
0049 __u64 time_running;
0050 __u64 id;
0051 };
0052
0053 struct imc_counter_config {
0054 __u32 type;
0055 __u64 event;
0056 __u64 umask;
0057 struct perf_event_attr pe;
0058 struct membw_read_format return_value;
0059 int fd;
0060 };
0061
0062 static char mbm_total_path[1024];
0063 static int imcs;
0064 static struct imc_counter_config imc_counters_config[MAX_IMCS][2];
0065
0066 void membw_initialize_perf_event_attr(int i, int j)
0067 {
0068 memset(&imc_counters_config[i][j].pe, 0,
0069 sizeof(struct perf_event_attr));
0070 imc_counters_config[i][j].pe.type = imc_counters_config[i][j].type;
0071 imc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr);
0072 imc_counters_config[i][j].pe.disabled = 1;
0073 imc_counters_config[i][j].pe.inherit = 1;
0074 imc_counters_config[i][j].pe.exclude_guest = 0;
0075 imc_counters_config[i][j].pe.config =
0076 imc_counters_config[i][j].umask << 8 |
0077 imc_counters_config[i][j].event;
0078 imc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER;
0079 imc_counters_config[i][j].pe.read_format =
0080 PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
0081 }
0082
0083 void membw_ioctl_perf_event_ioc_reset_enable(int i, int j)
0084 {
0085 ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0);
0086 ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0);
0087 }
0088
0089 void membw_ioctl_perf_event_ioc_disable(int i, int j)
0090 {
0091 ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0);
0092 }
0093
0094
0095
0096
0097
0098
0099
0100 void get_event_and_umask(char *cas_count_cfg, int count, bool op)
0101 {
0102 char *token[MAX_TOKENS];
0103 int i = 0;
0104
0105 strcat(cas_count_cfg, ",");
0106 token[0] = strtok(cas_count_cfg, "=,");
0107
0108 for (i = 1; i < MAX_TOKENS; i++)
0109 token[i] = strtok(NULL, "=,");
0110
0111 for (i = 0; i < MAX_TOKENS; i++) {
0112 if (!token[i])
0113 break;
0114 if (strcmp(token[i], "event") == 0) {
0115 if (op == READ)
0116 imc_counters_config[count][READ].event =
0117 strtol(token[i + 1], NULL, 16);
0118 else
0119 imc_counters_config[count][WRITE].event =
0120 strtol(token[i + 1], NULL, 16);
0121 }
0122 if (strcmp(token[i], "umask") == 0) {
0123 if (op == READ)
0124 imc_counters_config[count][READ].umask =
0125 strtol(token[i + 1], NULL, 16);
0126 else
0127 imc_counters_config[count][WRITE].umask =
0128 strtol(token[i + 1], NULL, 16);
0129 }
0130 }
0131 }
0132
0133 static int open_perf_event(int i, int cpu_no, int j)
0134 {
0135 imc_counters_config[i][j].fd =
0136 perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1,
0137 PERF_FLAG_FD_CLOEXEC);
0138
0139 if (imc_counters_config[i][j].fd == -1) {
0140 fprintf(stderr, "Error opening leader %llx\n",
0141 imc_counters_config[i][j].pe.config);
0142
0143 return -1;
0144 }
0145
0146 return 0;
0147 }
0148
0149
0150 static int read_from_imc_dir(char *imc_dir, int count)
0151 {
0152 char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024];
0153 FILE *fp;
0154
0155
0156 sprintf(imc_counter_type, "%s%s", imc_dir, "type");
0157 fp = fopen(imc_counter_type, "r");
0158 if (!fp) {
0159 perror("Failed to open imc counter type file");
0160
0161 return -1;
0162 }
0163 if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) {
0164 perror("Could not get imc type");
0165 fclose(fp);
0166
0167 return -1;
0168 }
0169 fclose(fp);
0170
0171 imc_counters_config[count][WRITE].type =
0172 imc_counters_config[count][READ].type;
0173
0174
0175 sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME);
0176 fp = fopen(imc_counter_cfg, "r");
0177 if (!fp) {
0178 perror("Failed to open imc config file");
0179
0180 return -1;
0181 }
0182 if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
0183 perror("Could not get imc cas count read");
0184 fclose(fp);
0185
0186 return -1;
0187 }
0188 fclose(fp);
0189
0190 get_event_and_umask(cas_count_cfg, count, READ);
0191
0192
0193 sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME);
0194 fp = fopen(imc_counter_cfg, "r");
0195 if (!fp) {
0196 perror("Failed to open imc config file");
0197
0198 return -1;
0199 }
0200 if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
0201 perror("Could not get imc cas count write");
0202 fclose(fp);
0203
0204 return -1;
0205 }
0206 fclose(fp);
0207
0208 get_event_and_umask(cas_count_cfg, count, WRITE);
0209
0210 return 0;
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 static int num_of_imcs(void)
0223 {
0224 char imc_dir[512], *temp;
0225 unsigned int count = 0;
0226 struct dirent *ep;
0227 int ret;
0228 DIR *dp;
0229
0230 dp = opendir(DYN_PMU_PATH);
0231 if (dp) {
0232 while ((ep = readdir(dp))) {
0233 temp = strstr(ep->d_name, UNCORE_IMC);
0234 if (!temp)
0235 continue;
0236
0237
0238
0239
0240
0241
0242
0243
0244 temp = temp + sizeof(UNCORE_IMC);
0245
0246
0247
0248
0249
0250
0251 if (temp[0] >= '0' && temp[0] <= '9') {
0252 sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
0253 ep->d_name);
0254 ret = read_from_imc_dir(imc_dir, count);
0255 if (ret) {
0256 closedir(dp);
0257
0258 return ret;
0259 }
0260 count++;
0261 }
0262 }
0263 closedir(dp);
0264 if (count == 0) {
0265 perror("Unable find iMC counters!\n");
0266
0267 return -1;
0268 }
0269 } else {
0270 perror("Unable to open PMU directory!\n");
0271
0272 return -1;
0273 }
0274
0275 return count;
0276 }
0277
0278 static int initialize_mem_bw_imc(void)
0279 {
0280 int imc, j;
0281
0282 imcs = num_of_imcs();
0283 if (imcs <= 0)
0284 return imcs;
0285
0286
0287 for (imc = 0; imc < imcs; imc++) {
0288 for (j = 0; j < 2; j++)
0289 membw_initialize_perf_event_attr(imc, j);
0290 }
0291
0292 return 0;
0293 }
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
0306 {
0307 float reads, writes, of_mul_read, of_mul_write;
0308 int imc, j, ret;
0309
0310
0311 reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1;
0312 for (imc = 0; imc < imcs; imc++) {
0313 for (j = 0; j < 2; j++) {
0314 ret = open_perf_event(imc, cpu_no, j);
0315 if (ret)
0316 return -1;
0317 }
0318 for (j = 0; j < 2; j++)
0319 membw_ioctl_perf_event_ioc_reset_enable(imc, j);
0320 }
0321
0322 sleep(1);
0323
0324
0325 for (imc = 0; imc < imcs; imc++) {
0326 for (j = 0; j < 2; j++)
0327 membw_ioctl_perf_event_ioc_disable(imc, j);
0328 }
0329
0330
0331
0332
0333
0334 for (imc = 0; imc < imcs; imc++) {
0335 struct imc_counter_config *r =
0336 &imc_counters_config[imc][READ];
0337 struct imc_counter_config *w =
0338 &imc_counters_config[imc][WRITE];
0339
0340 if (read(r->fd, &r->return_value,
0341 sizeof(struct membw_read_format)) == -1) {
0342 perror("Couldn't get read b/w through iMC");
0343
0344 return -1;
0345 }
0346
0347 if (read(w->fd, &w->return_value,
0348 sizeof(struct membw_read_format)) == -1) {
0349 perror("Couldn't get write bw through iMC");
0350
0351 return -1;
0352 }
0353
0354 __u64 r_time_enabled = r->return_value.time_enabled;
0355 __u64 r_time_running = r->return_value.time_running;
0356
0357 if (r_time_enabled != r_time_running)
0358 of_mul_read = (float)r_time_enabled /
0359 (float)r_time_running;
0360
0361 __u64 w_time_enabled = w->return_value.time_enabled;
0362 __u64 w_time_running = w->return_value.time_running;
0363
0364 if (w_time_enabled != w_time_running)
0365 of_mul_write = (float)w_time_enabled /
0366 (float)w_time_running;
0367 reads += r->return_value.value * of_mul_read * SCALE;
0368 writes += w->return_value.value * of_mul_write * SCALE;
0369 }
0370
0371 for (imc = 0; imc < imcs; imc++) {
0372 close(imc_counters_config[imc][READ].fd);
0373 close(imc_counters_config[imc][WRITE].fd);
0374 }
0375
0376 if (strcmp(bw_report, "reads") == 0) {
0377 *bw_imc = reads;
0378 return 0;
0379 }
0380
0381 if (strcmp(bw_report, "writes") == 0) {
0382 *bw_imc = writes;
0383 return 0;
0384 }
0385
0386 *bw_imc = reads + writes;
0387 return 0;
0388 }
0389
0390 void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id)
0391 {
0392 if (ctrlgrp && mongrp)
0393 sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
0394 RESCTRL_PATH, ctrlgrp, mongrp, resource_id);
0395 else if (!ctrlgrp && mongrp)
0396 sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
0397 mongrp, resource_id);
0398 else if (ctrlgrp && !mongrp)
0399 sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
0400 ctrlgrp, resource_id);
0401 else if (!ctrlgrp && !mongrp)
0402 sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
0403 resource_id);
0404 }
0405
0406
0407
0408
0409
0410
0411
0412
0413 static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
0414 int cpu_no, char *resctrl_val)
0415 {
0416 int resource_id;
0417
0418 if (get_resource_id(cpu_no, &resource_id) < 0) {
0419 perror("Could not get resource_id");
0420 return;
0421 }
0422
0423 if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)))
0424 set_mbm_path(ctrlgrp, mongrp, resource_id);
0425
0426 if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0427 if (ctrlgrp)
0428 sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
0429 RESCTRL_PATH, ctrlgrp, resource_id);
0430 else
0431 sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
0432 RESCTRL_PATH, resource_id);
0433 }
0434 }
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446 static int get_mem_bw_resctrl(unsigned long *mbm_total)
0447 {
0448 FILE *fp;
0449
0450 fp = fopen(mbm_total_path, "r");
0451 if (!fp) {
0452 perror("Failed to open total bw file");
0453
0454 return -1;
0455 }
0456 if (fscanf(fp, "%lu", mbm_total) <= 0) {
0457 perror("Could not get mbm local bytes");
0458 fclose(fp);
0459
0460 return -1;
0461 }
0462 fclose(fp);
0463
0464 return 0;
0465 }
0466
0467 pid_t bm_pid, ppid;
0468
0469 void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
0470 {
0471 kill(bm_pid, SIGKILL);
0472 umount_resctrlfs();
0473 tests_cleanup();
0474 ksft_print_msg("Ending\n\n");
0475
0476 exit(EXIT_SUCCESS);
0477 }
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488 static int print_results_bw(char *filename, int bm_pid, float bw_imc,
0489 unsigned long bw_resc)
0490 {
0491 unsigned long diff = fabs(bw_imc - bw_resc);
0492 FILE *fp;
0493
0494 if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
0495 printf("Pid: %d \t Mem_BW_iMC: %f \t ", bm_pid, bw_imc);
0496 printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff);
0497 } else {
0498 fp = fopen(filename, "a");
0499 if (!fp) {
0500 perror("Cannot open results file");
0501
0502 return errno;
0503 }
0504 if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
0505 bm_pid, bw_imc, bw_resc, diff) <= 0) {
0506 fclose(fp);
0507 perror("Could not log results.");
0508
0509 return errno;
0510 }
0511 fclose(fp);
0512 }
0513
0514 return 0;
0515 }
0516
0517 static void set_cmt_path(const char *ctrlgrp, const char *mongrp, char sock_num)
0518 {
0519 if (strlen(ctrlgrp) && strlen(mongrp))
0520 sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH,
0521 ctrlgrp, mongrp, sock_num);
0522 else if (!strlen(ctrlgrp) && strlen(mongrp))
0523 sprintf(llc_occup_path, MON_LCC_OCCUP_PATH, RESCTRL_PATH,
0524 mongrp, sock_num);
0525 else if (strlen(ctrlgrp) && !strlen(mongrp))
0526 sprintf(llc_occup_path, CON_LCC_OCCUP_PATH, RESCTRL_PATH,
0527 ctrlgrp, sock_num);
0528 else if (!strlen(ctrlgrp) && !strlen(mongrp))
0529 sprintf(llc_occup_path, LCC_OCCUP_PATH, RESCTRL_PATH, sock_num);
0530 }
0531
0532
0533
0534
0535
0536
0537
0538
0539 static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp,
0540 int cpu_no, char *resctrl_val)
0541 {
0542 int resource_id;
0543
0544 if (get_resource_id(cpu_no, &resource_id) < 0) {
0545 perror("# Unable to resource_id");
0546 return;
0547 }
0548
0549 if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0550 set_cmt_path(ctrlgrp, mongrp, resource_id);
0551 }
0552
0553 static int
0554 measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
0555 {
0556 unsigned long bw_resc, bw_resc_end;
0557 float bw_imc;
0558 int ret;
0559
0560
0561
0562
0563
0564
0565
0566
0567 ret = get_mem_bw_imc(param->cpu_no, param->bw_report, &bw_imc);
0568 if (ret < 0)
0569 return ret;
0570
0571 ret = get_mem_bw_resctrl(&bw_resc_end);
0572 if (ret < 0)
0573 return ret;
0574
0575 bw_resc = (bw_resc_end - *bw_resc_start) / MB;
0576 ret = print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
0577 if (ret)
0578 return ret;
0579
0580 *bw_resc_start = bw_resc_end;
0581
0582 return 0;
0583 }
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593 int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
0594 {
0595 char *resctrl_val = param->resctrl_val;
0596 unsigned long bw_resc_start = 0;
0597 struct sigaction sigact;
0598 int ret = 0, pipefd[2];
0599 char pipe_message = 0;
0600 union sigval value;
0601
0602 if (strcmp(param->filename, "") == 0)
0603 sprintf(param->filename, "stdio");
0604
0605 if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) ||
0606 !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
0607 ret = validate_bw_report_request(param->bw_report);
0608 if (ret)
0609 return ret;
0610 }
0611
0612 ret = remount_resctrlfs(param->mum_resctrlfs);
0613 if (ret)
0614 return ret;
0615
0616
0617
0618
0619
0620 ppid = getpid();
0621
0622 if (pipe(pipefd)) {
0623 perror("# Unable to create pipe");
0624
0625 return -1;
0626 }
0627
0628
0629
0630
0631
0632 bm_pid = fork();
0633 if (bm_pid == -1) {
0634 perror("# Unable to fork");
0635
0636 return -1;
0637 }
0638
0639 if (bm_pid == 0) {
0640
0641
0642
0643
0644 sigfillset(&sigact.sa_mask);
0645 sigdelset(&sigact.sa_mask, SIGUSR1);
0646
0647 sigact.sa_sigaction = run_benchmark;
0648 sigact.sa_flags = SA_SIGINFO;
0649
0650
0651 if (sigaction(SIGUSR1, &sigact, NULL))
0652 PARENT_EXIT("Can't register child for signal");
0653
0654
0655 close(pipefd[0]);
0656 pipe_message = 1;
0657 if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) <
0658 sizeof(pipe_message)) {
0659 perror("# failed signaling parent process");
0660 close(pipefd[1]);
0661 return -1;
0662 }
0663 close(pipefd[1]);
0664
0665
0666 sigsuspend(&sigact.sa_mask);
0667
0668 PARENT_EXIT("Child is done");
0669 }
0670
0671 ksft_print_msg("Benchmark PID: %d\n", bm_pid);
0672
0673
0674
0675
0676
0677 sigact.sa_sigaction = ctrlc_handler;
0678 sigemptyset(&sigact.sa_mask);
0679 sigact.sa_flags = SA_SIGINFO;
0680 if (sigaction(SIGINT, &sigact, NULL) ||
0681 sigaction(SIGTERM, &sigact, NULL) ||
0682 sigaction(SIGHUP, &sigact, NULL)) {
0683 perror("# sigaction");
0684 ret = errno;
0685 goto out;
0686 }
0687
0688 value.sival_ptr = benchmark_cmd;
0689
0690
0691 ret = taskset_benchmark(bm_pid, param->cpu_no);
0692 if (ret)
0693 goto out;
0694
0695
0696 ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
0697 resctrl_val);
0698 if (ret)
0699 goto out;
0700
0701 if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
0702 !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0703 ret = initialize_mem_bw_imc();
0704 if (ret)
0705 goto out;
0706
0707 initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
0708 param->cpu_no, resctrl_val);
0709 } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0710 initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp,
0711 param->cpu_no, resctrl_val);
0712
0713
0714 close(pipefd[1]);
0715 while (pipe_message != 1) {
0716 if (read(pipefd[0], &pipe_message, sizeof(pipe_message)) <
0717 sizeof(pipe_message)) {
0718 perror("# failed reading message from child process");
0719 close(pipefd[0]);
0720 goto out;
0721 }
0722 }
0723 close(pipefd[0]);
0724
0725
0726 if (sigqueue(bm_pid, SIGUSR1, value) == -1) {
0727 perror("# sigqueue SIGUSR1 to child");
0728 ret = errno;
0729 goto out;
0730 }
0731
0732
0733 sleep(1);
0734
0735
0736 while (1) {
0737 if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
0738 !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0739 ret = param->setup(1, param);
0740 if (ret) {
0741 ret = 0;
0742 break;
0743 }
0744
0745 ret = measure_vals(param, &bw_resc_start);
0746 if (ret)
0747 break;
0748 } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) {
0749 ret = param->setup(1, param);
0750 if (ret) {
0751 ret = 0;
0752 break;
0753 }
0754 sleep(1);
0755 ret = measure_cache_vals(param, bm_pid);
0756 if (ret)
0757 break;
0758 } else {
0759 break;
0760 }
0761 }
0762
0763 out:
0764 kill(bm_pid, SIGKILL);
0765 umount_resctrlfs();
0766
0767 return ret;
0768 }