Skip to content

Commit a9c81cc

Browse files
Kan LiangPeter Zijlstra
authored andcommitted
perf/x86: Add structures for the attributes of Hybrid PMUs
Hybrid PMUs have different events and formats. In theory, Hybrid PMU specific attributes should be maintained in the dedicated struct x86_hybrid_pmu, but it wastes space because the events and formats are similar among Hybrid PMUs. To reduce duplication, all hybrid PMUs will share a group of attributes in the following patch. To distinguish an attribute from different Hybrid PMUs, a PMU aware attribute structure is introduced. A PMU type is required for the attribute structure. The type is internal usage. It is not visible in the sysfs API. Hybrid PMUs may support the same event name, but with different event encoding, e.g., the mem-loads event on an Atom PMU has different event encoding from a Core PMU. It brings issue if two attributes are created for them. Current sysfs_update_group finds an attribute by searching the attr name (aka event name). If two attributes have the same event name, the first attribute will be replaced. To address the issue, only one attribute is created for the event. The event_str is extended and stores event encodings from all Hybrid PMUs. Each event encoding is divided by ";". The order of the event encodings must follow the order of the hybrid PMU index. The event_str is internal usage as well. When a user wants to show the attribute of a Hybrid PMU, only the corresponding part of the string is displayed. Signed-off-by: Kan Liang <kan.liang@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Andi Kleen <ak@linux.intel.com> Link: https://lkml.kernel.org/r/1618237865-33448-18-git-send-email-kan.liang@linux.intel.com
1 parent d9977c4 commit a9c81cc

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

arch/x86/events/core.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,6 +1860,49 @@ ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr,
18601860
pmu_attr->event_str_noht);
18611861
}
18621862

1863+
ssize_t events_hybrid_sysfs_show(struct device *dev,
1864+
struct device_attribute *attr,
1865+
char *page)
1866+
{
1867+
struct perf_pmu_events_hybrid_attr *pmu_attr =
1868+
container_of(attr, struct perf_pmu_events_hybrid_attr, attr);
1869+
struct x86_hybrid_pmu *pmu;
1870+
const char *str, *next_str;
1871+
int i;
1872+
1873+
if (hweight64(pmu_attr->pmu_type) == 1)
1874+
return sprintf(page, "%s", pmu_attr->event_str);
1875+
1876+
/*
1877+
* Hybrid PMUs may support the same event name, but with different
1878+
* event encoding, e.g., the mem-loads event on an Atom PMU has
1879+
* different event encoding from a Core PMU.
1880+
*
1881+
* The event_str includes all event encodings. Each event encoding
1882+
* is divided by ";". The order of the event encodings must follow
1883+
* the order of the hybrid PMU index.
1884+
*/
1885+
pmu = container_of(dev_get_drvdata(dev), struct x86_hybrid_pmu, pmu);
1886+
1887+
str = pmu_attr->event_str;
1888+
for (i = 0; i < x86_pmu.num_hybrid_pmus; i++) {
1889+
if (!(x86_pmu.hybrid_pmu[i].cpu_type & pmu_attr->pmu_type))
1890+
continue;
1891+
if (x86_pmu.hybrid_pmu[i].cpu_type & pmu->cpu_type) {
1892+
next_str = strchr(str, ';');
1893+
if (next_str)
1894+
return snprintf(page, next_str - str + 1, "%s", str);
1895+
else
1896+
return sprintf(page, "%s", str);
1897+
}
1898+
str = strchr(str, ';');
1899+
str++;
1900+
}
1901+
1902+
return 0;
1903+
}
1904+
EXPORT_SYMBOL_GPL(events_hybrid_sysfs_show);
1905+
18631906
EVENT_ATTR(cpu-cycles, CPU_CYCLES );
18641907
EVENT_ATTR(instructions, INSTRUCTIONS );
18651908
EVENT_ATTR(cache-references, CACHE_REFERENCES );

arch/x86/events/perf_event.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,22 @@ static struct perf_pmu_events_ht_attr event_attr_##v = { \
979979
.event_str_ht = ht, \
980980
}
981981

982+
#define EVENT_ATTR_STR_HYBRID(_name, v, str, _pmu) \
983+
static struct perf_pmu_events_hybrid_attr event_attr_##v = { \
984+
.attr = __ATTR(_name, 0444, events_hybrid_sysfs_show, NULL),\
985+
.id = 0, \
986+
.event_str = str, \
987+
.pmu_type = _pmu, \
988+
}
989+
990+
#define FORMAT_HYBRID_PTR(_id) (&format_attr_hybrid_##_id.attr.attr)
991+
992+
#define FORMAT_ATTR_HYBRID(_name, _pmu) \
993+
static struct perf_pmu_format_hybrid_attr format_attr_hybrid_##_name = {\
994+
.attr = __ATTR_RO(_name), \
995+
.pmu_type = _pmu, \
996+
}
997+
982998
struct pmu *x86_get_pmu(unsigned int cpu);
983999
extern struct x86_pmu x86_pmu __read_mostly;
9841000

@@ -1149,6 +1165,9 @@ ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
11491165
char *page);
11501166
ssize_t events_ht_sysfs_show(struct device *dev, struct device_attribute *attr,
11511167
char *page);
1168+
ssize_t events_hybrid_sysfs_show(struct device *dev,
1169+
struct device_attribute *attr,
1170+
char *page);
11521171

11531172
static inline bool fixed_counter_disabled(int i, struct pmu *pmu)
11541173
{

include/linux/perf_event.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,18 @@ struct perf_pmu_events_ht_attr {
15491549
const char *event_str_noht;
15501550
};
15511551

1552+
struct perf_pmu_events_hybrid_attr {
1553+
struct device_attribute attr;
1554+
u64 id;
1555+
const char *event_str;
1556+
u64 pmu_type;
1557+
};
1558+
1559+
struct perf_pmu_format_hybrid_attr {
1560+
struct device_attribute attr;
1561+
u64 pmu_type;
1562+
};
1563+
15521564
ssize_t perf_event_sysfs_show(struct device *dev, struct device_attribute *attr,
15531565
char *page);
15541566

0 commit comments

Comments
 (0)