• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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