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]; 651d3f0868SSai Praneeth Prakhya 661d3f0868SSai Praneeth Prakhya void membw_initialize_perf_event_attr(int i, int j) 671d3f0868SSai Praneeth Prakhya { 681d3f0868SSai Praneeth Prakhya memset(&imc_counters_config[i][j].pe, 0, 691d3f0868SSai Praneeth Prakhya sizeof(struct perf_event_attr)); 701d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.type = imc_counters_config[i][j].type; 711d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr); 721d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.disabled = 1; 731d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.inherit = 1; 741d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.exclude_guest = 0; 751d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.config = 761d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].umask << 8 | 771d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].event; 781d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER; 791d3f0868SSai Praneeth Prakhya imc_counters_config[i][j].pe.read_format = 801d3f0868SSai Praneeth Prakhya PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; 811d3f0868SSai Praneeth Prakhya } 821d3f0868SSai Praneeth Prakhya 831d3f0868SSai Praneeth Prakhya void membw_ioctl_perf_event_ioc_reset_enable(int i, int j) 841d3f0868SSai Praneeth Prakhya { 851d3f0868SSai Praneeth Prakhya ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0); 861d3f0868SSai Praneeth Prakhya ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0); 871d3f0868SSai Praneeth Prakhya } 881d3f0868SSai Praneeth Prakhya 891d3f0868SSai Praneeth Prakhya void membw_ioctl_perf_event_ioc_disable(int i, int j) 901d3f0868SSai Praneeth Prakhya { 911d3f0868SSai Praneeth Prakhya ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0); 921d3f0868SSai Praneeth Prakhya } 931d3f0868SSai Praneeth Prakhya 941d3f0868SSai Praneeth Prakhya /* 951d3f0868SSai Praneeth Prakhya * get_event_and_umask: Parse config into event and umask 961d3f0868SSai Praneeth Prakhya * @cas_count_cfg: Config 971d3f0868SSai Praneeth Prakhya * @count: iMC number 981d3f0868SSai Praneeth Prakhya * @op: Operation (read/write) 991d3f0868SSai Praneeth Prakhya */ 1001d3f0868SSai Praneeth Prakhya void get_event_and_umask(char *cas_count_cfg, int count, bool op) 1011d3f0868SSai Praneeth Prakhya { 1021d3f0868SSai Praneeth Prakhya char *token[MAX_TOKENS]; 1031d3f0868SSai Praneeth Prakhya int i = 0; 1041d3f0868SSai Praneeth Prakhya 1051d3f0868SSai Praneeth Prakhya strcat(cas_count_cfg, ","); 1061d3f0868SSai Praneeth Prakhya token[0] = strtok(cas_count_cfg, "=,"); 1071d3f0868SSai Praneeth Prakhya 1081d3f0868SSai Praneeth Prakhya for (i = 1; i < MAX_TOKENS; i++) 1091d3f0868SSai Praneeth Prakhya token[i] = strtok(NULL, "=,"); 1101d3f0868SSai Praneeth Prakhya 1111d3f0868SSai Praneeth Prakhya for (i = 0; i < MAX_TOKENS; i++) { 1121d3f0868SSai Praneeth Prakhya if (!token[i]) 1131d3f0868SSai Praneeth Prakhya break; 1141d3f0868SSai Praneeth Prakhya if (strcmp(token[i], "event") == 0) { 1151d3f0868SSai Praneeth Prakhya if (op == READ) 1161d3f0868SSai Praneeth Prakhya imc_counters_config[count][READ].event = 1171d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1181d3f0868SSai Praneeth Prakhya else 1191d3f0868SSai Praneeth Prakhya imc_counters_config[count][WRITE].event = 1201d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1211d3f0868SSai Praneeth Prakhya } 1221d3f0868SSai Praneeth Prakhya if (strcmp(token[i], "umask") == 0) { 1231d3f0868SSai Praneeth Prakhya if (op == READ) 1241d3f0868SSai Praneeth Prakhya imc_counters_config[count][READ].umask = 1251d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1261d3f0868SSai Praneeth Prakhya else 1271d3f0868SSai Praneeth Prakhya imc_counters_config[count][WRITE].umask = 1281d3f0868SSai Praneeth Prakhya strtol(token[i + 1], NULL, 16); 1291d3f0868SSai Praneeth Prakhya } 1301d3f0868SSai Praneeth Prakhya } 1311d3f0868SSai Praneeth Prakhya } 1327f4d257eSSai Praneeth Prakhya 1337f4d257eSSai Praneeth Prakhya static int open_perf_event(int i, int cpu_no, int j) 1347f4d257eSSai Praneeth Prakhya { 1357f4d257eSSai Praneeth Prakhya imc_counters_config[i][j].fd = 1367f4d257eSSai Praneeth Prakhya perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1, 1377f4d257eSSai Praneeth Prakhya PERF_FLAG_FD_CLOEXEC); 1387f4d257eSSai Praneeth Prakhya 1397f4d257eSSai Praneeth Prakhya if (imc_counters_config[i][j].fd == -1) { 1407f4d257eSSai Praneeth Prakhya fprintf(stderr, "Error opening leader %llx\n", 1417f4d257eSSai Praneeth Prakhya imc_counters_config[i][j].pe.config); 1427f4d257eSSai Praneeth Prakhya 1437f4d257eSSai Praneeth Prakhya return -1; 1447f4d257eSSai Praneeth Prakhya } 1457f4d257eSSai Praneeth Prakhya 1467f4d257eSSai Praneeth Prakhya return 0; 1477f4d257eSSai Praneeth Prakhya } 1487f4d257eSSai Praneeth Prakhya 1497f4d257eSSai Praneeth Prakhya /* Get type and config (read and write) of an iMC counter */ 1507f4d257eSSai Praneeth Prakhya static int read_from_imc_dir(char *imc_dir, int count) 1517f4d257eSSai Praneeth Prakhya { 1527f4d257eSSai Praneeth Prakhya char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024]; 1537f4d257eSSai Praneeth Prakhya FILE *fp; 1547f4d257eSSai Praneeth Prakhya 1557f4d257eSSai Praneeth Prakhya /* Get type of iMC counter */ 1567f4d257eSSai Praneeth Prakhya sprintf(imc_counter_type, "%s%s", imc_dir, "type"); 1577f4d257eSSai Praneeth Prakhya fp = fopen(imc_counter_type, "r"); 1587f4d257eSSai Praneeth Prakhya if (!fp) { 159*cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open iMC counter type file"); 1607f4d257eSSai Praneeth Prakhya 1617f4d257eSSai Praneeth Prakhya return -1; 1627f4d257eSSai Praneeth Prakhya } 1637f4d257eSSai Praneeth Prakhya if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) { 164*cc8ff7f5SIlpo Järvinen ksft_perror("Could not get iMC type"); 1657f4d257eSSai Praneeth Prakhya fclose(fp); 1667f4d257eSSai Praneeth Prakhya 1677f4d257eSSai Praneeth Prakhya return -1; 1687f4d257eSSai Praneeth Prakhya } 1697f4d257eSSai Praneeth Prakhya fclose(fp); 1707f4d257eSSai Praneeth Prakhya 1717f4d257eSSai Praneeth Prakhya imc_counters_config[count][WRITE].type = 1727f4d257eSSai Praneeth Prakhya imc_counters_config[count][READ].type; 1737f4d257eSSai Praneeth Prakhya 1747f4d257eSSai Praneeth Prakhya /* Get read config */ 1757f4d257eSSai Praneeth Prakhya sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME); 1767f4d257eSSai Praneeth Prakhya fp = fopen(imc_counter_cfg, "r"); 1777f4d257eSSai Praneeth Prakhya if (!fp) { 178*cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open iMC config file"); 1797f4d257eSSai Praneeth Prakhya 1807f4d257eSSai Praneeth Prakhya return -1; 1817f4d257eSSai Praneeth Prakhya } 1827f4d257eSSai Praneeth Prakhya if (fscanf(fp, "%s", cas_count_cfg) <= 0) { 183*cc8ff7f5SIlpo Järvinen ksft_perror("Could not get iMC cas count read"); 1847f4d257eSSai Praneeth Prakhya fclose(fp); 1857f4d257eSSai Praneeth Prakhya 1867f4d257eSSai Praneeth Prakhya return -1; 1877f4d257eSSai Praneeth Prakhya } 1887f4d257eSSai Praneeth Prakhya fclose(fp); 1897f4d257eSSai Praneeth Prakhya 1907f4d257eSSai Praneeth Prakhya get_event_and_umask(cas_count_cfg, count, READ); 1917f4d257eSSai Praneeth Prakhya 1927f4d257eSSai Praneeth Prakhya /* Get write config */ 1937f4d257eSSai Praneeth Prakhya sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME); 1947f4d257eSSai Praneeth Prakhya fp = fopen(imc_counter_cfg, "r"); 1957f4d257eSSai Praneeth Prakhya if (!fp) { 196*cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open iMC config file"); 1977f4d257eSSai Praneeth Prakhya 1987f4d257eSSai Praneeth Prakhya return -1; 1997f4d257eSSai Praneeth Prakhya } 2007f4d257eSSai Praneeth Prakhya if (fscanf(fp, "%s", cas_count_cfg) <= 0) { 201*cc8ff7f5SIlpo Järvinen ksft_perror("Could not get iMC cas count write"); 2027f4d257eSSai Praneeth Prakhya fclose(fp); 2037f4d257eSSai Praneeth Prakhya 2047f4d257eSSai Praneeth Prakhya return -1; 2057f4d257eSSai Praneeth Prakhya } 2067f4d257eSSai Praneeth Prakhya fclose(fp); 2077f4d257eSSai Praneeth Prakhya 2087f4d257eSSai Praneeth Prakhya get_event_and_umask(cas_count_cfg, count, WRITE); 2097f4d257eSSai Praneeth Prakhya 2107f4d257eSSai Praneeth Prakhya return 0; 2117f4d257eSSai Praneeth Prakhya } 2127f4d257eSSai Praneeth Prakhya 2137f4d257eSSai Praneeth Prakhya /* 2147f4d257eSSai Praneeth Prakhya * A system can have 'n' number of iMC (Integrated Memory Controller) 2157f4d257eSSai Praneeth Prakhya * counters, get that 'n'. For each iMC counter get it's type and config. 2167f4d257eSSai Praneeth Prakhya * Also, each counter has two configs, one for read and the other for write. 2177f4d257eSSai Praneeth Prakhya * A config again has two parts, event and umask. 2187f4d257eSSai Praneeth Prakhya * Enumerate all these details into an array of structures. 2197f4d257eSSai Praneeth Prakhya * 2207f4d257eSSai Praneeth Prakhya * Return: >= 0 on success. < 0 on failure. 2217f4d257eSSai Praneeth Prakhya */ 2227f4d257eSSai Praneeth Prakhya static int num_of_imcs(void) 2237f4d257eSSai Praneeth Prakhya { 224d81343b5SFenghua Yu char imc_dir[512], *temp; 2257f4d257eSSai Praneeth Prakhya unsigned int count = 0; 2267f4d257eSSai Praneeth Prakhya struct dirent *ep; 2277f4d257eSSai Praneeth Prakhya int ret; 2287f4d257eSSai Praneeth Prakhya DIR *dp; 2297f4d257eSSai Praneeth Prakhya 2307f4d257eSSai Praneeth Prakhya dp = opendir(DYN_PMU_PATH); 2317f4d257eSSai Praneeth Prakhya if (dp) { 2327f4d257eSSai Praneeth Prakhya while ((ep = readdir(dp))) { 233d81343b5SFenghua Yu temp = strstr(ep->d_name, UNCORE_IMC); 234d81343b5SFenghua Yu if (!temp) 235d81343b5SFenghua Yu continue; 236d81343b5SFenghua Yu 237d81343b5SFenghua Yu /* 238d81343b5SFenghua Yu * imc counters are named as "uncore_imc_<n>", hence 239d81343b5SFenghua Yu * increment the pointer to point to <n>. Note that 240d81343b5SFenghua Yu * sizeof(UNCORE_IMC) would count for null character as 241d81343b5SFenghua Yu * well and hence the last underscore character in 242d81343b5SFenghua Yu * uncore_imc'_' need not be counted. 243d81343b5SFenghua Yu */ 244d81343b5SFenghua Yu temp = temp + sizeof(UNCORE_IMC); 245d81343b5SFenghua Yu 246d81343b5SFenghua Yu /* 247d81343b5SFenghua Yu * Some directories under "DYN_PMU_PATH" could have 248d81343b5SFenghua Yu * names like "uncore_imc_free_running", hence, check if 249d81343b5SFenghua Yu * first character is a numerical digit or not. 250d81343b5SFenghua Yu */ 251d81343b5SFenghua Yu if (temp[0] >= '0' && temp[0] <= '9') { 2527f4d257eSSai Praneeth Prakhya sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH, 2537f4d257eSSai Praneeth Prakhya ep->d_name); 2547f4d257eSSai Praneeth Prakhya ret = read_from_imc_dir(imc_dir, count); 2557f4d257eSSai Praneeth Prakhya if (ret) { 2567f4d257eSSai Praneeth Prakhya closedir(dp); 2577f4d257eSSai Praneeth Prakhya 2587f4d257eSSai Praneeth Prakhya return ret; 2597f4d257eSSai Praneeth Prakhya } 2607f4d257eSSai Praneeth Prakhya count++; 2617f4d257eSSai Praneeth Prakhya } 2627f4d257eSSai Praneeth Prakhya } 2637f4d257eSSai Praneeth Prakhya closedir(dp); 2647f4d257eSSai Praneeth Prakhya if (count == 0) { 265*cc8ff7f5SIlpo Järvinen ksft_print_msg("Unable to find iMC counters\n"); 2667f4d257eSSai Praneeth Prakhya 2677f4d257eSSai Praneeth Prakhya return -1; 2687f4d257eSSai Praneeth Prakhya } 2697f4d257eSSai Praneeth Prakhya } else { 270*cc8ff7f5SIlpo Järvinen ksft_perror("Unable to open PMU directory"); 2717f4d257eSSai Praneeth Prakhya 2727f4d257eSSai Praneeth Prakhya return -1; 2737f4d257eSSai Praneeth Prakhya } 2747f4d257eSSai Praneeth Prakhya 2757f4d257eSSai Praneeth Prakhya return count; 2767f4d257eSSai Praneeth Prakhya } 2777f4d257eSSai Praneeth Prakhya 2787f4d257eSSai Praneeth Prakhya static int initialize_mem_bw_imc(void) 2797f4d257eSSai Praneeth Prakhya { 2807f4d257eSSai Praneeth Prakhya int imc, j; 2817f4d257eSSai Praneeth Prakhya 2827f4d257eSSai Praneeth Prakhya imcs = num_of_imcs(); 2837f4d257eSSai Praneeth Prakhya if (imcs <= 0) 2847f4d257eSSai Praneeth Prakhya return imcs; 2857f4d257eSSai Praneeth Prakhya 2867f4d257eSSai Praneeth Prakhya /* Initialize perf_event_attr structures for all iMC's */ 2877f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 2887f4d257eSSai Praneeth Prakhya for (j = 0; j < 2; j++) 2897f4d257eSSai Praneeth Prakhya membw_initialize_perf_event_attr(imc, j); 2907f4d257eSSai Praneeth Prakhya } 2917f4d257eSSai Praneeth Prakhya 2927f4d257eSSai Praneeth Prakhya return 0; 2937f4d257eSSai Praneeth Prakhya } 2947f4d257eSSai Praneeth Prakhya 2957f4d257eSSai Praneeth Prakhya /* 2967f4d257eSSai Praneeth Prakhya * get_mem_bw_imc: Memory band width as reported by iMC counters 2977f4d257eSSai Praneeth Prakhya * @cpu_no: CPU number that the benchmark PID is binded to 2987f4d257eSSai Praneeth Prakhya * @bw_report: Bandwidth report type (reads, writes) 2997f4d257eSSai Praneeth Prakhya * 3007f4d257eSSai Praneeth Prakhya * Memory B/W utilized by a process on a socket can be calculated using 3017f4d257eSSai Praneeth Prakhya * iMC counters. Perf events are used to read these counters. 3027f4d257eSSai Praneeth Prakhya * 3031205b688SFenghua Yu * Return: = 0 on success. < 0 on failure. 3047f4d257eSSai Praneeth Prakhya */ 3051205b688SFenghua Yu static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc) 3067f4d257eSSai Praneeth Prakhya { 3077f4d257eSSai Praneeth Prakhya float reads, writes, of_mul_read, of_mul_write; 3087f4d257eSSai Praneeth Prakhya int imc, j, ret; 3097f4d257eSSai Praneeth Prakhya 3107f4d257eSSai Praneeth Prakhya /* Start all iMC counters to log values (both read and write) */ 3117f4d257eSSai Praneeth Prakhya reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1; 3127f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 3137f4d257eSSai Praneeth Prakhya for (j = 0; j < 2; j++) { 3147f4d257eSSai Praneeth Prakhya ret = open_perf_event(imc, cpu_no, j); 3157f4d257eSSai Praneeth Prakhya if (ret) 3167f4d257eSSai Praneeth Prakhya return -1; 3177f4d257eSSai Praneeth Prakhya } 3187f4d257eSSai Praneeth Prakhya for (j = 0; j < 2; j++) 3197f4d257eSSai Praneeth Prakhya membw_ioctl_perf_event_ioc_reset_enable(imc, j); 3207f4d257eSSai Praneeth Prakhya } 3217f4d257eSSai Praneeth Prakhya 3227f4d257eSSai Praneeth Prakhya sleep(1); 3237f4d257eSSai Praneeth Prakhya 3247f4d257eSSai Praneeth Prakhya /* Stop counters after a second to get results (both read and write) */ 3257f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 3267f4d257eSSai Praneeth Prakhya for (j = 0; j < 2; j++) 3277f4d257eSSai Praneeth Prakhya membw_ioctl_perf_event_ioc_disable(imc, j); 3287f4d257eSSai Praneeth Prakhya } 3297f4d257eSSai Praneeth Prakhya 3307f4d257eSSai Praneeth Prakhya /* 3317f4d257eSSai Praneeth Prakhya * Get results which are stored in struct type imc_counter_config 3327f4d257eSSai Praneeth Prakhya * Take over flow into consideration before calculating total b/w 3337f4d257eSSai Praneeth Prakhya */ 3347f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 3357f4d257eSSai Praneeth Prakhya struct imc_counter_config *r = 3367f4d257eSSai Praneeth Prakhya &imc_counters_config[imc][READ]; 3377f4d257eSSai Praneeth Prakhya struct imc_counter_config *w = 3387f4d257eSSai Praneeth Prakhya &imc_counters_config[imc][WRITE]; 3397f4d257eSSai Praneeth Prakhya 3407f4d257eSSai Praneeth Prakhya if (read(r->fd, &r->return_value, 3417f4d257eSSai Praneeth Prakhya sizeof(struct membw_read_format)) == -1) { 342*cc8ff7f5SIlpo Järvinen ksft_perror("Couldn't get read b/w through iMC"); 3437f4d257eSSai Praneeth Prakhya 3447f4d257eSSai Praneeth Prakhya return -1; 3457f4d257eSSai Praneeth Prakhya } 3467f4d257eSSai Praneeth Prakhya 3477f4d257eSSai Praneeth Prakhya if (read(w->fd, &w->return_value, 3487f4d257eSSai Praneeth Prakhya sizeof(struct membw_read_format)) == -1) { 349*cc8ff7f5SIlpo Järvinen ksft_perror("Couldn't get write bw through iMC"); 3507f4d257eSSai Praneeth Prakhya 3517f4d257eSSai Praneeth Prakhya return -1; 3527f4d257eSSai Praneeth Prakhya } 3537f4d257eSSai Praneeth Prakhya 3547f4d257eSSai Praneeth Prakhya __u64 r_time_enabled = r->return_value.time_enabled; 3557f4d257eSSai Praneeth Prakhya __u64 r_time_running = r->return_value.time_running; 3567f4d257eSSai Praneeth Prakhya 3577f4d257eSSai Praneeth Prakhya if (r_time_enabled != r_time_running) 3587f4d257eSSai Praneeth Prakhya of_mul_read = (float)r_time_enabled / 3597f4d257eSSai Praneeth Prakhya (float)r_time_running; 3607f4d257eSSai Praneeth Prakhya 3617f4d257eSSai Praneeth Prakhya __u64 w_time_enabled = w->return_value.time_enabled; 3627f4d257eSSai Praneeth Prakhya __u64 w_time_running = w->return_value.time_running; 3637f4d257eSSai Praneeth Prakhya 3647f4d257eSSai Praneeth Prakhya if (w_time_enabled != w_time_running) 3657f4d257eSSai Praneeth Prakhya of_mul_write = (float)w_time_enabled / 3667f4d257eSSai Praneeth Prakhya (float)w_time_running; 3677f4d257eSSai Praneeth Prakhya reads += r->return_value.value * of_mul_read * SCALE; 3687f4d257eSSai Praneeth Prakhya writes += w->return_value.value * of_mul_write * SCALE; 3697f4d257eSSai Praneeth Prakhya } 3707f4d257eSSai Praneeth Prakhya 3717f4d257eSSai Praneeth Prakhya for (imc = 0; imc < imcs; imc++) { 3727f4d257eSSai Praneeth Prakhya close(imc_counters_config[imc][READ].fd); 3737f4d257eSSai Praneeth Prakhya close(imc_counters_config[imc][WRITE].fd); 3747f4d257eSSai Praneeth Prakhya } 3757f4d257eSSai Praneeth Prakhya 3761205b688SFenghua Yu if (strcmp(bw_report, "reads") == 0) { 3771205b688SFenghua Yu *bw_imc = reads; 3781205b688SFenghua Yu return 0; 3791205b688SFenghua Yu } 3807f4d257eSSai Praneeth Prakhya 3811205b688SFenghua Yu if (strcmp(bw_report, "writes") == 0) { 3821205b688SFenghua Yu *bw_imc = writes; 3831205b688SFenghua Yu return 0; 3841205b688SFenghua Yu } 3857f4d257eSSai Praneeth Prakhya 3861205b688SFenghua Yu *bw_imc = reads + writes; 3871205b688SFenghua Yu return 0; 3887f4d257eSSai Praneeth Prakhya } 3897f4d257eSSai Praneeth Prakhya 3907f4d257eSSai Praneeth Prakhya void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id) 3917f4d257eSSai Praneeth Prakhya { 3927f4d257eSSai Praneeth Prakhya if (ctrlgrp && mongrp) 3937f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH, 3947f4d257eSSai Praneeth Prakhya RESCTRL_PATH, ctrlgrp, mongrp, resource_id); 3957f4d257eSSai Praneeth Prakhya else if (!ctrlgrp && mongrp) 3967f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH, 3977f4d257eSSai Praneeth Prakhya mongrp, resource_id); 3987f4d257eSSai Praneeth Prakhya else if (ctrlgrp && !mongrp) 3997f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH, 4007f4d257eSSai Praneeth Prakhya ctrlgrp, resource_id); 4017f4d257eSSai Praneeth Prakhya else if (!ctrlgrp && !mongrp) 4027f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH, 4037f4d257eSSai Praneeth Prakhya resource_id); 4047f4d257eSSai Praneeth Prakhya } 4057f4d257eSSai Praneeth Prakhya 4067f4d257eSSai Praneeth Prakhya /* 4077f4d257eSSai Praneeth Prakhya * initialize_mem_bw_resctrl: Appropriately populate "mbm_total_path" 4087f4d257eSSai Praneeth Prakhya * @ctrlgrp: Name of the control monitor group (con_mon grp) 4097f4d257eSSai Praneeth Prakhya * @mongrp: Name of the monitor group (mon grp) 4107f4d257eSSai Praneeth Prakhya * @cpu_no: CPU number that the benchmark PID is binded to 4117f4d257eSSai Praneeth Prakhya * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc) 4127f4d257eSSai Praneeth Prakhya */ 4137f4d257eSSai Praneeth Prakhya static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp, 4147f4d257eSSai Praneeth Prakhya int cpu_no, char *resctrl_val) 4157f4d257eSSai Praneeth Prakhya { 4167f4d257eSSai Praneeth Prakhya int resource_id; 4177f4d257eSSai Praneeth Prakhya 4187f4d257eSSai Praneeth Prakhya if (get_resource_id(cpu_no, &resource_id) < 0) { 419*cc8ff7f5SIlpo Järvinen ksft_print_msg("Could not get resource_id\n"); 4207f4d257eSSai Praneeth Prakhya return; 4217f4d257eSSai Praneeth Prakhya } 4227f4d257eSSai Praneeth Prakhya 42324286736SFenghua Yu if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) 4247f4d257eSSai Praneeth Prakhya set_mbm_path(ctrlgrp, mongrp, resource_id); 4257f4d257eSSai Praneeth Prakhya 42624286736SFenghua Yu if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) { 4277f4d257eSSai Praneeth Prakhya if (ctrlgrp) 4287f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, 4297f4d257eSSai Praneeth Prakhya RESCTRL_PATH, ctrlgrp, resource_id); 4307f4d257eSSai Praneeth Prakhya else 4317f4d257eSSai Praneeth Prakhya sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, 4327f4d257eSSai Praneeth Prakhya RESCTRL_PATH, resource_id); 4337f4d257eSSai Praneeth Prakhya } 4347f4d257eSSai Praneeth Prakhya } 4357f4d257eSSai Praneeth Prakhya 4367f4d257eSSai Praneeth Prakhya /* 4377f4d257eSSai Praneeth Prakhya * Get MBM Local bytes as reported by resctrl FS 4387f4d257eSSai Praneeth Prakhya * For MBM, 4397f4d257eSSai Praneeth Prakhya * 1. If con_mon grp and mon grp are given, then read from con_mon grp's mon grp 4407f4d257eSSai Praneeth Prakhya * 2. If only con_mon grp is given, then read from con_mon grp 4417f4d257eSSai Praneeth Prakhya * 3. If both are not given, then read from root con_mon grp 4427f4d257eSSai Praneeth Prakhya * For MBA, 4437f4d257eSSai Praneeth Prakhya * 1. If con_mon grp is given, then read from it 4447f4d257eSSai Praneeth Prakhya * 2. If con_mon grp is not given, then read from root con_mon grp 4457f4d257eSSai Praneeth Prakhya */ 4461205b688SFenghua Yu static int get_mem_bw_resctrl(unsigned long *mbm_total) 4477f4d257eSSai Praneeth Prakhya { 4487f4d257eSSai Praneeth Prakhya FILE *fp; 4497f4d257eSSai Praneeth Prakhya 4507f4d257eSSai Praneeth Prakhya fp = fopen(mbm_total_path, "r"); 4517f4d257eSSai Praneeth Prakhya if (!fp) { 452*cc8ff7f5SIlpo Järvinen ksft_perror("Failed to open total bw file"); 4537f4d257eSSai Praneeth Prakhya 4547f4d257eSSai Praneeth Prakhya return -1; 4557f4d257eSSai Praneeth Prakhya } 4561205b688SFenghua Yu if (fscanf(fp, "%lu", mbm_total) <= 0) { 457*cc8ff7f5SIlpo Järvinen ksft_perror("Could not get mbm local bytes"); 4587f4d257eSSai Praneeth Prakhya fclose(fp); 4597f4d257eSSai Praneeth Prakhya 4607f4d257eSSai Praneeth Prakhya return -1; 4617f4d257eSSai Praneeth Prakhya } 4627f4d257eSSai Praneeth Prakhya fclose(fp); 4637f4d257eSSai Praneeth Prakhya 4641205b688SFenghua Yu return 0; 4657f4d257eSSai Praneeth Prakhya } 4667f4d257eSSai Praneeth Prakhya 4677f4d257eSSai Praneeth Prakhya pid_t bm_pid, ppid; 4687f4d257eSSai Praneeth Prakhya 46978941183SFenghua Yu void ctrlc_handler(int signum, siginfo_t *info, void *ptr) 4707f4d257eSSai Praneeth Prakhya { 4713aff5146SIlpo Järvinen /* Only kill child after bm_pid is set after fork() */ 4723aff5146SIlpo Järvinen if (bm_pid) 4737f4d257eSSai Praneeth Prakhya kill(bm_pid, SIGKILL); 474ecdbb911SFenghua Yu umount_resctrlfs(); 475ecdbb911SFenghua Yu tests_cleanup(); 476ca2f4214SFenghua Yu ksft_print_msg("Ending\n\n"); 4777f4d257eSSai Praneeth Prakhya 4787f4d257eSSai Praneeth Prakhya exit(EXIT_SUCCESS); 4797f4d257eSSai Praneeth Prakhya } 4807f4d257eSSai Praneeth Prakhya 4817f4d257eSSai Praneeth Prakhya /* 48273c55fa5SShaopeng Tan * Register CTRL-C handler for parent, as it has to kill 48373c55fa5SShaopeng Tan * child process before exiting. 48473c55fa5SShaopeng Tan */ 48573c55fa5SShaopeng Tan int signal_handler_register(void) 48673c55fa5SShaopeng Tan { 487beb7f471SIlpo Järvinen struct sigaction sigact = {}; 48873c55fa5SShaopeng Tan int ret = 0; 48973c55fa5SShaopeng Tan 4903aff5146SIlpo Järvinen bm_pid = 0; 4913aff5146SIlpo Järvinen 49273c55fa5SShaopeng Tan sigact.sa_sigaction = ctrlc_handler; 49373c55fa5SShaopeng Tan sigemptyset(&sigact.sa_mask); 49473c55fa5SShaopeng Tan sigact.sa_flags = SA_SIGINFO; 49573c55fa5SShaopeng Tan if (sigaction(SIGINT, &sigact, NULL) || 49673c55fa5SShaopeng Tan sigaction(SIGTERM, &sigact, NULL) || 49773c55fa5SShaopeng Tan sigaction(SIGHUP, &sigact, NULL)) { 498*cc8ff7f5SIlpo Järvinen ksft_perror("sigaction"); 49973c55fa5SShaopeng Tan ret = -1; 50073c55fa5SShaopeng Tan } 50173c55fa5SShaopeng Tan return ret; 50273c55fa5SShaopeng Tan } 50373c55fa5SShaopeng Tan 50473c55fa5SShaopeng Tan /* 50573c55fa5SShaopeng Tan * Reset signal handler to SIG_DFL. 50673c55fa5SShaopeng Tan * Non-Value return because the caller should keep 50773c55fa5SShaopeng Tan * the error code of other path even if sigaction fails. 50873c55fa5SShaopeng Tan */ 50973c55fa5SShaopeng Tan void signal_handler_unregister(void) 51073c55fa5SShaopeng Tan { 511beb7f471SIlpo Järvinen struct sigaction sigact = {}; 51273c55fa5SShaopeng Tan 51373c55fa5SShaopeng Tan sigact.sa_handler = SIG_DFL; 51473c55fa5SShaopeng Tan sigemptyset(&sigact.sa_mask); 51573c55fa5SShaopeng Tan if (sigaction(SIGINT, &sigact, NULL) || 51673c55fa5SShaopeng Tan sigaction(SIGTERM, &sigact, NULL) || 51773c55fa5SShaopeng Tan sigaction(SIGHUP, &sigact, NULL)) { 518*cc8ff7f5SIlpo Järvinen ksft_perror("sigaction"); 51973c55fa5SShaopeng Tan } 52073c55fa5SShaopeng Tan } 52173c55fa5SShaopeng Tan 52273c55fa5SShaopeng Tan /* 5237f4d257eSSai Praneeth Prakhya * print_results_bw: the memory bandwidth results are stored in a file 5247f4d257eSSai Praneeth Prakhya * @filename: file that stores the results 5257f4d257eSSai Praneeth Prakhya * @bm_pid: child pid that runs benchmark 5267f4d257eSSai Praneeth Prakhya * @bw_imc: perf imc counter value 5277f4d257eSSai Praneeth Prakhya * @bw_resc: memory bandwidth value 5287f4d257eSSai Praneeth Prakhya * 5297f4d257eSSai Praneeth Prakhya * Return: 0 on success. non-zero on failure. 5307f4d257eSSai Praneeth Prakhya */ 5317f4d257eSSai Praneeth Prakhya static int print_results_bw(char *filename, int bm_pid, float bw_imc, 5327f4d257eSSai Praneeth Prakhya unsigned long bw_resc) 5337f4d257eSSai Praneeth Prakhya { 5347f4d257eSSai Praneeth Prakhya unsigned long diff = fabs(bw_imc - bw_resc); 5357f4d257eSSai Praneeth Prakhya FILE *fp; 5367f4d257eSSai Praneeth Prakhya 5377f4d257eSSai Praneeth Prakhya if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) { 5387f4d257eSSai Praneeth Prakhya printf("Pid: %d \t Mem_BW_iMC: %f \t ", bm_pid, bw_imc); 5397f4d257eSSai Praneeth Prakhya printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff); 5407f4d257eSSai Praneeth Prakhya } else { 5417f4d257eSSai Praneeth Prakhya fp = fopen(filename, "a"); 5427f4d257eSSai Praneeth Prakhya if (!fp) { 543*cc8ff7f5SIlpo Järvinen ksft_perror("Cannot open results file"); 5447f4d257eSSai Praneeth Prakhya 5457f4d257eSSai Praneeth Prakhya return errno; 5467f4d257eSSai Praneeth Prakhya } 5477f4d257eSSai Praneeth Prakhya if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n", 5487f4d257eSSai Praneeth Prakhya bm_pid, bw_imc, bw_resc, diff) <= 0) { 549*cc8ff7f5SIlpo Järvinen ksft_print_msg("Could not log results\n"); 5507f4d257eSSai Praneeth Prakhya fclose(fp); 5517f4d257eSSai Praneeth Prakhya 5527f4d257eSSai Praneeth Prakhya return errno; 5537f4d257eSSai Praneeth Prakhya } 5547f4d257eSSai Praneeth Prakhya fclose(fp); 5557f4d257eSSai Praneeth Prakhya } 5567f4d257eSSai Praneeth Prakhya 5577f4d257eSSai Praneeth Prakhya return 0; 5587f4d257eSSai Praneeth Prakhya } 5597f4d257eSSai Praneeth Prakhya 5602f320911SFenghua Yu static void set_cmt_path(const char *ctrlgrp, const char *mongrp, char sock_num) 56178941183SFenghua Yu { 56278941183SFenghua Yu if (strlen(ctrlgrp) && strlen(mongrp)) 56378941183SFenghua Yu sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH, 56478941183SFenghua Yu ctrlgrp, mongrp, sock_num); 56578941183SFenghua Yu else if (!strlen(ctrlgrp) && strlen(mongrp)) 56678941183SFenghua Yu sprintf(llc_occup_path, MON_LCC_OCCUP_PATH, RESCTRL_PATH, 56778941183SFenghua Yu mongrp, sock_num); 56878941183SFenghua Yu else if (strlen(ctrlgrp) && !strlen(mongrp)) 56978941183SFenghua Yu sprintf(llc_occup_path, CON_LCC_OCCUP_PATH, RESCTRL_PATH, 57078941183SFenghua Yu ctrlgrp, sock_num); 57178941183SFenghua Yu else if (!strlen(ctrlgrp) && !strlen(mongrp)) 57278941183SFenghua Yu sprintf(llc_occup_path, LCC_OCCUP_PATH, RESCTRL_PATH, sock_num); 57378941183SFenghua Yu } 57478941183SFenghua Yu 57578941183SFenghua Yu /* 57678941183SFenghua Yu * initialize_llc_occu_resctrl: Appropriately populate "llc_occup_path" 57778941183SFenghua Yu * @ctrlgrp: Name of the control monitor group (con_mon grp) 57878941183SFenghua Yu * @mongrp: Name of the monitor group (mon grp) 57978941183SFenghua Yu * @cpu_no: CPU number that the benchmark PID is binded to 5802f320911SFenghua Yu * @resctrl_val: Resctrl feature (Eg: cat, cmt.. etc) 58178941183SFenghua Yu */ 58278941183SFenghua Yu static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp, 58378941183SFenghua Yu int cpu_no, char *resctrl_val) 58478941183SFenghua Yu { 58578941183SFenghua Yu int resource_id; 58678941183SFenghua Yu 58778941183SFenghua Yu if (get_resource_id(cpu_no, &resource_id) < 0) { 588*cc8ff7f5SIlpo Järvinen ksft_print_msg("Could not get resource_id\n"); 58978941183SFenghua Yu return; 59078941183SFenghua Yu } 59178941183SFenghua Yu 5922f320911SFenghua Yu if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) 5932f320911SFenghua Yu set_cmt_path(ctrlgrp, mongrp, resource_id); 59478941183SFenghua Yu } 59578941183SFenghua Yu 5967f4d257eSSai Praneeth Prakhya static int 5977f4d257eSSai Praneeth Prakhya measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start) 5987f4d257eSSai Praneeth Prakhya { 5991205b688SFenghua Yu unsigned long bw_resc, bw_resc_end; 6001205b688SFenghua Yu float bw_imc; 6017f4d257eSSai Praneeth Prakhya int ret; 6027f4d257eSSai Praneeth Prakhya 6037f4d257eSSai Praneeth Prakhya /* 6047f4d257eSSai Praneeth Prakhya * Measure memory bandwidth from resctrl and from 6057f4d257eSSai Praneeth Prakhya * another source which is perf imc value or could 6067f4d257eSSai Praneeth Prakhya * be something else if perf imc event is not available. 6077f4d257eSSai Praneeth Prakhya * Compare the two values to validate resctrl value. 6087f4d257eSSai Praneeth Prakhya * It takes 1sec to measure the data. 6097f4d257eSSai Praneeth Prakhya */ 6101205b688SFenghua Yu ret = get_mem_bw_imc(param->cpu_no, param->bw_report, &bw_imc); 6111205b688SFenghua Yu if (ret < 0) 6121205b688SFenghua Yu return ret; 6137f4d257eSSai Praneeth Prakhya 6141205b688SFenghua Yu ret = get_mem_bw_resctrl(&bw_resc_end); 6151205b688SFenghua Yu if (ret < 0) 6161205b688SFenghua Yu return ret; 6177f4d257eSSai Praneeth Prakhya 6187f4d257eSSai Praneeth Prakhya bw_resc = (bw_resc_end - *bw_resc_start) / MB; 6197f4d257eSSai Praneeth Prakhya ret = print_results_bw(param->filename, bm_pid, bw_imc, bw_resc); 6207f4d257eSSai Praneeth Prakhya if (ret) 6217f4d257eSSai Praneeth Prakhya return ret; 6227f4d257eSSai Praneeth Prakhya 6237f4d257eSSai Praneeth Prakhya *bw_resc_start = bw_resc_end; 6247f4d257eSSai Praneeth Prakhya 6257f4d257eSSai Praneeth Prakhya return 0; 6267f4d257eSSai Praneeth Prakhya } 6277f4d257eSSai Praneeth Prakhya 6287f4d257eSSai Praneeth Prakhya /* 629508934b5SMaciej Wieczor-Retman * run_benchmark - Run a specified benchmark or fill_buf (default benchmark) 630508934b5SMaciej Wieczor-Retman * in specified signal. Direct benchmark stdio to /dev/null. 631508934b5SMaciej Wieczor-Retman * @signum: signal number 632508934b5SMaciej Wieczor-Retman * @info: signal info 633508934b5SMaciej Wieczor-Retman * @ucontext: user context in signal handling 634508934b5SMaciej Wieczor-Retman */ 635508934b5SMaciej Wieczor-Retman static void run_benchmark(int signum, siginfo_t *info, void *ucontext) 636508934b5SMaciej Wieczor-Retman { 637508934b5SMaciej Wieczor-Retman int operation, ret, memflush; 638508934b5SMaciej Wieczor-Retman char **benchmark_cmd; 639508934b5SMaciej Wieczor-Retman size_t span; 640508934b5SMaciej Wieczor-Retman bool once; 641508934b5SMaciej Wieczor-Retman FILE *fp; 642508934b5SMaciej Wieczor-Retman 643508934b5SMaciej Wieczor-Retman benchmark_cmd = info->si_ptr; 644508934b5SMaciej Wieczor-Retman 645508934b5SMaciej Wieczor-Retman /* 646508934b5SMaciej Wieczor-Retman * Direct stdio of child to /dev/null, so that only parent writes to 647508934b5SMaciej Wieczor-Retman * stdio (console) 648508934b5SMaciej Wieczor-Retman */ 649508934b5SMaciej Wieczor-Retman fp = freopen("/dev/null", "w", stdout); 650*cc8ff7f5SIlpo Järvinen if (!fp) { 651*cc8ff7f5SIlpo Järvinen ksft_perror("Unable to direct benchmark status to /dev/null"); 652*cc8ff7f5SIlpo Järvinen PARENT_EXIT(); 653*cc8ff7f5SIlpo Järvinen } 654508934b5SMaciej Wieczor-Retman 655508934b5SMaciej Wieczor-Retman if (strcmp(benchmark_cmd[0], "fill_buf") == 0) { 656508934b5SMaciej Wieczor-Retman /* Execute default fill_buf benchmark */ 657508934b5SMaciej Wieczor-Retman span = strtoul(benchmark_cmd[1], NULL, 10); 658508934b5SMaciej Wieczor-Retman memflush = atoi(benchmark_cmd[2]); 659508934b5SMaciej Wieczor-Retman operation = atoi(benchmark_cmd[3]); 660*cc8ff7f5SIlpo Järvinen if (!strcmp(benchmark_cmd[4], "true")) { 661508934b5SMaciej Wieczor-Retman once = true; 662*cc8ff7f5SIlpo Järvinen } else if (!strcmp(benchmark_cmd[4], "false")) { 663508934b5SMaciej Wieczor-Retman once = false; 664*cc8ff7f5SIlpo Järvinen } else { 665*cc8ff7f5SIlpo Järvinen ksft_print_msg("Invalid once parameter\n"); 666*cc8ff7f5SIlpo Järvinen PARENT_EXIT(); 667*cc8ff7f5SIlpo Järvinen } 668508934b5SMaciej Wieczor-Retman 669508934b5SMaciej Wieczor-Retman if (run_fill_buf(span, memflush, operation, once)) 670508934b5SMaciej Wieczor-Retman fprintf(stderr, "Error in running fill buffer\n"); 671508934b5SMaciej Wieczor-Retman } else { 672508934b5SMaciej Wieczor-Retman /* Execute specified benchmark */ 673508934b5SMaciej Wieczor-Retman ret = execvp(benchmark_cmd[0], benchmark_cmd); 674508934b5SMaciej Wieczor-Retman if (ret) 675*cc8ff7f5SIlpo Järvinen ksft_perror("execvp"); 676508934b5SMaciej Wieczor-Retman } 677508934b5SMaciej Wieczor-Retman 678508934b5SMaciej Wieczor-Retman fclose(stdout); 679*cc8ff7f5SIlpo Järvinen ksft_print_msg("Unable to run specified benchmark\n"); 680*cc8ff7f5SIlpo Järvinen PARENT_EXIT(); 681508934b5SMaciej Wieczor-Retman } 682508934b5SMaciej Wieczor-Retman 683508934b5SMaciej Wieczor-Retman /* 6847f4d257eSSai Praneeth Prakhya * resctrl_val: execute benchmark and measure memory bandwidth on 6857f4d257eSSai Praneeth Prakhya * the benchmark 6867f4d257eSSai Praneeth Prakhya * @benchmark_cmd: benchmark command and its arguments 6877f4d257eSSai Praneeth Prakhya * @param: parameters passed to resctrl_val() 6887f4d257eSSai Praneeth Prakhya * 6897f4d257eSSai Praneeth Prakhya * Return: 0 on success. non-zero on failure. 6907f4d257eSSai Praneeth Prakhya */ 691e33cb570SIlpo Järvinen int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *param) 6927f4d257eSSai Praneeth Prakhya { 6937f4d257eSSai Praneeth Prakhya char *resctrl_val = param->resctrl_val; 6947f4d257eSSai Praneeth Prakhya unsigned long bw_resc_start = 0; 6957f4d257eSSai Praneeth Prakhya struct sigaction sigact; 6967f4d257eSSai Praneeth Prakhya int ret = 0, pipefd[2]; 6977f4d257eSSai Praneeth Prakhya char pipe_message = 0; 6987f4d257eSSai Praneeth Prakhya union sigval value; 6997f4d257eSSai Praneeth Prakhya 7007f4d257eSSai Praneeth Prakhya if (strcmp(param->filename, "") == 0) 7017f4d257eSSai Praneeth Prakhya sprintf(param->filename, "stdio"); 7027f4d257eSSai Praneeth Prakhya 70324286736SFenghua Yu if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) || 70424286736SFenghua Yu !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) { 7057f4d257eSSai Praneeth Prakhya ret = validate_bw_report_request(param->bw_report); 7067f4d257eSSai Praneeth Prakhya if (ret) 7077f4d257eSSai Praneeth Prakhya return ret; 7087f4d257eSSai Praneeth Prakhya } 7097f4d257eSSai Praneeth Prakhya 7107f4d257eSSai Praneeth Prakhya /* 7117f4d257eSSai Praneeth Prakhya * If benchmark wasn't successfully started by child, then child should 7127f4d257eSSai Praneeth Prakhya * kill parent, so save parent's pid 7137f4d257eSSai Praneeth Prakhya */ 7147f4d257eSSai Praneeth Prakhya ppid = getpid(); 7157f4d257eSSai Praneeth Prakhya 7167f4d257eSSai Praneeth Prakhya if (pipe(pipefd)) { 717*cc8ff7f5SIlpo Järvinen ksft_perror("Unable to create pipe"); 7187f4d257eSSai Praneeth Prakhya 7197f4d257eSSai Praneeth Prakhya return -1; 7207f4d257eSSai Praneeth Prakhya } 7217f4d257eSSai Praneeth Prakhya 7227f4d257eSSai Praneeth Prakhya /* 7237f4d257eSSai Praneeth Prakhya * Fork to start benchmark, save child's pid so that it can be killed 7247f4d257eSSai Praneeth Prakhya * when needed 7257f4d257eSSai Praneeth Prakhya */ 726a080b6e7SShaopeng Tan fflush(stdout); 7277f4d257eSSai Praneeth Prakhya bm_pid = fork(); 7287f4d257eSSai Praneeth Prakhya if (bm_pid == -1) { 729*cc8ff7f5SIlpo Järvinen ksft_perror("Unable to fork"); 7307f4d257eSSai Praneeth Prakhya 7317f4d257eSSai Praneeth Prakhya return -1; 7327f4d257eSSai Praneeth Prakhya } 7337f4d257eSSai Praneeth Prakhya 7347f4d257eSSai Praneeth Prakhya if (bm_pid == 0) { 7357f4d257eSSai Praneeth Prakhya /* 7367f4d257eSSai Praneeth Prakhya * Mask all signals except SIGUSR1, parent uses SIGUSR1 to 7377f4d257eSSai Praneeth Prakhya * start benchmark 7387f4d257eSSai Praneeth Prakhya */ 7397f4d257eSSai Praneeth Prakhya sigfillset(&sigact.sa_mask); 7407f4d257eSSai Praneeth Prakhya sigdelset(&sigact.sa_mask, SIGUSR1); 7417f4d257eSSai Praneeth Prakhya 7427f4d257eSSai Praneeth Prakhya sigact.sa_sigaction = run_benchmark; 7437f4d257eSSai Praneeth Prakhya sigact.sa_flags = SA_SIGINFO; 7447f4d257eSSai Praneeth Prakhya 7457f4d257eSSai Praneeth Prakhya /* Register for "SIGUSR1" signal from parent */ 746*cc8ff7f5SIlpo Järvinen if (sigaction(SIGUSR1, &sigact, NULL)) { 747*cc8ff7f5SIlpo Järvinen ksft_perror("Can't register child for signal"); 748*cc8ff7f5SIlpo Järvinen PARENT_EXIT(); 749*cc8ff7f5SIlpo Järvinen } 7507f4d257eSSai Praneeth Prakhya 7517f4d257eSSai Praneeth Prakhya /* Tell parent that child is ready */ 7527f4d257eSSai Praneeth Prakhya close(pipefd[0]); 7537f4d257eSSai Praneeth Prakhya pipe_message = 1; 7547f4d257eSSai Praneeth Prakhya if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) < 7557f4d257eSSai Praneeth Prakhya sizeof(pipe_message)) { 756*cc8ff7f5SIlpo Järvinen ksft_perror("Failed signaling parent process"); 7577f4d257eSSai Praneeth Prakhya close(pipefd[1]); 7587f4d257eSSai Praneeth Prakhya return -1; 7597f4d257eSSai Praneeth Prakhya } 7607f4d257eSSai Praneeth Prakhya close(pipefd[1]); 7617f4d257eSSai Praneeth Prakhya 7627f4d257eSSai Praneeth Prakhya /* Suspend child until delivery of "SIGUSR1" from parent */ 7637f4d257eSSai Praneeth Prakhya sigsuspend(&sigact.sa_mask); 7647f4d257eSSai Praneeth Prakhya 765*cc8ff7f5SIlpo Järvinen ksft_perror("Child is done"); 766*cc8ff7f5SIlpo Järvinen PARENT_EXIT(); 7677f4d257eSSai Praneeth Prakhya } 7687f4d257eSSai Praneeth Prakhya 769ca2f4214SFenghua Yu ksft_print_msg("Benchmark PID: %d\n", bm_pid); 7707f4d257eSSai Praneeth Prakhya 771e33cb570SIlpo Järvinen /* 772e33cb570SIlpo Järvinen * The cast removes constness but nothing mutates benchmark_cmd within 773e33cb570SIlpo Järvinen * the context of this process. At the receiving process, it becomes 774e33cb570SIlpo Järvinen * argv, which is mutable, on exec() but that's after fork() so it 775e33cb570SIlpo Järvinen * doesn't matter for the process running the tests. 776e33cb570SIlpo Järvinen */ 777e33cb570SIlpo Järvinen value.sival_ptr = (void *)benchmark_cmd; 7787f4d257eSSai Praneeth Prakhya 7797f4d257eSSai Praneeth Prakhya /* Taskset benchmark to specified cpu */ 7807f4d257eSSai Praneeth Prakhya ret = taskset_benchmark(bm_pid, param->cpu_no); 7817f4d257eSSai Praneeth Prakhya if (ret) 7823aff5146SIlpo Järvinen goto out; 7837f4d257eSSai Praneeth Prakhya 7847f4d257eSSai Praneeth Prakhya /* Write benchmark to specified control&monitoring grp in resctrl FS */ 7857f4d257eSSai Praneeth Prakhya ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp, 7867f4d257eSSai Praneeth Prakhya resctrl_val); 7877f4d257eSSai Praneeth Prakhya if (ret) 7883aff5146SIlpo Järvinen goto out; 7897f4d257eSSai Praneeth Prakhya 79024286736SFenghua Yu if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) || 79124286736SFenghua Yu !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) { 7927f4d257eSSai Praneeth Prakhya ret = initialize_mem_bw_imc(); 7937f4d257eSSai Praneeth Prakhya if (ret) 7943aff5146SIlpo Järvinen goto out; 7957f4d257eSSai Praneeth Prakhya 7967f4d257eSSai Praneeth Prakhya initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp, 7977f4d257eSSai Praneeth Prakhya param->cpu_no, resctrl_val); 7982f320911SFenghua Yu } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) 79978941183SFenghua Yu initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp, 80078941183SFenghua Yu param->cpu_no, resctrl_val); 8017f4d257eSSai Praneeth Prakhya 8027f4d257eSSai Praneeth Prakhya /* Parent waits for child to be ready. */ 8037f4d257eSSai Praneeth Prakhya close(pipefd[1]); 8047f4d257eSSai Praneeth Prakhya while (pipe_message != 1) { 8057f4d257eSSai Praneeth Prakhya if (read(pipefd[0], &pipe_message, sizeof(pipe_message)) < 8067f4d257eSSai Praneeth Prakhya sizeof(pipe_message)) { 807*cc8ff7f5SIlpo Järvinen ksft_perror("Failed reading message from child process"); 8087f4d257eSSai Praneeth Prakhya close(pipefd[0]); 8093aff5146SIlpo Järvinen goto out; 8107f4d257eSSai Praneeth Prakhya } 8117f4d257eSSai Praneeth Prakhya } 8127f4d257eSSai Praneeth Prakhya close(pipefd[0]); 8137f4d257eSSai Praneeth Prakhya 8147f4d257eSSai Praneeth Prakhya /* Signal child to start benchmark */ 8157f4d257eSSai Praneeth Prakhya if (sigqueue(bm_pid, SIGUSR1, value) == -1) { 816*cc8ff7f5SIlpo Järvinen ksft_perror("sigqueue SIGUSR1 to child"); 8177f4d257eSSai Praneeth Prakhya ret = errno; 8183aff5146SIlpo Järvinen goto out; 8197f4d257eSSai Praneeth Prakhya } 8207f4d257eSSai Praneeth Prakhya 8217f4d257eSSai Praneeth Prakhya /* Give benchmark enough time to fully run */ 8227f4d257eSSai Praneeth Prakhya sleep(1); 8237f4d257eSSai Praneeth Prakhya 8247f4d257eSSai Praneeth Prakhya /* Test runs until the callback setup() tells the test to stop. */ 8257f4d257eSSai Praneeth Prakhya while (1) { 8268ee592a6SIlpo Järvinen ret = param->setup(param); 827fa10366cSIlpo Järvinen if (ret == END_OF_TESTS) { 8287f4d257eSSai Praneeth Prakhya ret = 0; 8297f4d257eSSai Praneeth Prakhya break; 8307f4d257eSSai Praneeth Prakhya } 831fa10366cSIlpo Järvinen if (ret < 0) 832fa10366cSIlpo Järvinen break; 8337f4d257eSSai Praneeth Prakhya 834c90b3b58SIlpo Järvinen if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) || 835c90b3b58SIlpo Järvinen !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) { 8367f4d257eSSai Praneeth Prakhya ret = measure_vals(param, &bw_resc_start); 8377f4d257eSSai Praneeth Prakhya if (ret) 8387f4d257eSSai Praneeth Prakhya break; 8392f320911SFenghua Yu } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) { 84078941183SFenghua Yu sleep(1); 84178941183SFenghua Yu ret = measure_cache_vals(param, bm_pid); 8427f4d257eSSai Praneeth Prakhya if (ret) 8437f4d257eSSai Praneeth Prakhya break; 8447f4d257eSSai Praneeth Prakhya } 8457f4d257eSSai Praneeth Prakhya } 8467f4d257eSSai Praneeth Prakhya 8477f4d257eSSai Praneeth Prakhya out: 8487f4d257eSSai Praneeth Prakhya kill(bm_pid, SIGKILL); 8497f4d257eSSai Praneeth Prakhya 8507f4d257eSSai Praneeth Prakhya return ret; 8517f4d257eSSai Praneeth Prakhya } 852