Skip to content

Commit 57e1326

Browse files
captain5050namhyung
authored andcommitted
perf pmus: Restructure pmu_read_sysfs to scan fewer PMUs
Rather than scanning core or all PMUs, allow pmu_read_sysfs to read some combination of core, other, hwmon and tool PMUs. The PMUs that should be read and are already read are held as bitmaps. It is known that a "hwmon_" prefix is necessary for a hwmon PMU's name, similarly with "tool", so only scan those PMUs in situations the PMU name or the PMU's type number make sense to. The number of openat system calls reduces from 276 to 98 for a hwmon event. The number of openats for regular perf events isn't changed. Signed-off-by: Ian Rogers <[email protected]> Reviewed-by: Kan Liang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Namhyung Kim <[email protected]>
1 parent 340c345 commit 57e1326

File tree

2 files changed

+97
-51
lines changed

2 files changed

+97
-51
lines changed

tools/perf/util/pmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ struct perf_pmu_caps {
3737
};
3838

3939
enum {
40+
PERF_PMU_TYPE_PE_START = 0,
41+
PERF_PMU_TYPE_PE_END = 0xFFFEFFFF,
4042
PERF_PMU_TYPE_HWMON_START = 0xFFFF0000,
4143
PERF_PMU_TYPE_HWMON_END = 0xFFFFFFFD,
4244
PERF_PMU_TYPE_TOOL = 0xFFFFFFFE,

tools/perf/util/pmus.c

Lines changed: 95 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,25 @@
3737
*/
3838
static LIST_HEAD(core_pmus);
3939
static LIST_HEAD(other_pmus);
40-
static bool read_sysfs_core_pmus;
41-
static bool read_sysfs_all_pmus;
40+
enum perf_tool_pmu_type {
41+
PERF_TOOL_PMU_TYPE_PE_CORE,
42+
PERF_TOOL_PMU_TYPE_PE_OTHER,
43+
PERF_TOOL_PMU_TYPE_TOOL,
44+
PERF_TOOL_PMU_TYPE_HWMON,
45+
46+
#define PERF_TOOL_PMU_TYPE_PE_CORE_MASK (1 << PERF_TOOL_PMU_TYPE_PE_CORE)
47+
#define PERF_TOOL_PMU_TYPE_PE_OTHER_MASK (1 << PERF_TOOL_PMU_TYPE_PE_OTHER)
48+
#define PERF_TOOL_PMU_TYPE_TOOL_MASK (1 << PERF_TOOL_PMU_TYPE_TOOL)
49+
#define PERF_TOOL_PMU_TYPE_HWMON_MASK (1 << PERF_TOOL_PMU_TYPE_HWMON)
50+
51+
#define PERF_TOOL_PMU_TYPE_ALL_MASK (PERF_TOOL_PMU_TYPE_PE_CORE_MASK | \
52+
PERF_TOOL_PMU_TYPE_PE_OTHER_MASK | \
53+
PERF_TOOL_PMU_TYPE_TOOL_MASK | \
54+
PERF_TOOL_PMU_TYPE_HWMON_MASK)
55+
};
56+
static unsigned int read_pmu_types;
4257

43-
static void pmu_read_sysfs(bool core_only);
58+
static void pmu_read_sysfs(unsigned int to_read_pmus);
4459

4560
size_t pmu_name_len_no_suffix(const char *str)
4661
{
@@ -102,8 +117,7 @@ void perf_pmus__destroy(void)
102117

103118
perf_pmu__delete(pmu);
104119
}
105-
read_sysfs_core_pmus = false;
106-
read_sysfs_all_pmus = false;
120+
read_pmu_types = 0;
107121
}
108122

109123
static struct perf_pmu *pmu_find(const char *name)
@@ -129,6 +143,7 @@ struct perf_pmu *perf_pmus__find(const char *name)
129143
struct perf_pmu *pmu;
130144
int dirfd;
131145
bool core_pmu;
146+
unsigned int to_read_pmus = 0;
132147

133148
/*
134149
* Once PMU is loaded it stays in the list,
@@ -139,27 +154,39 @@ struct perf_pmu *perf_pmus__find(const char *name)
139154
if (pmu)
140155
return pmu;
141156

142-
if (read_sysfs_all_pmus)
157+
if (read_pmu_types == PERF_TOOL_PMU_TYPE_ALL_MASK)
143158
return NULL;
144159

145160
core_pmu = is_pmu_core(name);
146-
if (core_pmu && read_sysfs_core_pmus)
161+
if (core_pmu && (read_pmu_types & PERF_TOOL_PMU_TYPE_PE_CORE_MASK))
147162
return NULL;
148163

149164
dirfd = perf_pmu__event_source_devices_fd();
150165
pmu = perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name,
151166
/*eager_load=*/false);
152167
close(dirfd);
153168

154-
if (!pmu) {
155-
/*
156-
* Looking up an inidividual PMU failed. This may mean name is
157-
* an alias, so read the PMUs from sysfs and try to find again.
158-
*/
159-
pmu_read_sysfs(core_pmu);
169+
if (pmu)
170+
return pmu;
171+
172+
/* Looking up an individual perf event PMU failed, check if a tool PMU should be read. */
173+
if (!strncmp(name, "hwmon_", 6))
174+
to_read_pmus |= PERF_TOOL_PMU_TYPE_HWMON_MASK;
175+
else if (!strcmp(name, "tool"))
176+
to_read_pmus |= PERF_TOOL_PMU_TYPE_TOOL_MASK;
177+
178+
if (to_read_pmus) {
179+
pmu_read_sysfs(to_read_pmus);
160180
pmu = pmu_find(name);
181+
if (pmu)
182+
return pmu;
161183
}
162-
return pmu;
184+
/* Read all necessary PMUs from sysfs and see if the PMU is found. */
185+
to_read_pmus = PERF_TOOL_PMU_TYPE_PE_CORE_MASK;
186+
if (!core_pmu)
187+
to_read_pmus |= PERF_TOOL_PMU_TYPE_PE_OTHER_MASK;
188+
pmu_read_sysfs(to_read_pmus);
189+
return pmu_find(name);
163190
}
164191

165192
static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
@@ -176,11 +203,11 @@ static struct perf_pmu *perf_pmu__find2(int dirfd, const char *name)
176203
if (pmu)
177204
return pmu;
178205

179-
if (read_sysfs_all_pmus)
206+
if (read_pmu_types == PERF_TOOL_PMU_TYPE_ALL_MASK)
180207
return NULL;
181208

182209
core_pmu = is_pmu_core(name);
183-
if (core_pmu && read_sysfs_core_pmus)
210+
if (core_pmu && (read_pmu_types & PERF_TOOL_PMU_TYPE_PE_CORE_MASK))
184211
return NULL;
185212

186213
return perf_pmu__lookup(core_pmu ? &core_pmus : &other_pmus, dirfd, name,
@@ -197,52 +224,60 @@ static int pmus_cmp(void *priv __maybe_unused,
197224
}
198225

199226
/* Add all pmus in sysfs to pmu list: */
200-
static void pmu_read_sysfs(bool core_only)
227+
static void pmu_read_sysfs(unsigned int to_read_types)
201228
{
202-
int fd;
203-
DIR *dir;
204-
struct dirent *dent;
205229
struct perf_pmu *tool_pmu;
206230

207-
if (read_sysfs_all_pmus || (core_only && read_sysfs_core_pmus))
231+
if ((read_pmu_types & to_read_types) == to_read_types) {
232+
/* All requested PMU types have been read. */
208233
return;
234+
}
209235

210-
fd = perf_pmu__event_source_devices_fd();
211-
if (fd < 0)
212-
return;
236+
if (to_read_types & (PERF_TOOL_PMU_TYPE_PE_CORE_MASK | PERF_TOOL_PMU_TYPE_PE_OTHER_MASK)) {
237+
int fd = perf_pmu__event_source_devices_fd();
238+
DIR *dir;
239+
struct dirent *dent;
240+
bool core_only = (to_read_types & PERF_TOOL_PMU_TYPE_PE_OTHER_MASK) == 0;
213241

214-
dir = fdopendir(fd);
215-
if (!dir) {
216-
close(fd);
217-
return;
218-
}
242+
if (fd < 0)
243+
goto skip_pe_pmus;
219244

220-
while ((dent = readdir(dir))) {
221-
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
222-
continue;
223-
if (core_only && !is_pmu_core(dent->d_name))
224-
continue;
225-
/* add to static LIST_HEAD(core_pmus) or LIST_HEAD(other_pmus): */
226-
perf_pmu__find2(fd, dent->d_name);
227-
}
245+
dir = fdopendir(fd);
246+
if (!dir) {
247+
close(fd);
248+
goto skip_pe_pmus;
249+
}
228250

229-
closedir(dir);
230-
if (list_empty(&core_pmus)) {
251+
while ((dent = readdir(dir))) {
252+
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
253+
continue;
254+
if (core_only && !is_pmu_core(dent->d_name))
255+
continue;
256+
/* add to static LIST_HEAD(core_pmus) or LIST_HEAD(other_pmus): */
257+
perf_pmu__find2(fd, dent->d_name);
258+
}
259+
260+
closedir(dir);
261+
}
262+
skip_pe_pmus:
263+
if ((to_read_types & PERF_TOOL_PMU_TYPE_PE_CORE_MASK) && list_empty(&core_pmus)) {
231264
if (!perf_pmu__create_placeholder_core_pmu(&core_pmus))
232265
pr_err("Failure to set up any core PMUs\n");
233266
}
234267
list_sort(NULL, &core_pmus, pmus_cmp);
235-
if (!core_only) {
268+
269+
if ((to_read_types & PERF_TOOL_PMU_TYPE_TOOL_MASK) != 0 &&
270+
(read_pmu_types & PERF_TOOL_PMU_TYPE_TOOL_MASK) == 0) {
236271
tool_pmu = perf_pmus__tool_pmu();
237272
list_add_tail(&tool_pmu->list, &other_pmus);
238-
perf_pmus__read_hwmon_pmus(&other_pmus);
239273
}
274+
if ((to_read_types & PERF_TOOL_PMU_TYPE_HWMON_MASK) != 0 &&
275+
(read_pmu_types & PERF_TOOL_PMU_TYPE_HWMON_MASK) == 0)
276+
perf_pmus__read_hwmon_pmus(&other_pmus);
277+
240278
list_sort(NULL, &other_pmus, pmus_cmp);
241-
if (!list_empty(&core_pmus)) {
242-
read_sysfs_core_pmus = true;
243-
if (!core_only)
244-
read_sysfs_all_pmus = true;
245-
}
279+
280+
read_pmu_types |= to_read_types;
246281
}
247282

248283
static struct perf_pmu *__perf_pmus__find_by_type(unsigned int type)
@@ -263,12 +298,21 @@ static struct perf_pmu *__perf_pmus__find_by_type(unsigned int type)
263298

264299
struct perf_pmu *perf_pmus__find_by_type(unsigned int type)
265300
{
301+
unsigned int to_read_pmus;
266302
struct perf_pmu *pmu = __perf_pmus__find_by_type(type);
267303

268-
if (pmu || read_sysfs_all_pmus)
304+
if (pmu || (read_pmu_types == PERF_TOOL_PMU_TYPE_ALL_MASK))
269305
return pmu;
270306

271-
pmu_read_sysfs(/*core_only=*/false);
307+
if (type >= PERF_PMU_TYPE_PE_START && type <= PERF_PMU_TYPE_PE_END) {
308+
to_read_pmus = PERF_TOOL_PMU_TYPE_PE_CORE_MASK |
309+
PERF_TOOL_PMU_TYPE_PE_OTHER_MASK;
310+
} else if (type >= PERF_PMU_TYPE_HWMON_START && type <= PERF_PMU_TYPE_HWMON_END) {
311+
to_read_pmus = PERF_TOOL_PMU_TYPE_HWMON_MASK;
312+
} else {
313+
to_read_pmus = PERF_TOOL_PMU_TYPE_TOOL_MASK;
314+
}
315+
pmu_read_sysfs(to_read_pmus);
272316
pmu = __perf_pmus__find_by_type(type);
273317
return pmu;
274318
}
@@ -282,7 +326,7 @@ struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu)
282326
bool use_core_pmus = !pmu || pmu->is_core;
283327

284328
if (!pmu) {
285-
pmu_read_sysfs(/*core_only=*/false);
329+
pmu_read_sysfs(PERF_TOOL_PMU_TYPE_ALL_MASK);
286330
pmu = list_prepare_entry(pmu, &core_pmus, list);
287331
}
288332
if (use_core_pmus) {
@@ -300,7 +344,7 @@ struct perf_pmu *perf_pmus__scan(struct perf_pmu *pmu)
300344
struct perf_pmu *perf_pmus__scan_core(struct perf_pmu *pmu)
301345
{
302346
if (!pmu) {
303-
pmu_read_sysfs(/*core_only=*/true);
347+
pmu_read_sysfs(PERF_TOOL_PMU_TYPE_PE_CORE_MASK);
304348
return list_first_entry_or_null(&core_pmus, typeof(*pmu), list);
305349
}
306350
list_for_each_entry_continue(pmu, &core_pmus, list)
@@ -316,7 +360,7 @@ static struct perf_pmu *perf_pmus__scan_skip_duplicates(struct perf_pmu *pmu)
316360
const char *last_pmu_name = (pmu && pmu->name) ? pmu->name : "";
317361

318362
if (!pmu) {
319-
pmu_read_sysfs(/*core_only=*/false);
363+
pmu_read_sysfs(PERF_TOOL_PMU_TYPE_ALL_MASK);
320364
pmu = list_prepare_entry(pmu, &core_pmus, list);
321365
} else
322366
last_pmu_name_len = pmu_name_len_no_suffix(pmu->name ?: "");

0 commit comments

Comments
 (0)