@@ -84,6 +84,55 @@ static int arm_spe_info_fill(struct auxtrace_record *itr,
8484 return 0 ;
8585}
8686
87+ static void
88+ arm_spe_snapshot_resolve_auxtrace_defaults (struct record_opts * opts ,
89+ bool privileged )
90+ {
91+ /*
92+ * The default snapshot size is the auxtrace mmap size. If neither auxtrace mmap size nor
93+ * snapshot size is specified, then the default is 4MiB for privileged users, 128KiB for
94+ * unprivileged users.
95+ *
96+ * The default auxtrace mmap size is 4MiB/page_size for privileged users, 128KiB for
97+ * unprivileged users. If an unprivileged user does not specify mmap pages, the mmap pages
98+ * will be reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the
99+ * user is likely to get an error as they exceed their mlock limmit.
100+ */
101+
102+ /*
103+ * No size were given to '-S' or '-m,', so go with the default
104+ */
105+ if (!opts -> auxtrace_snapshot_size && !opts -> auxtrace_mmap_pages ) {
106+ if (privileged ) {
107+ opts -> auxtrace_mmap_pages = MiB (4 ) / page_size ;
108+ } else {
109+ opts -> auxtrace_mmap_pages = KiB (128 ) / page_size ;
110+ if (opts -> mmap_pages == UINT_MAX )
111+ opts -> mmap_pages = KiB (256 ) / page_size ;
112+ }
113+ } else if (!opts -> auxtrace_mmap_pages && !privileged && opts -> mmap_pages == UINT_MAX ) {
114+ opts -> mmap_pages = KiB (256 ) / page_size ;
115+ }
116+
117+ /*
118+ * '-m,xyz' was specified but no snapshot size, so make the snapshot size as big as the
119+ * auxtrace mmap area.
120+ */
121+ if (!opts -> auxtrace_snapshot_size )
122+ opts -> auxtrace_snapshot_size = opts -> auxtrace_mmap_pages * (size_t )page_size ;
123+
124+ /*
125+ * '-Sxyz' was specified but no auxtrace mmap area, so make the auxtrace mmap area big
126+ * enough to fit the requested snapshot size.
127+ */
128+ if (!opts -> auxtrace_mmap_pages ) {
129+ size_t sz = opts -> auxtrace_snapshot_size ;
130+
131+ sz = round_up (sz , page_size ) / page_size ;
132+ opts -> auxtrace_mmap_pages = roundup_pow_of_two (sz );
133+ }
134+ }
135+
87136static int arm_spe_recording_options (struct auxtrace_record * itr ,
88137 struct evlist * evlist ,
89138 struct record_opts * opts )
@@ -115,6 +164,36 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
115164 if (!opts -> full_auxtrace )
116165 return 0 ;
117166
167+ /*
168+ * we are in snapshot mode.
169+ */
170+ if (opts -> auxtrace_snapshot_mode ) {
171+ /*
172+ * Command arguments '-Sxyz' and/or '-m,xyz' are missing, so fill those in with
173+ * default values.
174+ */
175+ if (!opts -> auxtrace_snapshot_size || !opts -> auxtrace_mmap_pages )
176+ arm_spe_snapshot_resolve_auxtrace_defaults (opts , privileged );
177+
178+ /*
179+ * Snapshot size can't be bigger than the auxtrace area.
180+ */
181+ if (opts -> auxtrace_snapshot_size > opts -> auxtrace_mmap_pages * (size_t )page_size ) {
182+ pr_err ("Snapshot size %zu must not be greater than AUX area tracing mmap size %zu\n" ,
183+ opts -> auxtrace_snapshot_size ,
184+ opts -> auxtrace_mmap_pages * (size_t )page_size );
185+ return - EINVAL ;
186+ }
187+
188+ /*
189+ * Something went wrong somewhere - this shouldn't happen.
190+ */
191+ if (!opts -> auxtrace_snapshot_size || !opts -> auxtrace_mmap_pages ) {
192+ pr_err ("Failed to calculate default snapshot size and/or AUX area tracing mmap pages\n" );
193+ return - EINVAL ;
194+ }
195+ }
196+
118197 /* We are in full trace mode but '-m,xyz' wasn't specified */
119198 if (!opts -> auxtrace_mmap_pages ) {
120199 if (privileged ) {
@@ -138,6 +217,9 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
138217 }
139218 }
140219
220+ if (opts -> auxtrace_snapshot_mode )
221+ pr_debug2 ("%sx snapshot size: %zu\n" , ARM_SPE_PMU_NAME ,
222+ opts -> auxtrace_snapshot_size );
141223
142224 /*
143225 * To obtain the auxtrace buffer file descriptor, the auxtrace event
@@ -172,6 +254,51 @@ static int arm_spe_recording_options(struct auxtrace_record *itr,
172254 return 0 ;
173255}
174256
257+ static int arm_spe_parse_snapshot_options (struct auxtrace_record * itr __maybe_unused ,
258+ struct record_opts * opts ,
259+ const char * str )
260+ {
261+ unsigned long long snapshot_size = 0 ;
262+ char * endptr ;
263+
264+ if (str ) {
265+ snapshot_size = strtoull (str , & endptr , 0 );
266+ if (* endptr || snapshot_size > SIZE_MAX )
267+ return -1 ;
268+ }
269+
270+ opts -> auxtrace_snapshot_mode = true;
271+ opts -> auxtrace_snapshot_size = snapshot_size ;
272+
273+ return 0 ;
274+ }
275+
276+ static int arm_spe_snapshot_start (struct auxtrace_record * itr )
277+ {
278+ struct arm_spe_recording * ptr =
279+ container_of (itr , struct arm_spe_recording , itr );
280+ struct evsel * evsel ;
281+
282+ evlist__for_each_entry (ptr -> evlist , evsel ) {
283+ if (evsel -> core .attr .type == ptr -> arm_spe_pmu -> type )
284+ return evsel__disable (evsel );
285+ }
286+ return - EINVAL ;
287+ }
288+
289+ static int arm_spe_snapshot_finish (struct auxtrace_record * itr )
290+ {
291+ struct arm_spe_recording * ptr =
292+ container_of (itr , struct arm_spe_recording , itr );
293+ struct evsel * evsel ;
294+
295+ evlist__for_each_entry (ptr -> evlist , evsel ) {
296+ if (evsel -> core .attr .type == ptr -> arm_spe_pmu -> type )
297+ return evsel__enable (evsel );
298+ }
299+ return - EINVAL ;
300+ }
301+
175302static u64 arm_spe_reference (struct auxtrace_record * itr __maybe_unused )
176303{
177304 struct timespec ts ;
@@ -207,6 +334,9 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
207334
208335 sper -> arm_spe_pmu = arm_spe_pmu ;
209336 sper -> itr .pmu = arm_spe_pmu ;
337+ sper -> itr .snapshot_start = arm_spe_snapshot_start ;
338+ sper -> itr .snapshot_finish = arm_spe_snapshot_finish ;
339+ sper -> itr .parse_snapshot_options = arm_spe_parse_snapshot_options ;
210340 sper -> itr .recording_options = arm_spe_recording_options ;
211341 sper -> itr .info_priv_size = arm_spe_info_priv_size ;
212342 sper -> itr .info_fill = arm_spe_info_fill ;
0 commit comments