1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/profiling/perf/event_config.h"
18
19 #include <linux/perf_event.h>
20 #include <time.h>
21
22 #include <unwindstack/Regs.h>
23 #include <optional>
24 #include <vector>
25
26 #include "perfetto/base/flat_set.h"
27 #include "perfetto/ext/base/utils.h"
28 #include "src/profiling/perf/regs_parsing.h"
29
30 #include "protos/perfetto/common/perf_events.gen.h"
31 #include "protos/perfetto/config/profiling/perf_event_config.gen.h"
32
33 namespace perfetto {
34 namespace profiling {
35
36 namespace {
37 constexpr uint64_t kDefaultSamplingFrequencyHz = 10;
38 constexpr uint32_t kDefaultDataPagesPerRingBuffer = 256; // 1 MB: 256x 4k pages
39 constexpr uint32_t kDefaultReadTickPeriodMs = 100;
40 constexpr uint32_t kDefaultRemoteDescriptorTimeoutMs = 100;
41
42 // Acceptable forms: "sched/sched_switch" or "sched:sched_switch".
SplitTracepointString(const std::string & input)43 std::pair<std::string, std::string> SplitTracepointString(
44 const std::string& input) {
45 auto slash_pos = input.find("/");
46 if (slash_pos != std::string::npos)
47 return std::make_pair(input.substr(0, slash_pos),
48 input.substr(slash_pos + 1));
49
50 auto colon_pos = input.find(":");
51 if (colon_pos != std::string::npos)
52 return std::make_pair(input.substr(0, colon_pos),
53 input.substr(colon_pos + 1));
54
55 return std::make_pair("", input);
56 }
57
58 // If set, the returned id is guaranteed to be non-zero.
ParseTracepointAndResolveId(const protos::gen::PerfEvents::Tracepoint & tracepoint,EventConfig::tracepoint_id_fn_t tracepoint_id_lookup)59 std::optional<uint32_t> ParseTracepointAndResolveId(
60 const protos::gen::PerfEvents::Tracepoint& tracepoint,
61 EventConfig::tracepoint_id_fn_t tracepoint_id_lookup) {
62 std::string full_name = tracepoint.name();
63 std::string tp_group;
64 std::string tp_name;
65 std::tie(tp_group, tp_name) = SplitTracepointString(full_name);
66 if (tp_group.empty() || tp_name.empty()) {
67 PERFETTO_ELOG(
68 "Invalid tracepoint format: %s. Should be a full path like "
69 "sched:sched_switch or sched/sched_switch.",
70 full_name.c_str());
71 return std::nullopt;
72 }
73
74 uint32_t tracepoint_id = tracepoint_id_lookup(tp_group, tp_name);
75 if (!tracepoint_id) {
76 PERFETTO_ELOG(
77 "Failed to resolve tracepoint %s to its id. Check that tracefs is "
78 "accessible and the event exists.",
79 full_name.c_str());
80 return std::nullopt;
81 }
82 return std::make_optional(tracepoint_id);
83 }
84
85 // |T| is either gen::PerfEventConfig or gen::PerfEventConfig::Scope.
86 // Note: the semantics of target_cmdline and exclude_cmdline were changed since
87 // their original introduction. They used to be put through a canonicalization
88 // function that simplified them to the binary name alone. We no longer do this,
89 // regardless of whether we're parsing an old-style config. The overall outcome
90 // shouldn't change for almost all existing uses.
91 template <typename T>
ParseTargetFilter(const T & cfg,std::optional<ProcessSharding> process_sharding)92 TargetFilter ParseTargetFilter(
93 const T& cfg,
94 std::optional<ProcessSharding> process_sharding) {
95 TargetFilter filter;
96 for (const auto& str : cfg.target_cmdline()) {
97 filter.cmdlines.push_back(str);
98 }
99 for (const auto& str : cfg.exclude_cmdline()) {
100 filter.exclude_cmdlines.push_back(str);
101 }
102 for (const int32_t pid : cfg.target_pid()) {
103 filter.pids.insert(pid);
104 }
105 for (const int32_t pid : cfg.exclude_pid()) {
106 filter.exclude_pids.insert(pid);
107 }
108 filter.additional_cmdline_count = cfg.additional_cmdline_count();
109 filter.process_sharding = process_sharding;
110 return filter;
111 }
112
IsPowerOfTwo(size_t v)113 constexpr bool IsPowerOfTwo(size_t v) {
114 return (v != 0 && ((v & (v - 1)) == 0));
115 }
116
117 // returns |std::nullopt| if the input is invalid.
ChooseActualRingBufferPages(uint32_t config_value)118 std::optional<uint32_t> ChooseActualRingBufferPages(uint32_t config_value) {
119 if (!config_value) {
120 static_assert(IsPowerOfTwo(kDefaultDataPagesPerRingBuffer), "");
121 return std::make_optional(kDefaultDataPagesPerRingBuffer);
122 }
123
124 if (!IsPowerOfTwo(config_value)) {
125 PERFETTO_ELOG("kernel buffer size must be a power of two pages");
126 return std::nullopt;
127 }
128
129 return std::make_optional(config_value);
130 }
131
ToPerfCounter(std::string name,protos::gen::PerfEvents::Counter pb_enum)132 std::optional<PerfCounter> ToPerfCounter(
133 std::string name,
134 protos::gen::PerfEvents::Counter pb_enum) {
135 using protos::gen::PerfEvents;
136 switch (static_cast<int>(pb_enum)) { // cast to pacify -Wswitch-enum
137 case PerfEvents::SW_CPU_CLOCK:
138 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_CPU_CLOCK,
139 PERF_TYPE_SOFTWARE,
140 PERF_COUNT_SW_CPU_CLOCK);
141 case PerfEvents::SW_PAGE_FAULTS:
142 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_PAGE_FAULTS,
143 PERF_TYPE_SOFTWARE,
144 PERF_COUNT_SW_PAGE_FAULTS);
145 case PerfEvents::SW_TASK_CLOCK:
146 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_TASK_CLOCK,
147 PERF_TYPE_SOFTWARE,
148 PERF_COUNT_SW_TASK_CLOCK);
149 case PerfEvents::SW_CONTEXT_SWITCHES:
150 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_CONTEXT_SWITCHES,
151 PERF_TYPE_SOFTWARE,
152 PERF_COUNT_SW_CONTEXT_SWITCHES);
153 case PerfEvents::SW_CPU_MIGRATIONS:
154 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_CPU_MIGRATIONS,
155 PERF_TYPE_SOFTWARE,
156 PERF_COUNT_SW_CPU_MIGRATIONS);
157 case PerfEvents::SW_PAGE_FAULTS_MIN:
158 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_PAGE_FAULTS_MIN,
159 PERF_TYPE_SOFTWARE,
160 PERF_COUNT_SW_PAGE_FAULTS_MIN);
161 case PerfEvents::SW_PAGE_FAULTS_MAJ:
162 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_PAGE_FAULTS_MAJ,
163 PERF_TYPE_SOFTWARE,
164 PERF_COUNT_SW_PAGE_FAULTS_MAJ);
165 case PerfEvents::SW_ALIGNMENT_FAULTS:
166 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_ALIGNMENT_FAULTS,
167 PERF_TYPE_SOFTWARE,
168 PERF_COUNT_SW_ALIGNMENT_FAULTS);
169 case PerfEvents::SW_EMULATION_FAULTS:
170 return PerfCounter::BuiltinCounter(name, PerfEvents::SW_EMULATION_FAULTS,
171 PERF_TYPE_SOFTWARE,
172 PERF_COUNT_SW_EMULATION_FAULTS);
173 case PerfEvents::SW_DUMMY:
174 return PerfCounter::BuiltinCounter(
175 name, PerfEvents::SW_DUMMY, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY);
176
177 case PerfEvents::HW_CPU_CYCLES:
178 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_CPU_CYCLES,
179 PERF_TYPE_HARDWARE,
180 PERF_COUNT_HW_CPU_CYCLES);
181 case PerfEvents::HW_INSTRUCTIONS:
182 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_INSTRUCTIONS,
183 PERF_TYPE_HARDWARE,
184 PERF_COUNT_HW_INSTRUCTIONS);
185 case PerfEvents::HW_CACHE_REFERENCES:
186 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_CACHE_REFERENCES,
187 PERF_TYPE_HARDWARE,
188 PERF_COUNT_HW_CACHE_REFERENCES);
189 case PerfEvents::HW_CACHE_MISSES:
190 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_CACHE_MISSES,
191 PERF_TYPE_HARDWARE,
192 PERF_COUNT_HW_CACHE_MISSES);
193 case PerfEvents::HW_BRANCH_INSTRUCTIONS:
194 return PerfCounter::BuiltinCounter(
195 name, PerfEvents::HW_BRANCH_INSTRUCTIONS, PERF_TYPE_HARDWARE,
196 PERF_COUNT_HW_BRANCH_INSTRUCTIONS);
197 case PerfEvents::HW_BRANCH_MISSES:
198 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_BRANCH_MISSES,
199 PERF_TYPE_HARDWARE,
200 PERF_COUNT_HW_BRANCH_MISSES);
201 case PerfEvents::HW_BUS_CYCLES:
202 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_BUS_CYCLES,
203 PERF_TYPE_HARDWARE,
204 PERF_COUNT_HW_BUS_CYCLES);
205 case PerfEvents::HW_STALLED_CYCLES_FRONTEND:
206 return PerfCounter::BuiltinCounter(
207 name, PerfEvents::HW_STALLED_CYCLES_FRONTEND, PERF_TYPE_HARDWARE,
208 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND);
209 case PerfEvents::HW_STALLED_CYCLES_BACKEND:
210 return PerfCounter::BuiltinCounter(
211 name, PerfEvents::HW_STALLED_CYCLES_BACKEND, PERF_TYPE_HARDWARE,
212 PERF_COUNT_HW_STALLED_CYCLES_BACKEND);
213 case PerfEvents::HW_REF_CPU_CYCLES:
214 return PerfCounter::BuiltinCounter(name, PerfEvents::HW_REF_CPU_CYCLES,
215 PERF_TYPE_HARDWARE,
216 PERF_COUNT_HW_REF_CPU_CYCLES);
217
218 default:
219 PERFETTO_ELOG("Unrecognised PerfEvents::Counter enum value: %zu",
220 static_cast<size_t>(pb_enum));
221 return std::nullopt;
222 }
223 }
224
ToClockId(protos::gen::PerfEvents::PerfClock pb_enum)225 int32_t ToClockId(protos::gen::PerfEvents::PerfClock pb_enum) {
226 using protos::gen::PerfEvents;
227 switch (static_cast<int>(pb_enum)) { // cast to pacify -Wswitch-enum
228 case PerfEvents::PERF_CLOCK_REALTIME:
229 return CLOCK_REALTIME;
230 case PerfEvents::PERF_CLOCK_MONOTONIC:
231 return CLOCK_MONOTONIC;
232 case PerfEvents::PERF_CLOCK_MONOTONIC_RAW:
233 return CLOCK_MONOTONIC_RAW;
234 case PerfEvents::PERF_CLOCK_BOOTTIME:
235 return CLOCK_BOOTTIME;
236 // Default to a monotonic clock since it should be compatible with all types
237 // of events. Whereas boottime cannot be used with hardware events due to
238 // potential access within non-maskable interrupts.
239 default:
240 return CLOCK_MONOTONIC_RAW;
241 }
242 }
243
244 // Build a singular event from an event description provided by either
245 // a PerfEvents::Timebase or a FollowerEvent materialized by the
246 // polymorphic parameter event_desc.
247 template <typename T>
MakePerfCounter(EventConfig::tracepoint_id_fn_t & tracepoint_id_lookup,const std::string & name,const T & event_desc)248 std::optional<PerfCounter> MakePerfCounter(
249 EventConfig::tracepoint_id_fn_t& tracepoint_id_lookup,
250 const std::string& name,
251 const T& event_desc) {
252 if (event_desc.has_counter()) {
253 auto maybe_counter = ToPerfCounter(name, event_desc.counter());
254 if (!maybe_counter)
255 return std::nullopt;
256 return *maybe_counter;
257 } else if (event_desc.has_tracepoint()) {
258 const auto& tracepoint_pb = event_desc.tracepoint();
259 std::optional<uint32_t> maybe_id =
260 ParseTracepointAndResolveId(tracepoint_pb, tracepoint_id_lookup);
261 if (!maybe_id)
262 return std::nullopt;
263 return PerfCounter::Tracepoint(name, tracepoint_pb.name(),
264 tracepoint_pb.filter(), *maybe_id);
265 } else if (event_desc.has_raw_event()) {
266 const auto& raw = event_desc.raw_event();
267 return PerfCounter::RawEvent(name, raw.type(), raw.config(), raw.config1(),
268 raw.config2());
269 } else {
270 return PerfCounter::BuiltinCounter(
271 name, protos::gen::PerfEvents::PerfEvents::SW_CPU_CLOCK,
272 PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK);
273 }
274 }
275
IsSupportedUnwindMode(protos::gen::PerfEventConfig::UnwindMode unwind_mode)276 bool IsSupportedUnwindMode(
277 protos::gen::PerfEventConfig::UnwindMode unwind_mode) {
278 using protos::gen::PerfEventConfig;
279 switch (static_cast<int>(unwind_mode)) { // cast to pacify -Wswitch-enum
280 case PerfEventConfig::UNWIND_UNKNOWN:
281 case PerfEventConfig::UNWIND_SKIP:
282 case PerfEventConfig::UNWIND_DWARF:
283 case PerfEventConfig::UNWIND_FRAME_POINTER:
284 return true;
285 default:
286 return false;
287 }
288 }
289
290 } // namespace
291
292 // static
BuiltinCounter(std::string name,protos::gen::PerfEvents::Counter counter,uint32_t type,uint64_t config)293 PerfCounter PerfCounter::BuiltinCounter(
294 std::string name,
295 protos::gen::PerfEvents::Counter counter,
296 uint32_t type,
297 uint64_t config) {
298 PerfCounter ret;
299 ret.type = PerfCounter::Type::kBuiltinCounter;
300 ret.counter = counter;
301 ret.name = std::move(name);
302
303 ret.attr_type = type;
304 ret.attr_config = config;
305 // none of the builtin counters require config1 and config2 at the moment
306 return ret;
307 }
308
309 // static
Tracepoint(std::string name,std::string tracepoint_name,std::string tracepoint_filter,uint64_t id)310 PerfCounter PerfCounter::Tracepoint(std::string name,
311 std::string tracepoint_name,
312 std::string tracepoint_filter,
313 uint64_t id) {
314 PerfCounter ret;
315 ret.type = PerfCounter::Type::kTracepoint;
316 ret.tracepoint_name = std::move(tracepoint_name);
317 ret.tracepoint_filter = std::move(tracepoint_filter);
318 ret.name = std::move(name);
319
320 ret.attr_type = PERF_TYPE_TRACEPOINT;
321 ret.attr_config = id;
322 return ret;
323 }
324
325 // static
RawEvent(std::string name,uint32_t type,uint64_t config,uint64_t config1,uint64_t config2)326 PerfCounter PerfCounter::RawEvent(std::string name,
327 uint32_t type,
328 uint64_t config,
329 uint64_t config1,
330 uint64_t config2) {
331 PerfCounter ret;
332 ret.type = PerfCounter::Type::kRawEvent;
333 ret.name = std::move(name);
334
335 ret.attr_type = type;
336 ret.attr_config = config;
337 ret.attr_config1 = config1;
338 ret.attr_config2 = config2;
339 return ret;
340 }
341
342 // static
Create(const protos::gen::PerfEventConfig & pb_config,const DataSourceConfig & raw_ds_config,std::optional<ProcessSharding> process_sharding,tracepoint_id_fn_t tracepoint_id_lookup)343 std::optional<EventConfig> EventConfig::Create(
344 const protos::gen::PerfEventConfig& pb_config,
345 const DataSourceConfig& raw_ds_config,
346 std::optional<ProcessSharding> process_sharding,
347 tracepoint_id_fn_t tracepoint_id_lookup) {
348 // Timebase: sampling interval.
349 uint64_t sampling_frequency = 0;
350 uint64_t sampling_period = 0;
351 if (pb_config.timebase().period()) {
352 sampling_period = pb_config.timebase().period();
353 } else if (pb_config.timebase().frequency()) {
354 sampling_frequency = pb_config.timebase().frequency();
355 } else if (pb_config.sampling_frequency()) { // backwards compatibility
356 sampling_frequency = pb_config.sampling_frequency();
357 } else {
358 sampling_frequency = kDefaultSamplingFrequencyHz;
359 }
360 PERFETTO_DCHECK(sampling_period && !sampling_frequency ||
361 !sampling_period && sampling_frequency);
362
363 // Leader event. Default: CPU timer.
364 PerfCounter timebase_event;
365 std::string timebase_name = pb_config.timebase().name();
366
367 // Build timebase.
368 auto maybe_perf_counter = MakePerfCounter(tracepoint_id_lookup, timebase_name,
369 pb_config.timebase());
370 if (!maybe_perf_counter) {
371 return std::nullopt;
372 }
373 timebase_event = std::move(*maybe_perf_counter);
374
375 // Build the followers.
376 std::vector<PerfCounter> followers;
377 for (const auto& event : pb_config.followers()) {
378 const auto& name = event.name();
379 auto maybe_follower_counter =
380 MakePerfCounter(tracepoint_id_lookup, name, event);
381 if (!maybe_follower_counter) {
382 return std::nullopt;
383 }
384 followers.push_back(std::move(*maybe_follower_counter));
385 }
386
387 // Callstack sampling.
388 bool kernel_frames = false;
389 // Disable user_frames by default.
390 auto unwind_mode = protos::gen::PerfEventConfig::UNWIND_SKIP;
391
392 TargetFilter target_filter;
393 bool legacy_config = pb_config.all_cpus(); // all_cpus was mandatory before
394 if (pb_config.has_callstack_sampling() || legacy_config) {
395 // Userspace callstacks.
396 unwind_mode = pb_config.callstack_sampling().user_frames();
397 if (!IsSupportedUnwindMode(unwind_mode)) {
398 // enum value from the future that we don't yet know, refuse the config
399 return std::nullopt;
400 }
401
402 // Process scoping. Sharding parameter is supplied from outside as it is
403 // shared by all data sources within a tracing session.
404 target_filter =
405 pb_config.callstack_sampling().has_scope()
406 ? ParseTargetFilter(pb_config.callstack_sampling().scope(),
407 process_sharding)
408 : ParseTargetFilter(pb_config,
409 process_sharding); // backwards compatibility
410
411 // Kernel callstacks.
412 kernel_frames = pb_config.callstack_sampling().kernel_frames() ||
413 pb_config.kernel_frames();
414 }
415
416 // Ring buffer options.
417 std::optional<uint32_t> ring_buffer_pages =
418 ChooseActualRingBufferPages(pb_config.ring_buffer_pages());
419 if (!ring_buffer_pages.has_value())
420 return std::nullopt;
421
422 uint32_t read_tick_period_ms = pb_config.ring_buffer_read_period_ms()
423 ? pb_config.ring_buffer_read_period_ms()
424 : kDefaultReadTickPeriodMs;
425
426 // Calculate a rough upper limit for the amount of samples the producer
427 // should read per read tick, as a safeguard against getting stuck chasing the
428 // ring buffer head indefinitely.
429 uint64_t samples_per_tick_limit = 0;
430 if (sampling_frequency) {
431 // expected = rate * period, with a conversion of period from ms to s:
432 uint64_t expected_samples_per_tick =
433 1 + (sampling_frequency * read_tick_period_ms) / 1000;
434 // Double the limit to account of actual sample rate uncertainties, as
435 // well as any other factors:
436 samples_per_tick_limit = 2 * expected_samples_per_tick;
437 } else { // sampling_period
438 // We don't know the sample rate that a fixed period would cause, but we can
439 // still estimate how many samples will fit in one pass of the ring buffer
440 // (with the assumption that we don't want to read more than one buffer's
441 // capacity within a tick).
442 // TODO(rsavitski): for now, make an extremely conservative guess of an 8
443 // byte sample (stack sampling samples can be up to 64KB). This is most
444 // likely as good as no limit in practice.
445 samples_per_tick_limit = *ring_buffer_pages * (base::GetSysPageSize() / 8);
446 }
447 PERFETTO_DLOG("Capping samples (not records) per tick to [%" PRIu64 "]",
448 samples_per_tick_limit);
449 if (samples_per_tick_limit == 0)
450 return std::nullopt;
451
452 // Optional footprint controls.
453 uint64_t max_enqueued_footprint_bytes =
454 pb_config.max_enqueued_footprint_kb() * 1024;
455
456 // Android-specific options.
457 uint32_t remote_descriptor_timeout_ms =
458 pb_config.remote_descriptor_timeout_ms()
459 ? pb_config.remote_descriptor_timeout_ms()
460 : kDefaultRemoteDescriptorTimeoutMs;
461
462 // Build the underlying syscall config struct.
463 perf_event_attr pe = {};
464 pe.size = sizeof(perf_event_attr);
465 pe.disabled = 1; // will be activated via ioctl
466
467 // Sampling timebase.
468 pe.type = timebase_event.attr_type;
469 pe.config = timebase_event.attr_config;
470 pe.config1 = timebase_event.attr_config1;
471 pe.config2 = timebase_event.attr_config2;
472 if (sampling_frequency) {
473 pe.freq = true;
474 pe.sample_freq = sampling_frequency;
475 } else {
476 pe.sample_period = sampling_period;
477 }
478
479 // What the samples will contain.
480 pe.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_READ;
481 // PERF_SAMPLE_TIME:
482 pe.clockid = ToClockId(pb_config.timebase().timestamp_clock());
483 pe.use_clockid = true;
484
485 if (IsUserFramesEnabled(unwind_mode)) {
486 pe.sample_type |= PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER;
487 // PERF_SAMPLE_STACK_USER:
488 // Needs to be < ((u16)(~0u)), and have bottom 8 bits clear.
489 // Note that the kernel still needs to make space for the other parts of the
490 // sample (up to the max record size of 64k), so the effective maximum
491 // can be lower than this.
492 pe.sample_stack_user = (1u << 16) - 256;
493 // PERF_SAMPLE_REGS_USER:
494 pe.sample_regs_user =
495 PerfUserRegsMaskForArch(unwindstack::Regs::CurrentArch());
496 }
497 if (kernel_frames) {
498 pe.sample_type |= PERF_SAMPLE_CALLCHAIN;
499 pe.exclude_callchain_user = true;
500 }
501
502 // Build the events associated with the timebase event (pe).
503 // The timebase event drives the capture with its frequency or period
504 // parameter. When linux captures the timebase event it also reads and report
505 // the values of associated events.
506 std::vector<perf_event_attr> pe_followers;
507 if (!followers.empty()) {
508 pe.read_format = PERF_FORMAT_GROUP;
509 pe_followers.reserve(followers.size());
510 }
511
512 for (const auto& e : followers) {
513 perf_event_attr pe_follower = {};
514 pe_follower.size = sizeof(perf_event_attr);
515 pe_follower.disabled = 0; // activated when the timebase is activated
516 pe_follower.type = e.attr_type;
517 pe_follower.config = e.attr_config;
518 pe_follower.config1 = e.attr_config1;
519 pe_follower.config2 = e.attr_config2;
520 pe_follower.sample_type =
521 PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_READ;
522 pe_follower.freq = 0;
523 pe_follower.sample_period = 0;
524 pe_follower.clockid = ToClockId(pb_config.timebase().timestamp_clock());
525 pe_follower.use_clockid = true;
526
527 pe_followers.push_back(pe_follower);
528 }
529
530 return EventConfig(
531 raw_ds_config, pe, std::move(pe_followers), timebase_event, followers,
532 kernel_frames, unwind_mode, std::move(target_filter),
533 ring_buffer_pages.value(), read_tick_period_ms, samples_per_tick_limit,
534 remote_descriptor_timeout_ms, pb_config.unwind_state_clear_period_ms(),
535 max_enqueued_footprint_bytes, pb_config.target_installed_by());
536 }
537
538 // static
IsUserFramesEnabled(const protos::gen::PerfEventConfig::UnwindMode unwind_mode)539 bool EventConfig::IsUserFramesEnabled(
540 const protos::gen::PerfEventConfig::UnwindMode unwind_mode) {
541 using protos::gen::PerfEventConfig;
542 switch (unwind_mode) {
543 case PerfEventConfig::UNWIND_UNKNOWN:
544 // default to true, both for backwards compatibility and because it's
545 // almost always what the user wants.
546 case PerfEventConfig::UNWIND_DWARF:
547 case PerfEventConfig::UNWIND_FRAME_POINTER:
548 return true;
549 case PerfEventConfig::UNWIND_SKIP:
550 return false;
551 }
552 }
553
EventConfig(const DataSourceConfig & raw_ds_config,const perf_event_attr & pe_timebase,std::vector<perf_event_attr> pe_followers,const PerfCounter & timebase_event,std::vector<PerfCounter> follower_events,bool kernel_frames,protos::gen::PerfEventConfig::UnwindMode unwind_mode,TargetFilter target_filter,uint32_t ring_buffer_pages,uint32_t read_tick_period_ms,uint64_t samples_per_tick_limit,uint32_t remote_descriptor_timeout_ms,uint32_t unwind_state_clear_period_ms,uint64_t max_enqueued_footprint_bytes,std::vector<std::string> target_installed_by)554 EventConfig::EventConfig(const DataSourceConfig& raw_ds_config,
555 const perf_event_attr& pe_timebase,
556 std::vector<perf_event_attr> pe_followers,
557 const PerfCounter& timebase_event,
558 std::vector<PerfCounter> follower_events,
559 bool kernel_frames,
560 protos::gen::PerfEventConfig::UnwindMode unwind_mode,
561 TargetFilter target_filter,
562 uint32_t ring_buffer_pages,
563 uint32_t read_tick_period_ms,
564 uint64_t samples_per_tick_limit,
565 uint32_t remote_descriptor_timeout_ms,
566 uint32_t unwind_state_clear_period_ms,
567 uint64_t max_enqueued_footprint_bytes,
568 std::vector<std::string> target_installed_by)
569 : perf_event_attr_(pe_timebase),
570 perf_event_followers_(std::move(pe_followers)),
571 timebase_event_(timebase_event),
572 follower_events_(std::move(follower_events)),
573 kernel_frames_(kernel_frames),
574 unwind_mode_(unwind_mode),
575 target_filter_(std::move(target_filter)),
576 ring_buffer_pages_(ring_buffer_pages),
577 read_tick_period_ms_(read_tick_period_ms),
578 samples_per_tick_limit_(samples_per_tick_limit),
579 remote_descriptor_timeout_ms_(remote_descriptor_timeout_ms),
580 unwind_state_clear_period_ms_(unwind_state_clear_period_ms),
581 max_enqueued_footprint_bytes_(max_enqueued_footprint_bytes),
582 target_installed_by_(std::move(target_installed_by)),
583 raw_ds_config_(raw_ds_config) /* full copy */ {}
584
585 } // namespace profiling
586 } // namespace perfetto
587