Skip to content

Commit 7d97dfe

Browse files
rchatreshuahkh
authored andcommitted
selftests/resctrl: Support multiple events associated with iMC
The resctrl selftests discover needed parameters to perf_event_open() via sysfs. The PMU associated with every memory controller (iMC) is discovered via the /sys/bus/event_source/devices/uncore_imc_N/type file while the read memory bandwidth event type and umask is discovered via /sys/bus/event_source/devices/uncore_imc_N/events/cas_count_read. Newer systems may have multiple events that expose read memory bandwidth. Running a recent kernel that includes commit 6a8a486 ("perf/x86/intel/uncore: Add per-scheduler IMC CAS count events") on these systems expose the multiple events. For example, /sys/bus/event_source/devices/uncore_imc_N/events/cas_count_read_sch0 /sys/bus/event_source/devices/uncore_imc_N/events/cas_count_read_sch1 Support parsing of iMC PMU properties when the PMU may have multiple events to measure read memory bandwidth. The PMU only needs to be discovered once. Split the parsing of event details from actual PMU discovery in order to loop over all events associated with the PMU. Match all events with the cas_count_read prefix instead of requiring there to be one file with that name. Make the parsing code more robust. With strings passed around to create needed paths, use snprintf() instead of sprintf() to ensure there is always enough space to create the path while using the standard PATH_MAX for path lengths. Ensure there is enough room in imc_counters_config[] before attempting to add an entry. Link: https://lore.kernel.org/r/b03ca0fa21a09500c56ee589e32516c2c5effeaf.1775266384.git.reinette.chatre@intel.com Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Tested-by: Chen Yu <yu.c.chen@intel.com> Reviewed-by: Zide Chen <zide.chen@intel.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
1 parent f3d3a8f commit 7d97dfe

1 file changed

Lines changed: 93 additions & 25 deletions

File tree

tools/testing/selftests/resctrl/resctrl_val.c

Lines changed: 93 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
#include "resctrl.h"
1212

1313
#define UNCORE_IMC "uncore_imc"
14-
#define READ_FILE_NAME "events/cas_count_read"
14+
#define READ_FILE_NAME "cas_count_read"
1515
#define DYN_PMU_PATH "/sys/bus/event_source/devices"
1616
#define SCALE 0.00006103515625
17-
#define MAX_IMCS 20
17+
#define MAX_IMCS 40
1818
#define MAX_TOKENS 5
1919

2020
#define CON_MBM_LOCAL_BYTES_PATH \
@@ -109,46 +109,114 @@ static int open_perf_read_event(int i, int cpu_no)
109109
return 0;
110110
}
111111

112-
/* Get type and config of an iMC counter's read event. */
113-
static int read_from_imc_dir(char *imc_dir, unsigned int *count)
112+
static int parse_imc_read_bw_events(char *imc_dir, unsigned int type,
113+
unsigned int *count)
114114
{
115-
char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024];
115+
char imc_events_dir[PATH_MAX], imc_counter_cfg[PATH_MAX];
116+
unsigned int orig_count = *count;
117+
char cas_count_cfg[1024];
118+
struct dirent *ep;
119+
int path_len;
120+
int ret = -1;
121+
int num_cfg;
116122
FILE *fp;
123+
DIR *dp;
117124

118-
/* Get type of iMC counter */
119-
sprintf(imc_counter_type, "%s%s", imc_dir, "type");
120-
fp = fopen(imc_counter_type, "r");
121-
if (!fp) {
122-
ksft_perror("Failed to open iMC counter type file");
125+
path_len = snprintf(imc_events_dir, sizeof(imc_events_dir), "%sevents",
126+
imc_dir);
127+
if (path_len >= sizeof(imc_events_dir)) {
128+
ksft_print_msg("Unable to create path to %sevents\n", imc_dir);
129+
return -1;
130+
}
123131

132+
dp = opendir(imc_events_dir);
133+
if (!dp) {
134+
ksft_perror("Unable to open PMU events directory");
124135
return -1;
125136
}
126-
if (fscanf(fp, "%u", &imc_counters_config[*count].type) <= 0) {
127-
ksft_perror("Could not get iMC type");
137+
138+
while ((ep = readdir(dp))) {
139+
/*
140+
* Parse all event files with READ_FILE_NAME prefix that
141+
* contain the event number and umask. Skip files containing
142+
* "." that contain unused properties of event.
143+
*/
144+
if (!strstr(ep->d_name, READ_FILE_NAME) ||
145+
strchr(ep->d_name, '.'))
146+
continue;
147+
148+
path_len = snprintf(imc_counter_cfg, sizeof(imc_counter_cfg),
149+
"%s/%s", imc_events_dir, ep->d_name);
150+
if (path_len >= sizeof(imc_counter_cfg)) {
151+
ksft_print_msg("Unable to create path to %s/%s\n",
152+
imc_events_dir, ep->d_name);
153+
goto out_close;
154+
}
155+
fp = fopen(imc_counter_cfg, "r");
156+
if (!fp) {
157+
ksft_perror("Failed to open iMC config file");
158+
goto out_close;
159+
}
160+
num_cfg = fscanf(fp, "%1023s", cas_count_cfg);
128161
fclose(fp);
162+
if (num_cfg <= 0) {
163+
ksft_perror("Could not get iMC cas count read");
164+
goto out_close;
165+
}
166+
if (*count >= MAX_IMCS) {
167+
ksft_print_msg("Maximum iMC count exceeded\n");
168+
goto out_close;
169+
}
129170

130-
return -1;
171+
imc_counters_config[*count].type = type;
172+
get_read_event_and_umask(cas_count_cfg, *count);
173+
/* Do not fail after incrementing *count. */
174+
*count += 1;
131175
}
132-
fclose(fp);
176+
if (*count == orig_count) {
177+
ksft_print_msg("Unable to find events in %s\n", imc_events_dir);
178+
goto out_close;
179+
}
180+
ret = 0;
181+
out_close:
182+
closedir(dp);
183+
return ret;
184+
}
133185

134-
/* Get read config */
135-
sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME);
136-
fp = fopen(imc_counter_cfg, "r");
137-
if (!fp) {
138-
ksft_perror("Failed to open iMC config file");
186+
/* Get type and config of an iMC counter's read event. */
187+
static int read_from_imc_dir(char *imc_dir, unsigned int *count)
188+
{
189+
char imc_counter_type[PATH_MAX];
190+
unsigned int type;
191+
int path_len;
192+
FILE *fp;
193+
int ret;
139194

195+
/* Get type of iMC counter */
196+
path_len = snprintf(imc_counter_type, sizeof(imc_counter_type),
197+
"%s%s", imc_dir, "type");
198+
if (path_len >= sizeof(imc_counter_type)) {
199+
ksft_print_msg("Unable to create path to %s%s\n",
200+
imc_dir, "type");
140201
return -1;
141202
}
142-
if (fscanf(fp, "%1023s", cas_count_cfg) <= 0) {
143-
ksft_perror("Could not get iMC cas count read");
144-
fclose(fp);
203+
fp = fopen(imc_counter_type, "r");
204+
if (!fp) {
205+
ksft_perror("Failed to open iMC counter type file");
145206

146207
return -1;
147208
}
209+
ret = fscanf(fp, "%u", &type);
148210
fclose(fp);
149-
150-
get_read_event_and_umask(cas_count_cfg, *count);
151-
*count += 1;
211+
if (ret <= 0) {
212+
ksft_perror("Could not get iMC type");
213+
return -1;
214+
}
215+
ret = parse_imc_read_bw_events(imc_dir, type, count);
216+
if (ret) {
217+
ksft_print_msg("Unable to parse bandwidth event and umask\n");
218+
return ret;
219+
}
152220

153221
return 0;
154222
}

0 commit comments

Comments
 (0)