1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Basic resctrl file system operations
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2018 Intel Corporation
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Authors:
8*4882a593Smuzhiyun * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
9*4882a593Smuzhiyun * Fenghua Yu <fenghua.yu@intel.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun #include "resctrl.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun int tests_run;
14*4882a593Smuzhiyun
find_resctrl_mount(char * buffer)15*4882a593Smuzhiyun static int find_resctrl_mount(char *buffer)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun FILE *mounts;
18*4882a593Smuzhiyun char line[256], *fs, *mntpoint;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun mounts = fopen("/proc/mounts", "r");
21*4882a593Smuzhiyun if (!mounts) {
22*4882a593Smuzhiyun perror("/proc/mounts");
23*4882a593Smuzhiyun return -ENXIO;
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun while (!feof(mounts)) {
26*4882a593Smuzhiyun if (!fgets(line, 256, mounts))
27*4882a593Smuzhiyun break;
28*4882a593Smuzhiyun fs = strtok(line, " \t");
29*4882a593Smuzhiyun if (!fs)
30*4882a593Smuzhiyun continue;
31*4882a593Smuzhiyun mntpoint = strtok(NULL, " \t");
32*4882a593Smuzhiyun if (!mntpoint)
33*4882a593Smuzhiyun continue;
34*4882a593Smuzhiyun fs = strtok(NULL, " \t");
35*4882a593Smuzhiyun if (!fs)
36*4882a593Smuzhiyun continue;
37*4882a593Smuzhiyun if (strcmp(fs, "resctrl"))
38*4882a593Smuzhiyun continue;
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun fclose(mounts);
41*4882a593Smuzhiyun if (buffer)
42*4882a593Smuzhiyun strncpy(buffer, mntpoint, 256);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun return 0;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun fclose(mounts);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun return -ENOENT;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * remount_resctrlfs - Remount resctrl FS at /sys/fs/resctrl
54*4882a593Smuzhiyun * @mum_resctrlfs: Should the resctrl FS be remounted?
55*4882a593Smuzhiyun *
56*4882a593Smuzhiyun * If not mounted, mount it.
57*4882a593Smuzhiyun * If mounted and mum_resctrlfs then remount resctrl FS.
58*4882a593Smuzhiyun * If mounted and !mum_resctrlfs then noop
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * Return: 0 on success, non-zero on failure
61*4882a593Smuzhiyun */
remount_resctrlfs(bool mum_resctrlfs)62*4882a593Smuzhiyun int remount_resctrlfs(bool mum_resctrlfs)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun char mountpoint[256];
65*4882a593Smuzhiyun int ret;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun ret = find_resctrl_mount(mountpoint);
68*4882a593Smuzhiyun if (ret)
69*4882a593Smuzhiyun strcpy(mountpoint, RESCTRL_PATH);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (!ret && mum_resctrlfs && umount(mountpoint)) {
72*4882a593Smuzhiyun printf("not ok unmounting \"%s\"\n", mountpoint);
73*4882a593Smuzhiyun perror("# umount");
74*4882a593Smuzhiyun tests_run++;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (!ret && !mum_resctrlfs)
78*4882a593Smuzhiyun return 0;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL);
81*4882a593Smuzhiyun printf("%sok mounting resctrl to \"%s\"\n", ret ? "not " : "",
82*4882a593Smuzhiyun RESCTRL_PATH);
83*4882a593Smuzhiyun if (ret)
84*4882a593Smuzhiyun perror("# mount");
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun tests_run++;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun return ret;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
umount_resctrlfs(void)91*4882a593Smuzhiyun int umount_resctrlfs(void)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun if (umount(RESCTRL_PATH)) {
94*4882a593Smuzhiyun perror("# Unable to umount resctrl");
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return errno;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun return 0;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /*
103*4882a593Smuzhiyun * get_resource_id - Get socket number/l3 id for a specified CPU
104*4882a593Smuzhiyun * @cpu_no: CPU number
105*4882a593Smuzhiyun * @resource_id: Socket number or l3_id
106*4882a593Smuzhiyun *
107*4882a593Smuzhiyun * Return: >= 0 on success, < 0 on failure.
108*4882a593Smuzhiyun */
get_resource_id(int cpu_no,int * resource_id)109*4882a593Smuzhiyun int get_resource_id(int cpu_no, int *resource_id)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun char phys_pkg_path[1024];
112*4882a593Smuzhiyun FILE *fp;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (is_amd)
115*4882a593Smuzhiyun sprintf(phys_pkg_path, "%s%d/cache/index3/id",
116*4882a593Smuzhiyun PHYS_ID_PATH, cpu_no);
117*4882a593Smuzhiyun else
118*4882a593Smuzhiyun sprintf(phys_pkg_path, "%s%d/topology/physical_package_id",
119*4882a593Smuzhiyun PHYS_ID_PATH, cpu_no);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun fp = fopen(phys_pkg_path, "r");
122*4882a593Smuzhiyun if (!fp) {
123*4882a593Smuzhiyun perror("Failed to open physical_package_id");
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun return -1;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun if (fscanf(fp, "%d", resource_id) <= 0) {
128*4882a593Smuzhiyun perror("Could not get socket number or l3 id");
129*4882a593Smuzhiyun fclose(fp);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return -1;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun fclose(fp);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun * get_cache_size - Get cache size for a specified CPU
140*4882a593Smuzhiyun * @cpu_no: CPU number
141*4882a593Smuzhiyun * @cache_type: Cache level L2/L3
142*4882a593Smuzhiyun * @cache_size: pointer to cache_size
143*4882a593Smuzhiyun *
144*4882a593Smuzhiyun * Return: = 0 on success, < 0 on failure.
145*4882a593Smuzhiyun */
get_cache_size(int cpu_no,char * cache_type,unsigned long * cache_size)146*4882a593Smuzhiyun int get_cache_size(int cpu_no, char *cache_type, unsigned long *cache_size)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun char cache_path[1024], cache_str[64];
149*4882a593Smuzhiyun int length, i, cache_num;
150*4882a593Smuzhiyun FILE *fp;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (!strcmp(cache_type, "L3")) {
153*4882a593Smuzhiyun cache_num = 3;
154*4882a593Smuzhiyun } else if (!strcmp(cache_type, "L2")) {
155*4882a593Smuzhiyun cache_num = 2;
156*4882a593Smuzhiyun } else {
157*4882a593Smuzhiyun perror("Invalid cache level");
158*4882a593Smuzhiyun return -1;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
162*4882a593Smuzhiyun cpu_no, cache_num);
163*4882a593Smuzhiyun fp = fopen(cache_path, "r");
164*4882a593Smuzhiyun if (!fp) {
165*4882a593Smuzhiyun perror("Failed to open cache size");
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun return -1;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun if (fscanf(fp, "%s", cache_str) <= 0) {
170*4882a593Smuzhiyun perror("Could not get cache_size");
171*4882a593Smuzhiyun fclose(fp);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return -1;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun fclose(fp);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun length = (int)strlen(cache_str);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun *cache_size = 0;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun for (i = 0; i < length; i++) {
182*4882a593Smuzhiyun if ((cache_str[i] >= '0') && (cache_str[i] <= '9'))
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun *cache_size = *cache_size * 10 + (cache_str[i] - '0');
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun else if (cache_str[i] == 'K')
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun *cache_size = *cache_size * 1024;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun else if (cache_str[i] == 'M')
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun *cache_size = *cache_size * 1024 * 1024;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun else
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun #define CORE_SIBLINGS_PATH "/sys/bus/cpu/devices/cpu"
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * get_cbm_mask - Get cbm mask for given cache
205*4882a593Smuzhiyun * @cache_type: Cache level L2/L3
206*4882a593Smuzhiyun * @cbm_mask: cbm_mask returned as a string
207*4882a593Smuzhiyun *
208*4882a593Smuzhiyun * Return: = 0 on success, < 0 on failure.
209*4882a593Smuzhiyun */
get_cbm_mask(char * cache_type,char * cbm_mask)210*4882a593Smuzhiyun int get_cbm_mask(char *cache_type, char *cbm_mask)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun char cbm_mask_path[1024];
213*4882a593Smuzhiyun FILE *fp;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun if (!cbm_mask)
216*4882a593Smuzhiyun return -1;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun sprintf(cbm_mask_path, "%s/%s/cbm_mask", CBM_MASK_PATH, cache_type);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun fp = fopen(cbm_mask_path, "r");
221*4882a593Smuzhiyun if (!fp) {
222*4882a593Smuzhiyun perror("Failed to open cache level");
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun return -1;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun if (fscanf(fp, "%s", cbm_mask) <= 0) {
227*4882a593Smuzhiyun perror("Could not get max cbm_mask");
228*4882a593Smuzhiyun fclose(fp);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun return -1;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun fclose(fp);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return 0;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /*
238*4882a593Smuzhiyun * get_core_sibling - Get sibling core id from the same socket for given CPU
239*4882a593Smuzhiyun * @cpu_no: CPU number
240*4882a593Smuzhiyun *
241*4882a593Smuzhiyun * Return: > 0 on success, < 0 on failure.
242*4882a593Smuzhiyun */
get_core_sibling(int cpu_no)243*4882a593Smuzhiyun int get_core_sibling(int cpu_no)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun char core_siblings_path[1024], cpu_list_str[64];
246*4882a593Smuzhiyun int sibling_cpu_no = -1;
247*4882a593Smuzhiyun FILE *fp;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun sprintf(core_siblings_path, "%s%d/topology/core_siblings_list",
250*4882a593Smuzhiyun CORE_SIBLINGS_PATH, cpu_no);
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun fp = fopen(core_siblings_path, "r");
253*4882a593Smuzhiyun if (!fp) {
254*4882a593Smuzhiyun perror("Failed to open core siblings path");
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun return -1;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun if (fscanf(fp, "%s", cpu_list_str) <= 0) {
259*4882a593Smuzhiyun perror("Could not get core_siblings list");
260*4882a593Smuzhiyun fclose(fp);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun return -1;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun fclose(fp);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun char *token = strtok(cpu_list_str, "-,");
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun while (token) {
269*4882a593Smuzhiyun sibling_cpu_no = atoi(token);
270*4882a593Smuzhiyun /* Skipping core 0 as we don't want to run test on core 0 */
271*4882a593Smuzhiyun if (sibling_cpu_no != 0)
272*4882a593Smuzhiyun break;
273*4882a593Smuzhiyun token = strtok(NULL, "-,");
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return sibling_cpu_no;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /*
280*4882a593Smuzhiyun * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
281*4882a593Smuzhiyun * @bm_pid: PID that should be binded
282*4882a593Smuzhiyun * @cpu_no: CPU number at which the PID would be binded
283*4882a593Smuzhiyun *
284*4882a593Smuzhiyun * Return: 0 on success, non-zero on failure
285*4882a593Smuzhiyun */
taskset_benchmark(pid_t bm_pid,int cpu_no)286*4882a593Smuzhiyun int taskset_benchmark(pid_t bm_pid, int cpu_no)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun cpu_set_t my_set;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun CPU_ZERO(&my_set);
291*4882a593Smuzhiyun CPU_SET(cpu_no, &my_set);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
294*4882a593Smuzhiyun perror("Unable to taskset benchmark");
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun return -1;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /*
303*4882a593Smuzhiyun * run_benchmark - Run a specified benchmark or fill_buf (default benchmark)
304*4882a593Smuzhiyun * in specified signal. Direct benchmark stdio to /dev/null.
305*4882a593Smuzhiyun * @signum: signal number
306*4882a593Smuzhiyun * @info: signal info
307*4882a593Smuzhiyun * @ucontext: user context in signal handling
308*4882a593Smuzhiyun *
309*4882a593Smuzhiyun * Return: void
310*4882a593Smuzhiyun */
run_benchmark(int signum,siginfo_t * info,void * ucontext)311*4882a593Smuzhiyun void run_benchmark(int signum, siginfo_t *info, void *ucontext)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun int operation, ret, malloc_and_init_memory, memflush;
314*4882a593Smuzhiyun unsigned long span, buffer_span;
315*4882a593Smuzhiyun char **benchmark_cmd;
316*4882a593Smuzhiyun char resctrl_val[64];
317*4882a593Smuzhiyun FILE *fp;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun benchmark_cmd = info->si_ptr;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun * Direct stdio of child to /dev/null, so that only parent writes to
323*4882a593Smuzhiyun * stdio (console)
324*4882a593Smuzhiyun */
325*4882a593Smuzhiyun fp = freopen("/dev/null", "w", stdout);
326*4882a593Smuzhiyun if (!fp)
327*4882a593Smuzhiyun PARENT_EXIT("Unable to direct benchmark status to /dev/null");
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
330*4882a593Smuzhiyun /* Execute default fill_buf benchmark */
331*4882a593Smuzhiyun span = strtoul(benchmark_cmd[1], NULL, 10);
332*4882a593Smuzhiyun malloc_and_init_memory = atoi(benchmark_cmd[2]);
333*4882a593Smuzhiyun memflush = atoi(benchmark_cmd[3]);
334*4882a593Smuzhiyun operation = atoi(benchmark_cmd[4]);
335*4882a593Smuzhiyun sprintf(resctrl_val, "%s", benchmark_cmd[5]);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (strncmp(resctrl_val, CQM_STR, sizeof(CQM_STR)))
338*4882a593Smuzhiyun buffer_span = span * MB;
339*4882a593Smuzhiyun else
340*4882a593Smuzhiyun buffer_span = span;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (run_fill_buf(buffer_span, malloc_and_init_memory, memflush,
343*4882a593Smuzhiyun operation, resctrl_val))
344*4882a593Smuzhiyun fprintf(stderr, "Error in running fill buffer\n");
345*4882a593Smuzhiyun } else {
346*4882a593Smuzhiyun /* Execute specified benchmark */
347*4882a593Smuzhiyun ret = execvp(benchmark_cmd[0], benchmark_cmd);
348*4882a593Smuzhiyun if (ret)
349*4882a593Smuzhiyun perror("wrong\n");
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun fclose(stdout);
353*4882a593Smuzhiyun PARENT_EXIT("Unable to run specified benchmark");
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /*
357*4882a593Smuzhiyun * create_grp - Create a group only if one doesn't exist
358*4882a593Smuzhiyun * @grp_name: Name of the group
359*4882a593Smuzhiyun * @grp: Full path and name of the group
360*4882a593Smuzhiyun * @parent_grp: Full path and name of the parent group
361*4882a593Smuzhiyun *
362*4882a593Smuzhiyun * Return: 0 on success, non-zero on failure
363*4882a593Smuzhiyun */
create_grp(const char * grp_name,char * grp,const char * parent_grp)364*4882a593Smuzhiyun static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun int found_grp = 0;
367*4882a593Smuzhiyun struct dirent *ep;
368*4882a593Smuzhiyun DIR *dp;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /*
371*4882a593Smuzhiyun * At this point, we are guaranteed to have resctrl FS mounted and if
372*4882a593Smuzhiyun * length of grp_name == 0, it means, user wants to use root con_mon
373*4882a593Smuzhiyun * grp, so do nothing
374*4882a593Smuzhiyun */
375*4882a593Smuzhiyun if (strlen(grp_name) == 0)
376*4882a593Smuzhiyun return 0;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /* Check if requested grp exists or not */
379*4882a593Smuzhiyun dp = opendir(parent_grp);
380*4882a593Smuzhiyun if (dp) {
381*4882a593Smuzhiyun while ((ep = readdir(dp)) != NULL) {
382*4882a593Smuzhiyun if (strcmp(ep->d_name, grp_name) == 0)
383*4882a593Smuzhiyun found_grp = 1;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun closedir(dp);
386*4882a593Smuzhiyun } else {
387*4882a593Smuzhiyun perror("Unable to open resctrl for group");
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun return -1;
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* Requested grp doesn't exist, hence create it */
393*4882a593Smuzhiyun if (found_grp == 0) {
394*4882a593Smuzhiyun if (mkdir(grp, 0) == -1) {
395*4882a593Smuzhiyun perror("Unable to create group");
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun return -1;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
write_pid_to_tasks(char * tasks,pid_t pid)404*4882a593Smuzhiyun static int write_pid_to_tasks(char *tasks, pid_t pid)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun FILE *fp;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun fp = fopen(tasks, "w");
409*4882a593Smuzhiyun if (!fp) {
410*4882a593Smuzhiyun perror("Failed to open tasks file");
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun return -1;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun if (fprintf(fp, "%d\n", pid) < 0) {
415*4882a593Smuzhiyun perror("Failed to wr pid to tasks file");
416*4882a593Smuzhiyun fclose(fp);
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun return -1;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun fclose(fp);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun /*
426*4882a593Smuzhiyun * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS
427*4882a593Smuzhiyun * @bm_pid: PID that should be written
428*4882a593Smuzhiyun * @ctrlgrp: Name of the control monitor group (con_mon grp)
429*4882a593Smuzhiyun * @mongrp: Name of the monitor group (mon grp)
430*4882a593Smuzhiyun * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc)
431*4882a593Smuzhiyun *
432*4882a593Smuzhiyun * If a con_mon grp is requested, create it and write pid to it, otherwise
433*4882a593Smuzhiyun * write pid to root con_mon grp.
434*4882a593Smuzhiyun * If a mon grp is requested, create it and write pid to it, otherwise
435*4882a593Smuzhiyun * pid is not written, this means that pid is in con_mon grp and hence
436*4882a593Smuzhiyun * should consult con_mon grp's mon_data directory for results.
437*4882a593Smuzhiyun *
438*4882a593Smuzhiyun * Return: 0 on success, non-zero on failure
439*4882a593Smuzhiyun */
write_bm_pid_to_resctrl(pid_t bm_pid,char * ctrlgrp,char * mongrp,char * resctrl_val)440*4882a593Smuzhiyun int write_bm_pid_to_resctrl(pid_t bm_pid, char *ctrlgrp, char *mongrp,
441*4882a593Smuzhiyun char *resctrl_val)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
444*4882a593Smuzhiyun char tasks[1024];
445*4882a593Smuzhiyun int ret = 0;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun if (strlen(ctrlgrp))
448*4882a593Smuzhiyun sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
449*4882a593Smuzhiyun else
450*4882a593Smuzhiyun sprintf(controlgroup, "%s", RESCTRL_PATH);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* Create control and monitoring group and write pid into it */
453*4882a593Smuzhiyun ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
454*4882a593Smuzhiyun if (ret)
455*4882a593Smuzhiyun goto out;
456*4882a593Smuzhiyun sprintf(tasks, "%s/tasks", controlgroup);
457*4882a593Smuzhiyun ret = write_pid_to_tasks(tasks, bm_pid);
458*4882a593Smuzhiyun if (ret)
459*4882a593Smuzhiyun goto out;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* Create mon grp and write pid into it for "mbm" and "cqm" test */
462*4882a593Smuzhiyun if (!strncmp(resctrl_val, CQM_STR, sizeof(CQM_STR)) ||
463*4882a593Smuzhiyun !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
464*4882a593Smuzhiyun if (strlen(mongrp)) {
465*4882a593Smuzhiyun sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
466*4882a593Smuzhiyun sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
467*4882a593Smuzhiyun ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
468*4882a593Smuzhiyun if (ret)
469*4882a593Smuzhiyun goto out;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun sprintf(tasks, "%s/mon_groups/%s/tasks",
472*4882a593Smuzhiyun controlgroup, mongrp);
473*4882a593Smuzhiyun ret = write_pid_to_tasks(tasks, bm_pid);
474*4882a593Smuzhiyun if (ret)
475*4882a593Smuzhiyun goto out;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun out:
480*4882a593Smuzhiyun printf("%sok writing benchmark parameters to resctrl FS\n",
481*4882a593Smuzhiyun ret ? "not " : "");
482*4882a593Smuzhiyun if (ret)
483*4882a593Smuzhiyun perror("# writing to resctrlfs");
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun tests_run++;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun return ret;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /*
491*4882a593Smuzhiyun * write_schemata - Update schemata of a con_mon grp
492*4882a593Smuzhiyun * @ctrlgrp: Name of the con_mon grp
493*4882a593Smuzhiyun * @schemata: Schemata that should be updated to
494*4882a593Smuzhiyun * @cpu_no: CPU number that the benchmark PID is binded to
495*4882a593Smuzhiyun * @resctrl_val: Resctrl feature (Eg: mbm, mba.. etc)
496*4882a593Smuzhiyun *
497*4882a593Smuzhiyun * Update schemata of a con_mon grp *only* if requested resctrl feature is
498*4882a593Smuzhiyun * allocation type
499*4882a593Smuzhiyun *
500*4882a593Smuzhiyun * Return: 0 on success, non-zero on failure
501*4882a593Smuzhiyun */
write_schemata(char * ctrlgrp,char * schemata,int cpu_no,char * resctrl_val)502*4882a593Smuzhiyun int write_schemata(char *ctrlgrp, char *schemata, int cpu_no, char *resctrl_val)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun char controlgroup[1024], schema[1024], reason[64];
505*4882a593Smuzhiyun int resource_id, ret = 0;
506*4882a593Smuzhiyun FILE *fp;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun if (strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) &&
509*4882a593Smuzhiyun strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) &&
510*4882a593Smuzhiyun strncmp(resctrl_val, CQM_STR, sizeof(CQM_STR)))
511*4882a593Smuzhiyun return -ENOENT;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun if (!schemata) {
514*4882a593Smuzhiyun printf("# Skipping empty schemata update\n");
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun return -1;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun if (get_resource_id(cpu_no, &resource_id) < 0) {
520*4882a593Smuzhiyun sprintf(reason, "Failed to get resource id");
521*4882a593Smuzhiyun ret = -1;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun goto out;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun if (strlen(ctrlgrp) != 0)
527*4882a593Smuzhiyun sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp);
528*4882a593Smuzhiyun else
529*4882a593Smuzhiyun sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)) ||
532*4882a593Smuzhiyun !strncmp(resctrl_val, CQM_STR, sizeof(CQM_STR)))
533*4882a593Smuzhiyun sprintf(schema, "%s%d%c%s", "L3:", resource_id, '=', schemata);
534*4882a593Smuzhiyun if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)))
535*4882a593Smuzhiyun sprintf(schema, "%s%d%c%s", "MB:", resource_id, '=', schemata);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun fp = fopen(controlgroup, "w");
538*4882a593Smuzhiyun if (!fp) {
539*4882a593Smuzhiyun sprintf(reason, "Failed to open control group");
540*4882a593Smuzhiyun ret = -1;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun goto out;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun if (fprintf(fp, "%s\n", schema) < 0) {
546*4882a593Smuzhiyun sprintf(reason, "Failed to write schemata in control group");
547*4882a593Smuzhiyun fclose(fp);
548*4882a593Smuzhiyun ret = -1;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun goto out;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun fclose(fp);
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun out:
555*4882a593Smuzhiyun printf("%sok Write schema \"%s\" to resctrl FS%s%s\n",
556*4882a593Smuzhiyun ret ? "not " : "", schema, ret ? " # " : "",
557*4882a593Smuzhiyun ret ? reason : "");
558*4882a593Smuzhiyun tests_run++;
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun return ret;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
check_resctrlfs_support(void)563*4882a593Smuzhiyun bool check_resctrlfs_support(void)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun FILE *inf = fopen("/proc/filesystems", "r");
566*4882a593Smuzhiyun DIR *dp;
567*4882a593Smuzhiyun char *res;
568*4882a593Smuzhiyun bool ret = false;
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun if (!inf)
571*4882a593Smuzhiyun return false;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun res = fgrep(inf, "nodev\tresctrl\n");
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun if (res) {
576*4882a593Smuzhiyun ret = true;
577*4882a593Smuzhiyun free(res);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun fclose(inf);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun printf("%sok kernel supports resctrl filesystem\n", ret ? "" : "not ");
583*4882a593Smuzhiyun tests_run++;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun dp = opendir(RESCTRL_PATH);
586*4882a593Smuzhiyun printf("%sok resctrl mountpoint \"%s\" exists\n",
587*4882a593Smuzhiyun dp ? "" : "not ", RESCTRL_PATH);
588*4882a593Smuzhiyun if (dp)
589*4882a593Smuzhiyun closedir(dp);
590*4882a593Smuzhiyun tests_run++;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun printf("# resctrl filesystem %s mounted\n",
593*4882a593Smuzhiyun find_resctrl_mount(NULL) ? "not" : "is");
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun return ret;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
fgrep(FILE * inf,const char * str)598*4882a593Smuzhiyun char *fgrep(FILE *inf, const char *str)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun char line[256];
601*4882a593Smuzhiyun int slen = strlen(str);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun while (!feof(inf)) {
604*4882a593Smuzhiyun if (!fgets(line, 256, inf))
605*4882a593Smuzhiyun break;
606*4882a593Smuzhiyun if (strncmp(line, str, slen))
607*4882a593Smuzhiyun continue;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun return strdup(line);
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun return NULL;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun /*
616*4882a593Smuzhiyun * validate_resctrl_feature_request - Check if requested feature is valid.
617*4882a593Smuzhiyun * @resctrl_val: Requested feature
618*4882a593Smuzhiyun *
619*4882a593Smuzhiyun * Return: 0 on success, non-zero on failure
620*4882a593Smuzhiyun */
validate_resctrl_feature_request(char * resctrl_val)621*4882a593Smuzhiyun bool validate_resctrl_feature_request(char *resctrl_val)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun FILE *inf = fopen("/proc/cpuinfo", "r");
624*4882a593Smuzhiyun bool found = false;
625*4882a593Smuzhiyun char *res;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun if (!inf)
628*4882a593Smuzhiyun return false;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun res = fgrep(inf, "flags");
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun if (res) {
633*4882a593Smuzhiyun char *s = strchr(res, ':');
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun found = s && !strstr(s, resctrl_val);
636*4882a593Smuzhiyun free(res);
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun fclose(inf);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun return found;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
filter_dmesg(void)643*4882a593Smuzhiyun int filter_dmesg(void)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun char line[1024];
646*4882a593Smuzhiyun FILE *fp;
647*4882a593Smuzhiyun int pipefds[2];
648*4882a593Smuzhiyun pid_t pid;
649*4882a593Smuzhiyun int ret;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun ret = pipe(pipefds);
652*4882a593Smuzhiyun if (ret) {
653*4882a593Smuzhiyun perror("pipe");
654*4882a593Smuzhiyun return ret;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun pid = fork();
657*4882a593Smuzhiyun if (pid == 0) {
658*4882a593Smuzhiyun close(pipefds[0]);
659*4882a593Smuzhiyun dup2(pipefds[1], STDOUT_FILENO);
660*4882a593Smuzhiyun execlp("dmesg", "dmesg", NULL);
661*4882a593Smuzhiyun perror("executing dmesg");
662*4882a593Smuzhiyun exit(1);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun close(pipefds[1]);
665*4882a593Smuzhiyun fp = fdopen(pipefds[0], "r");
666*4882a593Smuzhiyun if (!fp) {
667*4882a593Smuzhiyun perror("fdopen(pipe)");
668*4882a593Smuzhiyun kill(pid, SIGTERM);
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun return -1;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun while (fgets(line, 1024, fp)) {
674*4882a593Smuzhiyun if (strstr(line, "intel_rdt:"))
675*4882a593Smuzhiyun printf("# dmesg: %s", line);
676*4882a593Smuzhiyun if (strstr(line, "resctrl:"))
677*4882a593Smuzhiyun printf("# dmesg: %s", line);
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun fclose(fp);
680*4882a593Smuzhiyun waitpid(pid, NULL, 0);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun return 0;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
validate_bw_report_request(char * bw_report)685*4882a593Smuzhiyun int validate_bw_report_request(char *bw_report)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun if (strcmp(bw_report, "reads") == 0)
688*4882a593Smuzhiyun return 0;
689*4882a593Smuzhiyun if (strcmp(bw_report, "writes") == 0)
690*4882a593Smuzhiyun return 0;
691*4882a593Smuzhiyun if (strcmp(bw_report, "nt-writes") == 0) {
692*4882a593Smuzhiyun strcpy(bw_report, "writes");
693*4882a593Smuzhiyun return 0;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun if (strcmp(bw_report, "total") == 0)
696*4882a593Smuzhiyun return 0;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun fprintf(stderr, "Requested iMC B/W report type unavailable\n");
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun return -1;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
perf_event_open(struct perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)703*4882a593Smuzhiyun int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
704*4882a593Smuzhiyun int group_fd, unsigned long flags)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun int ret;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
709*4882a593Smuzhiyun group_fd, flags);
710*4882a593Smuzhiyun return ret;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
count_bits(unsigned long n)713*4882a593Smuzhiyun unsigned int count_bits(unsigned long n)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun unsigned int count = 0;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun while (n) {
718*4882a593Smuzhiyun count += n & 1;
719*4882a593Smuzhiyun n >>= 1;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun return count;
723*4882a593Smuzhiyun }
724