Skip to content

Commit 057381a

Browse files
77liuqiacmel
authored andcommitted
perf auxtrace arm64: Add support for HiSilicon PCIe Tune and Trace device driver
HiSilicon PCIe tune and trace device (PTT) could dynamically tune the PCIe link's events, and trace the TLP headers). This patch add support for PTT device in perf tool, so users could use 'perf record' to get TLP headers trace data. Reviewed-by: Leo Yan <[email protected]> Signed-off-by: Qi Liu <[email protected]> Signed-off-by: Yicong Yang <[email protected]> Acked-by: John Garry <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Bjorn Helgaas <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jonathan Cameron <[email protected]> Cc: Lorenzo Pieralisi <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Poirier <[email protected]> Cc: Mike Leach <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Qi Liu <[email protected]> Cc: Shameerali Kolothum Thodi <[email protected]> Cc: Shaokun Zhang <[email protected]> Cc: Suzuki Poulouse <[email protected]> Cc: Will Deacon <[email protected]> Cc: Zeng Prime <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 45a3975 commit 057381a

File tree

7 files changed

+273
-1
lines changed

7 files changed

+273
-1
lines changed

tools/perf/arch/arm/util/auxtrace.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
* Author: Mathieu Poirier <[email protected]>
55
*/
66

7+
#include <dirent.h>
78
#include <stdbool.h>
89
#include <linux/coresight-pmu.h>
910
#include <linux/zalloc.h>
11+
#include <api/fs/fs.h>
1012

1113
#include "../../../util/auxtrace.h"
1214
#include "../../../util/debug.h"
1315
#include "../../../util/evlist.h"
1416
#include "../../../util/pmu.h"
1517
#include "cs-etm.h"
1618
#include "arm-spe.h"
19+
#include "hisi-ptt.h"
1720

1821
static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
1922
{
@@ -50,6 +53,52 @@ static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
5053
return arm_spe_pmus;
5154
}
5255

56+
static struct perf_pmu **find_all_hisi_ptt_pmus(int *nr_ptts, int *err)
57+
{
58+
const char *sysfs = sysfs__mountpoint();
59+
struct perf_pmu **hisi_ptt_pmus = NULL;
60+
struct dirent *dent;
61+
char path[PATH_MAX];
62+
DIR *dir = NULL;
63+
int idx = 0;
64+
65+
snprintf(path, PATH_MAX, "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
66+
dir = opendir(path);
67+
if (!dir) {
68+
pr_err("can't read directory '%s'\n", EVENT_SOURCE_DEVICE_PATH);
69+
*err = -EINVAL;
70+
return NULL;
71+
}
72+
73+
while ((dent = readdir(dir))) {
74+
if (strstr(dent->d_name, HISI_PTT_PMU_NAME))
75+
(*nr_ptts)++;
76+
}
77+
78+
if (!(*nr_ptts))
79+
goto out;
80+
81+
hisi_ptt_pmus = zalloc(sizeof(struct perf_pmu *) * (*nr_ptts));
82+
if (!hisi_ptt_pmus) {
83+
pr_err("hisi_ptt alloc failed\n");
84+
*err = -ENOMEM;
85+
goto out;
86+
}
87+
88+
rewinddir(dir);
89+
while ((dent = readdir(dir))) {
90+
if (strstr(dent->d_name, HISI_PTT_PMU_NAME) && idx < *nr_ptts) {
91+
hisi_ptt_pmus[idx] = perf_pmu__find(dent->d_name);
92+
if (hisi_ptt_pmus[idx])
93+
idx++;
94+
}
95+
}
96+
97+
out:
98+
closedir(dir);
99+
return hisi_ptt_pmus;
100+
}
101+
53102
static struct perf_pmu *find_pmu_for_event(struct perf_pmu **pmus,
54103
int pmu_nr, struct evsel *evsel)
55104
{
@@ -71,34 +120,45 @@ struct auxtrace_record
71120
{
72121
struct perf_pmu *cs_etm_pmu = NULL;
73122
struct perf_pmu **arm_spe_pmus = NULL;
123+
struct perf_pmu **hisi_ptt_pmus = NULL;
74124
struct evsel *evsel;
75125
struct perf_pmu *found_etm = NULL;
76126
struct perf_pmu *found_spe = NULL;
127+
struct perf_pmu *found_ptt = NULL;
77128
int auxtrace_event_cnt = 0;
78129
int nr_spes = 0;
130+
int nr_ptts = 0;
79131

80132
if (!evlist)
81133
return NULL;
82134

83135
cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
84136
arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
137+
hisi_ptt_pmus = find_all_hisi_ptt_pmus(&nr_ptts, err);
85138

86139
evlist__for_each_entry(evlist, evsel) {
87140
if (cs_etm_pmu && !found_etm)
88141
found_etm = find_pmu_for_event(&cs_etm_pmu, 1, evsel);
89142

90143
if (arm_spe_pmus && !found_spe)
91144
found_spe = find_pmu_for_event(arm_spe_pmus, nr_spes, evsel);
145+
146+
if (hisi_ptt_pmus && !found_ptt)
147+
found_ptt = find_pmu_for_event(hisi_ptt_pmus, nr_ptts, evsel);
92148
}
93149

94150
free(arm_spe_pmus);
151+
free(hisi_ptt_pmus);
95152

96153
if (found_etm)
97154
auxtrace_event_cnt++;
98155

99156
if (found_spe)
100157
auxtrace_event_cnt++;
101158

159+
if (found_ptt)
160+
auxtrace_event_cnt++;
161+
102162
if (auxtrace_event_cnt > 1) {
103163
pr_err("Concurrent AUX trace operation not currently supported\n");
104164
*err = -EOPNOTSUPP;
@@ -111,6 +171,9 @@ struct auxtrace_record
111171
#if defined(__aarch64__)
112172
if (found_spe)
113173
return arm_spe_recording_init(err, found_spe);
174+
175+
if (found_ptt)
176+
return hisi_ptt_recording_init(err, found_ptt);
114177
#endif
115178

116179
/*

tools/perf/arch/arm/util/pmu.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/string.h>
1111

1212
#include "arm-spe.h"
13+
#include "hisi-ptt.h"
1314
#include "../../../util/pmu.h"
1415

1516
struct perf_event_attr
@@ -22,6 +23,8 @@ struct perf_event_attr
2223
#if defined(__aarch64__)
2324
} else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) {
2425
return arm_spe_pmu_default_config(pmu);
26+
} else if (strstarts(pmu->name, HISI_PTT_PMU_NAME)) {
27+
pmu->selectable = true;
2528
#endif
2629
}
2730

tools/perf/arch/arm64/util/Build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
1111
perf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \
1212
../../arm/util/auxtrace.o \
1313
../../arm/util/cs-etm.o \
14-
arm-spe.o mem-events.o
14+
arm-spe.o mem-events.o hisi-ptt.o

tools/perf/arch/arm64/util/hisi-ptt.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* HiSilicon PCIe Trace and Tuning (PTT) support
4+
* Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
5+
*/
6+
7+
#include <linux/kernel.h>
8+
#include <linux/types.h>
9+
#include <linux/bitops.h>
10+
#include <linux/log2.h>
11+
#include <linux/zalloc.h>
12+
#include <time.h>
13+
14+
#include <internal/lib.h> // page_size
15+
#include "../../../util/auxtrace.h"
16+
#include "../../../util/cpumap.h"
17+
#include "../../../util/debug.h"
18+
#include "../../../util/event.h"
19+
#include "../../../util/evlist.h"
20+
#include "../../../util/evsel.h"
21+
#include "../../../util/hisi-ptt.h"
22+
#include "../../../util/pmu.h"
23+
#include "../../../util/record.h"
24+
#include "../../../util/session.h"
25+
#include "../../../util/tsc.h"
26+
27+
#define KiB(x) ((x) * 1024)
28+
#define MiB(x) ((x) * 1024 * 1024)
29+
30+
struct hisi_ptt_recording {
31+
struct auxtrace_record itr;
32+
struct perf_pmu *hisi_ptt_pmu;
33+
struct evlist *evlist;
34+
};
35+
36+
static size_t
37+
hisi_ptt_info_priv_size(struct auxtrace_record *itr __maybe_unused,
38+
struct evlist *evlist __maybe_unused)
39+
{
40+
return HISI_PTT_AUXTRACE_PRIV_SIZE;
41+
}
42+
43+
static int hisi_ptt_info_fill(struct auxtrace_record *itr,
44+
struct perf_session *session,
45+
struct perf_record_auxtrace_info *auxtrace_info,
46+
size_t priv_size)
47+
{
48+
struct hisi_ptt_recording *pttr =
49+
container_of(itr, struct hisi_ptt_recording, itr);
50+
struct perf_pmu *hisi_ptt_pmu = pttr->hisi_ptt_pmu;
51+
52+
if (priv_size != HISI_PTT_AUXTRACE_PRIV_SIZE)
53+
return -EINVAL;
54+
55+
if (!session->evlist->core.nr_mmaps)
56+
return -EINVAL;
57+
58+
auxtrace_info->type = PERF_AUXTRACE_HISI_PTT;
59+
auxtrace_info->priv[0] = hisi_ptt_pmu->type;
60+
61+
return 0;
62+
}
63+
64+
static int hisi_ptt_set_auxtrace_mmap_page(struct record_opts *opts)
65+
{
66+
bool privileged = perf_event_paranoid_check(-1);
67+
68+
if (!opts->full_auxtrace)
69+
return 0;
70+
71+
if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
72+
if (privileged) {
73+
opts->auxtrace_mmap_pages = MiB(16) / page_size;
74+
} else {
75+
opts->auxtrace_mmap_pages = KiB(128) / page_size;
76+
if (opts->mmap_pages == UINT_MAX)
77+
opts->mmap_pages = KiB(256) / page_size;
78+
}
79+
}
80+
81+
/* Validate auxtrace_mmap_pages */
82+
if (opts->auxtrace_mmap_pages) {
83+
size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
84+
size_t min_sz = KiB(8);
85+
86+
if (sz < min_sz || !is_power_of_2(sz)) {
87+
pr_err("Invalid mmap size for HISI PTT: must be at least %zuKiB and a power of 2\n",
88+
min_sz / 1024);
89+
return -EINVAL;
90+
}
91+
}
92+
93+
return 0;
94+
}
95+
96+
static int hisi_ptt_recording_options(struct auxtrace_record *itr,
97+
struct evlist *evlist,
98+
struct record_opts *opts)
99+
{
100+
struct hisi_ptt_recording *pttr =
101+
container_of(itr, struct hisi_ptt_recording, itr);
102+
struct perf_pmu *hisi_ptt_pmu = pttr->hisi_ptt_pmu;
103+
struct evsel *evsel, *hisi_ptt_evsel = NULL;
104+
struct evsel *tracking_evsel;
105+
int err;
106+
107+
pttr->evlist = evlist;
108+
evlist__for_each_entry(evlist, evsel) {
109+
if (evsel->core.attr.type == hisi_ptt_pmu->type) {
110+
if (hisi_ptt_evsel) {
111+
pr_err("There may be only one " HISI_PTT_PMU_NAME "x event\n");
112+
return -EINVAL;
113+
}
114+
evsel->core.attr.freq = 0;
115+
evsel->core.attr.sample_period = 1;
116+
evsel->needs_auxtrace_mmap = true;
117+
hisi_ptt_evsel = evsel;
118+
opts->full_auxtrace = true;
119+
}
120+
}
121+
122+
err = hisi_ptt_set_auxtrace_mmap_page(opts);
123+
if (err)
124+
return err;
125+
/*
126+
* To obtain the auxtrace buffer file descriptor, the auxtrace event
127+
* must come first.
128+
*/
129+
evlist__to_front(evlist, hisi_ptt_evsel);
130+
evsel__set_sample_bit(hisi_ptt_evsel, TIME);
131+
132+
/* Add dummy event to keep tracking */
133+
err = parse_event(evlist, "dummy:u");
134+
if (err)
135+
return err;
136+
137+
tracking_evsel = evlist__last(evlist);
138+
evlist__set_tracking_event(evlist, tracking_evsel);
139+
140+
tracking_evsel->core.attr.freq = 0;
141+
tracking_evsel->core.attr.sample_period = 1;
142+
evsel__set_sample_bit(tracking_evsel, TIME);
143+
144+
return 0;
145+
}
146+
147+
static u64 hisi_ptt_reference(struct auxtrace_record *itr __maybe_unused)
148+
{
149+
return rdtsc();
150+
}
151+
152+
static void hisi_ptt_recording_free(struct auxtrace_record *itr)
153+
{
154+
struct hisi_ptt_recording *pttr =
155+
container_of(itr, struct hisi_ptt_recording, itr);
156+
157+
free(pttr);
158+
}
159+
160+
struct auxtrace_record *hisi_ptt_recording_init(int *err,
161+
struct perf_pmu *hisi_ptt_pmu)
162+
{
163+
struct hisi_ptt_recording *pttr;
164+
165+
if (!hisi_ptt_pmu) {
166+
*err = -ENODEV;
167+
return NULL;
168+
}
169+
170+
pttr = zalloc(sizeof(*pttr));
171+
if (!pttr) {
172+
*err = -ENOMEM;
173+
return NULL;
174+
}
175+
176+
pttr->hisi_ptt_pmu = hisi_ptt_pmu;
177+
pttr->itr.pmu = hisi_ptt_pmu;
178+
pttr->itr.recording_options = hisi_ptt_recording_options;
179+
pttr->itr.info_priv_size = hisi_ptt_info_priv_size;
180+
pttr->itr.info_fill = hisi_ptt_info_fill;
181+
pttr->itr.free = hisi_ptt_recording_free;
182+
pttr->itr.reference = hisi_ptt_reference;
183+
pttr->itr.read_finish = auxtrace_record__read_finish;
184+
pttr->itr.alignment = 0;
185+
186+
*err = 0;
187+
return &pttr->itr;
188+
}

tools/perf/util/auxtrace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,6 +1320,7 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
13201320
case PERF_AUXTRACE_S390_CPUMSF:
13211321
err = s390_cpumsf_process_auxtrace_info(event, session);
13221322
break;
1323+
case PERF_AUXTRACE_HISI_PTT:
13231324
case PERF_AUXTRACE_UNKNOWN:
13241325
default:
13251326
return -EINVAL;

tools/perf/util/auxtrace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ enum auxtrace_type {
4848
PERF_AUXTRACE_CS_ETM,
4949
PERF_AUXTRACE_ARM_SPE,
5050
PERF_AUXTRACE_S390_CPUMSF,
51+
PERF_AUXTRACE_HISI_PTT,
5152
};
5253

5354
enum itrace_period_type {

tools/perf/util/hisi-ptt.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* HiSilicon PCIe Trace and Tuning (PTT) support
4+
* Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
5+
*/
6+
7+
#ifndef INCLUDE__PERF_HISI_PTT_H__
8+
#define INCLUDE__PERF_HISI_PTT_H__
9+
10+
#define HISI_PTT_PMU_NAME "hisi_ptt"
11+
#define HISI_PTT_AUXTRACE_PRIV_SIZE sizeof(u64)
12+
13+
struct auxtrace_record *hisi_ptt_recording_init(int *err,
14+
struct perf_pmu *hisi_ptt_pmu);
15+
16+
#endif

0 commit comments

Comments
 (0)