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