1 /*
2 * Copyright (C) 2023 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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PERF_AUX_STREAM_MANAGER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_PERF_AUX_STREAM_MANAGER_H_
19
20 #include <cstdint>
21 #include <functional>
22 #include <memory>
23 #include <optional>
24 #include <variant>
25
26 #include "perfetto/base/logging.h"
27 #include "perfetto/base/status.h"
28 #include "perfetto/ext/base/circular_queue.h"
29 #include "perfetto/ext/base/flat_hash_map.h"
30 #include "perfetto/ext/base/status_or.h"
31 #include "perfetto/trace_processor/trace_blob_view.h"
32 #include "src/trace_processor/importers/perf/aux_data_tokenizer.h"
33 #include "src/trace_processor/importers/perf/aux_record.h"
34 #include "src/trace_processor/importers/perf/auxtrace_record.h"
35 #include "src/trace_processor/importers/perf/itrace_start_record.h"
36 #include "src/trace_processor/importers/perf/perf_session.h"
37 #include "src/trace_processor/importers/perf/time_conv_record.h"
38 #include "src/trace_processor/storage/stats.h"
39
40 namespace perfetto {
41 namespace trace_processor {
42 class TraceProcessorContext;
43
44 namespace perf_importer {
45
46 struct Record;
47 class SampleId;
48 struct AuxtraceInfoRecord;
49
50 class AuxStreamManager;
51
52 // Takes care of reconstructing the original data stream out of AUX and AUXTRACE
53 // records. Does not parse tha actual data it just forwards it to the associated
54 // `AuxDataTokenizer` .
55 class AuxStream {
56 public:
57 enum class Type {
58 kCpuBound,
59 kThreadBound,
60 };
61
62 ~AuxStream();
63 std::optional<uint64_t> ConvertTscToPerfTime(uint64_t cycles);
64
type()65 Type type() const { return type_; }
66
cpu()67 uint32_t cpu() const {
68 PERFETTO_CHECK(type_ == Type::kCpuBound);
69 return tid_or_cpu_;
70 }
71
tid()72 uint32_t tid() const {
73 PERFETTO_CHECK(type_ == Type::kThreadBound);
74 return tid_or_cpu_;
75 }
76
77 private:
78 class AuxtraceDataReader {
79 public:
80 AuxtraceDataReader(AuxtraceRecord auxtrace, TraceBlobView data);
81
82 TraceBlobView ConsumeFront(uint64_t size);
83 void DropUntil(uint64_t offset);
84
offset()85 uint64_t offset() const { return offset_; }
end()86 uint64_t end() const { return offset_ + data_.size(); }
size()87 uint64_t size() const { return data_.size(); }
88
89 private:
90 uint64_t offset_;
91 TraceBlobView data_;
92 };
93
94 using OutstandingRecord = std::variant<ItraceStartRecord, AuxRecord>;
95
96 friend AuxStreamManager;
97 AuxStream(AuxStreamManager* manager, Type type, uint32_t tid_or_cpu);
98
99 base::Status OnAuxRecord(AuxRecord aux);
100 base::Status OnAuxtraceRecord(AuxtraceRecord auxtrace, TraceBlobView data);
101 base::Status NotifyEndOfStream();
102 base::Status OnItraceStartRecord(ItraceStartRecord start);
103
104 base::Status MaybeParse();
105
106 AuxStreamManager& manager_;
107 Type type_;
108 uint32_t tid_or_cpu_;
109 AuxDataStream* data_stream_;
110 base::CircularQueue<OutstandingRecord> outstanding_records_;
111 uint64_t aux_end_ = 0;
112 base::CircularQueue<AuxtraceDataReader> outstanding_auxtrace_data_;
113 uint64_t auxtrace_end_ = 0;
114 uint64_t tokenizer_offset_ = 0;
115 };
116
117 // Keeps track of all aux streams in a perf file.
118 class AuxStreamManager {
119 public:
AuxStreamManager(TraceProcessorContext * context)120 explicit AuxStreamManager(TraceProcessorContext* context)
121 : context_(context) {}
122 base::Status OnAuxtraceInfoRecord(AuxtraceInfoRecord info);
123 base::Status OnAuxRecord(AuxRecord aux);
124 base::Status OnAuxtraceRecord(AuxtraceRecord auxtrace, TraceBlobView data);
125 base::Status OnItraceStartRecord(ItraceStartRecord start);
OnTimeConvRecord(TimeConvRecord time_conv)126 base::Status OnTimeConvRecord(TimeConvRecord time_conv) {
127 time_conv_ = std::move(time_conv);
128 return base::OkStatus();
129 }
130
131 base::Status FinalizeStreams();
132
context()133 TraceProcessorContext* context() const { return context_; }
134
ConvertTscToPerfTime(uint64_t cycles)135 std::optional<uint64_t> ConvertTscToPerfTime(uint64_t cycles) {
136 if (!time_conv_) {
137 context_->storage->IncrementStats(stats::perf_no_tsc_data);
138 return std::nullopt;
139 }
140 return time_conv_->ConvertTscToPerfTime(cycles);
141 }
142
143 private:
144 base::StatusOr<std::reference_wrapper<AuxStream>>
145 GetOrCreateStreamForSampleId(const std::optional<SampleId>& sample_id);
146 base::StatusOr<std::reference_wrapper<AuxStream>> GetOrCreateStreamForCpu(
147 uint32_t cpu);
148
149 TraceProcessorContext* const context_;
150 std::unique_ptr<AuxDataTokenizer> tokenizer_;
151 base::FlatHashMap<uint32_t, std::unique_ptr<AuxStream>>
152 auxdata_streams_by_cpu_;
153 std::optional<TimeConvRecord> time_conv_;
154 };
155
ConvertTscToPerfTime(uint64_t cycles)156 inline std::optional<uint64_t> AuxStream::ConvertTscToPerfTime(
157 uint64_t cycles) {
158 return manager_.ConvertTscToPerfTime(cycles);
159 }
160
161 } // namespace perf_importer
162 } // namespace trace_processor
163 } // namespace perfetto
164
165 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PERF_AUX_STREAM_MANAGER_H_
166