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