1 // SPDX-License-Identifier: GPL-2.0
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
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>
14 #include "../../../util/cpumap.h"
15 #include "../../../util/event.h"
16 #include "../../../util/evsel.h"
17 #include "../../../util/evlist.h"
18 #include "../../../util/session.h"
19 #include <internal/lib.h> // page_size
20 #include "../../../util/pmu.h"
21 #include "../../../util/debug.h"
22 #include "../../../util/auxtrace.h"
23 #include "../../../util/record.h"
24 #include "../../../util/arm-spe.h"
26 #define KiB(x) ((x) * 1024)
27 #define MiB(x) ((x) * 1024 * 1024)
29 struct arm_spe_recording
{
30 struct auxtrace_record itr
;
31 struct perf_pmu
*arm_spe_pmu
;
32 struct evlist
*evlist
;
36 arm_spe_info_priv_size(struct auxtrace_record
*itr __maybe_unused
,
37 struct evlist
*evlist __maybe_unused
)
39 return ARM_SPE_AUXTRACE_PRIV_SIZE
;
42 static int arm_spe_info_fill(struct auxtrace_record
*itr
,
43 struct perf_session
*session
,
44 struct perf_record_auxtrace_info
*auxtrace_info
,
47 struct arm_spe_recording
*sper
=
48 container_of(itr
, struct arm_spe_recording
, itr
);
49 struct perf_pmu
*arm_spe_pmu
= sper
->arm_spe_pmu
;
51 if (priv_size
!= ARM_SPE_AUXTRACE_PRIV_SIZE
)
54 if (!session
->evlist
->core
.nr_mmaps
)
57 auxtrace_info
->type
= PERF_AUXTRACE_ARM_SPE
;
58 auxtrace_info
->priv
[ARM_SPE_PMU_TYPE
] = arm_spe_pmu
->type
;
63 static int arm_spe_recording_options(struct auxtrace_record
*itr
,
64 struct evlist
*evlist
,
65 struct record_opts
*opts
)
67 struct arm_spe_recording
*sper
=
68 container_of(itr
, struct arm_spe_recording
, itr
);
69 struct perf_pmu
*arm_spe_pmu
= sper
->arm_spe_pmu
;
70 struct evsel
*evsel
, *arm_spe_evsel
= NULL
;
71 bool privileged
= perf_event_paranoid_check(-1);
72 struct evsel
*tracking_evsel
;
75 sper
->evlist
= evlist
;
77 evlist__for_each_entry(evlist
, evsel
) {
78 if (evsel
->core
.attr
.type
== arm_spe_pmu
->type
) {
80 pr_err("There may be only one " ARM_SPE_PMU_NAME
"x event\n");
83 evsel
->core
.attr
.freq
= 0;
84 evsel
->core
.attr
.sample_period
= 1;
85 arm_spe_evsel
= evsel
;
86 opts
->full_auxtrace
= true;
90 if (!opts
->full_auxtrace
)
93 /* We are in full trace mode but '-m,xyz' wasn't specified */
94 if (opts
->full_auxtrace
&& !opts
->auxtrace_mmap_pages
) {
96 opts
->auxtrace_mmap_pages
= MiB(4) / page_size
;
98 opts
->auxtrace_mmap_pages
= KiB(128) / page_size
;
99 if (opts
->mmap_pages
== UINT_MAX
)
100 opts
->mmap_pages
= KiB(256) / page_size
;
104 /* Validate auxtrace_mmap_pages */
105 if (opts
->auxtrace_mmap_pages
) {
106 size_t sz
= opts
->auxtrace_mmap_pages
* (size_t)page_size
;
107 size_t min_sz
= KiB(8);
109 if (sz
< min_sz
|| !is_power_of_2(sz
)) {
110 pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n",
118 * To obtain the auxtrace buffer file descriptor, the auxtrace event
121 evlist__to_front(evlist
, arm_spe_evsel
);
123 evsel__set_sample_bit(arm_spe_evsel
, CPU
);
124 evsel__set_sample_bit(arm_spe_evsel
, TIME
);
125 evsel__set_sample_bit(arm_spe_evsel
, TID
);
127 /* Add dummy event to keep tracking */
128 err
= parse_events(evlist
, "dummy:u", NULL
);
132 tracking_evsel
= evlist__last(evlist
);
133 evlist__set_tracking_event(evlist
, tracking_evsel
);
135 tracking_evsel
->core
.attr
.freq
= 0;
136 tracking_evsel
->core
.attr
.sample_period
= 1;
137 evsel__set_sample_bit(tracking_evsel
, TIME
);
138 evsel__set_sample_bit(tracking_evsel
, CPU
);
139 evsel__reset_sample_bit(tracking_evsel
, BRANCH_STACK
);
144 static u64
arm_spe_reference(struct auxtrace_record
*itr __maybe_unused
)
148 clock_gettime(CLOCK_MONOTONIC_RAW
, &ts
);
150 return ts
.tv_sec
^ ts
.tv_nsec
;
153 static void arm_spe_recording_free(struct auxtrace_record
*itr
)
155 struct arm_spe_recording
*sper
=
156 container_of(itr
, struct arm_spe_recording
, itr
);
161 struct auxtrace_record
*arm_spe_recording_init(int *err
,
162 struct perf_pmu
*arm_spe_pmu
)
164 struct arm_spe_recording
*sper
;
171 sper
= zalloc(sizeof(struct arm_spe_recording
));
177 sper
->arm_spe_pmu
= arm_spe_pmu
;
178 sper
->itr
.pmu
= arm_spe_pmu
;
179 sper
->itr
.recording_options
= arm_spe_recording_options
;
180 sper
->itr
.info_priv_size
= arm_spe_info_priv_size
;
181 sper
->itr
.info_fill
= arm_spe_info_fill
;
182 sper
->itr
.free
= arm_spe_recording_free
;
183 sper
->itr
.reference
= arm_spe_reference
;
184 sper
->itr
.read_finish
= auxtrace_record__read_finish
;
185 sper
->itr
.alignment
= 0;
191 struct perf_event_attr
192 *arm_spe_pmu_default_config(struct perf_pmu
*arm_spe_pmu
)
194 struct perf_event_attr
*attr
;
196 attr
= zalloc(sizeof(struct perf_event_attr
));
198 pr_err("arm_spe default config cannot allocate a perf_event_attr\n");
203 * If kernel driver doesn't advertise a minimum,
204 * use max allowable by PMSIDR_EL1.INTERVAL
206 if (perf_pmu__scan_file(arm_spe_pmu
, "caps/min_interval", "%llu",
207 &attr
->sample_period
) != 1) {
208 pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n");
209 attr
->sample_period
= 4096;
212 arm_spe_pmu
->selectable
= true;
213 arm_spe_pmu
->is_uncore
= false;