11d3f0868SSai Praneeth Prakhya // SPDX-License-Identifier: GPL-2.0 21d3f0868SSai Praneeth Prakhya /* 31d3f0868SSai Praneeth Prakhya * Memory bandwidth monitoring and allocation library 41d3f0868SSai Praneeth Prakhya * 51d3f0868SSai Praneeth Prakhya * Copyright (C) 2018 Intel Corporation 61d3f0868SSai Praneeth Prakhya * 71d3f0868SSai Praneeth Prakhya * Authors: 81d3f0868SSai Praneeth Prakhya * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, 91d3f0868SSai Praneeth Prakhya * Fenghua Yu <fenghua.yu@intel.com> 101d3f0868SSai Praneeth Prakhya */ 111d3f0868SSai Praneeth Prakhya #include "resctrl.h" 121d3f0868SSai Praneeth Prakhya 131d3f0868SSai Praneeth Prakhya #define UNCORE_IMC "uncore_imc" 141d3f0868SSai Praneeth Prakhya #define READ_FILE_NAME "events/cas_count_read" 151d3f0868SSai Praneeth Prakhya #define WRITE_FILE_NAME "events/cas_count_write" 161d3f0868SSai Praneeth Prakhya #define DYN_PMU_PATH "/sys/bus/event_source/devices" 171d3f0868SSai Praneeth Prakhya #define SCALE 0.00006103515625 181d3f0868SSai Praneeth Prakhya #define MAX_IMCS 20 191d3f0868SSai Praneeth Prakhya #define MAX_TOKENS 5 201d3f0868SSai Praneeth Prakhya #define READ 0 211d3f0868SSai Praneeth Prakhya #define WRITE 1 221d3f0868SSai Praneeth Prakhya #define CON_MON_MBM_LOCAL_BYTES_PATH \ 231d3f0868SSai Praneeth Prakhya "%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes" 241d3f0868SSai Praneeth Prakhya 251d3f0868SSai Praneeth Prakhya #define CON_MBM_LOCAL_BYTES_PATH \ 261d3f0868SSai Praneeth Prakhya "%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes" 271d3f0868SSai Praneeth Prakhya 281d3f0868SSai Praneeth Prakhya #define MON_MBM_LOCAL_BYTES_PATH \ 291d3f0868SSai Praneeth Prakhya "%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes" 301d3f0868SSai Praneeth Prakhya 311d3f0868SSai Praneeth Prakhya #define MBM_LOCAL_BYTES_PATH \ 321d3f0868SSai Praneeth Prakhya "%s/mon_data/mon_L3_%02d/mbm_local_bytes" 331d3f0868SSai Praneeth Prakhya 3478941183SFenghua Yu #define CON_MON_LCC_OCCUP_PATH \ 3578941183SFenghua Yu "%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy" 3678941183SFenghua Yu 3778941183SFenghua Yu #define CON_LCC_OCCUP_PATH \ 3878941183SFenghua Yu "%s/%s/mon_data/mon_L3_%02d/llc_occupancy" 3978941183SFenghua Yu 4078941183SFenghua Yu #define MON_LCC_OCCUP_PATH \ 4178941183SFenghua Yu "%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy" 4278941183SFenghua Yu 4378941183SFenghua Yu #define LCC_OCCUP_PATH \ 4478941183SFenghua Yu "%s/mon_data/mon_L3_%02d/llc_occupancy" 4578941183SFenghua Yu 461d3f0868SSai Praneeth Prakhya struct membw_read_format { 471d3f0868SSai Praneeth Prakhya __u64 value; /* The value of the event */ 481d3f0868SSai Praneeth Prakhya __u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ 491d3f0868SSai Praneeth Prakhya __u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ 501d3f0868SSai Praneeth Prakhya __u64 id; /* if PERF_FORMAT_ID */ 511d3f0868SSai Praneeth Prakhya }; 521d3f0868SSai Praneeth Prakhya 531d3f0868SSai Praneeth Prakhya struct imc_counter_config { 541d3f0868SSai Praneeth Prakhya __u32 type; 551d3f0868SSai Praneeth Prakhya __u64 event; 561d3f0868SSai Praneeth Prakhya __u64 umask; 571d3f0868SSai Praneeth Prakhya struct perf_event_attr pe; 581d3f0868SSai Praneeth Prakhya struct membw_read_format return_value; 591d3f0868SSai Praneeth Prakhya int fd; 601d3f0868SSai Praneeth Prakhya }; 611d3f0868SSai Praneeth Prakhya 627f4d257eSSai Praneeth Prakhya static char mbm_total_path[1024]; 637f4d257eSSai Praneeth Prakhya static int imcs; 641d3f0868SSai Praneeth Prakhya static struct imc_counter_config imc_counters_config[MAX_IMCS][2]; 65e6487230SMaciej Wieczor-Retman static const struct resctrl_test *current_test; 661d3f0868SSai Praneeth Prakhya 671d3f0868SSai Praneeth Prakhya void membw_initialize_perf_event_attr(int i, int j) 681d3f0868SSai Praneeth Prakhya { 691d3f0868SSai Praneeth Prakhya memset(&imc_counters_config[i][j].pe, 0, 701d3f0868SSai Praneeth Prakhya sizeof(struct perf_event_attr)); 711d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.type = imc_counters_config[i][j].type; 721d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr); 731d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.disabled = 1; 741d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.inherit = 1; 751d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.exclude_guest = 0; 761d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.config = 771d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].umask << 8 | 781d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].event; 791d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER; 801d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.read_format = 811d3f0868SSai Praneeth Prakhya PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; 821d3f0868SSai Praneeth Prakhya } 831d3f0868SSai Praneeth Prakhya 841d3f0868SSai Praneeth Prakhya void membw_ioctl_perf_event_ioc_reset_enable(int i, int j) 851d3f0868SSai Praneeth Prakhya { 861d3f0868SSai Praneeth Prakhya ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0); 871d3f0868SSai Praneeth Prakhya ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0); 881d3f0868SSai Praneeth Prakhya } 891d3f0868SSai Praneeth Prakhya 901d3f0868SSai Praneeth Prakhya void membw_ioctl_perf_event_ioc_disable(int i, int j) 911d3f0868SSai Praneeth Prakhya { 921d3f0868SSai Praneeth Prakhya ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0); 931d3f0868SSai Praneeth Prakhya } 941d3f0868SSai Praneeth Prakhya 951d3f0868SSai Praneeth Prakhya /* 961d3f0868SSai Praneeth Prakhya * get_event_and_umask: Parse config into event and umask 971d3f0868SSai Praneeth Prakhya * @cas_count_cfg: Config 981d3f0868SSai Praneeth Prakhya * @count: iMC number 991d3f0868SSai Praneeth Prakhya * @op: Operation (read/write) 1001d3f0868SSai Praneeth Prakhya */ 1011d3f0868SSai Praneeth Prakhya void get_event_and_umask(char *cas_count_cfg, int count, bool op) 1021d3f0868SSai Praneeth Prakhya { 1031d3f0868SSai Praneeth Prakhya char *token[MAX_TOKENS]; 1041d3f0868SSai Praneeth Prakhya int i = 0; 1051d3f0868SSai Praneeth Prakhya 1061d3f0868SSai Praneeth Prakhya strcat(cas_count_cfg, ","); 1071d3f0868SSai Praneeth Prakhya token[0] = strtok(cas_count_cfg, "=,"); 1081d3f0868SSai Praneeth Prakhya 1091d3f0868SSai Praneeth Prakhya for (i = 1; i < MAX_TOKENS; i++) 1101d3f0868SSai Praneeth Prakhya token[i] = strtok(NULL, "=,"); 1111d3f0868SSai Praneeth Prakhya 1121d3f0868SSai Praneeth Prakhya for (i = 0; i < MAX_TOKENS; i++) { 1131d3f0868SSai Praneeth Prakhya if (!token[i]) 1141d3f0868SSai Praneeth Prakhya break; 1151d3f0868SSai Praneeth Prakhya if (strcmp(token[i], "event") == 0) { 1161d3f0868SSai Praneeth Prakhya if (op == READ) 1171d3f0868SSai Praneeth Prakhya imc_counters_config[count][READ].event = 1181d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1191d3f0868SSai Praneeth Prakhya else 1201d3f0868SSai Praneeth Prakhya imc_counters_config[count][WRITE].event = 1211d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1221d3f0868SSai Praneeth Prakhya } 1231d3f0868SSai Praneeth Prakhya if (strcmp(token[i], "umask") == 0) { 1241d3f0868SSai Praneeth Prakhya if (op == READ) 1251d3f0868SSai Praneeth Prakhya imc_counters_config[count][READ].umask = 1261d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1271d3f0868SSai Praneeth Prakhya else 1281d3f0868SSai Praneeth Prakhya imc_counters_config[count][WRITE].umask = 1291d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1301d3f0868SSai Praneeth Prakhya } 1311d3f0868SSai Praneeth Prakhya } 1321d3f0868SSai Praneeth Prakhya } 1337f4d257eSSai Praneeth Prakhya 1347f4d257eSSai Praneeth Prakhya static int open_perf_event(int i, int cpu_no, int j) 1357f4d257eSSai Praneeth Prakhya { 1367f4d257eSSai Praneeth Prakhya imc_counters_config[i][j].fd = 1377f4d257eSSai Praneeth Prakhya perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1, 1387f4d257eSSai Praneeth Prakhya PERF_FLAG_FD_CLOEXEC); 1397f4d257eSSai Praneeth Prakhya 1407f4d257eSSai Praneeth Prakhya if (imc_counters_config[i][j].fd == -1) { 1417f4d257eSSai Praneeth Prakhya fprintf(stderr, "Error opening leader %llx\n", 1427f4d257eSSai Praneeth Prakhya imc_counters_config[i][j].pe.config); 1437f4d257eSSai Praneeth Prakhya 1447f4d257eSSai Praneeth Prakhya return -1; 1457f4d257eSSai Praneeth Prakhya } 1467f4d257eSSai Praneeth Prakhya 1477f4d257eSSai Praneeth Prakhya return 0; 1487f4d257eSSai Praneeth Prakhya } 1497f4d257eSSai Praneeth Prakhya 1507f4d257eSSai Praneeth Prakhya /* Get type and config (read and write) of an iMC counter */ 1517f4d257eSSai Praneeth Prakhya static int read_from_imc_dir(char *imc_dir, int count) 1527f4d257eSSai Praneeth Prakhya { 1537f4d257eSSai Praneeth Prakhya char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024]; 1547f4d257eSSai Praneeth Prakhya FILE *fp; 1557f4d257eSSai Praneeth Prakhya 1567f4d257eSSai Praneeth Prakhya /* Get type of iMC counter */ 1577f4d257eSSai Praneeth Prakhya sprintf(imc_counter_type, "%s%s", imc_dir, "type"); 1587f4d257eSSai Praneeth Prakhya fp = fopen(imc_counter_type, "r"); 1597f4d257eSSai Praneeth Prakhya if (!fp) { 160cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open iMC counter type file"); 1617f4d257eSSai Praneeth Prakhya 1627f4d257eSSai Praneeth Prakhya return -1; 1637f4d257eSSai Praneeth Prakhya } 1647f4d257eSSai Praneeth Prakhya if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) { 165cc8ff7f5SIlpo Järvinen ksft_perror("Could not get iMC type"); 1667f4d257eSSai Praneeth Prakhya fclose(fp); 1677f4d257eSSai Praneeth Prakhya 1687f4d257eSSai Praneeth Prakhya return -1; 1697f4d257eSSai Praneeth Prakhya } 1707f4d257eSSai Praneeth Prakhya fclose(fp); 1717f4d257eSSai Praneeth Prakhya 1727f4d257eSSai Praneeth Prakhya imc_counters_config[count][WRITE].type = 1737f4d257eSSai Praneeth Prakhya imc_counters_config[count][READ].type; 1747f4d257eSSai Praneeth Prakhya 1757f4d257eSSai Praneeth Prakhya /* Get read config */ 1767f4d257eSSai Praneeth Prakhya sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME); 1777f4d257eSSai Praneeth Prakhya fp = fopen(imc_counter_cfg, "r"); 1787f4d257eSSai Praneeth Prakhya if (!fp) { 179cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open iMC config file"); 1807f4d257eSSai Praneeth Prakhya 1817f4d257eSSai Praneeth Prakhya return -1; 1827f4d257eSSai Praneeth Prakhya } 1837f4d257eSSai Praneeth Prakhya if (fscanf(fp, "%s", cas_count_cfg) <= 0) { 184cc8ff7f5SIlpo Järvinen ksft_perror("Could not get iMC cas count read"); 1857f4d257eSSai Praneeth Prakhya fclose(fp); 1867f4d257eSSai Praneeth Prakhya 1877f4d257eSSai Praneeth Prakhya return -1; 1887f4d257eSSai Praneeth Prakhya } 1897f4d257eSSai Praneeth Prakhya fclose(fp); 1907f4d257eSSai Praneeth Prakhya 1917f4d257eSSai Praneeth Prakhya get_event_and_umask(cas_count_cfg, count, READ); 1927f4d257eSSai Praneeth Prakhya 1937f4d257eSSai Praneeth Prakhya /* Get write config */ 1947f4d257eSSai Praneeth Prakhya sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME); 1957f4d257eSSai Praneeth Prakhya fp = fopen(imc_counter_cfg, "r"); 1967f4d257eSSai Praneeth Prakhya if (!fp) { 197cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open iMC config file"); 1987f4d257eSSai Praneeth Prakhya 1997f4d257eSSai Praneeth Prakhya return -1; 2007f4d257eSSai Praneeth Prakhya } 2017f4d257eSSai Praneeth Prakhya if (fscanf(fp, "%s", cas_count_cfg) <= 0) { 202cc8ff7f5SIlpo Järvinen ksft_perror("Could not get iMC cas count write"); 2037f4d257eSSai Praneeth Prakhya fclose(fp); 2047f4d257eSSai Praneeth Prakhya 2057f4d257eSSai Praneeth Prakhya return -1; 2067f4d257eSSai Praneeth Prakhya } 2077f4d257eSSai Praneeth Prakhya fclose(fp); 2087f4d257eSSai Praneeth Prakhya 2097f4d257eSSai Praneeth Prakhya get_event_and_umask(cas_count_cfg, count, WRITE); 2107f4d257eSSai Praneeth Prakhya 2117f4d257eSSai Praneeth Prakhya return 0; 2127f4d257eSSai Praneeth Prakhya } 2137f4d257eSSai Praneeth Prakhya 2147f4d257eSSai Praneeth Prakhya /* 2157f4d257eSSai Praneeth Prakhya * A system can have 'n' number of iMC (Integrated Memory Controller) 2167f4d257eSSai Praneeth Prakhya * counters, get that 'n'. For each iMC counter get it's type and config. 2177f4d257eSSai Praneeth Prakhya * Also, each counter has two configs, one for read and the other for write. 2187f4d257eSSai Praneeth Prakhya * A config again has two parts, event and umask. 2197f4d257eSSai Praneeth Prakhya * Enumerate all these details into an array of structures. 2207f4d257eSSai Praneeth Prakhya * 2217f4d257eSSai Praneeth Prakhya * Return: >= 0 on success. < 0 on failure. 2227f4d257eSSai Praneeth Prakhya */ 2237f4d257eSSai Praneeth Prakhya static int num_of_imcs(void) 2247f4d257eSSai Praneeth Prakhya { 225d81343b5SFenghua Yu char imc_dir[512], *temp; 2267f4d257eSSai Praneeth Prakhya unsigned int count = 0; 2277f4d257eSSai Praneeth Prakhya struct dirent *ep; 2287f4d257eSSai Praneeth Prakhya int ret; 2297f4d257eSSai Praneeth Prakhya DIR *dp; 2307f4d257eSSai Praneeth Prakhya 2317f4d257eSSai Praneeth Prakhya dp = opendir(DYN_PMU_PATH); 2327f4d257eSSai Praneeth Prakhya if (dp) { 2337f4d257eSSai Praneeth Prakhya while ((ep = readdir(dp))) { 234d81343b5SFenghua Yu temp = strstr(ep->d_name, UNCORE_IMC); 235d81343b5SFenghua Yu if (!temp) 236d81343b5SFenghua Yu continue; 237d81343b5SFenghua Yu 238d81343b5SFenghua Yu /* 239d81343b5SFenghua Yu * imc counters are named as "uncore_imc_<n>", hence 240d81343b5SFenghua Yu * increment the pointer to point to <n>. Note that 241d81343b5SFenghua Yu * sizeof(UNCORE_IMC) would count for null character as 242d81343b5SFenghua Yu * well and hence the last underscore character in 243d81343b5SFenghua Yu * uncore_imc'_' need not be counted. 244d81343b5SFenghua Yu */ 245d81343b5SFenghua Yu temp = temp + sizeof(UNCORE_IMC); 246d81343b5SFenghua Yu 247d81343b5SFenghua Yu /* 248d81343b5SFenghua Yu * Some directories under "DYN_PMU_PATH" could have 249d81343b5SFenghua Yu * names like "uncore_imc_free_running", hence, check if 250d81343b5SFenghua Yu * first character is a numerical digit or not. 251d81343b5SFenghua Yu */ 252d81343b5SFenghua Yu if (temp[0] >= '0' && temp[0] <= '9') { 2537f4d257eSSai Praneeth Prakhya sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH, 2547f4d257eSSai Praneeth Prakhya ep->d_name); 2557f4d257eSSai Praneeth Prakhya ret = read_from_imc_dir(imc_dir, count); 2567f4d257eSSai Praneeth Prakhya if (ret) { 2577f4d257eSSai Praneeth Prakhya closedir(dp); 2587f4d257eSSai Praneeth Prakhya 2597f4d257eSSai Praneeth Prakhya return ret; 2607f4d257eSSai Praneeth Prakhya } 2617f4d257eSSai Praneeth Prakhya count++; 2627f4d257eSSai Praneeth Prakhya } 2637f4d257eSSai Praneeth Prakhya } 2647f4d257eSSai Praneeth Prakhya closedir(dp); 2657f4d257eSSai Praneeth Prakhya if (count == 0) { 266cc8ff7f5SIlpo Järvinen ksft_print_msg("Unable to find iMC counters\n"); 2677f4d257eSSai Praneeth Prakhya 2687f4d257eSSai Praneeth Prakhya return -1; 2697f4d257eSSai Praneeth Prakhya } 2707f4d257eSSai Praneeth Prakhya } else { 271cc8ff7f5SIlpo Järvinen ksft_perror("Unable to open PMU directory"); 2727f4d257eSSai Praneeth Prakhya 2737f4d257eSSai Praneeth Prakhya return -1; 2747f4d257eSSai Praneeth Prakhya } 2757f4d257eSSai Praneeth Prakhya 2767f4d257eSSai Praneeth Prakhya return count; 2777f4d257eSSai Praneeth Prakhya } 2787f4d257eSSai Praneeth Prakhya 2797f4d257eSSai Praneeth Prakhya static int initialize_mem_bw_imc(void) 2807f4d257eSSai Praneeth Prakhya { 2817f4d257eSSai Praneeth Prakhya int imc, j; 2827f4d257eSSai Praneeth Prakhya 2837f4d257eSSai Praneeth Prakhya imcs = num_of_imcs(); 2847f4d257eSSai Praneeth Prakhya if (imcs <= 0) 2857f4d257eSSai Praneeth Prakhya return imcs; 2867f4d257eSSai Praneeth Prakhya 2877f4d257eSSai Praneeth Prakhya /* Initialize perf_event_attr structures for all iMC's */ 2887f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 2897f4d257eSSai Praneeth Prakhya for (j = 0; j < 2; j++) 2907f4d257eSSai Praneeth Prakhya membw_initialize_perf_event_attr(imc, j); 2917f4d257eSSai Praneeth Prakhya } 2927f4d257eSSai Praneeth Prakhya 2937f4d257eSSai Praneeth Prakhya return 0; 2947f4d257eSSai Praneeth Prakhya } 2957f4d257eSSai Praneeth Prakhya 296c44000b6SIlpo Järvinen static void perf_close_imc_mem_bw(void) 297c44000b6SIlpo Järvinen { 298c44000b6SIlpo Järvinen int mc; 299c44000b6SIlpo Järvinen 300c44000b6SIlpo Järvinen for (mc = 0; mc < imcs; mc++) { 301c44000b6SIlpo Järvinen if (imc_counters_config[mc][READ].fd != -1) 302c44000b6SIlpo Järvinen close(imc_counters_config[mc][READ].fd); 303c44000b6SIlpo Järvinen if (imc_counters_config[mc][WRITE].fd != -1) 304c44000b6SIlpo Järvinen close(imc_counters_config[mc][WRITE].fd); 305c44000b6SIlpo Järvinen } 306c44000b6SIlpo Järvinen } 307c44000b6SIlpo Järvinen 3087f4d257eSSai Praneeth Prakhya /* 309da50de0aSIlpo Järvinen * perf_open_imc_mem_bw - Open perf fds for IMCs 310da50de0aSIlpo Järvinen * @cpu_no: CPU number that the benchmark PID is bound to 3117f4d257eSSai Praneeth Prakhya * 3121205b688SFenghua Yu * Return: = 0 on success. < 0 on failure. 3137f4d257eSSai Praneeth Prakhya */ 314da50de0aSIlpo Järvinen static int perf_open_imc_mem_bw(int cpu_no) 3157f4d257eSSai Praneeth Prakhya { 316c44000b6SIlpo Järvinen int imc, ret; 317c44000b6SIlpo Järvinen 318c44000b6SIlpo Järvinen for (imc = 0; imc < imcs; imc++) { 319c44000b6SIlpo Järvinen imc_counters_config[imc][READ].fd = -1; 320c44000b6SIlpo Järvinen imc_counters_config[imc][WRITE].fd = -1; 321c44000b6SIlpo Järvinen } 3227f4d257eSSai Praneeth Prakhya 3237f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 324c44000b6SIlpo Järvinen ret = open_perf_event(imc, cpu_no, READ); 3257f4d257eSSai Praneeth Prakhya if (ret) 326c44000b6SIlpo Järvinen goto close_fds; 327c44000b6SIlpo Järvinen ret = open_perf_event(imc, cpu_no, WRITE); 328c44000b6SIlpo Järvinen if (ret) 329c44000b6SIlpo Järvinen goto close_fds; 330da50de0aSIlpo Järvinen } 331c44000b6SIlpo Järvinen 332da50de0aSIlpo Järvinen return 0; 333da50de0aSIlpo Järvinen 334da50de0aSIlpo Järvinen close_fds: 335da50de0aSIlpo Järvinen perf_close_imc_mem_bw(); 336da50de0aSIlpo Järvinen return -1; 337da50de0aSIlpo Järvinen } 338da50de0aSIlpo Järvinen 339da50de0aSIlpo Järvinen /* 340da50de0aSIlpo Järvinen * do_mem_bw_test - Perform memory bandwidth test 341da50de0aSIlpo Järvinen * 342da50de0aSIlpo Järvinen * Runs memory bandwidth test over one second period. Also, handles starting 343da50de0aSIlpo Järvinen * and stopping of the IMC perf counters around the test. 344da50de0aSIlpo Järvinen */ 345da50de0aSIlpo Järvinen static void do_imc_mem_bw_test(void) 346da50de0aSIlpo Järvinen { 347da50de0aSIlpo Järvinen int imc; 348da50de0aSIlpo Järvinen 349da50de0aSIlpo Järvinen for (imc = 0; imc < imcs; imc++) { 350c44000b6SIlpo Järvinen membw_ioctl_perf_event_ioc_reset_enable(imc, READ); 351c44000b6SIlpo Järvinen membw_ioctl_perf_event_ioc_reset_enable(imc, WRITE); 3527f4d257eSSai Praneeth Prakhya } 3537f4d257eSSai Praneeth Prakhya 3547f4d257eSSai Praneeth Prakhya sleep(1); 3557f4d257eSSai Praneeth Prakhya 3567f4d257eSSai Praneeth Prakhya /* Stop counters after a second to get results (both read and write) */ 3577f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 358c44000b6SIlpo Järvinen membw_ioctl_perf_event_ioc_disable(imc, READ); 359c44000b6SIlpo Järvinen membw_ioctl_perf_event_ioc_disable(imc, WRITE); 3607f4d257eSSai Praneeth Prakhya } 361da50de0aSIlpo Järvinen } 362da50de0aSIlpo Järvinen 363da50de0aSIlpo Järvinen /* 364da50de0aSIlpo Järvinen * get_mem_bw_imc - Memory bandwidth as reported by iMC counters 365da50de0aSIlpo Järvinen * @bw_report: Bandwidth report type (reads, writes) 366da50de0aSIlpo Järvinen * 3672704b2d1SIlpo Järvinen * Memory bandwidth utilized by a process on a socket can be calculated 3682704b2d1SIlpo Järvinen * using iMC counters. Perf events are used to read these counters. 369da50de0aSIlpo Järvinen * 370da50de0aSIlpo Järvinen * Return: = 0 on success. < 0 on failure. 371da50de0aSIlpo Järvinen */ 372da50de0aSIlpo Järvinen static int get_mem_bw_imc(char *bw_report, float *bw_imc) 373da50de0aSIlpo Järvinen { 374da50de0aSIlpo Järvinen float reads, writes, of_mul_read, of_mul_write; 375da50de0aSIlpo Järvinen int imc; 376da50de0aSIlpo Järvinen 377da50de0aSIlpo Järvinen /* Start all iMC counters to log values (both read and write) */ 378da50de0aSIlpo Järvinen reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1; 3797f4d257eSSai Praneeth Prakhya 3807f4d257eSSai Praneeth Prakhya /* 3817f4d257eSSai Praneeth Prakhya * Get results which are stored in struct type imc_counter_config 3822704b2d1SIlpo Järvinen * Take overflow into consideration before calculating total bandwidth. 3837f4d257eSSai Praneeth Prakhya */ 3847f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 3857f4d257eSSai Praneeth Prakhya struct imc_counter_config *r = 3867f4d257eSSai Praneeth Prakhya &imc_counters_config[imc][READ]; 3877f4d257eSSai Praneeth Prakhya struct imc_counter_config *w = 3887f4d257eSSai Praneeth Prakhya &imc_counters_config[imc][WRITE]; 3897f4d257eSSai Praneeth Prakhya 3907f4d257eSSai Praneeth Prakhya if (read(r->fd, &r->return_value, 3917f4d257eSSai Praneeth Prakhya sizeof(struct membw_read_format)) == -1) { 3922704b2d1SIlpo Järvinen ksft_perror("Couldn't get read bandwidth through iMC"); 393da50de0aSIlpo Järvinen return -1; 3947f4d257eSSai Praneeth Prakhya } 3957f4d257eSSai Praneeth Prakhya 3967f4d257eSSai Praneeth Prakhya if (read(w->fd, &w->return_value, 3977f4d257eSSai Praneeth Prakhya sizeof(struct membw_read_format)) == -1) { 3982704b2d1SIlpo Järvinen ksft_perror("Couldn't get write bandwidth through iMC"); 399da50de0aSIlpo Järvinen return -1; 4007f4d257eSSai Praneeth Prakhya } 4017f4d257eSSai Praneeth Prakhya 4027f4d257eSSai Praneeth Prakhya __u64 r_time_enabled = r->return_value.time_enabled; 4037f4d257eSSai Praneeth Prakhya __u64 r_time_running = r->return_value.time_running; 4047f4d257eSSai Praneeth Prakhya 4057f4d257eSSai Praneeth Prakhya if (r_time_enabled != r_time_running) 4067f4d257eSSai Praneeth Prakhya of_mul_read = (float)r_time_enabled / 4077f4d257eSSai Praneeth Prakhya (float)r_time_running; 4087f4d257eSSai Praneeth Prakhya 4097f4d257eSSai Praneeth Prakhya __u64 w_time_enabled = w->return_value.time_enabled; 4107f4d257eSSai Praneeth Prakhya __u64 w_time_running = w->return_value.time_running; 4117f4d257eSSai Praneeth Prakhya 4127f4d257eSSai Praneeth Prakhya if (w_time_enabled != w_time_running) 4137f4d257eSSai Praneeth Prakhya of_mul_write = (float)w_time_enabled / 4147f4d257eSSai Praneeth Prakhya (float)w_time_running; 4157f4d257eSSai Praneeth Prakhya reads += r->return_value.value * of_mul_read * SCALE; 4167f4d257eSSai Praneeth Prakhya writes += w->return_value.value * of_mul_write * SCALE; 4177f4d257eSSai Praneeth Prakhya } 4187f4d257eSSai Praneeth Prakhya 4191205b688SFenghua Yu if (strcmp(bw_report, "reads") == 0) { 4201205b688SFenghua Yu *bw_imc = reads; 4211205b688SFenghua Yu return 0; 4221205b688SFenghua Yu } 4237f4d257eSSai Praneeth Prakhya 4241205b688SFenghua Yu if (strcmp(bw_report, "writes") == 0) { 4251205b688SFenghua Yu *bw_imc = writes; 4261205b688SFenghua Yu return 0; 4271205b688SFenghua Yu } 4287f4d257eSSai Praneeth Prakhya 4291205b688SFenghua Yu *bw_imc = reads + writes; 4301205b688SFenghua Yu return 0; 4317f4d257eSSai Praneeth Prakhya } 4327f4d257eSSai Praneeth Prakhya 4336874f6edSIlpo Järvinen void set_mbm_path(const char *ctrlgrp, const char *mongrp, int domain_id) 4347f4d257eSSai Praneeth Prakhya { 4357f4d257eSSai Praneeth Prakhya if (ctrlgrp && mongrp) 4367f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH, 4376874f6edSIlpo Järvinen RESCTRL_PATH, ctrlgrp, mongrp, domain_id); 4387f4d257eSSai Praneeth Prakhya else if (!ctrlgrp && mongrp) 4397f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH, 4406874f6edSIlpo Järvinen mongrp, domain_id); 4417f4d257eSSai Praneeth Prakhya else if (ctrlgrp && !mongrp) 4427f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH, 4436874f6edSIlpo Järvinen ctrlgrp, domain_id); 4447f4d257eSSai Praneeth Prakhya else if (!ctrlgrp && !mongrp) 4457f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH, 4466874f6edSIlpo Järvinen domain_id); 4477f4d257eSSai Praneeth Prakhya } 4487f4d257eSSai Praneeth Prakhya 4497f4d257eSSai Praneeth Prakhya /* 4507f4d257eSSai Praneeth Prakhya * initialize_mem_bw_resctrl: Appropriately populate "mbm_total_path" 4517f4d257eSSai Praneeth Prakhya * @ctrlgrp: Name of the control monitor group (con_mon grp) 4527f4d257eSSai Praneeth Prakhya * @mongrp: Name of the monitor group (mon grp) 4539224db51SIlpo Järvinen * @domain_id: Domain ID (cache ID; for MB, L3 cache ID) 4547f4d257eSSai Praneeth Prakhya * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc) 4557f4d257eSSai Praneeth Prakhya */ 4567f4d257eSSai Praneeth Prakhya static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp, 4579224db51SIlpo Järvinen int domain_id, char *resctrl_val) 4587f4d257eSSai Praneeth Prakhya { 45924286736SFenghua Yu if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) 4606874f6edSIlpo Järvinen set_mbm_path(ctrlgrp, mongrp, domain_id); 4617f4d257eSSai Praneeth Prakhya 46224286736SFenghua Yu if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) { 4637f4d257eSSai Praneeth Prakhya if (ctrlgrp) 4647f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, 4656874f6edSIlpo Järvinen RESCTRL_PATH, ctrlgrp, domain_id); 4667f4d257eSSai Praneeth Prakhya else 4677f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, 4686874f6edSIlpo Järvinen RESCTRL_PATH, domain_id); 4697f4d257eSSai Praneeth Prakhya } 4707f4d257eSSai Praneeth Prakhya } 4717f4d257eSSai Praneeth Prakhya 4727f4d257eSSai Praneeth Prakhya /* 4737f4d257eSSai Praneeth Prakhya * Get MBM Local bytes as reported by resctrl FS 4747f4d257eSSai Praneeth Prakhya * For MBM, 4757f4d257eSSai Praneeth Prakhya * 1. If con_mon grp and mon grp are given, then read from con_mon grp's mon grp 4767f4d257eSSai Praneeth Prakhya * 2. If only con_mon grp is given, then read from con_mon grp 4777f4d257eSSai Praneeth Prakhya * 3. If both are not given, then read from root con_mon grp 4787f4d257eSSai Praneeth Prakhya * For MBA, 4797f4d257eSSai Praneeth Prakhya * 1. If con_mon grp is given, then read from it 4807f4d257eSSai Praneeth Prakhya * 2. If con_mon grp is not given, then read from root con_mon grp 4817f4d257eSSai Praneeth Prakhya */ 482da50de0aSIlpo Järvinen static FILE *open_mem_bw_resctrl(const char *mbm_bw_file) 4837f4d257eSSai Praneeth Prakhya { 4847f4d257eSSai Praneeth Prakhya FILE *fp; 4857f4d257eSSai Praneeth Prakhya 486da50de0aSIlpo Järvinen fp = fopen(mbm_bw_file, "r"); 487da50de0aSIlpo Järvinen if (!fp) 4882704b2d1SIlpo Järvinen ksft_perror("Failed to open total memory bandwidth file"); 4897f4d257eSSai Praneeth Prakhya 490da50de0aSIlpo Järvinen return fp; 491da50de0aSIlpo Järvinen } 492da50de0aSIlpo Järvinen 493da50de0aSIlpo Järvinen static int get_mem_bw_resctrl(FILE *fp, unsigned long *mbm_total) 494da50de0aSIlpo Järvinen { 495da50de0aSIlpo Järvinen if (fscanf(fp, "%lu\n", mbm_total) <= 0) { 496da50de0aSIlpo Järvinen ksft_perror("Could not get MBM local bytes"); 4977f4d257eSSai Praneeth Prakhya return -1; 4987f4d257eSSai Praneeth Prakhya } 4991205b688SFenghua Yu return 0; 5007f4d257eSSai Praneeth Prakhya } 5017f4d257eSSai Praneeth Prakhya 502*b0bd742aSIlpo Järvinen static pid_t bm_pid, ppid; 5037f4d257eSSai Praneeth Prakhya 50478941183SFenghua Yu void ctrlc_handler(int signum, siginfo_t *info, void *ptr) 5057f4d257eSSai Praneeth Prakhya { 5063aff5146SIlpo Järvinen /* Only kill child after bm_pid is set after fork() */ 5073aff5146SIlpo Järvinen if (bm_pid) 5087f4d257eSSai Praneeth Prakhya kill(bm_pid, SIGKILL); 509ecdbb911SFenghua Yu umount_resctrlfs(); 510e6487230SMaciej Wieczor-Retman if (current_test && current_test->cleanup) 511e6487230SMaciej Wieczor-Retman current_test->cleanup(); 512ca2f4214SFenghua Yu ksft_print_msg("Ending\n\n"); 5137f4d257eSSai Praneeth Prakhya 5147f4d257eSSai Praneeth Prakhya exit(EXIT_SUCCESS); 5157f4d257eSSai Praneeth Prakhya } 5167f4d257eSSai Praneeth Prakhya 5177f4d257eSSai Praneeth Prakhya /* 51873c55fa5SShaopeng Tan * Register CTRL-C handler for parent, as it has to kill 51973c55fa5SShaopeng Tan * child process before exiting. 52073c55fa5SShaopeng Tan */ 521e6487230SMaciej Wieczor-Retman int signal_handler_register(const struct resctrl_test *test) 52273c55fa5SShaopeng Tan { 523beb7f471SIlpo Järvinen struct sigaction sigact = {}; 52473c55fa5SShaopeng Tan int ret = 0; 52573c55fa5SShaopeng Tan 5263aff5146SIlpo Järvinen bm_pid = 0; 5273aff5146SIlpo Järvinen 528e6487230SMaciej Wieczor-Retman current_test = test; 52973c55fa5SShaopeng Tan sigact.sa_sigaction = ctrlc_handler; 53073c55fa5SShaopeng Tan sigemptyset(&sigact.sa_mask); 53173c55fa5SShaopeng Tan sigact.sa_flags = SA_SIGINFO; 53273c55fa5SShaopeng Tan if (sigaction(SIGINT, &sigact, NULL) || 53373c55fa5SShaopeng Tan sigaction(SIGTERM, &sigact, NULL) || 53473c55fa5SShaopeng Tan sigaction(SIGHUP, &sigact, NULL)) { 535cc8ff7f5SIlpo Järvinen ksft_perror("sigaction"); 53673c55fa5SShaopeng Tan ret = -1; 53773c55fa5SShaopeng Tan } 53873c55fa5SShaopeng Tan return ret; 53973c55fa5SShaopeng Tan } 54073c55fa5SShaopeng Tan 54173c55fa5SShaopeng Tan /* 54273c55fa5SShaopeng Tan * Reset signal handler to SIG_DFL. 54373c55fa5SShaopeng Tan * Non-Value return because the caller should keep 54473c55fa5SShaopeng Tan * the error code of other path even if sigaction fails. 54573c55fa5SShaopeng Tan */ 54673c55fa5SShaopeng Tan void signal_handler_unregister(void) 54773c55fa5SShaopeng Tan { 548beb7f471SIlpo Järvinen struct sigaction sigact = {}; 54973c55fa5SShaopeng Tan 550e6487230SMaciej Wieczor-Retman current_test = NULL; 55173c55fa5SShaopeng Tan sigact.sa_handler = SIG_DFL; 55273c55fa5SShaopeng Tan sigemptyset(&sigact.sa_mask); 55373c55fa5SShaopeng Tan if (sigaction(SIGINT, &sigact, NULL) || 55473c55fa5SShaopeng Tan sigaction(SIGTERM, &sigact, NULL) || 55573c55fa5SShaopeng Tan sigaction(SIGHUP, &sigact, NULL)) { 556cc8ff7f5SIlpo Järvinen ksft_perror("sigaction"); 55773c55fa5SShaopeng Tan } 55873c55fa5SShaopeng Tan } 55973c55fa5SShaopeng Tan 560*b0bd742aSIlpo Järvinen static void parent_exit(pid_t ppid) 561*b0bd742aSIlpo Järvinen { 562*b0bd742aSIlpo Järvinen kill(ppid, SIGKILL); 563*b0bd742aSIlpo Järvinen umount_resctrlfs(); 564*b0bd742aSIlpo Järvinen exit(EXIT_FAILURE); 565*b0bd742aSIlpo Järvinen } 566*b0bd742aSIlpo Järvinen 56773c55fa5SShaopeng Tan /* 5687f4d257eSSai Praneeth Prakhya * print_results_bw: the memory bandwidth results are stored in a file 5697f4d257eSSai Praneeth Prakhya * @filename: file that stores the results 5707f4d257eSSai Praneeth Prakhya * @bm_pid: child pid that runs benchmark 5717f4d257eSSai Praneeth Prakhya * @bw_imc: perf imc counter value 5727f4d257eSSai Praneeth Prakhya * @bw_resc: memory bandwidth value 5737f4d257eSSai Praneeth Prakhya * 574c90fba60SIlpo Järvinen * Return: 0 on success, < 0 on error. 5757f4d257eSSai Praneeth Prakhya */ 5768245a70eSIlpo Järvinen static int print_results_bw(char *filename, pid_t bm_pid, float bw_imc, 5777f4d257eSSai Praneeth Prakhya unsigned long bw_resc) 5787f4d257eSSai Praneeth Prakhya { 5797f4d257eSSai Praneeth Prakhya unsigned long diff = fabs(bw_imc - bw_resc); 5807f4d257eSSai Praneeth Prakhya FILE *fp; 5817f4d257eSSai Praneeth Prakhya 5827f4d257eSSai Praneeth Prakhya if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) { 5838245a70eSIlpo Järvinen printf("Pid: %d \t Mem_BW_iMC: %f \t ", (int)bm_pid, bw_imc); 5847f4d257eSSai Praneeth Prakhya printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff); 5857f4d257eSSai Praneeth Prakhya } else { 5867f4d257eSSai Praneeth Prakhya fp = fopen(filename, "a"); 5877f4d257eSSai Praneeth Prakhya if (!fp) { 588cc8ff7f5SIlpo Järvinen ksft_perror("Cannot open results file"); 5897f4d257eSSai Praneeth Prakhya 590c90fba60SIlpo Järvinen return -1; 5917f4d257eSSai Praneeth Prakhya } 5927f4d257eSSai Praneeth Prakhya if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n", 5938245a70eSIlpo Järvinen (int)bm_pid, bw_imc, bw_resc, diff) <= 0) { 594cc8ff7f5SIlpo Järvinen ksft_print_msg("Could not log results\n"); 5957f4d257eSSai Praneeth Prakhya fclose(fp); 5967f4d257eSSai Praneeth Prakhya 597c90fba60SIlpo Järvinen return -1; 5987f4d257eSSai Praneeth Prakhya } 5997f4d257eSSai Praneeth Prakhya fclose(fp); 6007f4d257eSSai Praneeth Prakhya } 6017f4d257eSSai Praneeth Prakhya 6027f4d257eSSai Praneeth Prakhya return 0; 6037f4d257eSSai Praneeth Prakhya } 6047f4d257eSSai Praneeth Prakhya 6052f320911SFenghua Yu static void set_cmt_path(const char *ctrlgrp, const char *mongrp, char sock_num) 60678941183SFenghua Yu { 60778941183SFenghua Yu if (strlen(ctrlgrp) && strlen(mongrp)) 60878941183SFenghua Yu sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH, 60978941183SFenghua Yu ctrlgrp, mongrp, sock_num); 61078941183SFenghua Yu else if (!strlen(ctrlgrp) && strlen(mongrp)) 61178941183SFenghua Yu sprintf(llc_occup_path, MON_LCC_OCCUP_PATH, RESCTRL_PATH, 61278941183SFenghua Yu mongrp, sock_num); 61378941183SFenghua Yu else if (strlen(ctrlgrp) && !strlen(mongrp)) 61478941183SFenghua Yu sprintf(llc_occup_path, CON_LCC_OCCUP_PATH, RESCTRL_PATH, 61578941183SFenghua Yu ctrlgrp, sock_num); 61678941183SFenghua Yu else if (!strlen(ctrlgrp) && !strlen(mongrp)) 61778941183SFenghua Yu sprintf(llc_occup_path, LCC_OCCUP_PATH, RESCTRL_PATH, sock_num); 61878941183SFenghua Yu } 61978941183SFenghua Yu 62078941183SFenghua Yu /* 62178941183SFenghua Yu * initialize_llc_occu_resctrl: Appropriately populate "llc_occup_path" 62278941183SFenghua Yu * @ctrlgrp: Name of the control monitor group (con_mon grp) 62378941183SFenghua Yu * @mongrp: Name of the monitor group (mon grp) 6249224db51SIlpo Järvinen * @domain_id: Domain ID (cache ID; for MB, L3 cache ID) 6252f320911SFenghua Yu * @resctrl_val: Resctrl feature (Eg: cat, cmt.. etc) 62678941183SFenghua Yu */ 62778941183SFenghua Yu static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp, 6289224db51SIlpo Järvinen int domain_id, char *resctrl_val) 62978941183SFenghua Yu { 6302f320911SFenghua Yu if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) 6316874f6edSIlpo Järvinen set_cmt_path(ctrlgrp, mongrp, domain_id); 63278941183SFenghua Yu } 63378941183SFenghua Yu 634da50de0aSIlpo Järvinen /* 635da50de0aSIlpo Järvinen * Measure memory bandwidth from resctrl and from another source which is 636da50de0aSIlpo Järvinen * perf imc value or could be something else if perf imc event is not 637da50de0aSIlpo Järvinen * available. Compare the two values to validate resctrl value. It takes 638da50de0aSIlpo Järvinen * 1 sec to measure the data. 639da50de0aSIlpo Järvinen */ 64015f29882SIlpo Järvinen static int measure_vals(const struct user_params *uparams, 641*b0bd742aSIlpo Järvinen struct resctrl_val_param *param, pid_t bm_pid) 6427f4d257eSSai Praneeth Prakhya { 643da50de0aSIlpo Järvinen unsigned long bw_resc, bw_resc_start, bw_resc_end; 644da50de0aSIlpo Järvinen FILE *mem_bw_fp; 6451205b688SFenghua Yu float bw_imc; 6467f4d257eSSai Praneeth Prakhya int ret; 6477f4d257eSSai Praneeth Prakhya 648da50de0aSIlpo Järvinen mem_bw_fp = open_mem_bw_resctrl(mbm_total_path); 649da50de0aSIlpo Järvinen if (!mem_bw_fp) 650da50de0aSIlpo Järvinen return -1; 651da50de0aSIlpo Järvinen 652da50de0aSIlpo Järvinen ret = perf_open_imc_mem_bw(uparams->cpu); 6531205b688SFenghua Yu if (ret < 0) 654da50de0aSIlpo Järvinen goto close_fp; 6557f4d257eSSai Praneeth Prakhya 656da50de0aSIlpo Järvinen ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_start); 6571205b688SFenghua Yu if (ret < 0) 658da50de0aSIlpo Järvinen goto close_imc; 659da50de0aSIlpo Järvinen 660da50de0aSIlpo Järvinen rewind(mem_bw_fp); 661da50de0aSIlpo Järvinen 662da50de0aSIlpo Järvinen do_imc_mem_bw_test(); 663da50de0aSIlpo Järvinen 664da50de0aSIlpo Järvinen ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_end); 665da50de0aSIlpo Järvinen if (ret < 0) 666da50de0aSIlpo Järvinen goto close_imc; 667da50de0aSIlpo Järvinen 668da50de0aSIlpo Järvinen ret = get_mem_bw_imc(param->bw_report, &bw_imc); 669da50de0aSIlpo Järvinen if (ret < 0) 670da50de0aSIlpo Järvinen goto close_imc; 671da50de0aSIlpo Järvinen 672da50de0aSIlpo Järvinen perf_close_imc_mem_bw(); 673da50de0aSIlpo Järvinen fclose(mem_bw_fp); 674da50de0aSIlpo Järvinen 675da50de0aSIlpo Järvinen bw_resc = (bw_resc_end - bw_resc_start) / MB; 676da50de0aSIlpo Järvinen 677da50de0aSIlpo Järvinen return print_results_bw(param->filename, bm_pid, bw_imc, bw_resc); 678da50de0aSIlpo Järvinen 679da50de0aSIlpo Järvinen close_imc: 680da50de0aSIlpo Järvinen perf_close_imc_mem_bw(); 681da50de0aSIlpo Järvinen close_fp: 682da50de0aSIlpo Järvinen fclose(mem_bw_fp); 6831205b688SFenghua Yu return ret; 6847f4d257eSSai Praneeth Prakhya } 6857f4d257eSSai Praneeth Prakhya 6867f4d257eSSai Praneeth Prakhya /* 687508934b5SMaciej Wieczor-Retman * run_benchmark - Run a specified benchmark or fill_buf (default benchmark) 688508934b5SMaciej Wieczor-Retman * in specified signal. Direct benchmark stdio to /dev/null. 689508934b5SMaciej Wieczor-Retman * @signum: signal number 690508934b5SMaciej Wieczor-Retman * @info: signal info 691508934b5SMaciej Wieczor-Retman * @ucontext: user context in signal handling 692508934b5SMaciej Wieczor-Retman */ 693508934b5SMaciej Wieczor-Retman static void run_benchmark(int signum, siginfo_t *info, void *ucontext) 694508934b5SMaciej Wieczor-Retman { 695508934b5SMaciej Wieczor-Retman int operation, ret, memflush; 696508934b5SMaciej Wieczor-Retman char **benchmark_cmd; 697508934b5SMaciej Wieczor-Retman size_t span; 698508934b5SMaciej Wieczor-Retman bool once; 699508934b5SMaciej Wieczor-Retman FILE *fp; 700508934b5SMaciej Wieczor-Retman 701508934b5SMaciej Wieczor-Retman benchmark_cmd = info->si_ptr; 702508934b5SMaciej Wieczor-Retman 703508934b5SMaciej Wieczor-Retman /* 704508934b5SMaciej Wieczor-Retman * Direct stdio of child to /dev/null, so that only parent writes to 705508934b5SMaciej Wieczor-Retman * stdio (console) 706508934b5SMaciej Wieczor-Retman */ 707508934b5SMaciej Wieczor-Retman fp = freopen("/dev/null", "w", stdout); 708cc8ff7f5SIlpo Järvinen if (!fp) { 709cc8ff7f5SIlpo Järvinen ksft_perror("Unable to direct benchmark status to /dev/null"); 710*b0bd742aSIlpo Järvinen parent_exit(ppid); 711cc8ff7f5SIlpo Järvinen } 712508934b5SMaciej Wieczor-Retman 713508934b5SMaciej Wieczor-Retman if (strcmp(benchmark_cmd[0], "fill_buf") == 0) { 714508934b5SMaciej Wieczor-Retman /* Execute default fill_buf benchmark */ 715508934b5SMaciej Wieczor-Retman span = strtoul(benchmark_cmd[1], NULL, 10); 716508934b5SMaciej Wieczor-Retman memflush = atoi(benchmark_cmd[2]); 717508934b5SMaciej Wieczor-Retman operation = atoi(benchmark_cmd[3]); 718cc8ff7f5SIlpo Järvinen if (!strcmp(benchmark_cmd[4], "true")) { 719508934b5SMaciej Wieczor-Retman once = true; 720cc8ff7f5SIlpo Järvinen } else if (!strcmp(benchmark_cmd[4], "false")) { 721508934b5SMaciej Wieczor-Retman once = false; 722cc8ff7f5SIlpo Järvinen } else { 723cc8ff7f5SIlpo Järvinen ksft_print_msg("Invalid once parameter\n"); 724*b0bd742aSIlpo Järvinen parent_exit(ppid); 725cc8ff7f5SIlpo Järvinen } 726508934b5SMaciej Wieczor-Retman 727508934b5SMaciej Wieczor-Retman if (run_fill_buf(span, memflush, operation, once)) 728508934b5SMaciej Wieczor-Retman fprintf(stderr, "Error in running fill buffer\n"); 729508934b5SMaciej Wieczor-Retman } else { 730508934b5SMaciej Wieczor-Retman /* Execute specified benchmark */ 731508934b5SMaciej Wieczor-Retman ret = execvp(benchmark_cmd[0], benchmark_cmd); 732508934b5SMaciej Wieczor-Retman if (ret) 733cc8ff7f5SIlpo Järvinen ksft_perror("execvp"); 734508934b5SMaciej Wieczor-Retman } 735508934b5SMaciej Wieczor-Retman 736508934b5SMaciej Wieczor-Retman fclose(stdout); 737cc8ff7f5SIlpo Järvinen ksft_print_msg("Unable to run specified benchmark\n"); 738*b0bd742aSIlpo Järvinen parent_exit(ppid); 739508934b5SMaciej Wieczor-Retman } 740508934b5SMaciej Wieczor-Retman 741508934b5SMaciej Wieczor-Retman /* 7427f4d257eSSai Praneeth Prakhya * resctrl_val: execute benchmark and measure memory bandwidth on 7437f4d257eSSai Praneeth Prakhya * the benchmark 744ca160887SIlpo Järvinen * @test: test information structure 74515f29882SIlpo Järvinen * @uparams: user supplied parameters 7467f4d257eSSai Praneeth Prakhya * @benchmark_cmd: benchmark command and its arguments 7477f4d257eSSai Praneeth Prakhya * @param: parameters passed to resctrl_val() 7487f4d257eSSai Praneeth Prakhya * 749c90fba60SIlpo Järvinen * Return: 0 when the test was run, < 0 on error. 7507f4d257eSSai Praneeth Prakhya */ 751ca160887SIlpo Järvinen int resctrl_val(const struct resctrl_test *test, 752ca160887SIlpo Järvinen const struct user_params *uparams, 753ca160887SIlpo Järvinen const char * const *benchmark_cmd, 75415f29882SIlpo Järvinen struct resctrl_val_param *param) 7557f4d257eSSai Praneeth Prakhya { 7567f4d257eSSai Praneeth Prakhya char *resctrl_val = param->resctrl_val; 7577f4d257eSSai Praneeth Prakhya struct sigaction sigact; 7587f4d257eSSai Praneeth Prakhya int ret = 0, pipefd[2]; 7597f4d257eSSai Praneeth Prakhya char pipe_message = 0; 7607f4d257eSSai Praneeth Prakhya union sigval value; 7619224db51SIlpo Järvinen int domain_id; 7627f4d257eSSai Praneeth Prakhya 7637f4d257eSSai Praneeth Prakhya if (strcmp(param->filename, "") == 0) 7647f4d257eSSai Praneeth Prakhya sprintf(param->filename, "stdio"); 7657f4d257eSSai Praneeth Prakhya 7669224db51SIlpo Järvinen ret = get_domain_id(test->resource, uparams->cpu, &domain_id); 7679224db51SIlpo Järvinen if (ret < 0) { 7689224db51SIlpo Järvinen ksft_print_msg("Could not get domain ID\n"); 7699224db51SIlpo Järvinen return ret; 7709224db51SIlpo Järvinen } 7719224db51SIlpo Järvinen 77224286736SFenghua Yu if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) || 77324286736SFenghua Yu !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) { 7747f4d257eSSai Praneeth Prakhya ret = validate_bw_report_request(param->bw_report); 7757f4d257eSSai Praneeth Prakhya if (ret) 7767f4d257eSSai Praneeth Prakhya return ret; 7777f4d257eSSai Praneeth Prakhya } 7787f4d257eSSai Praneeth Prakhya 7797f4d257eSSai Praneeth Prakhya /* 7807f4d257eSSai Praneeth Prakhya * If benchmark wasn't successfully started by child, then child should 7817f4d257eSSai Praneeth Prakhya * kill parent, so save parent's pid 7827f4d257eSSai Praneeth Prakhya */ 7837f4d257eSSai Praneeth Prakhya ppid = getpid(); 7847f4d257eSSai Praneeth Prakhya 7857f4d257eSSai Praneeth Prakhya if (pipe(pipefd)) { 786cc8ff7f5SIlpo Järvinen ksft_perror("Unable to create pipe"); 7877f4d257eSSai Praneeth Prakhya 7887f4d257eSSai Praneeth Prakhya return -1; 7897f4d257eSSai Praneeth Prakhya } 7907f4d257eSSai Praneeth Prakhya 7917f4d257eSSai Praneeth Prakhya /* 7927f4d257eSSai Praneeth Prakhya * Fork to start benchmark, save child's pid so that it can be killed 7937f4d257eSSai Praneeth Prakhya * when needed 7947f4d257eSSai Praneeth Prakhya */ 795a080b6e7SShaopeng Tan fflush(stdout); 7967f4d257eSSai Praneeth Prakhya bm_pid = fork(); 7977f4d257eSSai Praneeth Prakhya if (bm_pid == -1) { 798cc8ff7f5SIlpo Järvinen ksft_perror("Unable to fork"); 7997f4d257eSSai Praneeth Prakhya 8007f4d257eSSai Praneeth Prakhya return -1; 8017f4d257eSSai Praneeth Prakhya } 8027f4d257eSSai Praneeth Prakhya 8037f4d257eSSai Praneeth Prakhya if (bm_pid == 0) { 8047f4d257eSSai Praneeth Prakhya /* 8057f4d257eSSai Praneeth Prakhya * Mask all signals except SIGUSR1, parent uses SIGUSR1 to 8067f4d257eSSai Praneeth Prakhya * start benchmark 8077f4d257eSSai Praneeth Prakhya */ 8087f4d257eSSai Praneeth Prakhya sigfillset(&sigact.sa_mask); 8097f4d257eSSai Praneeth Prakhya sigdelset(&sigact.sa_mask, SIGUSR1); 8107f4d257eSSai Praneeth Prakhya 8117f4d257eSSai Praneeth Prakhya sigact.sa_sigaction = run_benchmark; 8127f4d257eSSai Praneeth Prakhya sigact.sa_flags = SA_SIGINFO; 8137f4d257eSSai Praneeth Prakhya 8147f4d257eSSai Praneeth Prakhya /* Register for "SIGUSR1" signal from parent */ 815cc8ff7f5SIlpo Järvinen if (sigaction(SIGUSR1, &sigact, NULL)) { 816cc8ff7f5SIlpo Järvinen ksft_perror("Can't register child for signal"); 817*b0bd742aSIlpo Järvinen parent_exit(ppid); 818cc8ff7f5SIlpo Järvinen } 8197f4d257eSSai Praneeth Prakhya 8207f4d257eSSai Praneeth Prakhya /* Tell parent that child is ready */ 8217f4d257eSSai Praneeth Prakhya close(pipefd[0]); 8227f4d257eSSai Praneeth Prakhya pipe_message = 1; 8237f4d257eSSai Praneeth Prakhya if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) < 8247f4d257eSSai Praneeth Prakhya sizeof(pipe_message)) { 825cc8ff7f5SIlpo Järvinen ksft_perror("Failed signaling parent process"); 8267f4d257eSSai Praneeth Prakhya close(pipefd[1]); 8277f4d257eSSai Praneeth Prakhya return -1; 8287f4d257eSSai Praneeth Prakhya } 8297f4d257eSSai Praneeth Prakhya close(pipefd[1]); 8307f4d257eSSai Praneeth Prakhya 8317f4d257eSSai Praneeth Prakhya /* Suspend child until delivery of "SIGUSR1" from parent */ 8327f4d257eSSai Praneeth Prakhya sigsuspend(&sigact.sa_mask); 8337f4d257eSSai Praneeth Prakhya 834cc8ff7f5SIlpo Järvinen ksft_perror("Child is done"); 835*b0bd742aSIlpo Järvinen parent_exit(ppid); 8367f4d257eSSai Praneeth Prakhya } 8377f4d257eSSai Praneeth Prakhya 8388245a70eSIlpo Järvinen ksft_print_msg("Benchmark PID: %d\n", (int)bm_pid); 8397f4d257eSSai Praneeth Prakhya 840e33cb570SIlpo Järvinen /* 841e33cb570SIlpo Järvinen * The cast removes constness but nothing mutates benchmark_cmd within 842e33cb570SIlpo Järvinen * the context of this process. At the receiving process, it becomes 843e33cb570SIlpo Järvinen * argv, which is mutable, on exec() but that's after fork() so it 844e33cb570SIlpo Järvinen * doesn't matter for the process running the tests. 845e33cb570SIlpo Järvinen */ 846e33cb570SIlpo Järvinen value.sival_ptr = (void *)benchmark_cmd; 8477f4d257eSSai Praneeth Prakhya 8487f4d257eSSai Praneeth Prakhya /* Taskset benchmark to specified cpu */ 84915f29882SIlpo Järvinen ret = taskset_benchmark(bm_pid, uparams->cpu, NULL); 8507f4d257eSSai Praneeth Prakhya if (ret) 8513aff5146SIlpo Järvinen goto out; 8527f4d257eSSai Praneeth Prakhya 8537f4d257eSSai Praneeth Prakhya /* Write benchmark to specified control&monitoring grp in resctrl FS */ 8547f4d257eSSai Praneeth Prakhya ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp, 8557f4d257eSSai Praneeth Prakhya resctrl_val); 8567f4d257eSSai Praneeth Prakhya if (ret) 8573aff5146SIlpo Järvinen goto out; 8587f4d257eSSai Praneeth Prakhya 85924286736SFenghua Yu if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) || 86024286736SFenghua Yu !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) { 8617f4d257eSSai Praneeth Prakhya ret = initialize_mem_bw_imc(); 8627f4d257eSSai Praneeth Prakhya if (ret) 8633aff5146SIlpo Järvinen goto out; 8647f4d257eSSai Praneeth Prakhya 8657f4d257eSSai Praneeth Prakhya initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp, 8669224db51SIlpo Järvinen domain_id, resctrl_val); 8672f320911SFenghua Yu } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) 86878941183SFenghua Yu initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp, 8699224db51SIlpo Järvinen domain_id, resctrl_val); 8707f4d257eSSai Praneeth Prakhya 8717f4d257eSSai Praneeth Prakhya /* Parent waits for child to be ready. */ 8727f4d257eSSai Praneeth Prakhya close(pipefd[1]); 8737f4d257eSSai Praneeth Prakhya while (pipe_message != 1) { 8747f4d257eSSai Praneeth Prakhya if (read(pipefd[0], &pipe_message, sizeof(pipe_message)) < 8757f4d257eSSai Praneeth Prakhya sizeof(pipe_message)) { 876cc8ff7f5SIlpo Järvinen ksft_perror("Failed reading message from child process"); 8777f4d257eSSai Praneeth Prakhya close(pipefd[0]); 8783aff5146SIlpo Järvinen goto out; 8797f4d257eSSai Praneeth Prakhya } 8807f4d257eSSai Praneeth Prakhya } 8817f4d257eSSai Praneeth Prakhya close(pipefd[0]); 8827f4d257eSSai Praneeth Prakhya 8837f4d257eSSai Praneeth Prakhya /* Signal child to start benchmark */ 8847f4d257eSSai Praneeth Prakhya if (sigqueue(bm_pid, SIGUSR1, value) == -1) { 885cc8ff7f5SIlpo Järvinen ksft_perror("sigqueue SIGUSR1 to child"); 886c90fba60SIlpo Järvinen ret = -1; 8873aff5146SIlpo Järvinen goto out; 8887f4d257eSSai Praneeth Prakhya } 8897f4d257eSSai Praneeth Prakhya 8907f4d257eSSai Praneeth Prakhya /* Give benchmark enough time to fully run */ 8917f4d257eSSai Praneeth Prakhya sleep(1); 8927f4d257eSSai Praneeth Prakhya 8937f4d257eSSai Praneeth Prakhya /* Test runs until the callback setup() tells the test to stop. */ 8947f4d257eSSai Praneeth Prakhya while (1) { 895ca160887SIlpo Järvinen ret = param->setup(test, uparams, param); 896fa10366cSIlpo Järvinen if (ret == END_OF_TESTS) { 8977f4d257eSSai Praneeth Prakhya ret = 0; 8987f4d257eSSai Praneeth Prakhya break; 8997f4d257eSSai Praneeth Prakhya } 900fa10366cSIlpo Järvinen if (ret < 0) 901fa10366cSIlpo Järvinen break; 9027f4d257eSSai Praneeth Prakhya 903c90b3b58SIlpo Järvinen if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) || 904c90b3b58SIlpo Järvinen !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) { 905*b0bd742aSIlpo Järvinen ret = measure_vals(uparams, param, bm_pid); 9067f4d257eSSai Praneeth Prakhya if (ret) 9077f4d257eSSai Praneeth Prakhya break; 9082f320911SFenghua Yu } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) { 90978941183SFenghua Yu sleep(1); 910a575c973SIlpo Järvinen ret = measure_llc_resctrl(param->filename, bm_pid); 9117f4d257eSSai Praneeth Prakhya if (ret) 9127f4d257eSSai Praneeth Prakhya break; 9137f4d257eSSai Praneeth Prakhya } 9147f4d257eSSai Praneeth Prakhya } 9157f4d257eSSai Praneeth Prakhya 9167f4d257eSSai Praneeth Prakhya out: 9177f4d257eSSai Praneeth Prakhya kill(bm_pid, SIGKILL); 9187f4d257eSSai Praneeth Prakhya 9197f4d257eSSai Praneeth Prakhya return ret; 9207f4d257eSSai Praneeth Prakhya } 921