1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Basic resctrl file system operations
4   *
5   * Copyright (C) 2018 Intel Corporation
6   *
7   * Authors:
8   *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
9   *    Fenghua Yu <fenghua.yu@intel.com>
10   */
11  #include <fcntl.h>
12  #include <limits.h>
13  
14  #include "resctrl.h"
15  
find_resctrl_mount(char * buffer)16  static int find_resctrl_mount(char *buffer)
17  {
18  	FILE *mounts;
19  	char line[256], *fs, *mntpoint;
20  
21  	mounts = fopen("/proc/mounts", "r");
22  	if (!mounts) {
23  		ksft_perror("/proc/mounts");
24  		return -ENXIO;
25  	}
26  	while (!feof(mounts)) {
27  		if (!fgets(line, 256, mounts))
28  			break;
29  		fs = strtok(line, " \t");
30  		if (!fs)
31  			continue;
32  		mntpoint = strtok(NULL, " \t");
33  		if (!mntpoint)
34  			continue;
35  		fs = strtok(NULL, " \t");
36  		if (!fs)
37  			continue;
38  		if (strcmp(fs, "resctrl"))
39  			continue;
40  
41  		fclose(mounts);
42  		if (buffer)
43  			strncpy(buffer, mntpoint, 256);
44  
45  		return 0;
46  	}
47  
48  	fclose(mounts);
49  
50  	return -ENOENT;
51  }
52  
53  /*
54   * mount_resctrlfs - Mount resctrl FS at /sys/fs/resctrl
55   *
56   * Mounts resctrl FS. Fails if resctrl FS is already mounted to avoid
57   * pre-existing settings interfering with the test results.
58   *
59   * Return: 0 on success, < 0 on error.
60   */
mount_resctrlfs(void)61  int mount_resctrlfs(void)
62  {
63  	int ret;
64  
65  	ret = find_resctrl_mount(NULL);
66  	if (ret != -ENOENT)
67  		return -1;
68  
69  	ksft_print_msg("Mounting resctrl to \"%s\"\n", RESCTRL_PATH);
70  	ret = mount("resctrl", RESCTRL_PATH, "resctrl", 0, NULL);
71  	if (ret)
72  		ksft_perror("mount");
73  
74  	return ret;
75  }
76  
umount_resctrlfs(void)77  int umount_resctrlfs(void)
78  {
79  	char mountpoint[256];
80  	int ret;
81  
82  	ret = find_resctrl_mount(mountpoint);
83  	if (ret == -ENOENT)
84  		return 0;
85  	if (ret)
86  		return ret;
87  
88  	if (umount(mountpoint)) {
89  		ksft_perror("Unable to umount resctrl");
90  
91  		return -1;
92  	}
93  
94  	return 0;
95  }
96  
97  /*
98   * get_cache_level - Convert cache level from string to integer
99   * @cache_type:		Cache level as string
100   *
101   * Return: cache level as integer or -1 if @cache_type is invalid.
102   */
get_cache_level(const char * cache_type)103  static int get_cache_level(const char *cache_type)
104  {
105  	if (!strcmp(cache_type, "L3"))
106  		return 3;
107  	if (!strcmp(cache_type, "L2"))
108  		return 2;
109  
110  	ksft_print_msg("Invalid cache level\n");
111  	return -1;
112  }
113  
get_resource_cache_level(const char * resource)114  static int get_resource_cache_level(const char *resource)
115  {
116  	/* "MB" use L3 (LLC) as resource */
117  	if (!strcmp(resource, "MB"))
118  		return 3;
119  	return get_cache_level(resource);
120  }
121  
122  /*
123   * get_domain_id - Get resctrl domain ID for a specified CPU
124   * @resource:	resource name
125   * @cpu_no:	CPU number
126   * @domain_id:	domain ID (cache ID; for MB, L3 cache ID)
127   *
128   * Return: >= 0 on success, < 0 on failure.
129   */
get_domain_id(const char * resource,int cpu_no,int * domain_id)130  int get_domain_id(const char *resource, int cpu_no, int *domain_id)
131  {
132  	char phys_pkg_path[1024];
133  	int cache_num;
134  	FILE *fp;
135  
136  	cache_num = get_resource_cache_level(resource);
137  	if (cache_num < 0)
138  		return cache_num;
139  
140  	sprintf(phys_pkg_path, "%s%d/cache/index%d/id", PHYS_ID_PATH, cpu_no, cache_num);
141  
142  	fp = fopen(phys_pkg_path, "r");
143  	if (!fp) {
144  		ksft_perror("Failed to open cache id file");
145  
146  		return -1;
147  	}
148  	if (fscanf(fp, "%d", domain_id) <= 0) {
149  		ksft_perror("Could not get domain ID");
150  		fclose(fp);
151  
152  		return -1;
153  	}
154  	fclose(fp);
155  
156  	return 0;
157  }
158  
159  /*
160   * get_cache_size - Get cache size for a specified CPU
161   * @cpu_no:	CPU number
162   * @cache_type:	Cache level L2/L3
163   * @cache_size:	pointer to cache_size
164   *
165   * Return: = 0 on success, < 0 on failure.
166   */
get_cache_size(int cpu_no,const char * cache_type,unsigned long * cache_size)167  int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size)
168  {
169  	char cache_path[1024], cache_str[64];
170  	int length, i, cache_num;
171  	FILE *fp;
172  
173  	cache_num = get_cache_level(cache_type);
174  	if (cache_num < 0)
175  		return cache_num;
176  
177  	sprintf(cache_path, "/sys/bus/cpu/devices/cpu%d/cache/index%d/size",
178  		cpu_no, cache_num);
179  	fp = fopen(cache_path, "r");
180  	if (!fp) {
181  		ksft_perror("Failed to open cache size");
182  
183  		return -1;
184  	}
185  	if (fscanf(fp, "%s", cache_str) <= 0) {
186  		ksft_perror("Could not get cache_size");
187  		fclose(fp);
188  
189  		return -1;
190  	}
191  	fclose(fp);
192  
193  	length = (int)strlen(cache_str);
194  
195  	*cache_size = 0;
196  
197  	for (i = 0; i < length; i++) {
198  		if ((cache_str[i] >= '0') && (cache_str[i] <= '9'))
199  
200  			*cache_size = *cache_size * 10 + (cache_str[i] - '0');
201  
202  		else if (cache_str[i] == 'K')
203  
204  			*cache_size = *cache_size * 1024;
205  
206  		else if (cache_str[i] == 'M')
207  
208  			*cache_size = *cache_size * 1024 * 1024;
209  
210  		else
211  			break;
212  	}
213  
214  	return 0;
215  }
216  
217  #define CORE_SIBLINGS_PATH	"/sys/bus/cpu/devices/cpu"
218  
219  /*
220   * get_bit_mask - Get bit mask from given file
221   * @filename:	File containing the mask
222   * @mask:	The bit mask returned as unsigned long
223   *
224   * Return: = 0 on success, < 0 on failure.
225   */
get_bit_mask(const char * filename,unsigned long * mask)226  static int get_bit_mask(const char *filename, unsigned long *mask)
227  {
228  	FILE *fp;
229  
230  	if (!filename || !mask)
231  		return -1;
232  
233  	fp = fopen(filename, "r");
234  	if (!fp) {
235  		ksft_print_msg("Failed to open bit mask file '%s': %s\n",
236  			       filename, strerror(errno));
237  		return -1;
238  	}
239  
240  	if (fscanf(fp, "%lx", mask) <= 0) {
241  		ksft_print_msg("Could not read bit mask file '%s': %s\n",
242  			       filename, strerror(errno));
243  		fclose(fp);
244  
245  		return -1;
246  	}
247  	fclose(fp);
248  
249  	return 0;
250  }
251  
252  /*
253   * resource_info_unsigned_get - Read an unsigned value from
254   * /sys/fs/resctrl/info/@resource/@filename
255   * @resource:	Resource name that matches directory name in
256   *		/sys/fs/resctrl/info
257   * @filename:	File in /sys/fs/resctrl/info/@resource
258   * @val:	Contains read value on success.
259   *
260   * Return: = 0 on success, < 0 on failure. On success the read
261   * value is saved into @val.
262   */
resource_info_unsigned_get(const char * resource,const char * filename,unsigned int * val)263  int resource_info_unsigned_get(const char *resource, const char *filename,
264  			       unsigned int *val)
265  {
266  	char file_path[PATH_MAX];
267  	FILE *fp;
268  
269  	snprintf(file_path, sizeof(file_path), "%s/%s/%s", INFO_PATH, resource,
270  		 filename);
271  
272  	fp = fopen(file_path, "r");
273  	if (!fp) {
274  		ksft_print_msg("Error opening %s: %m\n", file_path);
275  		return -1;
276  	}
277  
278  	if (fscanf(fp, "%u", val) <= 0) {
279  		ksft_print_msg("Could not get contents of %s: %m\n", file_path);
280  		fclose(fp);
281  		return -1;
282  	}
283  
284  	fclose(fp);
285  	return 0;
286  }
287  
288  /*
289   * create_bit_mask- Create bit mask from start, len pair
290   * @start:	LSB of the mask
291   * @len		Number of bits in the mask
292   */
create_bit_mask(unsigned int start,unsigned int len)293  unsigned long create_bit_mask(unsigned int start, unsigned int len)
294  {
295  	return ((1UL << len) - 1UL) << start;
296  }
297  
298  /*
299   * count_contiguous_bits - Returns the longest train of bits in a bit mask
300   * @val		A bit mask
301   * @start	The location of the least-significant bit of the longest train
302   *
303   * Return:	The length of the contiguous bits in the longest train of bits
304   */
count_contiguous_bits(unsigned long val,unsigned int * start)305  unsigned int count_contiguous_bits(unsigned long val, unsigned int *start)
306  {
307  	unsigned long last_val;
308  	unsigned int count = 0;
309  
310  	while (val) {
311  		last_val = val;
312  		val &= (val >> 1);
313  		count++;
314  	}
315  
316  	if (start) {
317  		if (count)
318  			*start = ffsl(last_val) - 1;
319  		else
320  			*start = 0;
321  	}
322  
323  	return count;
324  }
325  
326  /*
327   * get_full_cbm - Get full Cache Bit Mask (CBM)
328   * @cache_type:	Cache type as "L2" or "L3"
329   * @mask:	Full cache bit mask representing the maximal portion of cache
330   *		available for allocation, returned as unsigned long.
331   *
332   * Return: = 0 on success, < 0 on failure.
333   */
get_full_cbm(const char * cache_type,unsigned long * mask)334  int get_full_cbm(const char *cache_type, unsigned long *mask)
335  {
336  	char cbm_path[PATH_MAX];
337  	int ret;
338  
339  	if (!cache_type)
340  		return -1;
341  
342  	snprintf(cbm_path, sizeof(cbm_path), "%s/%s/cbm_mask",
343  		 INFO_PATH, cache_type);
344  
345  	ret = get_bit_mask(cbm_path, mask);
346  	if (ret || !*mask)
347  		return -1;
348  
349  	return 0;
350  }
351  
352  /*
353   * get_shareable_mask - Get shareable mask from shareable_bits
354   * @cache_type:		Cache type as "L2" or "L3"
355   * @shareable_mask:	Shareable mask returned as unsigned long
356   *
357   * Return: = 0 on success, < 0 on failure.
358   */
get_shareable_mask(const char * cache_type,unsigned long * shareable_mask)359  static int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask)
360  {
361  	char mask_path[PATH_MAX];
362  
363  	if (!cache_type)
364  		return -1;
365  
366  	snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits",
367  		 INFO_PATH, cache_type);
368  
369  	return get_bit_mask(mask_path, shareable_mask);
370  }
371  
372  /*
373   * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits
374   * @cache_type:		Cache type as "L2" or "L3"
375   * @mask:		The largest exclusive portion of the cache out of the
376   *			full CBM, returned as unsigned long
377   *
378   * Parts of a cache may be shared with other devices such as GPU. This function
379   * calculates the largest exclusive portion of the cache where no other devices
380   * besides CPU have access to the cache portion.
381   *
382   * Return: = 0 on success, < 0 on failure.
383   */
get_mask_no_shareable(const char * cache_type,unsigned long * mask)384  int get_mask_no_shareable(const char *cache_type, unsigned long *mask)
385  {
386  	unsigned long full_mask, shareable_mask;
387  	unsigned int start, len;
388  
389  	if (get_full_cbm(cache_type, &full_mask) < 0)
390  		return -1;
391  	if (get_shareable_mask(cache_type, &shareable_mask) < 0)
392  		return -1;
393  
394  	len = count_contiguous_bits(full_mask & ~shareable_mask, &start);
395  	if (!len)
396  		return -1;
397  
398  	*mask = create_bit_mask(start, len);
399  
400  	return 0;
401  }
402  
403  /*
404   * taskset_benchmark - Taskset PID (i.e. benchmark) to a specified cpu
405   * @bm_pid:		PID that should be binded
406   * @cpu_no:		CPU number at which the PID would be binded
407   * @old_affinity:	When not NULL, set to old CPU affinity
408   *
409   * Return: 0 on success, < 0 on error.
410   */
taskset_benchmark(pid_t bm_pid,int cpu_no,cpu_set_t * old_affinity)411  int taskset_benchmark(pid_t bm_pid, int cpu_no, cpu_set_t *old_affinity)
412  {
413  	cpu_set_t my_set;
414  
415  	if (old_affinity) {
416  		CPU_ZERO(old_affinity);
417  		if (sched_getaffinity(bm_pid, sizeof(*old_affinity),
418  				      old_affinity)) {
419  			ksft_perror("Unable to read CPU affinity");
420  			return -1;
421  		}
422  	}
423  
424  	CPU_ZERO(&my_set);
425  	CPU_SET(cpu_no, &my_set);
426  
427  	if (sched_setaffinity(bm_pid, sizeof(cpu_set_t), &my_set)) {
428  		ksft_perror("Unable to taskset benchmark");
429  
430  		return -1;
431  	}
432  
433  	return 0;
434  }
435  
436  /*
437   * taskset_restore - Taskset PID to the earlier CPU affinity
438   * @bm_pid:		PID that should be reset
439   * @old_affinity:	The old CPU affinity to restore
440   *
441   * Return: 0 on success, < 0 on error.
442   */
taskset_restore(pid_t bm_pid,cpu_set_t * old_affinity)443  int taskset_restore(pid_t bm_pid, cpu_set_t *old_affinity)
444  {
445  	if (sched_setaffinity(bm_pid, sizeof(*old_affinity), old_affinity)) {
446  		ksft_perror("Unable to restore CPU affinity");
447  		return -1;
448  	}
449  
450  	return 0;
451  }
452  
453  /*
454   * create_grp - Create a group only if one doesn't exist
455   * @grp_name:	Name of the group
456   * @grp:	Full path and name of the group
457   * @parent_grp:	Full path and name of the parent group
458   *
459   * Creates a group @grp_name if it does not exist yet. If @grp_name is NULL,
460   * it is interpreted as the root group which always results in success.
461   *
462   * Return: 0 on success, < 0 on error.
463   */
create_grp(const char * grp_name,char * grp,const char * parent_grp)464  static int create_grp(const char *grp_name, char *grp, const char *parent_grp)
465  {
466  	int found_grp = 0;
467  	struct dirent *ep;
468  	DIR *dp;
469  
470  	if (!grp_name)
471  		return 0;
472  
473  	/* Check if requested grp exists or not */
474  	dp = opendir(parent_grp);
475  	if (dp) {
476  		while ((ep = readdir(dp)) != NULL) {
477  			if (strcmp(ep->d_name, grp_name) == 0)
478  				found_grp = 1;
479  		}
480  		closedir(dp);
481  	} else {
482  		ksft_perror("Unable to open resctrl for group");
483  
484  		return -1;
485  	}
486  
487  	/* Requested grp doesn't exist, hence create it */
488  	if (found_grp == 0) {
489  		if (mkdir(grp, 0) == -1) {
490  			ksft_perror("Unable to create group");
491  
492  			return -1;
493  		}
494  	}
495  
496  	return 0;
497  }
498  
write_pid_to_tasks(char * tasks,pid_t pid)499  static int write_pid_to_tasks(char *tasks, pid_t pid)
500  {
501  	FILE *fp;
502  
503  	fp = fopen(tasks, "w");
504  	if (!fp) {
505  		ksft_perror("Failed to open tasks file");
506  
507  		return -1;
508  	}
509  	if (fprintf(fp, "%d\n", (int)pid) < 0) {
510  		ksft_print_msg("Failed to write pid to tasks file\n");
511  		fclose(fp);
512  
513  		return -1;
514  	}
515  	fclose(fp);
516  
517  	return 0;
518  }
519  
520  /*
521   * write_bm_pid_to_resctrl - Write a PID (i.e. benchmark) to resctrl FS
522   * @bm_pid:		PID that should be written
523   * @ctrlgrp:		Name of the control monitor group (con_mon grp)
524   * @mongrp:		Name of the monitor group (mon grp)
525   *
526   * If a con_mon grp is requested, create it and write pid to it, otherwise
527   * write pid to root con_mon grp.
528   * If a mon grp is requested, create it and write pid to it, otherwise
529   * pid is not written, this means that pid is in con_mon grp and hence
530   * should consult con_mon grp's mon_data directory for results.
531   *
532   * Return: 0 on success, < 0 on error.
533   */
write_bm_pid_to_resctrl(pid_t bm_pid,const char * ctrlgrp,const char * mongrp)534  int write_bm_pid_to_resctrl(pid_t bm_pid, const char *ctrlgrp, const char *mongrp)
535  {
536  	char controlgroup[128], monitorgroup[512], monitorgroup_p[256];
537  	char tasks[1024];
538  	int ret = 0;
539  
540  	if (ctrlgrp)
541  		sprintf(controlgroup, "%s/%s", RESCTRL_PATH, ctrlgrp);
542  	else
543  		sprintf(controlgroup, "%s", RESCTRL_PATH);
544  
545  	/* Create control and monitoring group and write pid into it */
546  	ret = create_grp(ctrlgrp, controlgroup, RESCTRL_PATH);
547  	if (ret)
548  		goto out;
549  	sprintf(tasks, "%s/tasks", controlgroup);
550  	ret = write_pid_to_tasks(tasks, bm_pid);
551  	if (ret)
552  		goto out;
553  
554  	/* Create monitor group and write pid into if it is used */
555  	if (mongrp) {
556  		sprintf(monitorgroup_p, "%s/mon_groups", controlgroup);
557  		sprintf(monitorgroup, "%s/%s", monitorgroup_p, mongrp);
558  		ret = create_grp(mongrp, monitorgroup, monitorgroup_p);
559  		if (ret)
560  			goto out;
561  
562  		sprintf(tasks, "%s/mon_groups/%s/tasks",
563  			controlgroup, mongrp);
564  		ret = write_pid_to_tasks(tasks, bm_pid);
565  		if (ret)
566  			goto out;
567  	}
568  
569  out:
570  	ksft_print_msg("Writing benchmark parameters to resctrl FS\n");
571  	if (ret)
572  		ksft_print_msg("Failed writing to resctrlfs\n");
573  
574  	return ret;
575  }
576  
577  /*
578   * write_schemata - Update schemata of a con_mon grp
579   * @ctrlgrp:		Name of the con_mon grp
580   * @schemata:		Schemata that should be updated to
581   * @cpu_no:		CPU number that the benchmark PID is binded to
582   * @resource:		Resctrl resource (Eg: MB, L3, L2, etc.)
583   *
584   * Update schemata of a con_mon grp *only* if requested resctrl resource is
585   * allocation type
586   *
587   * Return: 0 on success, < 0 on error.
588   */
write_schemata(const char * ctrlgrp,char * schemata,int cpu_no,const char * resource)589  int write_schemata(const char *ctrlgrp, char *schemata, int cpu_no,
590  		   const char *resource)
591  {
592  	char controlgroup[1024], reason[128], schema[1024] = {};
593  	int domain_id, fd, schema_len, ret = 0;
594  
595  	if (!schemata) {
596  		ksft_print_msg("Skipping empty schemata update\n");
597  
598  		return -1;
599  	}
600  
601  	if (get_domain_id(resource, cpu_no, &domain_id) < 0) {
602  		sprintf(reason, "Failed to get domain ID");
603  		ret = -1;
604  
605  		goto out;
606  	}
607  
608  	if (ctrlgrp)
609  		sprintf(controlgroup, "%s/%s/schemata", RESCTRL_PATH, ctrlgrp);
610  	else
611  		sprintf(controlgroup, "%s/schemata", RESCTRL_PATH);
612  
613  	schema_len = snprintf(schema, sizeof(schema), "%s:%d=%s\n",
614  			      resource, domain_id, schemata);
615  	if (schema_len < 0 || schema_len >= sizeof(schema)) {
616  		snprintf(reason, sizeof(reason),
617  			 "snprintf() failed with return value : %d", schema_len);
618  		ret = -1;
619  		goto out;
620  	}
621  
622  	fd = open(controlgroup, O_WRONLY);
623  	if (fd < 0) {
624  		snprintf(reason, sizeof(reason),
625  			 "open() failed : %s", strerror(errno));
626  		ret = -1;
627  
628  		goto err_schema_not_empty;
629  	}
630  	if (write(fd, schema, schema_len) < 0) {
631  		snprintf(reason, sizeof(reason),
632  			 "write() failed : %s", strerror(errno));
633  		close(fd);
634  		ret = -1;
635  
636  		goto err_schema_not_empty;
637  	}
638  	close(fd);
639  
640  err_schema_not_empty:
641  	schema[schema_len - 1] = 0;
642  out:
643  	ksft_print_msg("Write schema \"%s\" to resctrl FS%s%s\n",
644  		       schema, ret ? " # " : "",
645  		       ret ? reason : "");
646  
647  	return ret;
648  }
649  
check_resctrlfs_support(void)650  bool check_resctrlfs_support(void)
651  {
652  	FILE *inf = fopen("/proc/filesystems", "r");
653  	DIR *dp;
654  	char *res;
655  	bool ret = false;
656  
657  	if (!inf)
658  		return false;
659  
660  	res = fgrep(inf, "nodev\tresctrl\n");
661  
662  	if (res) {
663  		ret = true;
664  		free(res);
665  	}
666  
667  	fclose(inf);
668  
669  	ksft_print_msg("%s Check kernel supports resctrl filesystem\n",
670  		       ret ? "Pass:" : "Fail:");
671  
672  	if (!ret)
673  		return ret;
674  
675  	dp = opendir(RESCTRL_PATH);
676  	ksft_print_msg("%s Check resctrl mountpoint \"%s\" exists\n",
677  		       dp ? "Pass:" : "Fail:", RESCTRL_PATH);
678  	if (dp)
679  		closedir(dp);
680  
681  	ksft_print_msg("resctrl filesystem %s mounted\n",
682  		       find_resctrl_mount(NULL) ? "not" : "is");
683  
684  	return ret;
685  }
686  
fgrep(FILE * inf,const char * str)687  char *fgrep(FILE *inf, const char *str)
688  {
689  	char line[256];
690  	int slen = strlen(str);
691  
692  	while (!feof(inf)) {
693  		if (!fgets(line, 256, inf))
694  			break;
695  		if (strncmp(line, str, slen))
696  			continue;
697  
698  		return strdup(line);
699  	}
700  
701  	return NULL;
702  }
703  
704  /*
705   * resctrl_resource_exists - Check if a resource is supported.
706   * @resource:	Resctrl resource (e.g., MB, L3, L2, L3_MON, etc.)
707   *
708   * Return: True if the resource is supported, else false. False is
709   *         also returned if resctrl FS is not mounted.
710   */
resctrl_resource_exists(const char * resource)711  bool resctrl_resource_exists(const char *resource)
712  {
713  	char res_path[PATH_MAX];
714  	struct stat statbuf;
715  	int ret;
716  
717  	if (!resource)
718  		return false;
719  
720  	ret = find_resctrl_mount(NULL);
721  	if (ret)
722  		return false;
723  
724  	snprintf(res_path, sizeof(res_path), "%s/%s", INFO_PATH, resource);
725  
726  	if (stat(res_path, &statbuf))
727  		return false;
728  
729  	return true;
730  }
731  
732  /*
733   * resctrl_mon_feature_exists - Check if requested monitoring feature is valid.
734   * @resource:	Resource that uses the mon_features file. Currently only L3_MON
735   *		is valid.
736   * @feature:	Required monitor feature (in mon_features file).
737   *
738   * Return: True if the feature is supported, else false.
739   */
resctrl_mon_feature_exists(const char * resource,const char * feature)740  bool resctrl_mon_feature_exists(const char *resource, const char *feature)
741  {
742  	char res_path[PATH_MAX];
743  	char *res;
744  	FILE *inf;
745  
746  	if (!feature || !resource)
747  		return false;
748  
749  	snprintf(res_path, sizeof(res_path), "%s/%s/mon_features", INFO_PATH, resource);
750  	inf = fopen(res_path, "r");
751  	if (!inf)
752  		return false;
753  
754  	res = fgrep(inf, feature);
755  	free(res);
756  	fclose(inf);
757  
758  	return !!res;
759  }
760  
761  /*
762   * resource_info_file_exists - Check if a file is present inside
763   * /sys/fs/resctrl/info/@resource.
764   * @resource:	Required resource (Eg: MB, L3, L2, etc.)
765   * @file:	Required file.
766   *
767   * Return: True if the /sys/fs/resctrl/info/@resource/@file exists, else false.
768   */
resource_info_file_exists(const char * resource,const char * file)769  bool resource_info_file_exists(const char *resource, const char *file)
770  {
771  	char res_path[PATH_MAX];
772  	struct stat statbuf;
773  
774  	if (!file || !resource)
775  		return false;
776  
777  	snprintf(res_path, sizeof(res_path), "%s/%s/%s", INFO_PATH, resource,
778  		 file);
779  
780  	if (stat(res_path, &statbuf))
781  		return false;
782  
783  	return true;
784  }
785  
test_resource_feature_check(const struct resctrl_test * test)786  bool test_resource_feature_check(const struct resctrl_test *test)
787  {
788  	return resctrl_resource_exists(test->resource);
789  }
790  
filter_dmesg(void)791  int filter_dmesg(void)
792  {
793  	char line[1024];
794  	FILE *fp;
795  	int pipefds[2];
796  	pid_t pid;
797  	int ret;
798  
799  	ret = pipe(pipefds);
800  	if (ret) {
801  		ksft_perror("pipe");
802  		return ret;
803  	}
804  	fflush(stdout);
805  	pid = fork();
806  	if (pid == 0) {
807  		close(pipefds[0]);
808  		dup2(pipefds[1], STDOUT_FILENO);
809  		execlp("dmesg", "dmesg", NULL);
810  		ksft_perror("Executing dmesg");
811  		exit(1);
812  	}
813  	close(pipefds[1]);
814  	fp = fdopen(pipefds[0], "r");
815  	if (!fp) {
816  		ksft_perror("fdopen(pipe)");
817  		kill(pid, SIGTERM);
818  
819  		return -1;
820  	}
821  
822  	while (fgets(line, 1024, fp)) {
823  		if (strstr(line, "intel_rdt:"))
824  			ksft_print_msg("dmesg: %s", line);
825  		if (strstr(line, "resctrl:"))
826  			ksft_print_msg("dmesg: %s", line);
827  	}
828  	fclose(fp);
829  	waitpid(pid, NULL, 0);
830  
831  	return 0;
832  }
833  
get_bw_report_type(const char * bw_report)834  const char *get_bw_report_type(const char *bw_report)
835  {
836  	if (strcmp(bw_report, "reads") == 0)
837  		return bw_report;
838  	if (strcmp(bw_report, "writes") == 0)
839  		return bw_report;
840  	if (strcmp(bw_report, "nt-writes") == 0) {
841  		return "writes";
842  	}
843  	if (strcmp(bw_report, "total") == 0)
844  		return bw_report;
845  
846  	fprintf(stderr, "Requested iMC bandwidth report type unavailable\n");
847  
848  	return NULL;
849  }
850  
perf_event_open(struct perf_event_attr * hw_event,pid_t pid,int cpu,int group_fd,unsigned long flags)851  int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu,
852  		    int group_fd, unsigned long flags)
853  {
854  	int ret;
855  
856  	ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
857  		      group_fd, flags);
858  	return ret;
859  }
860  
count_bits(unsigned long n)861  unsigned int count_bits(unsigned long n)
862  {
863  	unsigned int count = 0;
864  
865  	while (n) {
866  		count += n & 1;
867  		n >>= 1;
868  	}
869  
870  	return count;
871  }
872