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 <optional>
23
24 #include "perfetto/ext/base/string_view.h"
25 #include "src/trace_processor/importers/perf/perf_counter.h"
26 #include "src/trace_processor/importers/perf/perf_event.h"
27 #include "src/trace_processor/storage/trace_storage.h"
28 #include "src/trace_processor/tables/profiler_tables_py.h"
29 #include "src/trace_processor/types/trace_processor_context.h"
30
31 namespace perfetto::trace_processor::perf_importer {
32
33 namespace {
34
35 constexpr auto kBytesPerField = 8;
36
CountSetFlags(uint64_t sample_type)37 size_t CountSetFlags(uint64_t sample_type) {
38 return static_cast<size_t>(__builtin_popcountll(sample_type));
39 }
40
TimeOffsetFromEndOfNonSampleRecord(const perf_event_attr & attr)41 std::optional<size_t> TimeOffsetFromEndOfNonSampleRecord(
42 const perf_event_attr& attr) {
43 constexpr uint64_t kFlagsFromTimeToEnd =
44 PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID |
45 PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
46 if (!attr.sample_id_all || !(attr.sample_type & PERF_SAMPLE_TIME)) {
47 return std::nullopt;
48 }
49 return CountSetFlags(attr.sample_type & kFlagsFromTimeToEnd) * kBytesPerField;
50 }
51
TimeOffsetFromStartOfSampleRecord(const perf_event_attr & attr)52 std::optional<size_t> TimeOffsetFromStartOfSampleRecord(
53 const perf_event_attr& attr) {
54 constexpr uint64_t kFlagsFromStartToTime =
55 PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP | PERF_SAMPLE_TID;
56 if (!(attr.sample_type & PERF_SAMPLE_TIME)) {
57 return std::nullopt;
58 }
59 return CountSetFlags(attr.sample_type & kFlagsFromStartToTime) *
60 kBytesPerField;
61 }
62
IdOffsetFromStartOfSampleRecord(const perf_event_attr & attr)63 std::optional<size_t> IdOffsetFromStartOfSampleRecord(
64 const perf_event_attr& attr) {
65 constexpr uint64_t kFlagsFromStartToId = PERF_SAMPLE_IDENTIFIER |
66 PERF_SAMPLE_IP | PERF_SAMPLE_TID |
67 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR;
68
69 if (attr.sample_type & PERF_SAMPLE_IDENTIFIER) {
70 return 0;
71 }
72
73 if (attr.sample_type & PERF_SAMPLE_ID) {
74 return CountSetFlags(attr.sample_type & kFlagsFromStartToId) *
75 kBytesPerField;
76 }
77 return std::nullopt;
78 }
79
IdOffsetFromEndOfNonSampleRecord(const perf_event_attr & attr)80 std::optional<size_t> IdOffsetFromEndOfNonSampleRecord(
81 const perf_event_attr& attr) {
82 constexpr uint64_t kFlagsFromIdToEnd =
83 PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU |
84 PERF_SAMPLE_IDENTIFIER;
85
86 if (attr.sample_type & PERF_SAMPLE_IDENTIFIER) {
87 return kBytesPerField;
88 }
89
90 if (attr.sample_type & PERF_SAMPLE_ID) {
91 return CountSetFlags(attr.sample_type & kFlagsFromIdToEnd) * kBytesPerField;
92 }
93
94 return std::nullopt;
95 }
96 } // namespace
97
PerfEventAttr(TraceProcessorContext * context,tables::PerfSessionTable::Id perf_session_id,perf_event_attr attr)98 PerfEventAttr::PerfEventAttr(TraceProcessorContext* context,
99 tables::PerfSessionTable::Id perf_session_id,
100 perf_event_attr attr)
101 : context_(context),
102 perf_session_id_(perf_session_id),
103 attr_(std::move(attr)),
104 time_offset_from_start_(TimeOffsetFromStartOfSampleRecord(attr_)),
105 time_offset_from_end_(TimeOffsetFromEndOfNonSampleRecord(attr_)),
106 id_offset_from_start_(IdOffsetFromStartOfSampleRecord(attr_)),
107 id_offset_from_end_(IdOffsetFromEndOfNonSampleRecord(attr_)) {}
108
109 PerfEventAttr::~PerfEventAttr() = default;
110
GetOrCreateCounter(uint32_t cpu) const111 PerfCounter& PerfEventAttr::GetOrCreateCounter(uint32_t cpu) const {
112 auto it = counters_.find(cpu);
113 if (it == counters_.end()) {
114 it = counters_.emplace(cpu, CreateCounter(cpu)).first;
115 }
116 return it->second;
117 }
118
CreateCounter(uint32_t cpu) const119 PerfCounter PerfEventAttr::CreateCounter(uint32_t cpu) const {
120 tables::PerfCounterTrackTable::Row row;
121 row.name = context_->storage->InternString(base::StringView(event_name_));
122 row.unit = context_->storage->InternString(base::StringView(""));
123 row.description = context_->storage->InternString(base::StringView(""));
124 row.perf_session_id = perf_session_id_;
125 row.cpu = cpu;
126 row.is_timebase = is_timebase();
127 const auto counter_track_ref =
128 context_->storage->mutable_perf_counter_track_table()
129 ->Insert(std::move(row))
130 .row_reference;
131 return PerfCounter(context_->storage->mutable_counter_table(),
132 std::move(counter_track_ref));
133 }
134
135 } // namespace perfetto::trace_processor::perf_importer
136