854 lines · 18.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Basic resctrl file system operations * * Copyright (C) 2018 Intel Corporation * * Authors: *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, *    Fenghua Yu <fenghua.yu@intel.com> */#include <fcntl.h>#include <limits.h> #include "resctrl.h" static int find_resctrl_mount(char *buffer){	FILE *mounts;	char line[256], *fs, *mntpoint; 	mounts = fopen("/proc/mounts", "r");	if (!mounts) {		ksft_perror("/proc/mounts");		return -ENXIO;	}	while (!feof(mounts)) {		if (!fgets(line, 256, mounts))			break;		fs = strtok(line, " \t");		if (!fs)			continue;		mntpoint = strtok(NULL, " \t");		if (!mntpoint)			continue;		fs = strtok(NULL, " \t");		if (!fs)			continue;		if (strcmp(fs, "resctrl"))			continue; 		fclose(mounts);		if (buffer)			strncpy(buffer, mntpoint, 256); 		return 0;	} 	fclose(mounts); 	return -ENOENT;} /* * mount_resctrlfs - Mount resctrl FS at /sys/fs/resctrl * * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid * pre-existing settings interfering with the test results. * * Return: 0 on success, < 0 on error. */int mount_resctrlfs(void){	int ret; 	ret = find_resctrl_mount(NULL);	if (ret != -ENOENT)		return -1; 	ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH);	ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL);	if (ret)		ksft_perror("mount"); 	return ret;} int umount_resctrlfs(void){	char mountpoint[256];	int ret; 	ret = find_resctrl_mount(mountpoint);	if (ret == -ENOENT)		return 0;	if (ret)		return ret; 	if (umount(mountpoint)) {		ksft_perror("Unable to umount resctrl"); 		return -1;	} 	return 0;} /* * get_cache_level - Convert cache level from string to integer * @cache_type:		Cache level as string * * Return: cache level as integer or -1 if @cache_type is invalid. */static int get_cache_level(const char *cache_type){	if (!strcmp(cache_type, "L3"))		return 3;	if (!strcmp(cache_type, "L2"))		return 2; 	ksft_print_msg("Invalid cache level\n");	return -1;} static int get_resource_cache_level(const char *resource){	/* "MB" use L3 (LLC) as resource */	if (!strcmp(resource, "MB"))		return 3;	return get_cache_level(resource);} /* * get_domain_id - Get resctrl domain ID for a specified CPU * @resource:	resource name * @cpu_no:	CPU number * @domain_id:	domain ID (cache ID; for MB, L3 cache ID) * * Return: >= 0 on success, < 0 on failure. */int get_domain_id(const char *resource, int cpu_no, int *domain_id){	char phys_pkg_path[1024];	int cache_num;	FILE *fp; 	cache_num = get_resource_cache_level(resource);	if (cache_num < 0)		return cache_num; 	sprintf(phys_pkg_path, "%s%d/cache/index%d/id", PHYS_ID_PATH, cpu_no, cache_num); 	fp = fopen(phys_pkg_path, "r");	if (!fp) {		ksft_perror("Failed to open cache id file"); 		return -1;	}	if (fscanf(fp, "%d", domain_id) <= 0) {		ksft_perror("Could not get domain ID");		fclose(fp); 		return -1;	}	fclose(fp); 	return 0;} /* * get_cache_size - Get cache size for a specified CPU * @cpu_no:	CPU number * @cache_type:	Cache level L2/L3 * @cache_size:	pointer to cache_size * * Return: = 0 on success, < 0 on failure. */int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size){	char cache_path[1024], cache_str[64];	int length, i, cache_num;	FILE *fp; 	cache_num = get_cache_level(cache_type);	if (cache_num < 0)		return cache_num; 	sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",		cpu_no, cache_num);	fp = fopen(cache_path, "r");	if (!fp) {		ksft_perror("Failed to open cache size"); 		return -1;	}	if (fscanf(fp, "%63s", cache_str) <= 0) {		ksft_perror("Could not get cache_size");		fclose(fp); 		return -1;	}	fclose(fp); 	length = (int)strlen(cache_str); 	*cache_size = 0; 	for (i = 0; i < length; i++) {		if ((cache_str[i] >= '0') && (cache_str[i] <= '9')) 			*cache_size = *cache_size * 10 + (cache_str[i] - '0'); 		else if (cache_str[i] == 'K') 			*cache_size = *cache_size * 1024; 		else if (cache_str[i] == 'M') 			*cache_size = *cache_size * 1024 * 1024; 		else			break;	} 	return 0;} #define CORE_SIBLINGS_PATH	"/sys/bus/cpu/devices/cpu" /* * get_bit_mask - Get bit mask from given file * @filename:	File containing the mask * @mask:	The bit mask returned as unsigned long * * Return: = 0 on success, < 0 on failure. */static int get_bit_mask(const char *filename, unsigned long *mask){	FILE *fp; 	if (!filename || !mask)		return -1; 	fp = fopen(filename, "r");	if (!fp) {		ksft_print_msg("Failed to open bit mask file '%s': %s\n",			       filename, strerror(errno));		return -1;	} 	if (fscanf(fp, "%lx", mask) <= 0) {		ksft_print_msg("Could not read bit mask file '%s': %s\n",			       filename, strerror(errno));		fclose(fp); 		return -1;	}	fclose(fp); 	return 0;} /* * resource_info_unsigned_get - Read an unsigned value from * /sys/fs/resctrl/info/@resource/@filename * @resource:	Resource name that matches directory name in *		/sys/fs/resctrl/info * @filename:	File in /sys/fs/resctrl/info/@resource * @val:	Contains read value on success. * * Return: = 0 on success, < 0 on failure. On success the read * value is saved into @val. */int resource_info_unsigned_get(const char *resource, const char *filename,			       unsigned int *val){	char file_path[PATH_MAX];	FILE *fp; 	snprintf(file_path, sizeof(file_path), "%s/%s/%s", INFO_PATH, resource,		 filename); 	fp = fopen(file_path, "r");	if (!fp) {		ksft_print_msg("Error opening %s: %m\n", file_path);		return -1;	} 	if (fscanf(fp, "%u", val) <= 0) {		ksft_print_msg("Could not get contents of %s: %m\n", file_path);		fclose(fp);		return -1;	} 	fclose(fp);	return 0;} /* * create_bit_mask- Create bit mask from start, len pair * @start:	LSB of the mask * @len		Number of bits in the mask */unsigned long create_bit_mask(unsigned int start, unsigned int len){	return ((1UL << len) - 1UL) << start;} /* * count_contiguous_bits - Returns the longest train of bits in a bit mask * @val		A bit mask * @start	The location of the least-significant bit of the longest train * * Return:	The length of the contiguous bits in the longest train of bits */unsigned int count_contiguous_bits(unsigned long val, unsigned int *start){	unsigned long last_val;	unsigned int count = 0; 	while (val) {		last_val = val;		val &= (val >> 1);		count++;	} 	if (start) {		if (count)			*start = ffsl(last_val) - 1;		else			*start = 0;	} 	return count;} /* * get_full_cbm - Get full Cache Bit Mask (CBM) * @cache_type:	Cache type as "L2" or "L3" * @mask:	Full cache bit mask representing the maximal portion of cache *		available for allocation, returned as unsigned long. * * Return: = 0 on success, < 0 on failure. */int get_full_cbm(const char *cache_type, unsigned long *mask){	char cbm_path[PATH_MAX];	int ret; 	if (!cache_type)		return -1; 	snprintf(cbm_path, sizeof(cbm_path), "%s/%s/cbm_mask",		 INFO_PATH, cache_type); 	ret = get_bit_mask(cbm_path, mask);	if (ret || !*mask)		return -1; 	return 0;} /* * get_shareable_mask - Get shareable mask from shareable_bits * @cache_type:		Cache type as "L2" or "L3" * @shareable_mask:	Shareable mask returned as unsigned long * * Return: = 0 on success, < 0 on failure. */static int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask){	char mask_path[PATH_MAX]; 	if (!cache_type)		return -1; 	snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits",		 INFO_PATH, cache_type); 	return get_bit_mask(mask_path, shareable_mask);} /* * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits * @cache_type:		Cache type as "L2" or "L3" * @mask:		The largest exclusive portion of the cache out of the *			full CBM, returned as unsigned long * * Parts of a cache may be shared with other devices such as GPU. This function * calculates the largest exclusive portion of the cache where no other devices * besides CPU have access to the cache portion. * * Return: = 0 on success, < 0 on failure. */int get_mask_no_shareable(const char *cache_type, unsigned long *mask){	unsigned long full_mask, shareable_mask;	unsigned int start, len; 	if (get_full_cbm(cache_type, &full_mask) < 0)		return -1;	if (get_shareable_mask(cache_type, &shareable_mask) < 0)		return -1; 	len = count_contiguous_bits(full_mask & ~shareable_mask, &start);	if (!len)		return -1; 	*mask = create_bit_mask(start, len); 	return 0;} /* * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu * @bm_pid:		PID that should be binded * @cpu_no:		CPU number at which the PID would be binded * @old_affinity:	When not NULL, set to old CPU affinity * * Return: 0 on success, < 0 on error. */int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity){	cpu_set_t my_set; 	if (old_affinity) {		CPU_ZERO(old_affinity);		if (sched_getaffinity(bm_pid, sizeof(*old_affinity),				      old_affinity)) {			ksft_perror("Unable to read CPU affinity");			return -1;		}	} 	CPU_ZERO(&my_set);	CPU_SET(cpu_no, &my_set); 	if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {		ksft_perror("Unable to taskset benchmark"); 		return -1;	} 	return 0;} /* * taskset_restore - Taskset PID to the earlier CPU affinity * @bm_pid:		PID that should be reset * @old_affinity:	The old CPU affinity to restore * * Return: 0 on success, < 0 on error. */int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity){	if (sched_setaffinity(bm_pid, sizeof(*old_affinity), old_affinity)) {		ksft_perror("Unable to restore CPU affinity");		return -1;	} 	return 0;} /* * create_grp - Create a group only if one doesn't exist * @grp_name:	Name of the group * @grp:	Full path and name of the group * @parent_grp:	Full path and name of the parent group * * Creates a group @grp_name if it does not exist yet. If @grp_name is NULL, * it is interpreted as the root group which always results in success. * * Return: 0 on success, < 0 on error. */static int create_grp(const char *grp_name, char *grp, const char *parent_grp){	int found_grp = 0;	struct dirent *ep;	DIR *dp; 	if (!grp_name)		return 0; 	/* Check if requested grp exists or not */	dp = opendir(parent_grp);	if (dp) {		while ((ep = readdir(dp)) != NULL) {			if (strcmp(ep->d_name, grp_name) == 0)				found_grp = 1;		}		closedir(dp);	} else {		ksft_perror("Unable to open resctrl for group"); 		return -1;	} 	/* Requested grp doesn't exist, hence create it */	if (found_grp == 0) {		if (mkdir(grp, 0) == -1) {			ksft_perror("Unable to create group"); 			return -1;		}	} 	return 0;} static int write_pid_to_tasks(char *tasks, pid_t pid){

Lines 1–500 of 854.