2021-04-16 14:25:54

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 00/25] perf tool: AlderLake hybrid support series 1

AlderLake uses a hybrid architecture utilizing Golden Cove cores
(core cpu) and Gracemont cores (atom cpu). Each cpu has dedicated
event list. Some events are available on core cpu, some events
are available on atom cpu and some events can be available on both.

Kernel exports new pmus "cpu_core" and "cpu_atom" through sysfs:
/sys/devices/cpu_core
/sys/devices/cpu_atom

cat /sys/devices/cpu_core/cpus
0-15

cat /sys/devices/cpu_atom/cpus
16-23

In this example, core cpus are 0-15 and atom cpus are 16-23.

To enable a core only event or atom only event:

cpu_core/<event name>/
or
cpu_atom/<event name>/

Count the 'cycles' event on core cpus.

# perf stat -e cpu_core/cycles/ -a -- sleep 1

Performance counter stats for 'system wide':

12,853,951,349 cpu_core/cycles/

1.002581249 seconds time elapsed

If one event is available on both atom cpu and core cpu, two events
are created automatically.

# perf stat -e cycles -a -- sleep 1

Performance counter stats for 'system wide':

12,856,467,438 cpu_core/cycles/
6,404,634,785 cpu_atom/cycles/

1.002453013 seconds time elapsed

Group is supported if the events are from same pmu, otherwise a warning
is displayed and disable grouping automatically.

# perf stat -e '{cpu_core/cycles/,cpu_core/instructions/}' -a -- sleep 1

Performance counter stats for 'system wide':

12,863,866,968 cpu_core/cycles/
554,795,017 cpu_core/instructions/

1.002616117 seconds time elapsed

# perf stat -e '{cpu_core/cycles/,cpu_atom/instructions/}' -a -- sleep 1
WARNING: events in group from different hybrid PMUs!
WARNING: grouped events cpus do not match, disabling group:
anon group { cpu_core/cycles/, cpu_atom/instructions/ }

Performance counter stats for 'system wide':

6,283,970 cpu_core/cycles/
765,635 cpu_atom/instructions/

1.003959036 seconds time elapsed

Note that, since the whole patchset for AlderLake hybrid support is very
large (40+ patches). For simplicity, it's splitted into several patch
series.

The patch series 1 only supports the basic functionality. The advanced
supports for perf-c2c/perf-mem/topdown/metrics/topology header and others
will be added in follow-up patch series.

The perf tool codes can also be found at:
https://github.com/yaoj/perf.git

v4:
---
- In Liang Kan's patch:
'[PATCH V6 21/25] perf: Extend PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE',
the user interface for hardware events and cache events are changed, so
perf tool patches are changed as well.

- Fix an issue when atom CPUs are offlined. "/sys/bus/event_source/devices/cpu_atom/cpus"
exists but the content is empty. For this case, we can't enable the cpu_atom
PMU. '[PATCH v4 05/25] perf pmu: Save detected hybrid pmus to a global pmu list'

- Define 'ret' variable for return value in patch
'[PATCH v4 09/25] perf parse-events: Create two hybrid cache events'

- Directly return add_raw_hybrid() in patch
'[PATCH v4 10/25] perf parse-events: Create two hybrid raw events'

- Drop the patch 'perf pmu: Support 'cycles' and 'branches' inside
hybrid PMU'.

- Separate '[PATCH v3 12/27] perf parse-events: Support no alias assigned event
inside hybrid PMU' into two patches:
'[PATCH v4 11/25] perf parse-events: Compare with hybrid pmu name'
'[PATCH v4 12/25] perf parse-events: Support event inside hybrid pmu'.
And these two patches are improved according to Jiri's comments.

v3:
---
- Drop 'perf evlist: Hybrid event uses its own cpus'. This patch is wide
and actually it's not very necessary. The current perf framework has
processed the cpus for evsel well even for hybrid evsel. So this patch can
be dropped.

- Drop 'perf evsel: Adjust hybrid event and global event mixed group'.
The patch is a bit tricky and hard to understand. In v3, we will disable
grouping when the group members are from different PMUs. So this patch
would be not necessary.

- Create parse-events-hybrid.c/parse-events-hybrid.h and evlist-hybrid.c/evlist-hybrid.h.
Move hybrid related codes to these files.

- Create a new patch 'perf pmu: Support 'cycles' and 'branches' inside hybrid PMU' to
support 'cycles' and 'branches' inside PMU.

- Create a new patch 'perf record: Uniquify hybrid event name' to tell user the
pmu which the event belongs to for perf-record.

- If group members are from different hybrid PMUs, shows warning and disable
grouping.

- Other refining and refactoring.

v2:
---
- Drop kernel patches (Kan posted the series "Add Alder Lake support for perf (kernel)" separately).
- Drop the patches for perf-c2c/perf-mem/topdown/metrics/topology header supports,
which will be added in series 2 or series 3.
- Simplify the arguments of __perf_pmu__new_alias() by passing
the 'struct pme_event' pointer.
- Check sysfs validity before access.
- Use pmu style event name, such as "cpu_core/cycles/".
- Move command output two chars to the right.
- Move pmu hybrid functions to new created pmu-hybrid.c/pmu-hybrid.h.
This is to pass the perf test python case.

Jin Yao (25):
tools headers uapi: Update tools's copy of linux/perf_event.h
perf jevents: Support unit value "cpu_core" and "cpu_atom"
perf pmu: Simplify arguments of __perf_pmu__new_alias
perf pmu: Save pmu name
perf pmu: Save detected hybrid pmus to a global pmu list
perf pmu: Add hybrid helper functions
perf stat: Uniquify hybrid event name
perf parse-events: Create two hybrid hardware events
perf parse-events: Create two hybrid cache events
perf parse-events: Create two hybrid raw events
perf parse-events: Compare with hybrid pmu name
perf parse-events: Support event inside hybrid pmu
perf record: Create two hybrid 'cycles' events by default
perf stat: Add default hybrid events
perf stat: Filter out unmatched aggregation for hybrid event
perf stat: Warn group events from different hybrid PMU
perf record: Uniquify hybrid event name
perf tests: Add hybrid cases for 'Parse event definition strings' test
perf tests: Add hybrid cases for 'Roundtrip evsel->name' test
perf tests: Skip 'Setup struct perf_event_attr' test for hybrid
perf tests: Support 'Track with sched_switch' test for hybrid
perf tests: Support 'Parse and process metrics' test for hybrid
perf tests: Support 'Session topology' test for hybrid
perf tests: Support 'Convert perf time to TSC' test for hybrid
perf tests: Skip 'perf stat metrics (shadow stat) test' for hybrid

include/uapi/linux/perf_event.h | 15 ++
tools/include/uapi/linux/perf_event.h | 15 ++
tools/perf/builtin-record.c | 47 +++++-
tools/perf/builtin-stat.c | 29 ++++
tools/perf/pmu-events/jevents.c | 2 +
tools/perf/tests/attr.c | 4 +
tools/perf/tests/evsel-roundtrip-name.c | 19 ++-
tools/perf/tests/parse-events.c | 152 ++++++++++++++++++
tools/perf/tests/parse-metric.c | 10 +-
tools/perf/tests/perf-time-to-tsc.c | 16 ++
tools/perf/tests/shell/stat+shadow_stat.sh | 3 +
tools/perf/tests/switch-tracking.c | 10 +-
tools/perf/tests/topology.c | 10 +-
tools/perf/util/Build | 3 +
tools/perf/util/evlist-hybrid.c | 88 ++++++++++
tools/perf/util/evlist-hybrid.h | 14 ++
tools/perf/util/evlist.c | 5 +-
tools/perf/util/evsel.c | 12 +-
tools/perf/util/evsel.h | 4 +-
tools/perf/util/parse-events-hybrid.c | 178 +++++++++++++++++++++
tools/perf/util/parse-events-hybrid.h | 23 +++
tools/perf/util/parse-events.c | 86 +++++++++-
tools/perf/util/parse-events.h | 9 +-
tools/perf/util/parse-events.y | 9 +-
tools/perf/util/pmu-hybrid.c | 89 +++++++++++
tools/perf/util/pmu-hybrid.h | 22 +++
tools/perf/util/pmu.c | 64 +++++---
tools/perf/util/pmu.h | 7 +
tools/perf/util/python-ext-sources | 2 +
tools/perf/util/stat-display.c | 35 +++-
30 files changed, 933 insertions(+), 49 deletions(-)
create mode 100644 tools/perf/util/evlist-hybrid.c
create mode 100644 tools/perf/util/evlist-hybrid.h
create mode 100644 tools/perf/util/parse-events-hybrid.c
create mode 100644 tools/perf/util/parse-events-hybrid.h
create mode 100644 tools/perf/util/pmu-hybrid.c
create mode 100644 tools/perf/util/pmu-hybrid.h

--
2.17.1


2021-04-16 14:25:56

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 01/25] tools headers uapi: Update tools's copy of linux/perf_event.h

To get the changes in:

Liang Kan's patch
[PATCH V6 21/25] perf: Extend PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE

Kan's patch is in review at the moment. The following perf tool
patches need this interface for hybrid support.

This patch can be removed after Kan's patch is upstreamed.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- Updated by Kan's latest patch,
'[PATCH V6 21/25] perf: Extend PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE'

include/uapi/linux/perf_event.h | 15 +++++++++++++++
tools/include/uapi/linux/perf_event.h | 15 +++++++++++++++
2 files changed, 30 insertions(+)

diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index ad15e40d7f5d..14332f4cf816 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -37,6 +37,21 @@ enum perf_type_id {
PERF_TYPE_MAX, /* non-ABI */
};

+/*
+ * attr.config layout for type PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE
+ * PERF_TYPE_HARDWARE: 0xEEEEEEEE000000AA
+ * AA: hardware event ID
+ * EEEEEEEE: PMU type ID
+ * PERF_TYPE_HW_CACHE: 0xEEEEEEEE00DDCCBB
+ * BB: hardware cache ID
+ * CC: hardware cache op ID
+ * DD: hardware cache op result ID
+ * EEEEEEEE: PMU type ID
+ * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied.
+ */
+#define PERF_PMU_TYPE_SHIFT 32
+#define PERF_HW_EVENT_MASK 0xffffffff
+
/*
* Generalized performance event event_id types, used by the
* attr.event_id parameter of the sys_perf_event_open()
diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h
index ad15e40d7f5d..14332f4cf816 100644
--- a/tools/include/uapi/linux/perf_event.h
+++ b/tools/include/uapi/linux/perf_event.h
@@ -37,6 +37,21 @@ enum perf_type_id {
PERF_TYPE_MAX, /* non-ABI */
};

+/*
+ * attr.config layout for type PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE
+ * PERF_TYPE_HARDWARE: 0xEEEEEEEE000000AA
+ * AA: hardware event ID
+ * EEEEEEEE: PMU type ID
+ * PERF_TYPE_HW_CACHE: 0xEEEEEEEE00DDCCBB
+ * BB: hardware cache ID
+ * CC: hardware cache op ID
+ * DD: hardware cache op result ID
+ * EEEEEEEE: PMU type ID
+ * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied.
+ */
+#define PERF_PMU_TYPE_SHIFT 32
+#define PERF_HW_EVENT_MASK 0xffffffff
+
/*
* Generalized performance event event_id types, used by the
* attr.event_id parameter of the sys_perf_event_open()
--
2.17.1

2021-04-16 14:26:19

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 20/25] perf tests: Skip 'Setup struct perf_event_attr' test for hybrid

For hybrid, the attr.type consists of pmu type id + original type.
There will be much changes for this test. Now we temporarily
skip this test case and TODO in future.

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/attr.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index dd39ce9b0277..b37c35fb5a46 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -34,6 +34,7 @@
#include "event.h"
#include "util.h"
#include "tests.h"
+#include "pmu.h"

#define ENV "PERF_TEST_ATTR"

@@ -184,6 +185,9 @@ int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
char path_dir[PATH_MAX];
char *exec_path;

+ if (perf_pmu__has_hybrid())
+ return 0;
+
/* First try development tree tests. */
if (!lstat("./tests", &st))
return run_dir("./tests", "./perf");
--
2.17.1

2021-04-16 14:26:26

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 03/25] perf pmu: Simplify arguments of __perf_pmu__new_alias

Simplify the arguments of __perf_pmu__new_alias() by passing
the whole 'struct pme_event' pointer.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- No change.

tools/perf/util/pmu.c | 36 ++++++++++++++++--------------------
1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 286d5e415bdc..8214def7b0f0 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -306,18 +306,25 @@ static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,
}

static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
- char *desc, char *val,
- char *long_desc, char *topic,
- char *unit, char *perpkg,
- char *metric_expr,
- char *metric_name,
- char *deprecated)
+ char *desc, char *val, struct pmu_event *pe)
{
struct parse_events_term *term;
struct perf_pmu_alias *alias;
int ret;
int num;
char newval[256];
+ char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL,
+ *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL;
+
+ if (pe) {
+ long_desc = (char *)pe->long_desc;
+ topic = (char *)pe->topic;
+ unit = (char *)pe->unit;
+ perpkg = (char *)pe->perpkg;
+ metric_expr = (char *)pe->metric_expr;
+ metric_name = (char *)pe->metric_name;
+ deprecated = (char *)pe->deprecated;
+ }

alias = malloc(sizeof(*alias));
if (!alias)
@@ -406,8 +413,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
/* Remove trailing newline from sysfs file */
strim(buf);

- return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL);
+ return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL);
}

static inline bool pmu_alias_info_file(char *name)
@@ -798,11 +804,7 @@ void pmu_add_cpu_aliases_map(struct list_head *head, struct perf_pmu *pmu,
/* need type casts to override 'const' */
__perf_pmu__new_alias(head, NULL, (char *)pe->name,
(char *)pe->desc, (char *)pe->event,
- (char *)pe->long_desc, (char *)pe->topic,
- (char *)pe->unit, (char *)pe->perpkg,
- (char *)pe->metric_expr,
- (char *)pe->metric_name,
- (char *)pe->deprecated);
+ pe);
}
}

@@ -869,13 +871,7 @@ static int pmu_add_sys_aliases_iter_fn(struct pmu_event *pe, void *data)
(char *)pe->name,
(char *)pe->desc,
(char *)pe->event,
- (char *)pe->long_desc,
- (char *)pe->topic,
- (char *)pe->unit,
- (char *)pe->perpkg,
- (char *)pe->metric_expr,
- (char *)pe->metric_name,
- (char *)pe->deprecated);
+ pe);
}

return 0;
--
2.17.1

2021-04-16 14:26:27

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 21/25] perf tests: Support 'Track with sched_switch' test for hybrid

Since for "cycles:u' on hybrid platform, it creates two "cycles".
So the number of events in evlist is not expected in next test
steps. Now we just use one event "cpu_core/cycles:u/" for hybrid.

# ./perf test 35
35: Track with sched_switch : Ok

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/switch-tracking.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index 3ebaa758df77..3a12176f8c46 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -18,6 +18,7 @@
#include "record.h"
#include "tests.h"
#include "util/mmap.h"
+#include "pmu.h"

static int spin_sleep(void)
{
@@ -340,6 +341,10 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_
struct evsel *switch_evsel, *tracking_evsel;
const char *comm;
int err = -1;
+ bool hybrid = false;
+
+ if (perf_pmu__has_hybrid())
+ hybrid = true;

threads = thread_map__new(-1, getpid(), UINT_MAX);
if (!threads) {
@@ -371,7 +376,10 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_
cpu_clocks_evsel = evlist__last(evlist);

/* Second event */
- err = parse_events(evlist, "cycles:u", NULL);
+ if (!hybrid)
+ err = parse_events(evlist, "cycles:u", NULL);
+ else
+ err = parse_events(evlist, "cpu_core/cycles/u", NULL);
if (err) {
pr_debug("Failed to parse event cycles:u\n");
goto out_err;
--
2.17.1

2021-04-16 14:26:35

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 04/25] perf pmu: Save pmu name

On hybrid platform, one event is available on one pmu
(such as, available on cpu_core or on cpu_atom).

This patch saves the pmu name to the pmu field of struct perf_pmu_alias.
Then next we can know the pmu which the event can be enabled on.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- No change.

v3:
- Change pmu to pmu_name in struct perf_pmu_alias.

tools/perf/util/pmu.c | 10 +++++++++-
tools/perf/util/pmu.h | 1 +
2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 8214def7b0f0..44225838eb03 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -283,6 +283,7 @@ void perf_pmu_free_alias(struct perf_pmu_alias *newalias)
zfree(&newalias->str);
zfree(&newalias->metric_expr);
zfree(&newalias->metric_name);
+ zfree(&newalias->pmu_name);
parse_events_terms__purge(&newalias->terms);
free(newalias);
}
@@ -297,6 +298,10 @@ static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias,

list_for_each_entry(a, alist, list) {
if (!strcasecmp(newalias->name, a->name)) {
+ if (newalias->pmu_name && a->pmu_name &&
+ !strcasecmp(newalias->pmu_name, a->pmu_name)) {
+ continue;
+ }
perf_pmu_update_alias(a, newalias);
perf_pmu_free_alias(newalias);
return true;
@@ -314,7 +319,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
int num;
char newval[256];
char *long_desc = NULL, *topic = NULL, *unit = NULL, *perpkg = NULL,
- *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL;
+ *metric_expr = NULL, *metric_name = NULL, *deprecated = NULL,
+ *pmu_name = NULL;

if (pe) {
long_desc = (char *)pe->long_desc;
@@ -324,6 +330,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
metric_expr = (char *)pe->metric_expr;
metric_name = (char *)pe->metric_name;
deprecated = (char *)pe->deprecated;
+ pmu_name = (char *)pe->pmu;
}

alias = malloc(sizeof(*alias));
@@ -389,6 +396,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
}
alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
alias->str = strdup(newval);
+ alias->pmu_name = pmu_name ? strdup(pmu_name) : NULL;

if (deprecated)
alias->deprecated = true;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 1f1749ba830f..4f100768c264 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -72,6 +72,7 @@ struct perf_pmu_alias {
bool deprecated;
char *metric_expr;
char *metric_name;
+ char *pmu_name;
};

struct perf_pmu *perf_pmu__find(const char *name);
--
2.17.1

2021-04-16 14:26:41

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 05/25] perf pmu: Save detected hybrid pmus to a global pmu list

We identify the cpu_core pmu and cpu_atom pmu by explicitly
checking following files:

For cpu_core, checks:
"/sys/bus/event_source/devices/cpu_core/cpus"

For cpu_atom, checks:
"/sys/bus/event_source/devices/cpu_atom/cpus"

If the 'cpus' file exists and it has data, the pmu exists.

But in order not to hardcode the "cpu_core" and "cpu_atom",
and make the code in a generic way. So if the path
"/sys/bus/event_source/devices/cpu_xxx/cpus" exists, the hybrid
pmu exists. All the detected hybrid pmus are linked to a
global list 'perf_pmu__hybrid_pmus' and then next we just need
to iterate the list to get all hybrid pmu by using
perf_pmu__for_each_hybrid_pmu.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- Check if 'cpus' file is empty. If so, don't create pmu.

v3:
- No functional change.

tools/perf/util/Build | 1 +
tools/perf/util/pmu-hybrid.c | 49 ++++++++++++++++++++++++++++++++++++
tools/perf/util/pmu-hybrid.h | 18 +++++++++++++
tools/perf/util/pmu.c | 9 ++++++-
tools/perf/util/pmu.h | 4 +++
5 files changed, 80 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/util/pmu-hybrid.c
create mode 100644 tools/perf/util/pmu-hybrid.h

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index e3e12f9d4733..37a8a63c7195 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -69,6 +69,7 @@ perf-y += parse-events-bison.o
perf-y += pmu.o
perf-y += pmu-flex.o
perf-y += pmu-bison.o
+perf-y += pmu-hybrid.o
perf-y += trace-event-read.o
perf-y += trace-event-info.o
perf-y += trace-event-scripting.o
diff --git a/tools/perf/util/pmu-hybrid.c b/tools/perf/util/pmu-hybrid.c
new file mode 100644
index 000000000000..8ed0e6e1776d
--- /dev/null
+++ b/tools/perf/util/pmu-hybrid.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <linux/string.h>
+#include <linux/zalloc.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <locale.h>
+#include <api/fs/fs.h>
+#include "fncache.h"
+#include "pmu-hybrid.h"
+
+LIST_HEAD(perf_pmu__hybrid_pmus);
+
+bool perf_pmu__hybrid_mounted(const char *name)
+{
+ char path[PATH_MAX];
+ const char *sysfs;
+ FILE *file;
+ int n, cpu;
+
+ if (strncmp(name, "cpu_", 4))
+ return false;
+
+ sysfs = sysfs__mountpoint();
+ if (!sysfs)
+ return false;
+
+ snprintf(path, PATH_MAX, CPUS_TEMPLATE_CPU, sysfs, name);
+ if (!file_available(path))
+ return false;
+
+ file = fopen(path, "r");
+ if (!file)
+ return false;
+
+ n = fscanf(file, "%u", &cpu);
+ fclose(file);
+ if (n <= 0)
+ return false;
+
+ return true;
+}
diff --git a/tools/perf/util/pmu-hybrid.h b/tools/perf/util/pmu-hybrid.h
new file mode 100644
index 000000000000..35bed3714438
--- /dev/null
+++ b/tools/perf/util/pmu-hybrid.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PMU_HYBRID_H
+#define __PMU_HYBRID_H
+
+#include <linux/perf_event.h>
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <stdbool.h>
+#include "pmu.h"
+
+extern struct list_head perf_pmu__hybrid_pmus;
+
+#define perf_pmu__for_each_hybrid_pmu(pmu) \
+ list_for_each_entry(pmu, &perf_pmu__hybrid_pmus, hybrid_list)
+
+bool perf_pmu__hybrid_mounted(const char *name);
+
+#endif /* __PMU_HYBRID_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 44225838eb03..6e49c7b8ad71 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -25,6 +25,7 @@
#include "string2.h"
#include "strbuf.h"
#include "fncache.h"
+#include "pmu-hybrid.h"

struct perf_pmu perf_pmu__fake;

@@ -613,7 +614,6 @@ static struct perf_cpu_map *__pmu_cpumask(const char *path)
*/
#define SYS_TEMPLATE_ID "./bus/event_source/devices/%s/identifier"
#define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask"
-#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus"

static struct perf_cpu_map *pmu_cpumask(const char *name)
{
@@ -645,6 +645,9 @@ static bool pmu_is_uncore(const char *name)
char path[PATH_MAX];
const char *sysfs;

+ if (perf_pmu__hybrid_mounted(name))
+ return false;
+
sysfs = sysfs__mountpoint();
snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name);
return file_available(path);
@@ -951,6 +954,7 @@ static struct perf_pmu *pmu_lookup(const char *name)
pmu->is_uncore = pmu_is_uncore(name);
if (pmu->is_uncore)
pmu->id = pmu_id(name);
+ pmu->is_hybrid = perf_pmu__hybrid_mounted(name);
pmu->max_precise = pmu_max_precise(name);
pmu_add_cpu_aliases(&aliases, pmu);
pmu_add_sys_aliases(&aliases, pmu);
@@ -962,6 +966,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
list_splice(&aliases, &pmu->aliases);
list_add_tail(&pmu->list, &pmus);

+ if (pmu->is_hybrid)
+ list_add_tail(&pmu->hybrid_list, &perf_pmu__hybrid_pmus);
+
pmu->default_config = perf_pmu__get_default_config(pmu);

return pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 4f100768c264..9a2f89eeab6f 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -5,6 +5,7 @@
#include <linux/bitmap.h>
#include <linux/compiler.h>
#include <linux/perf_event.h>
+#include <linux/list.h>
#include <stdbool.h>
#include "parse-events.h"
#include "pmu-events/pmu-events.h"
@@ -19,6 +20,7 @@ enum {

#define PERF_PMU_FORMAT_BITS 64
#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
+#define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus"

struct perf_event_attr;

@@ -34,6 +36,7 @@ struct perf_pmu {
__u32 type;
bool selectable;
bool is_uncore;
+ bool is_hybrid;
bool auxtrace;
int max_precise;
struct perf_event_attr *default_config;
@@ -42,6 +45,7 @@ struct perf_pmu {
struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */
struct list_head caps; /* HEAD struct perf_pmu_caps -> list */
struct list_head list; /* ELEM */
+ struct list_head hybrid_list;
};

extern struct perf_pmu perf_pmu__fake;
--
2.17.1

2021-04-16 14:27:10

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 09/25] perf parse-events: Create two hybrid cache events

For cache events, they have pre-defined configs. The kernel needs
to know where the cache event comes from (e.g. from cpu_core pmu
or from cpu_atom pmu). But the perf type PERF_TYPE_HW_CACHE
can't carry pmu information.

Now the type PERF_TYPE_HW_CACHE is extended to be PMU aware type.
The PMU type ID is stored at attr.config[63:32].

When enabling a hybrid cache event without specified pmu, such as,
'perf stat -e LLC-loads -a', two events are created
automatically. One is for atom, the other is for core.

# perf stat -e LLC-loads -a -vv -- sleep 1
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 3
size 120
config 0x400000002
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
...
------------------------------------------------------------
perf_event_attr:
type 3
size 120
config 0x400000002
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 15 group_fd -1 flags 0x8 = 19
------------------------------------------------------------
perf_event_attr:
type 3
size 120
config 0x800000002
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 16 group_fd -1 flags 0x8 = 20
------------------------------------------------------------
...
------------------------------------------------------------
perf_event_attr:
type 3
size 120
config 0x800000002
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 23 group_fd -1 flags 0x8 = 27
LLC-loads: 0: 1507 1001800280 1001800280
LLC-loads: 1: 666 1001812250 1001812250
LLC-loads: 2: 3353 1001813453 1001813453
LLC-loads: 3: 514 1001848795 1001848795
LLC-loads: 4: 627 1001952832 1001952832
LLC-loads: 5: 4399 1001451154 1001451154
LLC-loads: 6: 1240 1001481052 1001481052
LLC-loads: 7: 478 1001520348 1001520348
LLC-loads: 8: 691 1001551236 1001551236
LLC-loads: 9: 310 1001578945 1001578945
LLC-loads: 10: 1018 1001594354 1001594354
LLC-loads: 11: 3656 1001622355 1001622355
LLC-loads: 12: 882 1001661416 1001661416
LLC-loads: 13: 506 1001693963 1001693963
LLC-loads: 14: 3547 1001721013 1001721013
LLC-loads: 15: 1399 1001734818 1001734818
LLC-loads: 0: 1314 1001793826 1001793826
LLC-loads: 1: 2857 1001752764 1001752764
LLC-loads: 2: 646 1001830694 1001830694
LLC-loads: 3: 1612 1001864861 1001864861
LLC-loads: 4: 2244 1001912381 1001912381
LLC-loads: 5: 1255 1001943889 1001943889
LLC-loads: 6: 4624 1002021109 1002021109
LLC-loads: 7: 2703 1001959302 1001959302
LLC-loads: 24793 16026838264 16026838264
LLC-loads: 17255 8015078826 8015078826

Performance counter stats for 'system wide':

24,793 cpu_core/LLC-loads/
17,255 cpu_atom/LLC-loads/

1.001970988 seconds time elapsed

0x4 in 0x400000002 indicates the cpu_core pmu.
0x8 in 0x800000002 indicates the cpu_atom pmu.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- Use PERF_TYPE_HW_CACHE (v3 uses PERF_TYPE_HW_CACHE_PMU)
- Define 'ret' variable for return value.

v3:
- Raw event creation is moved to parse-events-hybrid.c.

tools/perf/util/parse-events-hybrid.c | 23 +++++++++++++++++++++++
tools/perf/util/parse-events-hybrid.h | 5 +++++
tools/perf/util/parse-events.c | 10 +++++++++-
3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/parse-events-hybrid.c b/tools/perf/util/parse-events-hybrid.c
index 8fd7f19a9865..7a7e065d2b5f 100644
--- a/tools/perf/util/parse-events-hybrid.c
+++ b/tools/perf/util/parse-events-hybrid.c
@@ -98,3 +98,26 @@ int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,

return -1;
}
+
+int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
+ struct perf_event_attr *attr, char *name,
+ struct list_head *config_terms,
+ bool *hybrid)
+{
+ struct perf_pmu *pmu;
+ int ret;
+
+ *hybrid = false;
+ if (!perf_pmu__has_hybrid())
+ return 0;
+
+ *hybrid = true;
+ perf_pmu__for_each_hybrid_pmu(pmu) {
+ ret = create_event_hybrid(PERF_TYPE_HW_CACHE, idx, list,
+ attr, name, config_terms, pmu);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/tools/perf/util/parse-events-hybrid.h b/tools/perf/util/parse-events-hybrid.h
index d81a76978480..9ad33cd0cef4 100644
--- a/tools/perf/util/parse-events-hybrid.h
+++ b/tools/perf/util/parse-events-hybrid.h
@@ -14,4 +14,9 @@ int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
char *name, struct list_head *config_terms,
bool *hybrid);

+int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
+ struct perf_event_attr *attr, char *name,
+ struct list_head *config_terms,
+ bool *hybrid);
+
#endif /* __PERF_PARSE_EVENTS_HYBRID_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index f8a147b53962..9b2588df22a4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -460,7 +460,8 @@ int parse_events_add_cache(struct list_head *list, int *idx,
char name[MAX_NAME_LEN], *config_name;
int cache_type = -1, cache_op = -1, cache_result = -1;
char *op_result[2] = { op_result1, op_result2 };
- int i, n;
+ int i, n, ret;
+ bool hybrid;

/*
* No fallback - if we cannot get a clear cache type
@@ -520,6 +521,13 @@ int parse_events_add_cache(struct list_head *list, int *idx,
if (get_config_terms(head_config, &config_terms))
return -ENOMEM;
}
+
+ ret = parse_events__add_cache_hybrid(list, idx, &attr,
+ config_name ? : name, &config_terms,
+ &hybrid);
+ if (hybrid)
+ return ret;
+
return add_event(list, idx, &attr, config_name ? : name, &config_terms);
}

--
2.17.1

2021-04-16 14:27:17

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 10/25] perf parse-events: Create two hybrid raw events

On hybrid platform, same raw event is possible to be available
on both cpu_core pmu and cpu_atom pmu. It's supported to create
two raw events for one event encoding. For raw events, the
attr.type is PMU type.

# perf stat -e r3c -a -vv -- sleep 1
Control descriptor is not initialized
------------------------------------------------------------
perf_event_attr:
type 4
size 120
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 = 3
------------------------------------------------------------
...
------------------------------------------------------------
perf_event_attr:
type 4
size 120
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 15 group_fd -1 flags 0x8 = 19
------------------------------------------------------------
perf_event_attr:
type 8
size 120
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 16 group_fd -1 flags 0x8 = 20
------------------------------------------------------------
...
------------------------------------------------------------
perf_event_attr:
type 8
size 120
config 0x3c
sample_type IDENTIFIER
read_format TOTAL_TIME_ENABLED|TOTAL_TIME_RUNNING
disabled 1
inherit 1
exclude_guest 1
------------------------------------------------------------
sys_perf_event_open: pid -1 cpu 23 group_fd -1 flags 0x8 = 27
r3c: 0: 434449 1001412521 1001412521
r3c: 1: 173162 1001482031 1001482031
r3c: 2: 231710 1001524974 1001524974
r3c: 3: 110012 1001563523 1001563523
r3c: 4: 191517 1001593221 1001593221
r3c: 5: 956458 1001628147 1001628147
r3c: 6: 416969 1001715626 1001715626
r3c: 7: 1047527 1001596650 1001596650
r3c: 8: 103877 1001633520 1001633520
r3c: 9: 70571 1001637898 1001637898
r3c: 10: 550284 1001714398 1001714398
r3c: 11: 1257274 1001738349 1001738349
r3c: 12: 107797 1001801432 1001801432
r3c: 13: 67471 1001836281 1001836281
r3c: 14: 286782 1001923161 1001923161
r3c: 15: 815509 1001952550 1001952550
r3c: 0: 95994 1002071117 1002071117
r3c: 1: 105570 1002142438 1002142438
r3c: 2: 115921 1002189147 1002189147
r3c: 3: 72747 1002238133 1002238133
r3c: 4: 103519 1002276753 1002276753
r3c: 5: 121382 1002315131 1002315131
r3c: 6: 80298 1002248050 1002248050
r3c: 7: 466790 1002278221 1002278221
r3c: 6821369 16026754282 16026754282
r3c: 1162221 8017758990 8017758990

Performance counter stats for 'system wide':

6,821,369 cpu_core/r3c/
1,162,221 cpu_atom/r3c/

1.002289965 seconds time elapsed

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- Directly return add_raw_hybrid().

v3:
- Raw event creation is moved to parse-events-hybrid.c.

tools/perf/util/parse-events-hybrid.c | 38 ++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/parse-events-hybrid.c b/tools/perf/util/parse-events-hybrid.c
index 7a7e065d2b5f..e27b747080e1 100644
--- a/tools/perf/util/parse-events-hybrid.c
+++ b/tools/perf/util/parse-events-hybrid.c
@@ -77,6 +77,41 @@ static int add_hw_hybrid(struct parse_events_state *parse_state,
return 0;
}

+static int create_raw_event_hybrid(int *idx, struct list_head *list,
+ struct perf_event_attr *attr, char *name,
+ struct list_head *config_terms,
+ struct perf_pmu *pmu)
+{
+ struct evsel *evsel;
+
+ attr->type = pmu->type;
+ evsel = parse_events__add_event_hybrid(list, idx, attr, name,
+ pmu, config_terms);
+ if (evsel)
+ evsel->pmu_name = strdup(pmu->name);
+ else
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int add_raw_hybrid(struct parse_events_state *parse_state,
+ struct list_head *list, struct perf_event_attr *attr,
+ char *name, struct list_head *config_terms)
+{
+ struct perf_pmu *pmu;
+ int ret;
+
+ perf_pmu__for_each_hybrid_pmu(pmu) {
+ ret = create_raw_event_hybrid(&parse_state->idx, list, attr,
+ name, config_terms, pmu);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
struct list_head *list,
struct perf_event_attr *attr,
@@ -96,7 +131,8 @@ int parse_events__add_numeric_hybrid(struct parse_events_state *parse_state,
config_terms);
}

- return -1;
+ return add_raw_hybrid(parse_state, list, attr, name,
+ config_terms);
}

int parse_events__add_cache_hybrid(struct list_head *list, int *idx,
--
2.17.1

2021-04-16 14:27:27

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 22/25] perf tests: Support 'Parse and process metrics' test for hybrid

Some events are not supported. Only pick up some cases for hybrid.

# ./perf test 67
67: Parse and process metrics : Ok

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/parse-metric.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
index 4968c4106254..24e5ddff515e 100644
--- a/tools/perf/tests/parse-metric.c
+++ b/tools/perf/tests/parse-metric.c
@@ -11,6 +11,7 @@
#include "debug.h"
#include "expr.h"
#include "stat.h"
+#include "pmu.h"

static struct pmu_event pme_test[] = {
{
@@ -370,12 +371,17 @@ static int test_metric_group(void)

int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
{
+ perf_pmu__scan(NULL);
+
TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
- TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
- TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
TEST_ASSERT_VAL("Memory bandwidth", test_memory_bandwidth() == 0);
+
+ if (!perf_pmu__has_hybrid()) {
+ TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
+ TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
+ }
return 0;
}
--
2.17.1

2021-04-16 14:27:49

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 23/25] perf tests: Support 'Session topology' test for hybrid

Force to create one event "cpu_core/cycles/" by default,
otherwise in evlist__valid_sample_type, the checking of
'if (evlist->core.nr_entries == 1)' would be failed.

# ./perf test 41
41: Session topology : Ok

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/topology.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index 050489807a47..30b4acb08d35 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -8,6 +8,7 @@
#include "session.h"
#include "evlist.h"
#include "debug.h"
+#include "pmu.h"
#include <linux/err.h>

#define TEMPL "/tmp/perf-test-XXXXXX"
@@ -40,7 +41,14 @@ static int session_write_header(char *path)
session = perf_session__new(&data, false, NULL);
TEST_ASSERT_VAL("can't get session", !IS_ERR(session));

- session->evlist = evlist__new_default();
+ if (!perf_pmu__has_hybrid()) {
+ session->evlist = evlist__new_default();
+ } else {
+ struct parse_events_error err;
+
+ session->evlist = evlist__new();
+ parse_events(session->evlist, "cpu_core/cycles/", &err);
+ }
TEST_ASSERT_VAL("can't get evlist", session->evlist);

perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
--
2.17.1

2021-04-16 14:27:53

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 25/25] perf tests: Skip 'perf stat metrics (shadow stat) test' for hybrid

Currently we don't support shadow stat for hybrid.

root@ssp-pwrt-002:~# ./perf stat -e cycles,instructions -a -- sleep 1

Performance counter stats for 'system wide':

12,883,109,591 cpu_core/cycles/
6,405,163,221 cpu_atom/cycles/
555,553,778 cpu_core/instructions/
841,158,734 cpu_atom/instructions/

1.002644773 seconds time elapsed

Now there is no shadow stat 'insn per cycle' reported. We will support
it later and now just skip the 'perf stat metrics (shadow stat) test'.

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/shell/stat+shadow_stat.sh | 3 +++
1 file changed, 3 insertions(+)

diff --git a/tools/perf/tests/shell/stat+shadow_stat.sh b/tools/perf/tests/shell/stat+shadow_stat.sh
index ebebd3596cf9..e6e35fc6c882 100755
--- a/tools/perf/tests/shell/stat+shadow_stat.sh
+++ b/tools/perf/tests/shell/stat+shadow_stat.sh
@@ -7,6 +7,9 @@ set -e
# skip if system-wide mode is forbidden
perf stat -a true > /dev/null 2>&1 || exit 2

+# skip if on hybrid platform
+perf stat -a -e cycles sleep 1 2>&1 | grep -e cpu_core && exit 2
+
test_global_aggr()
{
perf stat -a --no-big-num -e cycles,instructions sleep 1 2>&1 | \
--
2.17.1

2021-04-16 14:28:02

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 18/25] perf tests: Add hybrid cases for 'Parse event definition strings' test

Add basic hybrid test cases for 'Parse event definition strings' test.

# perf test 6
6: Parse event definition strings : Ok

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/parse-events.c | 152 ++++++++++++++++++++++++++++++++
1 file changed, 152 insertions(+)

diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 026c54743311..40eb08049ab2 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1512,6 +1512,110 @@ static int test__all_tracepoints(struct evlist *evlist)
return test__checkevent_tracepoint_multi(evlist);
}

+static int test__hybrid_hw_event_with_pmu(struct evlist *evlist)
+{
+ struct evsel *evsel = evlist__first(evlist);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config);
+ return 0;
+}
+
+static int test__hybrid_hw_group_event(struct evlist *evlist)
+{
+ struct evsel *evsel, *leader;
+
+ evsel = leader = evlist__first(evlist);
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+ evsel = evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0xc0 == evsel->core.attr.config);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+ return 0;
+}
+
+static int test__hybrid_sw_hw_group_event(struct evlist *evlist)
+{
+ struct evsel *evsel, *leader;
+
+ evsel = leader = evlist__first(evlist);
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+ evsel = evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+ return 0;
+}
+
+static int test__hybrid_hw_sw_group_event(struct evlist *evlist)
+{
+ struct evsel *evsel, *leader;
+
+ evsel = leader = evlist__first(evlist);
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+
+ evsel = evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+ return 0;
+}
+
+static int test__hybrid_group_modifier1(struct evlist *evlist)
+{
+ struct evsel *evsel, *leader;
+
+ evsel = leader = evlist__first(evlist);
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x3c == evsel->core.attr.config);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
+
+ evsel = evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0xc0 == evsel->core.attr.config);
+ TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+ TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
+ return 0;
+}
+
+static int test__hybrid_raw1(struct evlist *evlist)
+{
+ struct evsel *evsel = evlist__first(evlist);
+
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config);
+
+ /* The type of second event is randome value */
+ evsel = evsel__next(evsel);
+ TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config);
+ return 0;
+}
+
+static int test__hybrid_raw2(struct evlist *evlist)
+{
+ struct evsel *evsel = evlist__first(evlist);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x1a == evsel->core.attr.config);
+ return 0;
+}
+
struct evlist_test {
const char *name;
__u32 type;
@@ -1868,6 +1972,49 @@ static struct terms_test test__terms[] = {
},
};

+static struct evlist_test test__hybrid_events[] = {
+ {
+ .name = "cpu_core/cpu-cycles/",
+ .check = test__hybrid_hw_event_with_pmu,
+ .id = 0,
+ },
+ {
+ .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}",
+ .check = test__hybrid_hw_group_event,
+ .id = 1,
+ },
+ {
+ .name = "{cpu-clock,cpu_core/cpu-cycles/}",
+ .check = test__hybrid_sw_hw_group_event,
+ .id = 2,
+ },
+ {
+ .name = "{cpu_core/cpu-cycles/,cpu-clock}",
+ .check = test__hybrid_hw_sw_group_event,
+ .id = 3,
+ },
+ {
+ .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}",
+ .check = test__hybrid_group_modifier1,
+ .id = 4,
+ },
+ {
+ .name = "r1a",
+ .check = test__hybrid_raw1,
+ .id = 5,
+ },
+ {
+ .name = "cpu_core/r1a/",
+ .check = test__hybrid_raw2,
+ .id = 6,
+ },
+ {
+ .name = "cpu_core/config=10,config1,config2=3,period=1000/u",
+ .check = test__checkevent_pmu,
+ .id = 7,
+ },
+};
+
static int test_event(struct evlist_test *e)
{
struct parse_events_error err;
@@ -2035,6 +2182,11 @@ do { \
ret2 = ret1; \
} while (0)

+ if (perf_pmu__has_hybrid()) {
+ TEST_EVENTS(test__hybrid_events);
+ return ret2;
+ }
+
TEST_EVENTS(test__events);

if (test_pmu())
--
2.17.1

2021-04-16 14:29:46

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 19/25] perf tests: Add hybrid cases for 'Roundtrip evsel->name' test

Since for one hw event, two hybrid events are created.

For example,

evsel->idx evsel__name(evsel)
0 cycles
1 cycles
2 instructions
3 instructions
...

So for comparing the evsel name on hybrid, the evsel->idx
needs to be divided by 2.

# ./perf test 14
14: Roundtrip evsel->name : Ok

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/evsel-roundtrip-name.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index f7f3e5b4c180..b74cf80d1f10 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -4,6 +4,7 @@
#include "parse-events.h"
#include "tests.h"
#include "debug.h"
+#include "pmu.h"
#include <errno.h>
#include <linux/kernel.h>

@@ -62,7 +63,8 @@ static int perf_evsel__roundtrip_cache_name_test(void)
return ret;
}

-static int __perf_evsel__name_array_test(const char *names[], int nr_names)
+static int __perf_evsel__name_array_test(const char *names[], int nr_names,
+ int distance)
{
int i, err;
struct evsel *evsel;
@@ -82,9 +84,9 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)

err = 0;
evlist__for_each_entry(evlist, evsel) {
- if (strcmp(evsel__name(evsel), names[evsel->idx])) {
+ if (strcmp(evsel__name(evsel), names[evsel->idx / distance])) {
--err;
- pr_debug("%s != %s\n", evsel__name(evsel), names[evsel->idx]);
+ pr_debug("%s != %s\n", evsel__name(evsel), names[evsel->idx / distance]);
}
}

@@ -93,18 +95,21 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
return err;
}

-#define perf_evsel__name_array_test(names) \
- __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
+#define perf_evsel__name_array_test(names, distance) \
+ __perf_evsel__name_array_test(names, ARRAY_SIZE(names), distance)

int test__perf_evsel__roundtrip_name_test(struct test *test __maybe_unused, int subtest __maybe_unused)
{
int err = 0, ret = 0;

- err = perf_evsel__name_array_test(evsel__hw_names);
+ if (perf_pmu__has_hybrid())
+ return perf_evsel__name_array_test(evsel__hw_names, 2);
+
+ err = perf_evsel__name_array_test(evsel__hw_names, 1);
if (err)
ret = err;

- err = __perf_evsel__name_array_test(evsel__sw_names, PERF_COUNT_SW_DUMMY + 1);
+ err = __perf_evsel__name_array_test(evsel__sw_names, PERF_COUNT_SW_DUMMY + 1, 1);
if (err)
ret = err;

--
2.17.1

2021-04-16 15:43:26

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 14/25] perf stat: Add default hybrid events

Previously if '-e' is not specified in perf stat, some software events
and hardware events are added to evlist by default.

Before:

# ./perf stat -a -- sleep 1

Performance counter stats for 'system wide':

24,044.40 msec cpu-clock # 23.946 CPUs utilized
99 context-switches # 4.117 /sec
24 cpu-migrations # 0.998 /sec
3 page-faults # 0.125 /sec
7,000,244 cycles # 0.000 GHz
2,955,024 instructions # 0.42 insn per cycle
608,941 branches # 25.326 K/sec
31,991 branch-misses # 5.25% of all branches

1.004106859 seconds time elapsed

Among the events, cycles, instructions, branches and branch-misses
are hardware events.

One hybrid platform, two hardware events are created for one
hardware event.

cpu_core/cycles/,
cpu_atom/cycles/,
cpu_core/instructions/,
cpu_atom/instructions/,
cpu_core/branches/,
cpu_atom/branches/,
cpu_core/branch-misses/,
cpu_atom/branch-misses/

These events would be added to evlist on hybrid platform.

Since parse_events() has been supported to create two hardware events
for one event on hybrid platform, so we just use parse_events(evlist,
"cycles,instructions,branches,branch-misses") to create the default
events and add them to evlist.

After:

# ./perf stat -a -- sleep 1

Performance counter stats for 'system wide':

24,048.60 msec task-clock # 23.947 CPUs utilized
438 context-switches # 18.213 /sec
24 cpu-migrations # 0.998 /sec
6 page-faults # 0.249 /sec
24,813,157 cpu_core/cycles/ # 1.032 M/sec
8,072,687 cpu_atom/cycles/ # 335.682 K/sec
20,731,286 cpu_core/instructions/ # 862.058 K/sec
3,737,203 cpu_atom/instructions/ # 155.402 K/sec
2,620,924 cpu_core/branches/ # 108.984 K/sec
381,186 cpu_atom/branches/ # 15.851 K/sec
93,248 cpu_core/branch-misses/ # 3.877 K/sec
36,515 cpu_atom/branch-misses/ # 1.518 K/sec

1.004235472 seconds time elapsed

We can see two events are created for one hardware event.

One TODO is, the shadow stats looks a bit different, now it's just
'M/sec'.

The perf_stat__update_shadow_stats and perf_stat__print_shadow_stats
need to be improved in future if we want to get the original shadow
stats.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- No change.

tools/perf/builtin-stat.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1255af4751c2..0351b99d17a7 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1145,6 +1145,13 @@ static int parse_stat_cgroups(const struct option *opt,
return parse_cgroups(opt, str, unset);
}

+static int add_default_hybrid_events(struct evlist *evlist)
+{
+ struct parse_events_error err;
+
+ return parse_events(evlist, "cycles,instructions,branches,branch-misses", &err);
+}
+
static struct option stat_options[] = {
OPT_BOOLEAN('T', "transaction", &transaction_run,
"hardware transaction statistics"),
@@ -1626,6 +1633,12 @@ static int add_default_attributes(void)
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
{ .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },

+};
+ struct perf_event_attr default_sw_attrs[] = {
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
+ { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
};

/*
@@ -1863,6 +1876,14 @@ static int add_default_attributes(void)
}

if (!evsel_list->core.nr_entries) {
+ if (perf_pmu__has_hybrid()) {
+ if (evlist__add_default_attrs(evsel_list,
+ default_sw_attrs) < 0) {
+ return -1;
+ }
+ return add_default_hybrid_events(evsel_list);
+ }
+
if (target__has_cpu(&target))
default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK;

--
2.17.1

2021-04-16 15:43:29

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 16/25] perf stat: Warn group events from different hybrid PMU

If a group has events which are from different hybrid PMUs,
shows a warning:

"WARNING: events in group from different hybrid PMUs!"

This is to remind the user not to put the core event and atom
event into one group.

Next, just disable grouping.

# perf stat -e "{cpu_core/cycles/,cpu_atom/cycles/}" -a -- sleep 1
WARNING: events in group from different hybrid PMUs!
WARNING: grouped events cpus do not match, disabling group:
anon group { cpu_core/cycles/, cpu_atom/cycles/ }

Performance counter stats for 'system wide':

5,438,125 cpu_core/cycles/
3,914,586 cpu_atom/cycles/

1.004250966 seconds time elapsed

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- No change.

tools/perf/builtin-stat.c | 4 +++
tools/perf/util/evlist-hybrid.c | 47 ++++++++++++++++++++++++++++++
tools/perf/util/evlist-hybrid.h | 2 ++
tools/perf/util/evsel.c | 6 ++++
tools/perf/util/evsel.h | 1 +
tools/perf/util/python-ext-sources | 2 ++
6 files changed, 62 insertions(+)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 0351b99d17a7..c429aae6eeb6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -48,6 +48,7 @@
#include "util/pmu.h"
#include "util/event.h"
#include "util/evlist.h"
+#include "util/evlist-hybrid.h"
#include "util/evsel.h"
#include "util/debug.h"
#include "util/color.h"
@@ -240,6 +241,9 @@ static void evlist__check_cpu_maps(struct evlist *evlist)
struct evsel *evsel, *pos, *leader;
char buf[1024];

+ if (evlist__has_hybrid(evlist))
+ evlist__warn_hybrid_group(evlist);
+
evlist__for_each_entry(evlist, evsel) {
leader = evsel->leader;

diff --git a/tools/perf/util/evlist-hybrid.c b/tools/perf/util/evlist-hybrid.c
index e11998526f2e..db3f5fbdebe1 100644
--- a/tools/perf/util/evlist-hybrid.c
+++ b/tools/perf/util/evlist-hybrid.c
@@ -7,6 +7,7 @@
#include "../perf.h"
#include "util/pmu-hybrid.h"
#include "util/evlist-hybrid.h"
+#include "debug.h"
#include <unistd.h>
#include <stdlib.h>
#include <linux/err.h>
@@ -39,3 +40,49 @@ int evlist__add_default_hybrid(struct evlist *evlist, bool precise)

return 0;
}
+
+static bool group_hybrid_conflict(struct evsel *leader)
+{
+ struct evsel *pos, *prev = NULL;
+
+ for_each_group_evsel(pos, leader) {
+ if (!evsel__is_hybrid(pos))
+ continue;
+
+ if (prev && strcmp(prev->pmu_name, pos->pmu_name))
+ return true;
+
+ prev = pos;
+ }
+
+ return false;
+}
+
+void evlist__warn_hybrid_group(struct evlist *evlist)
+{
+ struct evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (evsel__is_group_leader(evsel) &&
+ evsel->core.nr_members > 1 &&
+ group_hybrid_conflict(evsel)) {
+ pr_warning("WARNING: events in group from "
+ "different hybrid PMUs!\n");
+ return;
+ }
+ }
+}
+
+bool evlist__has_hybrid(struct evlist *evlist)
+{
+ struct evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (evsel->pmu_name &&
+ perf_pmu__is_hybrid(evsel->pmu_name)) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/tools/perf/util/evlist-hybrid.h b/tools/perf/util/evlist-hybrid.h
index e25861649d8f..19f74b4c340a 100644
--- a/tools/perf/util/evlist-hybrid.h
+++ b/tools/perf/util/evlist-hybrid.h
@@ -8,5 +8,7 @@
#include <unistd.h>

int evlist__add_default_hybrid(struct evlist *evlist, bool precise);
+void evlist__warn_hybrid_group(struct evlist *evlist);
+bool evlist__has_hybrid(struct evlist *evlist);

#endif /* __PERF_EVLIST_HYBRID_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 0ba4daa09453..0f64a32ea9c5 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -47,6 +47,7 @@
#include "memswap.h"
#include "util.h"
#include "hashmap.h"
+#include "pmu-hybrid.h"
#include "../perf-sys.h"
#include "util/parse-branch-options.h"
#include <internal/xyarray.h>
@@ -2797,3 +2798,8 @@ void evsel__zero_per_pkg(struct evsel *evsel)
hashmap__clear(evsel->per_pkg_mask);
}
}
+
+bool evsel__is_hybrid(struct evsel *evsel)
+{
+ return evsel->pmu_name && perf_pmu__is_hybrid(evsel->pmu_name);
+}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index ff89196281bd..f6f90f68381b 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -453,4 +453,5 @@ struct perf_env *evsel__env(struct evsel *evsel);
int evsel__store_ids(struct evsel *evsel, struct evlist *evlist);

void evsel__zero_per_pkg(struct evsel *evsel);
+bool evsel__is_hybrid(struct evsel *evsel);
#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 845dd46e3c61..d7c976671e3a 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -37,3 +37,5 @@ util/units.c
util/affinity.c
util/rwsem.c
util/hashmap.c
+util/pmu-hybrid.c
+util/fncache.c
--
2.17.1

2021-04-16 15:43:29

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 17/25] perf record: Uniquify hybrid event name

For perf-record, it would be useful to tell user the pmu which the
event belongs to.

For example,

# perf record -a -- sleep 1
# perf report

# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 106 of event 'cpu_core/cycles/'
# Event count (approx.): 22043448
#
# Overhead Command Shared Object Symbol
# ........ ............ ....................... ............................
#
...

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- No change.

tools/perf/builtin-record.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 6af46c6a4fd8..3337b5f93336 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1605,6 +1605,32 @@ static void hit_auxtrace_snapshot_trigger(struct record *rec)
}
}

+static void record__uniquify_name(struct record *rec)
+{
+ struct evsel *pos;
+ struct evlist *evlist = rec->evlist;
+ char *new_name;
+ int ret;
+
+ if (!perf_pmu__has_hybrid())
+ return;
+
+ evlist__for_each_entry(evlist, pos) {
+ if (!evsel__is_hybrid(pos))
+ continue;
+
+ if (strchr(pos->name, '/'))
+ continue;
+
+ ret = asprintf(&new_name, "%s/%s/",
+ pos->pmu_name, pos->name);
+ if (ret) {
+ free(pos->name);
+ pos->name = new_name;
+ }
+ }
+}
+
static int __cmd_record(struct record *rec, int argc, const char **argv)
{
int err;
@@ -1709,6 +1735,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
if (data->is_pipe && rec->evlist->core.nr_entries == 1)
rec->opts.sample_id = true;

+ record__uniquify_name(rec);
+
if (record__open(rec) != 0) {
err = -1;
goto out_child;
--
2.17.1

2021-04-16 15:44:29

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 24/25] perf tests: Support 'Convert perf time to TSC' test for hybrid

Since for "cycles:u' on hybrid platform, it creates two "cycles".
So the second evsel in evlist also needs initialization.

With this patch,

# ./perf test 71
71: Convert perf time to TSC : Ok

Signed-off-by: Jin Yao <[email protected]>
---
tools/perf/tests/perf-time-to-tsc.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
index 680c3cffb128..72f268c6cc5d 100644
--- a/tools/perf/tests/perf-time-to-tsc.c
+++ b/tools/perf/tests/perf-time-to-tsc.c
@@ -20,6 +20,7 @@
#include "tsc.h"
#include "mmap.h"
#include "tests.h"
+#include "pmu.h"

#define CHECK__(x) { \
while ((x) < 0) { \
@@ -66,6 +67,10 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
u64 test_tsc, comm1_tsc, comm2_tsc;
u64 test_time, comm1_time = 0, comm2_time = 0;
struct mmap *md;
+ bool hybrid = false;
+
+ if (perf_pmu__has_hybrid())
+ hybrid = true;

threads = thread_map__new(-1, getpid(), UINT_MAX);
CHECK_NOT_NULL__(threads);
@@ -88,6 +93,17 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
evsel->core.attr.disabled = 1;
evsel->core.attr.enable_on_exec = 0;

+ /*
+ * For hybrid "cycles:u", it creates two events.
+ * Init the second evsel here.
+ */
+ if (hybrid) {
+ evsel = evsel__next(evsel);
+ evsel->core.attr.comm = 1;
+ evsel->core.attr.disabled = 1;
+ evsel->core.attr.enable_on_exec = 0;
+ }
+
CHECK__(evlist__open(evlist));

CHECK__(evlist__mmap(evlist, UINT_MAX));
--
2.17.1

2021-04-16 15:54:47

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 07/25] perf stat: Uniquify hybrid event name

It would be useful to tell user the pmu which the event belongs to.
perf-stat has supported '--no-merge' option and it can print the pmu
name after the event name, such as:

"cycles [cpu_core]"

Now this option is enabled by default for hybrid platform but change
the format to:

"cpu_core/cycles/"

If user configs the name, we still use the user specified name.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- If user configs the name, we still use the user specified name.

v3:
- No change.

tools/perf/builtin-stat.c | 4 ++++
tools/perf/util/evsel.h | 1 +
tools/perf/util/stat-display.c | 15 +++++++++++++--
3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2a2c15cac80a..1255af4751c2 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -68,6 +68,7 @@
#include "util/affinity.h"
#include "util/pfm.h"
#include "util/bpf_counter.h"
+#include "util/pmu-hybrid.h"
#include "asm/bug.h"

#include <linux/time64.h>
@@ -2378,6 +2379,9 @@ int cmd_stat(int argc, const char **argv)

evlist__check_cpu_maps(evsel_list);

+ if (perf_pmu__has_hybrid())
+ stat_config.no_merge = true;
+
/*
* Initialize thread_map with comm names,
* so we could print it out on output.
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index eccc4fd5b3eb..d518da2fd2eb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -115,6 +115,7 @@ struct evsel {
bool merged_stat;
bool reset_group;
bool errored;
+ bool use_config_name;
struct hashmap *per_pkg_mask;
struct evsel *leader;
struct list_head config_terms;
diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c
index d3137bc17065..5255d78b1c30 100644
--- a/tools/perf/util/stat-display.c
+++ b/tools/perf/util/stat-display.c
@@ -17,6 +17,7 @@
#include "cgroup.h"
#include <api/fs/fs.h>
#include "util.h"
+#include "pmu-hybrid.h"

#define CNTR_NOT_SUPPORTED "<not supported>"
#define CNTR_NOT_COUNTED "<not counted>"
@@ -532,6 +533,7 @@ static void uniquify_event_name(struct evsel *counter)
{
char *new_name;
char *config;
+ int ret = 0;

if (counter->uniquified_name ||
!counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
@@ -546,8 +548,17 @@ static void uniquify_event_name(struct evsel *counter)
counter->name = new_name;
}
} else {
- if (asprintf(&new_name,
- "%s [%s]", counter->name, counter->pmu_name) > 0) {
+ if (perf_pmu__has_hybrid()) {
+ if (!counter->use_config_name) {
+ ret = asprintf(&new_name, "%s/%s/",
+ counter->pmu_name, counter->name);
+ }
+ } else {
+ ret = asprintf(&new_name, "%s [%s]",
+ counter->name, counter->pmu_name);
+ }
+
+ if (ret) {
free(counter->name);
counter->name = new_name;
}
--
2.17.1

2021-04-16 15:54:58

by Jin Yao

[permalink] [raw]
Subject: [PATCH v4 06/25] perf pmu: Add hybrid helper functions

The functions perf_pmu__is_hybrid and perf_pmu__find_hybrid_pmu
can be used to identify the hybrid platform and return the found
hybrid cpu pmu. All the detected hybrid pmus have been saved in
'perf_pmu__hybrid_pmus' list. So we just need to search this list.

perf_pmu__hybrid_type_to_pmu converts the user specified string
to hybrid pmu name. This is used to support the '--cputype' option
in next patches.

perf_pmu__has_hybrid checks the existing of hybrid pmu. Note that,
we have to define it in pmu.c (make pmu-hybrid.c no more symbol
dependency), otherwise perf test python would be failed.

Signed-off-by: Jin Yao <[email protected]>
---
v4:
- No change.

v3:
- Move perf_pmu__has_hybrid from pmu-hybrid.c to pmu.c. We have to
add pmu-hybrid.c to python-ext-sources to solve symbol dependency
issue found in perf test python. For perf_pmu__has_hybrid, it calls
perf_pmu__scan, which is defined in pmu.c. It's very hard to add
pmu.c to python-ext-sources, too much symbol dependency here.

tools/perf/util/pmu-hybrid.c | 40 ++++++++++++++++++++++++++++++++++++
tools/perf/util/pmu-hybrid.h | 4 ++++
tools/perf/util/pmu.c | 11 ++++++++++
tools/perf/util/pmu.h | 2 ++
4 files changed, 57 insertions(+)

diff --git a/tools/perf/util/pmu-hybrid.c b/tools/perf/util/pmu-hybrid.c
index 8ed0e6e1776d..f51ccaac60ee 100644
--- a/tools/perf/util/pmu-hybrid.c
+++ b/tools/perf/util/pmu-hybrid.c
@@ -47,3 +47,43 @@ bool perf_pmu__hybrid_mounted(const char *name)

return true;
}
+
+struct perf_pmu *perf_pmu__find_hybrid_pmu(const char *name)
+{
+ struct perf_pmu *pmu;
+
+ if (!name)
+ return NULL;
+
+ perf_pmu__for_each_hybrid_pmu(pmu) {
+ if (!strcmp(name, pmu->name))
+ return pmu;
+ }
+
+ return NULL;
+}
+
+bool perf_pmu__is_hybrid(const char *name)
+{
+ return perf_pmu__find_hybrid_pmu(name) != NULL;
+}
+
+char *perf_pmu__hybrid_type_to_pmu(const char *type)
+{
+ char *pmu_name = NULL;
+
+ if (asprintf(&pmu_name, "cpu_%s", type) < 0)
+ return NULL;
+
+ if (perf_pmu__is_hybrid(pmu_name))
+ return pmu_name;
+
+ /*
+ * pmu may be not scanned, check the sysfs.
+ */
+ if (perf_pmu__hybrid_mounted(pmu_name))
+ return pmu_name;
+
+ free(pmu_name);
+ return NULL;
+}
diff --git a/tools/perf/util/pmu-hybrid.h b/tools/perf/util/pmu-hybrid.h
index 35bed3714438..d0fa7bc50a76 100644
--- a/tools/perf/util/pmu-hybrid.h
+++ b/tools/perf/util/pmu-hybrid.h
@@ -15,4 +15,8 @@ extern struct list_head perf_pmu__hybrid_pmus;

bool perf_pmu__hybrid_mounted(const char *name);

+struct perf_pmu *perf_pmu__find_hybrid_pmu(const char *name);
+bool perf_pmu__is_hybrid(const char *name);
+char *perf_pmu__hybrid_type_to_pmu(const char *type);
+
#endif /* __PMU_HYBRID_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 6e49c7b8ad71..88c8ecdc60b0 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -40,6 +40,7 @@ int perf_pmu_parse(struct list_head *list, char *name);
extern FILE *perf_pmu_in;

static LIST_HEAD(pmus);
+static bool hybrid_scanned;

/*
* Parse & process all the sysfs attributes located under
@@ -1861,3 +1862,13 @@ void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
"'%llx' not supported by kernel)!\n",
name ?: "N/A", buf, config);
}
+
+bool perf_pmu__has_hybrid(void)
+{
+ if (!hybrid_scanned) {
+ hybrid_scanned = true;
+ perf_pmu__scan(NULL);
+ }
+
+ return !list_empty(&perf_pmu__hybrid_pmus);
+}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 9a2f89eeab6f..a790ef758171 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -132,4 +132,6 @@ int perf_pmu__caps_parse(struct perf_pmu *pmu);
void perf_pmu__warn_invalid_config(struct perf_pmu *pmu, __u64 config,
char *name);

+bool perf_pmu__has_hybrid(void);
+
#endif /* __PMU_H */
--
2.17.1

2021-04-21 01:15:43

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 00/25] perf tool: AlderLake hybrid support series 1

Hi Arnaldo, Hi Jiri,

Kan's patch series for AlderLake perf core support has been upstreamed, so the interface will not be
changed any more.

For this perf tool series (v4), do you have any comments?

Thanks
Jin Yao

On 4/16/2021 10:04 PM, Jin Yao wrote:
> AlderLake uses a hybrid architecture utilizing Golden Cove cores
> (core cpu) and Gracemont cores (atom cpu). Each cpu has dedicated
> event list. Some events are available on core cpu, some events
> are available on atom cpu and some events can be available on both.
>
> Kernel exports new pmus "cpu_core" and "cpu_atom" through sysfs:
> /sys/devices/cpu_core
> /sys/devices/cpu_atom
>
> cat /sys/devices/cpu_core/cpus
> 0-15
>
> cat /sys/devices/cpu_atom/cpus
> 16-23
>
> In this example, core cpus are 0-15 and atom cpus are 16-23.
>
> To enable a core only event or atom only event:
>
> cpu_core/<event name>/
> or
> cpu_atom/<event name>/
>
> Count the 'cycles' event on core cpus.
>
> # perf stat -e cpu_core/cycles/ -a -- sleep 1
>
> Performance counter stats for 'system wide':
>
> 12,853,951,349 cpu_core/cycles/
>
> 1.002581249 seconds time elapsed
>
> If one event is available on both atom cpu and core cpu, two events
> are created automatically.
>
> # perf stat -e cycles -a -- sleep 1
>
> Performance counter stats for 'system wide':
>
> 12,856,467,438 cpu_core/cycles/
> 6,404,634,785 cpu_atom/cycles/
>
> 1.002453013 seconds time elapsed
>
> Group is supported if the events are from same pmu, otherwise a warning
> is displayed and disable grouping automatically.
>
> # perf stat -e '{cpu_core/cycles/,cpu_core/instructions/}' -a -- sleep 1
>
> Performance counter stats for 'system wide':
>
> 12,863,866,968 cpu_core/cycles/
> 554,795,017 cpu_core/instructions/
>
> 1.002616117 seconds time elapsed
>
> # perf stat -e '{cpu_core/cycles/,cpu_atom/instructions/}' -a -- sleep 1
> WARNING: events in group from different hybrid PMUs!
> WARNING: grouped events cpus do not match, disabling group:
> anon group { cpu_core/cycles/, cpu_atom/instructions/ }
>
> Performance counter stats for 'system wide':
>
> 6,283,970 cpu_core/cycles/
> 765,635 cpu_atom/instructions/
>
> 1.003959036 seconds time elapsed
>
> Note that, since the whole patchset for AlderLake hybrid support is very
> large (40+ patches). For simplicity, it's splitted into several patch
> series.
>
> The patch series 1 only supports the basic functionality. The advanced
> supports for perf-c2c/perf-mem/topdown/metrics/topology header and others
> will be added in follow-up patch series.
>
> The perf tool codes can also be found at:
> https://github.com/yaoj/perf.git
>
> v4:
> ---
> - In Liang Kan's patch:
> '[PATCH V6 21/25] perf: Extend PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE',
> the user interface for hardware events and cache events are changed, so
> perf tool patches are changed as well.
>
> - Fix an issue when atom CPUs are offlined. "/sys/bus/event_source/devices/cpu_atom/cpus"
> exists but the content is empty. For this case, we can't enable the cpu_atom
> PMU. '[PATCH v4 05/25] perf pmu: Save detected hybrid pmus to a global pmu list'
>
> - Define 'ret' variable for return value in patch
> '[PATCH v4 09/25] perf parse-events: Create two hybrid cache events'
>
> - Directly return add_raw_hybrid() in patch
> '[PATCH v4 10/25] perf parse-events: Create two hybrid raw events'
>
> - Drop the patch 'perf pmu: Support 'cycles' and 'branches' inside
> hybrid PMU'.
>
> - Separate '[PATCH v3 12/27] perf parse-events: Support no alias assigned event
> inside hybrid PMU' into two patches:
> '[PATCH v4 11/25] perf parse-events: Compare with hybrid pmu name'
> '[PATCH v4 12/25] perf parse-events: Support event inside hybrid pmu'.
> And these two patches are improved according to Jiri's comments.
>
> v3:
> ---
> - Drop 'perf evlist: Hybrid event uses its own cpus'. This patch is wide
> and actually it's not very necessary. The current perf framework has
> processed the cpus for evsel well even for hybrid evsel. So this patch can
> be dropped.
>
> - Drop 'perf evsel: Adjust hybrid event and global event mixed group'.
> The patch is a bit tricky and hard to understand. In v3, we will disable
> grouping when the group members are from different PMUs. So this patch
> would be not necessary.
>
> - Create parse-events-hybrid.c/parse-events-hybrid.h and evlist-hybrid.c/evlist-hybrid.h.
> Move hybrid related codes to these files.
>
> - Create a new patch 'perf pmu: Support 'cycles' and 'branches' inside hybrid PMU' to
> support 'cycles' and 'branches' inside PMU.
>
> - Create a new patch 'perf record: Uniquify hybrid event name' to tell user the
> pmu which the event belongs to for perf-record.
>
> - If group members are from different hybrid PMUs, shows warning and disable
> grouping.
>
> - Other refining and refactoring.
>
> v2:
> ---
> - Drop kernel patches (Kan posted the series "Add Alder Lake support for perf (kernel)" separately).
> - Drop the patches for perf-c2c/perf-mem/topdown/metrics/topology header supports,
> which will be added in series 2 or series 3.
> - Simplify the arguments of __perf_pmu__new_alias() by passing
> the 'struct pme_event' pointer.
> - Check sysfs validity before access.
> - Use pmu style event name, such as "cpu_core/cycles/".
> - Move command output two chars to the right.
> - Move pmu hybrid functions to new created pmu-hybrid.c/pmu-hybrid.h.
> This is to pass the perf test python case.
>
> Jin Yao (25):
> tools headers uapi: Update tools's copy of linux/perf_event.h
> perf jevents: Support unit value "cpu_core" and "cpu_atom"
> perf pmu: Simplify arguments of __perf_pmu__new_alias
> perf pmu: Save pmu name
> perf pmu: Save detected hybrid pmus to a global pmu list
> perf pmu: Add hybrid helper functions
> perf stat: Uniquify hybrid event name
> perf parse-events: Create two hybrid hardware events
> perf parse-events: Create two hybrid cache events
> perf parse-events: Create two hybrid raw events
> perf parse-events: Compare with hybrid pmu name
> perf parse-events: Support event inside hybrid pmu
> perf record: Create two hybrid 'cycles' events by default
> perf stat: Add default hybrid events
> perf stat: Filter out unmatched aggregation for hybrid event
> perf stat: Warn group events from different hybrid PMU
> perf record: Uniquify hybrid event name
> perf tests: Add hybrid cases for 'Parse event definition strings' test
> perf tests: Add hybrid cases for 'Roundtrip evsel->name' test
> perf tests: Skip 'Setup struct perf_event_attr' test for hybrid
> perf tests: Support 'Track with sched_switch' test for hybrid
> perf tests: Support 'Parse and process metrics' test for hybrid
> perf tests: Support 'Session topology' test for hybrid
> perf tests: Support 'Convert perf time to TSC' test for hybrid
> perf tests: Skip 'perf stat metrics (shadow stat) test' for hybrid
>
> include/uapi/linux/perf_event.h | 15 ++
> tools/include/uapi/linux/perf_event.h | 15 ++
> tools/perf/builtin-record.c | 47 +++++-
> tools/perf/builtin-stat.c | 29 ++++
> tools/perf/pmu-events/jevents.c | 2 +
> tools/perf/tests/attr.c | 4 +
> tools/perf/tests/evsel-roundtrip-name.c | 19 ++-
> tools/perf/tests/parse-events.c | 152 ++++++++++++++++++
> tools/perf/tests/parse-metric.c | 10 +-
> tools/perf/tests/perf-time-to-tsc.c | 16 ++
> tools/perf/tests/shell/stat+shadow_stat.sh | 3 +
> tools/perf/tests/switch-tracking.c | 10 +-
> tools/perf/tests/topology.c | 10 +-
> tools/perf/util/Build | 3 +
> tools/perf/util/evlist-hybrid.c | 88 ++++++++++
> tools/perf/util/evlist-hybrid.h | 14 ++
> tools/perf/util/evlist.c | 5 +-
> tools/perf/util/evsel.c | 12 +-
> tools/perf/util/evsel.h | 4 +-
> tools/perf/util/parse-events-hybrid.c | 178 +++++++++++++++++++++
> tools/perf/util/parse-events-hybrid.h | 23 +++
> tools/perf/util/parse-events.c | 86 +++++++++-
> tools/perf/util/parse-events.h | 9 +-
> tools/perf/util/parse-events.y | 9 +-
> tools/perf/util/pmu-hybrid.c | 89 +++++++++++
> tools/perf/util/pmu-hybrid.h | 22 +++
> tools/perf/util/pmu.c | 64 +++++---
> tools/perf/util/pmu.h | 7 +
> tools/perf/util/python-ext-sources | 2 +
> tools/perf/util/stat-display.c | 35 +++-
> 30 files changed, 933 insertions(+), 49 deletions(-)
> create mode 100644 tools/perf/util/evlist-hybrid.c
> create mode 100644 tools/perf/util/evlist-hybrid.h
> create mode 100644 tools/perf/util/parse-events-hybrid.c
> create mode 100644 tools/perf/util/parse-events-hybrid.h
> create mode 100644 tools/perf/util/pmu-hybrid.c
> create mode 100644 tools/perf/util/pmu-hybrid.h
>

2021-04-21 10:28:55

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 00/25] perf tool: AlderLake hybrid support series 1

On Wed, Apr 21, 2021 at 09:14:20AM +0800, Jin, Yao wrote:
> Hi Arnaldo, Hi Jiri,
>
> Kan's patch series for AlderLake perf core support has been upstreamed, so
> the interface will not be changed any more.
>
> For this perf tool series (v4), do you have any comments?

hi,
I plan to go through it this week

jirka

>
> Thanks
> Jin Yao
>
> On 4/16/2021 10:04 PM, Jin Yao wrote:
> > AlderLake uses a hybrid architecture utilizing Golden Cove cores
> > (core cpu) and Gracemont cores (atom cpu). Each cpu has dedicated
> > event list. Some events are available on core cpu, some events
> > are available on atom cpu and some events can be available on both.
> >
> > Kernel exports new pmus "cpu_core" and "cpu_atom" through sysfs:
> > /sys/devices/cpu_core
> > /sys/devices/cpu_atom
> >
> > cat /sys/devices/cpu_core/cpus
> > 0-15
> >
> > cat /sys/devices/cpu_atom/cpus
> > 16-23
> >
> > In this example, core cpus are 0-15 and atom cpus are 16-23.
> >
> > To enable a core only event or atom only event:
> >
> > cpu_core/<event name>/
> > or
> > cpu_atom/<event name>/
> >
> > Count the 'cycles' event on core cpus.
> >
> > # perf stat -e cpu_core/cycles/ -a -- sleep 1
> >
> > Performance counter stats for 'system wide':
> >
> > 12,853,951,349 cpu_core/cycles/
> >
> > 1.002581249 seconds time elapsed
> >
> > If one event is available on both atom cpu and core cpu, two events
> > are created automatically.
> >
> > # perf stat -e cycles -a -- sleep 1
> >
> > Performance counter stats for 'system wide':
> >
> > 12,856,467,438 cpu_core/cycles/
> > 6,404,634,785 cpu_atom/cycles/
> >
> > 1.002453013 seconds time elapsed
> >
> > Group is supported if the events are from same pmu, otherwise a warning
> > is displayed and disable grouping automatically.
> >
> > # perf stat -e '{cpu_core/cycles/,cpu_core/instructions/}' -a -- sleep 1
> >
> > Performance counter stats for 'system wide':
> >
> > 12,863,866,968 cpu_core/cycles/
> > 554,795,017 cpu_core/instructions/
> >
> > 1.002616117 seconds time elapsed
> >
> > # perf stat -e '{cpu_core/cycles/,cpu_atom/instructions/}' -a -- sleep 1
> > WARNING: events in group from different hybrid PMUs!
> > WARNING: grouped events cpus do not match, disabling group:
> > anon group { cpu_core/cycles/, cpu_atom/instructions/ }
> >
> > Performance counter stats for 'system wide':
> >
> > 6,283,970 cpu_core/cycles/
> > 765,635 cpu_atom/instructions/
> >
> > 1.003959036 seconds time elapsed
> >
> > Note that, since the whole patchset for AlderLake hybrid support is very
> > large (40+ patches). For simplicity, it's splitted into several patch
> > series.
> >
> > The patch series 1 only supports the basic functionality. The advanced
> > supports for perf-c2c/perf-mem/topdown/metrics/topology header and others
> > will be added in follow-up patch series.
> >
> > The perf tool codes can also be found at:
> > https://github.com/yaoj/perf.git
> >
> > v4:
> > ---
> > - In Liang Kan's patch:
> > '[PATCH V6 21/25] perf: Extend PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE',
> > the user interface for hardware events and cache events are changed, so
> > perf tool patches are changed as well.
> >
> > - Fix an issue when atom CPUs are offlined. "/sys/bus/event_source/devices/cpu_atom/cpus"
> > exists but the content is empty. For this case, we can't enable the cpu_atom
> > PMU. '[PATCH v4 05/25] perf pmu: Save detected hybrid pmus to a global pmu list'
> >
> > - Define 'ret' variable for return value in patch
> > '[PATCH v4 09/25] perf parse-events: Create two hybrid cache events'
> >
> > - Directly return add_raw_hybrid() in patch
> > '[PATCH v4 10/25] perf parse-events: Create two hybrid raw events'
> > - Drop the patch 'perf pmu: Support 'cycles' and 'branches' inside
> > hybrid PMU'.
> >
> > - Separate '[PATCH v3 12/27] perf parse-events: Support no alias assigned event
> > inside hybrid PMU' into two patches:
> > '[PATCH v4 11/25] perf parse-events: Compare with hybrid pmu name'
> > '[PATCH v4 12/25] perf parse-events: Support event inside hybrid pmu'.
> > And these two patches are improved according to Jiri's comments.
> >
> > v3:
> > ---
> > - Drop 'perf evlist: Hybrid event uses its own cpus'. This patch is wide
> > and actually it's not very necessary. The current perf framework has
> > processed the cpus for evsel well even for hybrid evsel. So this patch can
> > be dropped.
> >
> > - Drop 'perf evsel: Adjust hybrid event and global event mixed group'.
> > The patch is a bit tricky and hard to understand. In v3, we will disable
> > grouping when the group members are from different PMUs. So this patch
> > would be not necessary.
> >
> > - Create parse-events-hybrid.c/parse-events-hybrid.h and evlist-hybrid.c/evlist-hybrid.h.
> > Move hybrid related codes to these files.
> >
> > - Create a new patch 'perf pmu: Support 'cycles' and 'branches' inside hybrid PMU' to
> > support 'cycles' and 'branches' inside PMU.
> >
> > - Create a new patch 'perf record: Uniquify hybrid event name' to tell user the
> > pmu which the event belongs to for perf-record.
> >
> > - If group members are from different hybrid PMUs, shows warning and disable
> > grouping.
> >
> > - Other refining and refactoring.
> >
> > v2:
> > ---
> > - Drop kernel patches (Kan posted the series "Add Alder Lake support for perf (kernel)" separately).
> > - Drop the patches for perf-c2c/perf-mem/topdown/metrics/topology header supports,
> > which will be added in series 2 or series 3.
> > - Simplify the arguments of __perf_pmu__new_alias() by passing
> > the 'struct pme_event' pointer.
> > - Check sysfs validity before access.
> > - Use pmu style event name, such as "cpu_core/cycles/".
> > - Move command output two chars to the right.
> > - Move pmu hybrid functions to new created pmu-hybrid.c/pmu-hybrid.h.
> > This is to pass the perf test python case.
> >
> > Jin Yao (25):
> > tools headers uapi: Update tools's copy of linux/perf_event.h
> > perf jevents: Support unit value "cpu_core" and "cpu_atom"
> > perf pmu: Simplify arguments of __perf_pmu__new_alias
> > perf pmu: Save pmu name
> > perf pmu: Save detected hybrid pmus to a global pmu list
> > perf pmu: Add hybrid helper functions
> > perf stat: Uniquify hybrid event name
> > perf parse-events: Create two hybrid hardware events
> > perf parse-events: Create two hybrid cache events
> > perf parse-events: Create two hybrid raw events
> > perf parse-events: Compare with hybrid pmu name
> > perf parse-events: Support event inside hybrid pmu
> > perf record: Create two hybrid 'cycles' events by default
> > perf stat: Add default hybrid events
> > perf stat: Filter out unmatched aggregation for hybrid event
> > perf stat: Warn group events from different hybrid PMU
> > perf record: Uniquify hybrid event name
> > perf tests: Add hybrid cases for 'Parse event definition strings' test
> > perf tests: Add hybrid cases for 'Roundtrip evsel->name' test
> > perf tests: Skip 'Setup struct perf_event_attr' test for hybrid
> > perf tests: Support 'Track with sched_switch' test for hybrid
> > perf tests: Support 'Parse and process metrics' test for hybrid
> > perf tests: Support 'Session topology' test for hybrid
> > perf tests: Support 'Convert perf time to TSC' test for hybrid
> > perf tests: Skip 'perf stat metrics (shadow stat) test' for hybrid
> >
> > include/uapi/linux/perf_event.h | 15 ++
> > tools/include/uapi/linux/perf_event.h | 15 ++
> > tools/perf/builtin-record.c | 47 +++++-
> > tools/perf/builtin-stat.c | 29 ++++
> > tools/perf/pmu-events/jevents.c | 2 +
> > tools/perf/tests/attr.c | 4 +
> > tools/perf/tests/evsel-roundtrip-name.c | 19 ++-
> > tools/perf/tests/parse-events.c | 152 ++++++++++++++++++
> > tools/perf/tests/parse-metric.c | 10 +-
> > tools/perf/tests/perf-time-to-tsc.c | 16 ++
> > tools/perf/tests/shell/stat+shadow_stat.sh | 3 +
> > tools/perf/tests/switch-tracking.c | 10 +-
> > tools/perf/tests/topology.c | 10 +-
> > tools/perf/util/Build | 3 +
> > tools/perf/util/evlist-hybrid.c | 88 ++++++++++
> > tools/perf/util/evlist-hybrid.h | 14 ++
> > tools/perf/util/evlist.c | 5 +-
> > tools/perf/util/evsel.c | 12 +-
> > tools/perf/util/evsel.h | 4 +-
> > tools/perf/util/parse-events-hybrid.c | 178 +++++++++++++++++++++
> > tools/perf/util/parse-events-hybrid.h | 23 +++
> > tools/perf/util/parse-events.c | 86 +++++++++-
> > tools/perf/util/parse-events.h | 9 +-
> > tools/perf/util/parse-events.y | 9 +-
> > tools/perf/util/pmu-hybrid.c | 89 +++++++++++
> > tools/perf/util/pmu-hybrid.h | 22 +++
> > tools/perf/util/pmu.c | 64 +++++---
> > tools/perf/util/pmu.h | 7 +
> > tools/perf/util/python-ext-sources | 2 +
> > tools/perf/util/stat-display.c | 35 +++-
> > 30 files changed, 933 insertions(+), 49 deletions(-)
> > create mode 100644 tools/perf/util/evlist-hybrid.c
> > create mode 100644 tools/perf/util/evlist-hybrid.h
> > create mode 100644 tools/perf/util/parse-events-hybrid.c
> > create mode 100644 tools/perf/util/parse-events-hybrid.h
> > create mode 100644 tools/perf/util/pmu-hybrid.c
> > create mode 100644 tools/perf/util/pmu-hybrid.h
> >
>

2021-04-22 01:17:21

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 20/25] perf tests: Skip 'Setup struct perf_event_attr' test for hybrid

On Fri, Apr 16, 2021 at 10:05:12PM +0800, Jin Yao wrote:
> For hybrid, the attr.type consists of pmu type id + original type.
> There will be much changes for this test. Now we temporarily
> skip this test case and TODO in future.
>
> Signed-off-by: Jin Yao <[email protected]>
> ---
> tools/perf/tests/attr.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
> index dd39ce9b0277..b37c35fb5a46 100644
> --- a/tools/perf/tests/attr.c
> +++ b/tools/perf/tests/attr.c
> @@ -34,6 +34,7 @@
> #include "event.h"
> #include "util.h"
> #include "tests.h"
> +#include "pmu.h"
>
> #define ENV "PERF_TEST_ATTR"
>
> @@ -184,6 +185,9 @@ int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
> char path_dir[PATH_MAX];
> char *exec_path;
>
> + if (perf_pmu__has_hybrid())
> + return 0;

should return TEST_SKIP

jirka

> +
> /* First try development tree tests. */
> if (!lstat("./tests", &st))
> return run_dir("./tests", "./perf");
> --
> 2.17.1
>

2021-04-22 01:17:24

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 23/25] perf tests: Support 'Session topology' test for hybrid

On Fri, Apr 16, 2021 at 10:05:15PM +0800, Jin Yao wrote:
> Force to create one event "cpu_core/cycles/" by default,
> otherwise in evlist__valid_sample_type, the checking of
> 'if (evlist->core.nr_entries == 1)' would be failed.
>
> # ./perf test 41
> 41: Session topology : Ok
>
> Signed-off-by: Jin Yao <[email protected]>
> ---
> tools/perf/tests/topology.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
> index 050489807a47..30b4acb08d35 100644
> --- a/tools/perf/tests/topology.c
> +++ b/tools/perf/tests/topology.c
> @@ -8,6 +8,7 @@
> #include "session.h"
> #include "evlist.h"
> #include "debug.h"
> +#include "pmu.h"
> #include <linux/err.h>
>
> #define TEMPL "/tmp/perf-test-XXXXXX"
> @@ -40,7 +41,14 @@ static int session_write_header(char *path)
> session = perf_session__new(&data, false, NULL);
> TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
>
> - session->evlist = evlist__new_default();
> + if (!perf_pmu__has_hybrid()) {
> + session->evlist = evlist__new_default();
> + } else {
> + struct parse_events_error err;
> +
> + session->evlist = evlist__new();

you should ASSERT session->evlist in here

jirka

> + parse_events(session->evlist, "cpu_core/cycles/", &err);
> + }
> TEST_ASSERT_VAL("can't get evlist", session->evlist);
>
> perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
> --
> 2.17.1
>

2021-04-22 01:17:25

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 21/25] perf tests: Support 'Track with sched_switch' test for hybrid

On Fri, Apr 16, 2021 at 10:05:13PM +0800, Jin Yao wrote:
> Since for "cycles:u' on hybrid platform, it creates two "cycles".
> So the number of events in evlist is not expected in next test
> steps. Now we just use one event "cpu_core/cycles:u/" for hybrid.
>
> # ./perf test 35
> 35: Track with sched_switch : Ok
>
> Signed-off-by: Jin Yao <[email protected]>
> ---
> tools/perf/tests/switch-tracking.c | 10 +++++++++-
> 1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
> index 3ebaa758df77..3a12176f8c46 100644
> --- a/tools/perf/tests/switch-tracking.c
> +++ b/tools/perf/tests/switch-tracking.c
> @@ -18,6 +18,7 @@
> #include "record.h"
> #include "tests.h"
> #include "util/mmap.h"
> +#include "pmu.h"
>
> static int spin_sleep(void)
> {
> @@ -340,6 +341,10 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_
> struct evsel *switch_evsel, *tracking_evsel;
> const char *comm;
> int err = -1;
> + bool hybrid = false;
> +
> + if (perf_pmu__has_hybrid())
> + hybrid = true;
>
> threads = thread_map__new(-1, getpid(), UINT_MAX);
> if (!threads) {
> @@ -371,7 +376,10 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_
> cpu_clocks_evsel = evlist__last(evlist);
>
> /* Second event */
> - err = parse_events(evlist, "cycles:u", NULL);
> + if (!hybrid)

why the variable? some leftover? could be directly
'if (perf_pmu__has_hybrid())' no?

thanks,
jirka

> + err = parse_events(evlist, "cycles:u", NULL);
> + else
> + err = parse_events(evlist, "cpu_core/cycles/u", NULL);
> if (err) {
> pr_debug("Failed to parse event cycles:u\n");
> goto out_err;
> --
> 2.17.1
>

2021-04-22 01:17:32

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 14/25] perf stat: Add default hybrid events

On Fri, Apr 16, 2021 at 10:05:06PM +0800, Jin Yao wrote:

SNIP

> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> index 1255af4751c2..0351b99d17a7 100644
> --- a/tools/perf/builtin-stat.c
> +++ b/tools/perf/builtin-stat.c
> @@ -1145,6 +1145,13 @@ static int parse_stat_cgroups(const struct option *opt,
> return parse_cgroups(opt, str, unset);
> }
>
> +static int add_default_hybrid_events(struct evlist *evlist)
> +{
> + struct parse_events_error err;
> +
> + return parse_events(evlist, "cycles,instructions,branches,branch-misses", &err);
> +}
> +
> static struct option stat_options[] = {
> OPT_BOOLEAN('T', "transaction", &transaction_run,
> "hardware transaction statistics"),
> @@ -1626,6 +1633,12 @@ static int add_default_attributes(void)
> { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
> { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
>
> +};
> + struct perf_event_attr default_sw_attrs[] = {
> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },

hum, why not use default_attrs0, it's the same, no?

> };
>
> /*
> @@ -1863,6 +1876,14 @@ static int add_default_attributes(void)
> }
>
> if (!evsel_list->core.nr_entries) {
> + if (perf_pmu__has_hybrid()) {
> + if (evlist__add_default_attrs(evsel_list,
> + default_sw_attrs) < 0) {
> + return -1;
> + }
> + return add_default_hybrid_events(evsel_list);

please do it the same way like when topdown calls parse events,
we don't need to check for cycles, but please check result and
display the error


> + }
> +
> if (target__has_cpu(&target))
> default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK;

also you still want this change for hybrid pmus as well

thanks,
jirka

>
> --
> 2.17.1
>

2021-04-22 01:17:34

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 24/25] perf tests: Support 'Convert perf time to TSC' test for hybrid

On Fri, Apr 16, 2021 at 10:05:16PM +0800, Jin Yao wrote:
> Since for "cycles:u' on hybrid platform, it creates two "cycles".
> So the second evsel in evlist also needs initialization.
>
> With this patch,
>
> # ./perf test 71
> 71: Convert perf time to TSC : Ok
>
> Signed-off-by: Jin Yao <[email protected]>
> ---
> tools/perf/tests/perf-time-to-tsc.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
> index 680c3cffb128..72f268c6cc5d 100644
> --- a/tools/perf/tests/perf-time-to-tsc.c
> +++ b/tools/perf/tests/perf-time-to-tsc.c
> @@ -20,6 +20,7 @@
> #include "tsc.h"
> #include "mmap.h"
> #include "tests.h"
> +#include "pmu.h"
>
> #define CHECK__(x) { \
> while ((x) < 0) { \
> @@ -66,6 +67,10 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
> u64 test_tsc, comm1_tsc, comm2_tsc;
> u64 test_time, comm1_time = 0, comm2_time = 0;
> struct mmap *md;
> + bool hybrid = false;
> +
> + if (perf_pmu__has_hybrid())
> + hybrid = true;
>
> threads = thread_map__new(-1, getpid(), UINT_MAX);
> CHECK_NOT_NULL__(threads);
> @@ -88,6 +93,17 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
> evsel->core.attr.disabled = 1;
> evsel->core.attr.enable_on_exec = 0;
>
> + /*
> + * For hybrid "cycles:u", it creates two events.
> + * Init the second evsel here.
> + */
> + if (hybrid) {

same, don't see the reason for 'hybrid' variable

jirka

> + evsel = evsel__next(evsel);
> + evsel->core.attr.comm = 1;
> + evsel->core.attr.disabled = 1;
> + evsel->core.attr.enable_on_exec = 0;
> + }
> +
> CHECK__(evlist__open(evlist));
>
> CHECK__(evlist__mmap(evlist, UINT_MAX));
> --
> 2.17.1
>

2021-04-22 01:18:45

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 22/25] perf tests: Support 'Parse and process metrics' test for hybrid

On Fri, Apr 16, 2021 at 10:05:14PM +0800, Jin Yao wrote:
> Some events are not supported. Only pick up some cases for hybrid.
>
> # ./perf test 67
> 67: Parse and process metrics : Ok
>
> Signed-off-by: Jin Yao <[email protected]>
> ---
> tools/perf/tests/parse-metric.c | 10 ++++++++--
> 1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
> index 4968c4106254..24e5ddff515e 100644
> --- a/tools/perf/tests/parse-metric.c
> +++ b/tools/perf/tests/parse-metric.c
> @@ -11,6 +11,7 @@
> #include "debug.h"
> #include "expr.h"
> #include "stat.h"
> +#include "pmu.h"
>
> static struct pmu_event pme_test[] = {
> {
> @@ -370,12 +371,17 @@ static int test_metric_group(void)
>
> int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
> {
> + perf_pmu__scan(NULL);

perf_pmu__has_hybrid calls perf_pmu__scan no?

jirka

> +
> TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
> TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
> - TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
> TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
> - TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
> TEST_ASSERT_VAL("Memory bandwidth", test_memory_bandwidth() == 0);
> +
> + if (!perf_pmu__has_hybrid()) {
> + TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
> + TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
> + }
> return 0;
> }
> --
> 2.17.1
>

2021-04-22 02:15:08

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 14/25] perf stat: Add default hybrid events

Hi Jiri,

On 4/22/2021 2:29 AM, Jiri Olsa wrote:
> On Fri, Apr 16, 2021 at 10:05:06PM +0800, Jin Yao wrote:
>
> SNIP
>
>> diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
>> index 1255af4751c2..0351b99d17a7 100644
>> --- a/tools/perf/builtin-stat.c
>> +++ b/tools/perf/builtin-stat.c
>> @@ -1145,6 +1145,13 @@ static int parse_stat_cgroups(const struct option *opt,
>> return parse_cgroups(opt, str, unset);
>> }
>>
>> +static int add_default_hybrid_events(struct evlist *evlist)
>> +{
>> + struct parse_events_error err;
>> +
>> + return parse_events(evlist, "cycles,instructions,branches,branch-misses", &err);
>> +}
>> +
>> static struct option stat_options[] = {
>> OPT_BOOLEAN('T', "transaction", &transaction_run,
>> "hardware transaction statistics"),
>> @@ -1626,6 +1633,12 @@ static int add_default_attributes(void)
>> { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
>> { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
>>
>> +};
>> + struct perf_event_attr default_sw_attrs[] = {
>> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
>> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
>> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
>> + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
>
> hum, why not use default_attrs0, it's the same, no?
>

The default_attrs0 has one more item " {.type = PERF_TYPE_HARDWARE, .config =
PERF_COUNT_HW_CPU_CYCLES },"

So I have to only pick out the sw attrs and save them to default_sw_attrs.

>> };
>>
>> /*
>> @@ -1863,6 +1876,14 @@ static int add_default_attributes(void)
>> }
>>
>> if (!evsel_list->core.nr_entries) {
>> + if (perf_pmu__has_hybrid()) {
>> + if (evlist__add_default_attrs(evsel_list,
>> + default_sw_attrs) < 0) {
>> + return -1;
>> + }
>> + return add_default_hybrid_events(evsel_list);
>
> please do it the same way like when topdown calls parse events,
> we don't need to check for cycles, but please check result and
> display the error
>

Something like this?

err = parse_events(evsel_list, "cycles,instructions,branches,branch-misses", &errinfo);
if (err) {
fprintf(stderr,...);
parse_events_print_error(&errinfo, ...);
return -1;
}

>
>> + }
>> +
>> if (target__has_cpu(&target))
>> default_attrs0[0].config = PERF_COUNT_SW_CPU_CLOCK;
>
> also you still want this change for hybrid pmus as well
>

Yes, the default_sw_attr only uses 'PERF_COUNT_SW_TASK_CLOCK', we do need to change it to
PERF_COUNT_SW_CPU_CLOCK for system wide.

> thanks,
> jirka
>

Thanks
Jin Yao

>>
>> --
>> 2.17.1
>>
>

2021-04-22 03:13:28

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 20/25] perf tests: Skip 'Setup struct perf_event_attr' test for hybrid

Hi Jiri,

On 4/22/2021 2:29 AM, Jiri Olsa wrote:
> On Fri, Apr 16, 2021 at 10:05:12PM +0800, Jin Yao wrote:
>> For hybrid, the attr.type consists of pmu type id + original type.
>> There will be much changes for this test. Now we temporarily
>> skip this test case and TODO in future.
>>
>> Signed-off-by: Jin Yao <[email protected]>
>> ---
>> tools/perf/tests/attr.c | 4 ++++
>> 1 file changed, 4 insertions(+)
>>
>> diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
>> index dd39ce9b0277..b37c35fb5a46 100644
>> --- a/tools/perf/tests/attr.c
>> +++ b/tools/perf/tests/attr.c
>> @@ -34,6 +34,7 @@
>> #include "event.h"
>> #include "util.h"
>> #include "tests.h"
>> +#include "pmu.h"
>>
>> #define ENV "PERF_TEST_ATTR"
>>
>> @@ -184,6 +185,9 @@ int test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
>> char path_dir[PATH_MAX];
>> char *exec_path;
>>
>> + if (perf_pmu__has_hybrid())
>> + return 0;
>
> should return TEST_SKIP
>

Got it, thanks Jiri!

> jirka
>

Thanks
Jin Yao

>> +
>> /* First try development tree tests. */
>> if (!lstat("./tests", &st))
>> return run_dir("./tests", "./perf");
>> --
>> 2.17.1
>>
>

2021-04-22 03:16:51

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 21/25] perf tests: Support 'Track with sched_switch' test for hybrid

Hi Jiri,

On 4/22/2021 2:28 AM, Jiri Olsa wrote:
> On Fri, Apr 16, 2021 at 10:05:13PM +0800, Jin Yao wrote:
>> Since for "cycles:u' on hybrid platform, it creates two "cycles".
>> So the number of events in evlist is not expected in next test
>> steps. Now we just use one event "cpu_core/cycles:u/" for hybrid.
>>
>> # ./perf test 35
>> 35: Track with sched_switch : Ok
>>
>> Signed-off-by: Jin Yao <[email protected]>
>> ---
>> tools/perf/tests/switch-tracking.c | 10 +++++++++-
>> 1 file changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
>> index 3ebaa758df77..3a12176f8c46 100644
>> --- a/tools/perf/tests/switch-tracking.c
>> +++ b/tools/perf/tests/switch-tracking.c
>> @@ -18,6 +18,7 @@
>> #include "record.h"
>> #include "tests.h"
>> #include "util/mmap.h"
>> +#include "pmu.h"
>>
>> static int spin_sleep(void)
>> {
>> @@ -340,6 +341,10 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_
>> struct evsel *switch_evsel, *tracking_evsel;
>> const char *comm;
>> int err = -1;
>> + bool hybrid = false;
>> +
>> + if (perf_pmu__has_hybrid())
>> + hybrid = true;
>>
>> threads = thread_map__new(-1, getpid(), UINT_MAX);
>> if (!threads) {
>> @@ -371,7 +376,10 @@ int test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_
>> cpu_clocks_evsel = evlist__last(evlist);
>>
>> /* Second event */
>> - err = parse_events(evlist, "cycles:u", NULL);
>> + if (!hybrid)
>
> why the variable? some leftover? could be directly
> 'if (perf_pmu__has_hybrid())' no?
>

Yes, using 'if (perf_pmu__has_hybrid())' is the better style.

Thanks
Jin Yao

> thanks,
> jirka
>
>> + err = parse_events(evlist, "cycles:u", NULL);
>> + else
>> + err = parse_events(evlist, "cpu_core/cycles/u", NULL);
>> if (err) {
>> pr_debug("Failed to parse event cycles:u\n");
>> goto out_err;
>> --
>> 2.17.1
>>
>

2021-04-22 03:17:03

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 23/25] perf tests: Support 'Session topology' test for hybrid

Hi Jiri,

On 4/22/2021 2:29 AM, Jiri Olsa wrote:
> On Fri, Apr 16, 2021 at 10:05:15PM +0800, Jin Yao wrote:
>> Force to create one event "cpu_core/cycles/" by default,
>> otherwise in evlist__valid_sample_type, the checking of
>> 'if (evlist->core.nr_entries == 1)' would be failed.
>>
>> # ./perf test 41
>> 41: Session topology : Ok
>>
>> Signed-off-by: Jin Yao <[email protected]>
>> ---
>> tools/perf/tests/topology.c | 10 +++++++++-
>> 1 file changed, 9 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
>> index 050489807a47..30b4acb08d35 100644
>> --- a/tools/perf/tests/topology.c
>> +++ b/tools/perf/tests/topology.c
>> @@ -8,6 +8,7 @@
>> #include "session.h"
>> #include "evlist.h"
>> #include "debug.h"
>> +#include "pmu.h"
>> #include <linux/err.h>
>>
>> #define TEMPL "/tmp/perf-test-XXXXXX"
>> @@ -40,7 +41,14 @@ static int session_write_header(char *path)
>> session = perf_session__new(&data, false, NULL);
>> TEST_ASSERT_VAL("can't get session", !IS_ERR(session));
>>
>> - session->evlist = evlist__new_default();
>> + if (!perf_pmu__has_hybrid()) {
>> + session->evlist = evlist__new_default();
>> + } else {
>> + struct parse_events_error err;
>> +
>> + session->evlist = evlist__new();
>
> you should ASSERT session->evlist in here
>
> jirka
>

OK, will add "ASSERT session->evlist" in next version.

Thanks
Jin Yao

>> + parse_events(session->evlist, "cpu_core/cycles/", &err);
>> + }
>> TEST_ASSERT_VAL("can't get evlist", session->evlist);
>>
>> perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
>> --
>> 2.17.1
>>
>

2021-04-22 03:18:31

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 24/25] perf tests: Support 'Convert perf time to TSC' test for hybrid

Hi Jiri,

On 4/22/2021 2:29 AM, Jiri Olsa wrote:
> On Fri, Apr 16, 2021 at 10:05:16PM +0800, Jin Yao wrote:
>> Since for "cycles:u' on hybrid platform, it creates two "cycles".
>> So the second evsel in evlist also needs initialization.
>>
>> With this patch,
>>
>> # ./perf test 71
>> 71: Convert perf time to TSC : Ok
>>
>> Signed-off-by: Jin Yao <[email protected]>
>> ---
>> tools/perf/tests/perf-time-to-tsc.c | 16 ++++++++++++++++
>> 1 file changed, 16 insertions(+)
>>
>> diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c
>> index 680c3cffb128..72f268c6cc5d 100644
>> --- a/tools/perf/tests/perf-time-to-tsc.c
>> +++ b/tools/perf/tests/perf-time-to-tsc.c
>> @@ -20,6 +20,7 @@
>> #include "tsc.h"
>> #include "mmap.h"
>> #include "tests.h"
>> +#include "pmu.h"
>>
>> #define CHECK__(x) { \
>> while ((x) < 0) { \
>> @@ -66,6 +67,10 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
>> u64 test_tsc, comm1_tsc, comm2_tsc;
>> u64 test_time, comm1_time = 0, comm2_time = 0;
>> struct mmap *md;
>> + bool hybrid = false;
>> +
>> + if (perf_pmu__has_hybrid())
>> + hybrid = true;
>>
>> threads = thread_map__new(-1, getpid(), UINT_MAX);
>> CHECK_NOT_NULL__(threads);
>> @@ -88,6 +93,17 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe
>> evsel->core.attr.disabled = 1;
>> evsel->core.attr.enable_on_exec = 0;
>>
>> + /*
>> + * For hybrid "cycles:u", it creates two events.
>> + * Init the second evsel here.
>> + */
>> + if (hybrid) {
>
> same, don't see the reason for 'hybrid' variable
>

OK, will use 'if (perf_pmu__has_hybrid())' instead.

Thanks
Jin Yao

> jirka
>
>> + evsel = evsel__next(evsel);
>> + evsel->core.attr.comm = 1;
>> + evsel->core.attr.disabled = 1;
>> + evsel->core.attr.enable_on_exec = 0;
>> + }
>> +
>> CHECK__(evlist__open(evlist));
>>
>> CHECK__(evlist__mmap(evlist, UINT_MAX));
>> --
>> 2.17.1
>>
>

2021-04-22 03:21:22

by Jin Yao

[permalink] [raw]
Subject: Re: [PATCH v4 22/25] perf tests: Support 'Parse and process metrics' test for hybrid

Hi Jiri,

On 4/22/2021 2:29 AM, Jiri Olsa wrote:
> On Fri, Apr 16, 2021 at 10:05:14PM +0800, Jin Yao wrote:
>> Some events are not supported. Only pick up some cases for hybrid.
>>
>> # ./perf test 67
>> 67: Parse and process metrics : Ok
>>
>> Signed-off-by: Jin Yao <[email protected]>
>> ---
>> tools/perf/tests/parse-metric.c | 10 ++++++++--
>> 1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/tools/perf/tests/parse-metric.c b/tools/perf/tests/parse-metric.c
>> index 4968c4106254..24e5ddff515e 100644
>> --- a/tools/perf/tests/parse-metric.c
>> +++ b/tools/perf/tests/parse-metric.c
>> @@ -11,6 +11,7 @@
>> #include "debug.h"
>> #include "expr.h"
>> #include "stat.h"
>> +#include "pmu.h"
>>
>> static struct pmu_event pme_test[] = {
>> {
>> @@ -370,12 +371,17 @@ static int test_metric_group(void)
>>
>> int test__parse_metric(struct test *test __maybe_unused, int subtest __maybe_unused)
>> {
>> + perf_pmu__scan(NULL);
>
> perf_pmu__has_hybrid calls perf_pmu__scan no?
>
> jirka
>

Sorry, I don't need to call perf_pmu_scan here.

+bool perf_pmu__has_hybrid(void)
+{
+ if (!hybrid_scanned) {
+ hybrid_scanned = true;
+ perf_pmu__scan(NULL);
+ }
+
+ return !list_empty(&perf_pmu__hybrid_pmus);
+}

perf_pmu__has_hybrid calls perf_pmu__scan if it's not scanned yet.

Thanks
Jin Yao

>> +
>> TEST_ASSERT_VAL("IPC failed", test_ipc() == 0);
>> TEST_ASSERT_VAL("frontend failed", test_frontend() == 0);
>> - TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>> TEST_ASSERT_VAL("DCache_L2 failed", test_dcache_l2() == 0);
>> TEST_ASSERT_VAL("recursion fail failed", test_recursion_fail() == 0);
>> - TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
>> TEST_ASSERT_VAL("Memory bandwidth", test_memory_bandwidth() == 0);
>> +
>> + if (!perf_pmu__has_hybrid()) {
>> + TEST_ASSERT_VAL("cache_miss_cycles failed", test_cache_miss_cycles() == 0);
>> + TEST_ASSERT_VAL("test metric group", test_metric_group() == 0);
>> + }
>> return 0;
>> }
>> --
>> 2.17.1
>>
>

2021-04-22 10:26:18

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCH v4 14/25] perf stat: Add default hybrid events

On Thu, Apr 22, 2021 at 10:12:49AM +0800, Jin, Yao wrote:
> Hi Jiri,
>
> On 4/22/2021 2:29 AM, Jiri Olsa wrote:
> > On Fri, Apr 16, 2021 at 10:05:06PM +0800, Jin Yao wrote:
> >
> > SNIP
> >
> > > diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
> > > index 1255af4751c2..0351b99d17a7 100644
> > > --- a/tools/perf/builtin-stat.c
> > > +++ b/tools/perf/builtin-stat.c
> > > @@ -1145,6 +1145,13 @@ static int parse_stat_cgroups(const struct option *opt,
> > > return parse_cgroups(opt, str, unset);
> > > }
> > > +static int add_default_hybrid_events(struct evlist *evlist)
> > > +{
> > > + struct parse_events_error err;
> > > +
> > > + return parse_events(evlist, "cycles,instructions,branches,branch-misses", &err);
> > > +}
> > > +
> > > static struct option stat_options[] = {
> > > OPT_BOOLEAN('T', "transaction", &transaction_run,
> > > "hardware transaction statistics"),
> > > @@ -1626,6 +1633,12 @@ static int add_default_attributes(void)
> > > { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
> > > { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
> > > +};
> > > + struct perf_event_attr default_sw_attrs[] = {
> > > + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
> > > + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
> > > + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CPU_MIGRATIONS },
> > > + { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
> >
> > hum, why not use default_attrs0, it's the same, no?
> >
>
> The default_attrs0 has one more item " {.type = PERF_TYPE_HARDWARE, .config
> = PERF_COUNT_HW_CPU_CYCLES },"
>
> So I have to only pick out the sw attrs and save them to default_sw_attrs.
>
> > > };
> > > /*
> > > @@ -1863,6 +1876,14 @@ static int add_default_attributes(void)
> > > }
> > > if (!evsel_list->core.nr_entries) {
> > > + if (perf_pmu__has_hybrid()) {
> > > + if (evlist__add_default_attrs(evsel_list,
> > > + default_sw_attrs) < 0) {
> > > + return -1;
> > > + }
> > > + return add_default_hybrid_events(evsel_list);
> >
> > please do it the same way like when topdown calls parse events,
> > we don't need to check for cycles, but please check result and
> > display the error
> >
>
> Something like this?
>
> err = parse_events(evsel_list, "cycles,instructions,branches,branch-misses", &errinfo);
> if (err) {
> fprintf(stderr,...);
> parse_events_print_error(&errinfo, ...);
> return -1;
> }

yes

jirka