162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Basic resctrl file system operations 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018 Intel Corporation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: 862306a36Sopenharmony_ci * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, 962306a36Sopenharmony_ci * Fenghua Yu <fenghua.yu@intel.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <limits.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "resctrl.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic int find_resctrl_mount(char *buffer) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci FILE *mounts; 1862306a36Sopenharmony_ci char line[256], *fs, *mntpoint; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci mounts = fopen("/proc/mounts", "r"); 2162306a36Sopenharmony_ci if (!mounts) { 2262306a36Sopenharmony_ci perror("/proc/mounts"); 2362306a36Sopenharmony_ci return -ENXIO; 2462306a36Sopenharmony_ci } 2562306a36Sopenharmony_ci while (!feof(mounts)) { 2662306a36Sopenharmony_ci if (!fgets(line, 256, mounts)) 2762306a36Sopenharmony_ci break; 2862306a36Sopenharmony_ci fs = strtok(line, " \t"); 2962306a36Sopenharmony_ci if (!fs) 3062306a36Sopenharmony_ci continue; 3162306a36Sopenharmony_ci mntpoint = strtok(NULL, " \t"); 3262306a36Sopenharmony_ci if (!mntpoint) 3362306a36Sopenharmony_ci continue; 3462306a36Sopenharmony_ci fs = strtok(NULL, " \t"); 3562306a36Sopenharmony_ci if (!fs) 3662306a36Sopenharmony_ci continue; 3762306a36Sopenharmony_ci if (strcmp(fs, "resctrl")) 3862306a36Sopenharmony_ci continue; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci fclose(mounts); 4162306a36Sopenharmony_ci if (buffer) 4262306a36Sopenharmony_ci strncpy(buffer, mntpoint, 256); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return 0; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci fclose(mounts); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci return -ENOENT; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * mount_resctrlfs - Mount resctrl FS at /sys/fs/resctrl 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid 5662306a36Sopenharmony_ci * pre-existing settings interfering with the test results. 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ciint mount_resctrlfs(void) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci int ret; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ret = find_resctrl_mount(NULL); 6562306a36Sopenharmony_ci if (ret != -ENOENT) 6662306a36Sopenharmony_ci return -1; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH); 6962306a36Sopenharmony_ci ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL); 7062306a36Sopenharmony_ci if (ret) 7162306a36Sopenharmony_ci perror("# mount"); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciint umount_resctrlfs(void) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci char mountpoint[256]; 7962306a36Sopenharmony_ci int ret; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ret = find_resctrl_mount(mountpoint); 8262306a36Sopenharmony_ci if (ret == -ENOENT) 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci if (ret) 8562306a36Sopenharmony_ci return ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (umount(mountpoint)) { 8862306a36Sopenharmony_ci perror("# Unable to umount resctrl"); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return errno; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * get_resource_id - Get socket number/l3 id for a specified CPU 9862306a36Sopenharmony_ci * @cpu_no: CPU number 9962306a36Sopenharmony_ci * @resource_id: Socket number or l3_id 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Return: >= 0 on success, < 0 on failure. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ciint get_resource_id(int cpu_no, int *resource_id) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci char phys_pkg_path[1024]; 10662306a36Sopenharmony_ci FILE *fp; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (get_vendor() == ARCH_AMD) 10962306a36Sopenharmony_ci sprintf(phys_pkg_path, "%s%d/cache/index3/id", 11062306a36Sopenharmony_ci PHYS_ID_PATH, cpu_no); 11162306a36Sopenharmony_ci else 11262306a36Sopenharmony_ci sprintf(phys_pkg_path, "%s%d/topology/physical_package_id", 11362306a36Sopenharmony_ci PHYS_ID_PATH, cpu_no); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci fp = fopen(phys_pkg_path, "r"); 11662306a36Sopenharmony_ci if (!fp) { 11762306a36Sopenharmony_ci perror("Failed to open physical_package_id"); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return -1; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci if (fscanf(fp, "%d", resource_id) <= 0) { 12262306a36Sopenharmony_ci perror("Could not get socket number or l3 id"); 12362306a36Sopenharmony_ci fclose(fp); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return -1; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci fclose(fp); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * get_cache_size - Get cache size for a specified CPU 13462306a36Sopenharmony_ci * @cpu_no: CPU number 13562306a36Sopenharmony_ci * @cache_type: Cache level L2/L3 13662306a36Sopenharmony_ci * @cache_size: pointer to cache_size 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Return: = 0 on success, < 0 on failure. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ciint get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci char cache_path[1024], cache_str[64]; 14362306a36Sopenharmony_ci int length, i, cache_num; 14462306a36Sopenharmony_ci FILE *fp; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (!strcmp(cache_type, "L3")) { 14762306a36Sopenharmony_ci cache_num = 3; 14862306a36Sopenharmony_ci } else if (!strcmp(cache_type, "L2")) { 14962306a36Sopenharmony_ci cache_num = 2; 15062306a36Sopenharmony_ci } else { 15162306a36Sopenharmony_ci perror("Invalid cache level"); 15262306a36Sopenharmony_ci return -1; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size", 15662306a36Sopenharmony_ci cpu_no, cache_num); 15762306a36Sopenharmony_ci fp = fopen(cache_path, "r"); 15862306a36Sopenharmony_ci if (!fp) { 15962306a36Sopenharmony_ci perror("Failed to open cache size"); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return -1; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci if (fscanf(fp, "%s", cache_str) <= 0) { 16462306a36Sopenharmony_ci perror("Could not get cache_size"); 16562306a36Sopenharmony_ci fclose(fp); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return -1; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci fclose(fp); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci length = (int)strlen(cache_str); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci *cache_size = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci for (i = 0; i < length; i++) { 17662306a36Sopenharmony_ci if ((cache_str[i] >= '0') && (cache_str[i] <= '9')) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci *cache_size = *cache_size * 10 + (cache_str[i] - '0'); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci else if (cache_str[i] == 'K') 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci *cache_size = *cache_size * 1024; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci else if (cache_str[i] == 'M') 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci *cache_size = *cache_size * 1024 * 1024; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#define CORE_SIBLINGS_PATH "/sys/bus/cpu/devices/cpu" 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * get_cbm_mask - Get cbm mask for given cache 19962306a36Sopenharmony_ci * @cache_type: Cache level L2/L3 20062306a36Sopenharmony_ci * @cbm_mask: cbm_mask returned as a string 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * Return: = 0 on success, < 0 on failure. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ciint get_cbm_mask(char *cache_type, char *cbm_mask) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci char cbm_mask_path[1024]; 20762306a36Sopenharmony_ci FILE *fp; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (!cbm_mask) 21062306a36Sopenharmony_ci return -1; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci sprintf(cbm_mask_path, "%s/%s/cbm_mask", INFO_PATH, cache_type); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci fp = fopen(cbm_mask_path, "r"); 21562306a36Sopenharmony_ci if (!fp) { 21662306a36Sopenharmony_ci perror("Failed to open cache level"); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return -1; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci if (fscanf(fp, "%s", cbm_mask) <= 0) { 22162306a36Sopenharmony_ci perror("Could not get max cbm_mask"); 22262306a36Sopenharmony_ci fclose(fp); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return -1; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci fclose(fp); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* 23262306a36Sopenharmony_ci * get_core_sibling - Get sibling core id from the same socket for given CPU 23362306a36Sopenharmony_ci * @cpu_no: CPU number 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * Return: > 0 on success, < 0 on failure. 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ciint get_core_sibling(int cpu_no) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci char core_siblings_path[1024], cpu_list_str[64]; 24062306a36Sopenharmony_ci int sibling_cpu_no = -1; 24162306a36Sopenharmony_ci FILE *fp; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci sprintf(core_siblings_path, "%s%d/topology/core_siblings_list", 24462306a36Sopenharmony_ci CORE_SIBLINGS_PATH, cpu_no); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci fp = fopen(core_siblings_path, "r"); 24762306a36Sopenharmony_ci if (!fp) { 24862306a36Sopenharmony_ci perror("Failed to open core siblings path"); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return -1; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci if (fscanf(fp, "%s", cpu_list_str) <= 0) { 25362306a36Sopenharmony_ci perror("Could not get core_siblings list"); 25462306a36Sopenharmony_ci fclose(fp); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return -1; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci fclose(fp); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci char *token = strtok(cpu_list_str, "-,"); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci while (token) { 26362306a36Sopenharmony_ci sibling_cpu_no = atoi(token); 26462306a36Sopenharmony_ci /* Skipping core 0 as we don't want to run test on core 0 */ 26562306a36Sopenharmony_ci if (sibling_cpu_no != 0 && sibling_cpu_no != cpu_no) 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci token = strtok(NULL, "-,"); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return sibling_cpu_no; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* 27462306a36Sopenharmony_ci * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu 27562306a36Sopenharmony_ci * @bm_pid: PID that should be binded 27662306a36Sopenharmony_ci * @cpu_no: CPU number at which the PID would be binded 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ciint taskset_benchmark(pid_t bm_pid, int cpu_no) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci cpu_set_t my_set; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci CPU_ZERO(&my_set); 28562306a36Sopenharmony_ci CPU_SET(cpu_no, &my_set); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) { 28862306a36Sopenharmony_ci perror("Unable to taskset benchmark"); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return -1; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return 0; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/* 29762306a36Sopenharmony_ci * run_benchmark - Run a specified benchmark or fill_buf (default benchmark) 29862306a36Sopenharmony_ci * in specified signal. Direct benchmark stdio to /dev/null. 29962306a36Sopenharmony_ci * @signum: signal number 30062306a36Sopenharmony_ci * @info: signal info 30162306a36Sopenharmony_ci * @ucontext: user context in signal handling 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Return: void 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_civoid run_benchmark(int signum, siginfo_t *info, void *ucontext) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci int operation, ret, memflush; 30862306a36Sopenharmony_ci char **benchmark_cmd; 30962306a36Sopenharmony_ci size_t span; 31062306a36Sopenharmony_ci bool once; 31162306a36Sopenharmony_ci FILE *fp; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci benchmark_cmd = info->si_ptr; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * Direct stdio of child to /dev/null, so that only parent writes to 31762306a36Sopenharmony_ci * stdio (console) 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci fp = freopen("/dev/null", "w", stdout); 32062306a36Sopenharmony_ci if (!fp) 32162306a36Sopenharmony_ci PARENT_EXIT("Unable to direct benchmark status to /dev/null"); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (strcmp(benchmark_cmd[0], "fill_buf") == 0) { 32462306a36Sopenharmony_ci /* Execute default fill_buf benchmark */ 32562306a36Sopenharmony_ci span = strtoul(benchmark_cmd[1], NULL, 10); 32662306a36Sopenharmony_ci memflush = atoi(benchmark_cmd[2]); 32762306a36Sopenharmony_ci operation = atoi(benchmark_cmd[3]); 32862306a36Sopenharmony_ci if (!strcmp(benchmark_cmd[4], "true")) 32962306a36Sopenharmony_ci once = true; 33062306a36Sopenharmony_ci else if (!strcmp(benchmark_cmd[4], "false")) 33162306a36Sopenharmony_ci once = false; 33262306a36Sopenharmony_ci else 33362306a36Sopenharmony_ci PARENT_EXIT("Invalid once parameter"); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (run_fill_buf(span, memflush, operation, once)) 33662306a36Sopenharmony_ci fprintf(stderr, "Error in running fill buffer\n"); 33762306a36Sopenharmony_ci } else { 33862306a36Sopenharmony_ci /* Execute specified benchmark */ 33962306a36Sopenharmony_ci ret = execvp(benchmark_cmd[0], benchmark_cmd); 34062306a36Sopenharmony_ci if (ret) 34162306a36Sopenharmony_ci perror("wrong\n"); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci fclose(stdout); 34562306a36Sopenharmony_ci PARENT_EXIT("Unable to run specified benchmark"); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* 34962306a36Sopenharmony_ci * create_grp - Create a group only if one doesn't exist 35062306a36Sopenharmony_ci * @grp_name: Name of the group 35162306a36Sopenharmony_ci * @grp: Full path and name of the group 35262306a36Sopenharmony_ci * @parent_grp: Full path and name of the parent group 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_cistatic int create_grp(const char *grp_name, char *grp, const char *parent_grp) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int found_grp = 0; 35962306a36Sopenharmony_ci struct dirent *ep; 36062306a36Sopenharmony_ci DIR *dp; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* 36362306a36Sopenharmony_ci * At this point, we are guaranteed to have resctrl FS mounted and if 36462306a36Sopenharmony_ci * length of grp_name == 0, it means, user wants to use root con_mon 36562306a36Sopenharmony_ci * grp, so do nothing 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci if (strlen(grp_name) == 0) 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Check if requested grp exists or not */ 37162306a36Sopenharmony_ci dp = opendir(parent_grp); 37262306a36Sopenharmony_ci if (dp) { 37362306a36Sopenharmony_ci while ((ep = readdir(dp)) != NULL) { 37462306a36Sopenharmony_ci if (strcmp(ep->d_name, grp_name) == 0) 37562306a36Sopenharmony_ci found_grp = 1; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci closedir(dp); 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci perror("Unable to open resctrl for group"); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci return -1; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Requested grp doesn't exist, hence create it */ 38562306a36Sopenharmony_ci if (found_grp == 0) { 38662306a36Sopenharmony_ci if (mkdir(grp, 0) == -1) { 38762306a36Sopenharmony_ci perror("Unable to create group"); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return -1; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int write_pid_to_tasks(char *tasks, pid_t pid) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci FILE *fp; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci fp = fopen(tasks, "w"); 40162306a36Sopenharmony_ci if (!fp) { 40262306a36Sopenharmony_ci perror("Failed to open tasks file"); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return -1; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (fprintf(fp, "%d\n", pid) < 0) { 40762306a36Sopenharmony_ci perror("Failed to wr pid to tasks file"); 40862306a36Sopenharmony_ci fclose(fp); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return -1; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci fclose(fp); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS 41962306a36Sopenharmony_ci * @bm_pid: PID that should be written 42062306a36Sopenharmony_ci * @ctrlgrp: Name of the control monitor group (con_mon grp) 42162306a36Sopenharmony_ci * @mongrp: Name of the monitor group (mon grp) 42262306a36Sopenharmony_ci * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc) 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * If a con_mon grp is requested, create it and write pid to it, otherwise 42562306a36Sopenharmony_ci * write pid to root con_mon grp. 42662306a36Sopenharmony_ci * If a mon grp is requested, create it and write pid to it, otherwise 42762306a36Sopenharmony_ci * pid is not written, this means that pid is in con_mon grp and hence 42862306a36Sopenharmony_ci * should consult con_mon grp's mon_data directory for results. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ciint write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp, 43362306a36Sopenharmony_ci char *resctrl_val) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci char controlgroup[128], monitorgroup[512], monitorgroup_p[256]; 43662306a36Sopenharmony_ci char tasks[1024]; 43762306a36Sopenharmony_ci int ret = 0; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (strlen(ctrlgrp)) 44062306a36Sopenharmony_ci sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp); 44162306a36Sopenharmony_ci else 44262306a36Sopenharmony_ci sprintf(controlgroup, "%s", RESCTRL_PATH); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Create control and monitoring group and write pid into it */ 44562306a36Sopenharmony_ci ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH); 44662306a36Sopenharmony_ci if (ret) 44762306a36Sopenharmony_ci goto out; 44862306a36Sopenharmony_ci sprintf(tasks, "%s/tasks", controlgroup); 44962306a36Sopenharmony_ci ret = write_pid_to_tasks(tasks, bm_pid); 45062306a36Sopenharmony_ci if (ret) 45162306a36Sopenharmony_ci goto out; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Create mon grp and write pid into it for "mbm" and "cmt" test */ 45462306a36Sopenharmony_ci if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)) || 45562306a36Sopenharmony_ci !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) { 45662306a36Sopenharmony_ci if (strlen(mongrp)) { 45762306a36Sopenharmony_ci sprintf(monitorgroup_p, "%s/mon_groups", controlgroup); 45862306a36Sopenharmony_ci sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp); 45962306a36Sopenharmony_ci ret = create_grp(mongrp, monitorgroup, monitorgroup_p); 46062306a36Sopenharmony_ci if (ret) 46162306a36Sopenharmony_ci goto out; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci sprintf(tasks, "%s/mon_groups/%s/tasks", 46462306a36Sopenharmony_ci controlgroup, mongrp); 46562306a36Sopenharmony_ci ret = write_pid_to_tasks(tasks, bm_pid); 46662306a36Sopenharmony_ci if (ret) 46762306a36Sopenharmony_ci goto out; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciout: 47262306a36Sopenharmony_ci ksft_print_msg("Writing benchmark parameters to resctrl FS\n"); 47362306a36Sopenharmony_ci if (ret) 47462306a36Sopenharmony_ci perror("# writing to resctrlfs"); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return ret; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/* 48062306a36Sopenharmony_ci * write_schemata - Update schemata of a con_mon grp 48162306a36Sopenharmony_ci * @ctrlgrp: Name of the con_mon grp 48262306a36Sopenharmony_ci * @schemata: Schemata that should be updated to 48362306a36Sopenharmony_ci * @cpu_no: CPU number that the benchmark PID is binded to 48462306a36Sopenharmony_ci * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc) 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * Update schemata of a con_mon grp *only* if requested resctrl feature is 48762306a36Sopenharmony_ci * allocation type 48862306a36Sopenharmony_ci * 48962306a36Sopenharmony_ci * Return: 0 on success, non-zero on failure 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ciint write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci char controlgroup[1024], schema[1024], reason[64]; 49462306a36Sopenharmony_ci int resource_id, ret = 0; 49562306a36Sopenharmony_ci FILE *fp; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) && 49862306a36Sopenharmony_ci strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) && 49962306a36Sopenharmony_ci strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) && 50062306a36Sopenharmony_ci strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) 50162306a36Sopenharmony_ci return -ENOENT; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!schemata) { 50462306a36Sopenharmony_ci ksft_print_msg("Skipping empty schemata update\n"); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return -1; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (get_resource_id(cpu_no, &resource_id) < 0) { 51062306a36Sopenharmony_ci sprintf(reason, "Failed to get resource id"); 51162306a36Sopenharmony_ci ret = -1; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (strlen(ctrlgrp) != 0) 51762306a36Sopenharmony_ci sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp); 51862306a36Sopenharmony_ci else 51962306a36Sopenharmony_ci sprintf(controlgroup, "%s/schemata", RESCTRL_PATH); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) || 52262306a36Sopenharmony_ci !strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) 52362306a36Sopenharmony_ci sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=', schemata); 52462306a36Sopenharmony_ci if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) || 52562306a36Sopenharmony_ci !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) 52662306a36Sopenharmony_ci sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci fp = fopen(controlgroup, "w"); 52962306a36Sopenharmony_ci if (!fp) { 53062306a36Sopenharmony_ci sprintf(reason, "Failed to open control group"); 53162306a36Sopenharmony_ci ret = -1; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci goto out; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (fprintf(fp, "%s\n", schema) < 0) { 53762306a36Sopenharmony_ci sprintf(reason, "Failed to write schemata in control group"); 53862306a36Sopenharmony_ci fclose(fp); 53962306a36Sopenharmony_ci ret = -1; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci goto out; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci fclose(fp); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciout: 54662306a36Sopenharmony_ci ksft_print_msg("Write schema \"%s\" to resctrl FS%s%s\n", 54762306a36Sopenharmony_ci schema, ret ? " # " : "", 54862306a36Sopenharmony_ci ret ? reason : ""); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return ret; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cibool check_resctrlfs_support(void) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci FILE *inf = fopen("/proc/filesystems", "r"); 55662306a36Sopenharmony_ci DIR *dp; 55762306a36Sopenharmony_ci char *res; 55862306a36Sopenharmony_ci bool ret = false; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (!inf) 56162306a36Sopenharmony_ci return false; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci res = fgrep(inf, "nodev\tresctrl\n"); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (res) { 56662306a36Sopenharmony_ci ret = true; 56762306a36Sopenharmony_ci free(res); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci fclose(inf); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ksft_print_msg("%s Check kernel supports resctrl filesystem\n", 57362306a36Sopenharmony_ci ret ? "Pass:" : "Fail:"); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (!ret) 57662306a36Sopenharmony_ci return ret; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci dp = opendir(RESCTRL_PATH); 57962306a36Sopenharmony_ci ksft_print_msg("%s Check resctrl mountpoint \"%s\" exists\n", 58062306a36Sopenharmony_ci dp ? "Pass:" : "Fail:", RESCTRL_PATH); 58162306a36Sopenharmony_ci if (dp) 58262306a36Sopenharmony_ci closedir(dp); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ksft_print_msg("resctrl filesystem %s mounted\n", 58562306a36Sopenharmony_ci find_resctrl_mount(NULL) ? "not" : "is"); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return ret; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cichar *fgrep(FILE *inf, const char *str) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci char line[256]; 59362306a36Sopenharmony_ci int slen = strlen(str); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci while (!feof(inf)) { 59662306a36Sopenharmony_ci if (!fgets(line, 256, inf)) 59762306a36Sopenharmony_ci break; 59862306a36Sopenharmony_ci if (strncmp(line, str, slen)) 59962306a36Sopenharmony_ci continue; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return strdup(line); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return NULL; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci/* 60862306a36Sopenharmony_ci * validate_resctrl_feature_request - Check if requested feature is valid. 60962306a36Sopenharmony_ci * @resource: Required resource (e.g., MB, L3, L2, L3_MON, etc.) 61062306a36Sopenharmony_ci * @feature: Required monitor feature (in mon_features file). Can only be 61162306a36Sopenharmony_ci * set for L3_MON. Must be NULL for all other resources. 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * Return: True if the resource/feature is supported, else false. False is 61462306a36Sopenharmony_ci * also returned if resctrl FS is not mounted. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_cibool validate_resctrl_feature_request(const char *resource, const char *feature) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci char res_path[PATH_MAX]; 61962306a36Sopenharmony_ci struct stat statbuf; 62062306a36Sopenharmony_ci char *res; 62162306a36Sopenharmony_ci FILE *inf; 62262306a36Sopenharmony_ci int ret; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (!resource) 62562306a36Sopenharmony_ci return false; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci ret = find_resctrl_mount(NULL); 62862306a36Sopenharmony_ci if (ret) 62962306a36Sopenharmony_ci return false; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci snprintf(res_path, sizeof(res_path), "%s/%s", INFO_PATH, resource); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (stat(res_path, &statbuf)) 63462306a36Sopenharmony_ci return false; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (!feature) 63762306a36Sopenharmony_ci return true; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci snprintf(res_path, sizeof(res_path), "%s/%s/mon_features", INFO_PATH, resource); 64062306a36Sopenharmony_ci inf = fopen(res_path, "r"); 64162306a36Sopenharmony_ci if (!inf) 64262306a36Sopenharmony_ci return false; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci res = fgrep(inf, feature); 64562306a36Sopenharmony_ci free(res); 64662306a36Sopenharmony_ci fclose(inf); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return !!res; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ciint filter_dmesg(void) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci char line[1024]; 65462306a36Sopenharmony_ci FILE *fp; 65562306a36Sopenharmony_ci int pipefds[2]; 65662306a36Sopenharmony_ci pid_t pid; 65762306a36Sopenharmony_ci int ret; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci ret = pipe(pipefds); 66062306a36Sopenharmony_ci if (ret) { 66162306a36Sopenharmony_ci perror("pipe"); 66262306a36Sopenharmony_ci return ret; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci fflush(stdout); 66562306a36Sopenharmony_ci pid = fork(); 66662306a36Sopenharmony_ci if (pid == 0) { 66762306a36Sopenharmony_ci close(pipefds[0]); 66862306a36Sopenharmony_ci dup2(pipefds[1], STDOUT_FILENO); 66962306a36Sopenharmony_ci execlp("dmesg", "dmesg", NULL); 67062306a36Sopenharmony_ci perror("executing dmesg"); 67162306a36Sopenharmony_ci exit(1); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci close(pipefds[1]); 67462306a36Sopenharmony_ci fp = fdopen(pipefds[0], "r"); 67562306a36Sopenharmony_ci if (!fp) { 67662306a36Sopenharmony_ci perror("fdopen(pipe)"); 67762306a36Sopenharmony_ci kill(pid, SIGTERM); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return -1; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci while (fgets(line, 1024, fp)) { 68362306a36Sopenharmony_ci if (strstr(line, "intel_rdt:")) 68462306a36Sopenharmony_ci ksft_print_msg("dmesg: %s", line); 68562306a36Sopenharmony_ci if (strstr(line, "resctrl:")) 68662306a36Sopenharmony_ci ksft_print_msg("dmesg: %s", line); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci fclose(fp); 68962306a36Sopenharmony_ci waitpid(pid, NULL, 0); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ciint validate_bw_report_request(char *bw_report) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci if (strcmp(bw_report, "reads") == 0) 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_ci if (strcmp(bw_report, "writes") == 0) 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci if (strcmp(bw_report, "nt-writes") == 0) { 70162306a36Sopenharmony_ci strcpy(bw_report, "writes"); 70262306a36Sopenharmony_ci return 0; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci if (strcmp(bw_report, "total") == 0) 70562306a36Sopenharmony_ci return 0; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci fprintf(stderr, "Requested iMC B/W report type unavailable\n"); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return -1; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ciint perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, 71362306a36Sopenharmony_ci int group_fd, unsigned long flags) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci int ret; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, 71862306a36Sopenharmony_ci group_fd, flags); 71962306a36Sopenharmony_ci return ret; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ciunsigned int count_bits(unsigned long n) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci unsigned int count = 0; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci while (n) { 72762306a36Sopenharmony_ci count += n & 1; 72862306a36Sopenharmony_ci n >>= 1; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return count; 73262306a36Sopenharmony_ci} 733