xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/perf/perf_event_attr.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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/trace_processor/importers/perf/perf_event_attr.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 #include <ctime>
23 #include <optional>
24 
25 #include "perfetto/ext/base/string_view.h"
26 #include "protos/perfetto/common/builtin_clock.pbzero.h"
27 #include "src/trace_processor/importers/common/args_tracker.h"
28 #include "src/trace_processor/importers/common/track_tracker.h"
29 #include "src/trace_processor/importers/common/tracks.h"
30 #include "src/trace_processor/importers/common/tracks_common.h"
31 #include "src/trace_processor/importers/perf/perf_counter.h"
32 #include "src/trace_processor/importers/perf/perf_event.h"
33 #include "src/trace_processor/storage/trace_storage.h"
34 #include "src/trace_processor/tables/profiler_tables_py.h"
35 #include "src/trace_processor/tables/track_tables_py.h"
36 #include "src/trace_processor/types/trace_processor_context.h"
37 #include "src/trace_processor/types/variadic.h"
38 
39 namespace perfetto::trace_processor::perf_importer {
40 
41 namespace {
42 
43 constexpr auto kBytesPerField = 8;
44 
CountSetFlags(uint64_t sample_type)45 size_t CountSetFlags(uint64_t sample_type) {
46   return static_cast<size_t>(__builtin_popcountll(sample_type));
47 }
48 
TimeOffsetFromEndOfNonSampleRecord(const perf_event_attr & attr)49 std::optional<size_t> TimeOffsetFromEndOfNonSampleRecord(
50     const perf_event_attr& attr) {
51   constexpr uint64_t kFlagsFromTimeToEnd =
52       PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID |
53       PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
54   if (!attr.sample_id_all || !(attr.sample_type & PERF_SAMPLE_TIME)) {
55     return std::nullopt;
56   }
57   return CountSetFlags(attr.sample_type & kFlagsFromTimeToEnd) * kBytesPerField;
58 }
59 
TimeOffsetFromStartOfSampleRecord(const perf_event_attr & attr)60 std::optional<size_t> TimeOffsetFromStartOfSampleRecord(
61     const perf_event_attr& attr) {
62   constexpr uint64_t kFlagsFromStartToTime =
63       PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP | PERF_SAMPLE_TID;
64   if (!(attr.sample_type & PERF_SAMPLE_TIME)) {
65     return std::nullopt;
66   }
67   return CountSetFlags(attr.sample_type & kFlagsFromStartToTime) *
68          kBytesPerField;
69 }
70 
IdOffsetFromStartOfSampleRecord(const perf_event_attr & attr)71 std::optional<size_t> IdOffsetFromStartOfSampleRecord(
72     const perf_event_attr& attr) {
73   constexpr uint64_t kFlagsFromStartToId = PERF_SAMPLE_IDENTIFIER |
74                                            PERF_SAMPLE_IP | PERF_SAMPLE_TID |
75                                            PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR;
76 
77   if (attr.sample_type & PERF_SAMPLE_IDENTIFIER) {
78     return 0;
79   }
80 
81   if (attr.sample_type & PERF_SAMPLE_ID) {
82     return CountSetFlags(attr.sample_type & kFlagsFromStartToId) *
83            kBytesPerField;
84   }
85   return std::nullopt;
86 }
87 
IdOffsetFromEndOfNonSampleRecord(const perf_event_attr & attr)88 std::optional<size_t> IdOffsetFromEndOfNonSampleRecord(
89     const perf_event_attr& attr) {
90   constexpr uint64_t kFlagsFromIdToEnd =
91       PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU |
92       PERF_SAMPLE_IDENTIFIER;
93 
94   if (attr.sample_type & PERF_SAMPLE_IDENTIFIER) {
95     return kBytesPerField;
96   }
97 
98   if (attr.sample_type & PERF_SAMPLE_ID) {
99     return CountSetFlags(attr.sample_type & kFlagsFromIdToEnd) * kBytesPerField;
100   }
101 
102   return std::nullopt;
103 }
104 
GetSampleIdSize(const perf_event_attr & attr)105 size_t GetSampleIdSize(const perf_event_attr& attr) {
106   constexpr uint64_t kSampleIdFlags = PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
107                                       PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID |
108                                       PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
109   return CountSetFlags(attr.sample_type & kSampleIdFlags) * kBytesPerField;
110 }
111 
ExtractClockId(const perf_event_attr & attr)112 ClockTracker::ClockId ExtractClockId(const perf_event_attr& attr) {
113   if (!attr.use_clockid) {
114     return protos::pbzero::BUILTIN_CLOCK_PERF;
115   }
116   switch (attr.clockid) {
117     // Linux perf uses the values in <time.h> not sure if these are portable
118     // across platforms, so using the actual values here just in case.
119     case 0:  // CLOCK_REALTIME
120       return protos::pbzero::BUILTIN_CLOCK_REALTIME;
121     case 1:  // CLOCK_MONOTONIC
122       return protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
123     case 4:  // CLOCK_MONOTONIC_RAW
124       return protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW;
125     case 5:  // CLOCK_REALTIME_COARSE
126       return protos::pbzero::BUILTIN_CLOCK_REALTIME_COARSE;
127     case 6:  // CLOCK_MONOTONIC_COARSE
128       return protos::pbzero::BUILTIN_CLOCK_MONOTONIC_COARSE;
129     case 7:  // CLOCK_BOOTTIME
130       return protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
131     default:
132       return protos::pbzero::BUILTIN_CLOCK_UNKNOWN;
133   }
134 }
135 }  // namespace
136 
PerfEventAttr(TraceProcessorContext * context,tables::PerfSessionTable::Id perf_session_id,perf_event_attr attr)137 PerfEventAttr::PerfEventAttr(TraceProcessorContext* context,
138                              tables::PerfSessionTable::Id perf_session_id,
139                              perf_event_attr attr)
140     : context_(context),
141       clock_id_(ExtractClockId(attr)),
142       perf_session_id_(perf_session_id),
143       attr_(attr),
144       time_offset_from_start_(TimeOffsetFromStartOfSampleRecord(attr_)),
145       time_offset_from_end_(TimeOffsetFromEndOfNonSampleRecord(attr_)),
146       id_offset_from_start_(IdOffsetFromStartOfSampleRecord(attr_)),
147       id_offset_from_end_(IdOffsetFromEndOfNonSampleRecord(attr_)),
148       sample_id_size_(GetSampleIdSize(attr_)) {}
149 
150 PerfEventAttr::~PerfEventAttr() = default;
151 
GetOrCreateCounter(uint32_t cpu)152 PerfCounter& PerfEventAttr::GetOrCreateCounter(uint32_t cpu) {
153   auto it = counters_.find(cpu);
154   if (it == counters_.end()) {
155     it = counters_.emplace(cpu, CreateCounter(cpu)).first;
156   }
157   return it->second;
158 }
159 
CreateCounter(uint32_t cpu) const160 PerfCounter PerfEventAttr::CreateCounter(uint32_t cpu) const {
161   base::StringView name(event_name_);
162   TrackId track_id = context_->track_tracker->InternTrack(
163       tracks::kPerfCounterBlueprint,
164       tracks::Dimensions(cpu, perf_session_id_.value, name),
165       tracks::DynamicName(context_->storage->InternString(name)),
166       [this](ArgsTracker::BoundInserter& inserter) {
167         inserter.AddArg(context_->storage->InternString("is_timebase"),
168                         Variadic::Boolean(is_timebase()));
169       });
170   return {context_->storage->mutable_counter_table(), track_id, is_timebase()};
171 }
172 
173 }  // namespace perfetto::trace_processor::perf_importer
174