xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/etm/etm_v4_stream.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/etm/etm_v4_stream.h"
18 
19 #include <cstdint>
20 #include <memory>
21 #include <optional>
22 #include <utility>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/base/status.h"
26 #include "perfetto/trace_processor/trace_blob.h"
27 #include "perfetto/trace_processor/trace_blob_view.h"
28 #include "src/trace_processor/importers/etm/etm_v4_stream_demultiplexer.h"
29 #include "src/trace_processor/importers/etm/frame_decoder.h"
30 #include "src/trace_processor/importers/etm/opencsd.h"
31 #include "src/trace_processor/importers/etm/storage_handle.h"
32 #include "src/trace_processor/importers/perf/util.h"
33 #include "src/trace_processor/util/status_macros.h"
34 
35 namespace perfetto::trace_processor::etm {
36 namespace {
is_raw_format(const perf_importer::AuxRecord & aux)37 bool is_raw_format(const perf_importer::AuxRecord& aux) {
38   return (aux.flags & PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW);
39 }
40 }  // namespace
41 
EtmV4Stream(TraceProcessorContext * context,FrameDecoder * frame_decoder,tables::EtmV4ConfigurationTable::Id config_id)42 EtmV4Stream::EtmV4Stream(TraceProcessorContext* context,
43                          FrameDecoder* frame_decoder,
44                          tables::EtmV4ConfigurationTable::Id config_id)
45     : context_(context), frame_decoder_(frame_decoder), config_id_(config_id) {}
46 
47 EtmV4Stream::~EtmV4Stream() = default;
48 
Parse(perf_importer::AuxRecord aux,TraceBlobView data)49 base::Status EtmV4Stream::Parse(perf_importer::AuxRecord aux,
50                                 TraceBlobView data) {
51   if (!is_raw_format(aux)) {
52     return ParseFramedData(aux.offset, std::move(data));
53   }
54   AddTrace(std::move(data));
55   return base::OkStatus();
56 }
57 
ParseFramedData(uint64_t offset,TraceBlobView data)58 base::Status EtmV4Stream::ParseFramedData(uint64_t offset, TraceBlobView data) {
59   PERFETTO_CHECK(offset == index_);
60   uint32_t data_block_size;
61   PERFETTO_CHECK(perf_importer::SafeCast(data.size(), &data_block_size));
62 
63   ASSIGN_OR_RETURN(
64       bool keep_going,
65       frame_decoder_->TraceDataIn(OCSD_OP_RESET, index_, 0, nullptr, nullptr));
66   PERFETTO_CHECK(keep_going);
67 
68   uint32_t num_bytes_processed;
69   ASSIGN_OR_RETURN(keep_going, frame_decoder_->TraceDataIn(
70                                    OCSD_OP_DATA, index_, data_block_size,
71                                    data.data(), &num_bytes_processed));
72   PERFETTO_CHECK(keep_going);
73   PERFETTO_CHECK(num_bytes_processed == data_block_size);
74   PERFETTO_CHECK(perf_importer::SafeAdd(index_, data_block_size, &index_));
75 
76   ASSIGN_OR_RETURN(keep_going, frame_decoder_->TraceDataIn(
77                                    OCSD_OP_EOT, index_, 0, nullptr, nullptr));
78   PERFETTO_CHECK(keep_going);
79   return base::OkStatus();
80 }
81 
TraceDataIn(const ocsd_datapath_op_t op,const ocsd_trc_index_t,const uint32_t size,const uint8_t * data,uint32_t * num_bytes_processed)82 ocsd_datapath_resp_t EtmV4Stream::TraceDataIn(const ocsd_datapath_op_t op,
83                                               const ocsd_trc_index_t,
84                                               const uint32_t size,
85                                               const uint8_t* data,
86                                               uint32_t* num_bytes_processed) {
87   switch (op) {
88     case OCSD_OP_RESET:
89       StartChunkedTrace();
90       break;
91 
92     case OCSD_OP_DATA:
93       WriteChunkedTrace(data, size);
94       *num_bytes_processed = size;
95       break;
96 
97     case OCSD_OP_FLUSH:
98       PERFETTO_FATAL("Unreachable");
99       break;
100 
101     case OCSD_OP_EOT:
102       EndChunkedTrace();
103   }
104   return OCSD_RESP_CONT;
105 }
106 
OnDataLoss(uint64_t num_bytes)107 void EtmV4Stream::OnDataLoss(uint64_t num_bytes) {
108   index_ += num_bytes;
109   // No need to do anything else as we treat every AuxData as a new trace, or
110   // in the case of non raw data, the decoder is reset for each AuxData
111 }
112 
NotifyEndOfStream()113 base::Status EtmV4Stream::NotifyEndOfStream() {
114   PERFETTO_CHECK(stream_active_);
115   if (session_.has_value()) {
116     EndSession();
117   }
118   stream_active_ = false;
119   return base::OkStatus();
120 }
121 
OnItraceStartRecord(perf_importer::ItraceStartRecord start)122 base::Status EtmV4Stream::OnItraceStartRecord(
123     perf_importer::ItraceStartRecord start) {
124   std::optional<int64_t> start_ts;
125   if (start.time().has_value()) {
126     ASSIGN_OR_RETURN(start_ts, context_->clock_tracker->ToTraceTime(
127                                    start.attr->clock_id(),
128                                    static_cast<int64_t>(*start.time())));
129   }
130   if (session_.has_value()) {
131     EndSession();
132   }
133   StartSession(start_ts);
134   return base::OkStatus();
135 }
136 
StartSession(std::optional<int64_t> start_ts)137 void EtmV4Stream::StartSession(std::optional<int64_t> start_ts) {
138   PERFETTO_CHECK(stream_active_);
139   PERFETTO_CHECK(!session_.has_value());
140   session_.emplace(context_->storage->mutable_etm_v4_session_table()
141                        ->Insert({config_id_, start_ts})
142                        .id);
143 }
144 
AddTrace(TraceBlobView trace)145 void EtmV4Stream::AddTrace(TraceBlobView trace) {
146   PERFETTO_CHECK(session_.has_value());
147   session_->traces_.push_back(std::move(trace));
148 }
149 
EndSession()150 void EtmV4Stream::EndSession() {
151   PERFETTO_CHECK(session_.has_value());
152   // There should be no inflight framed data.
153   PERFETTO_CHECK(buffer_.empty());
154   uint32_t trace_set_id = context_->storage->etm_v4_trace_table().row_count();
155   for (auto& trace : session_->traces_) {
156     if (trace.size() == 0) {
157       continue;
158     }
159     auto id = context_->storage->mutable_etm_v4_trace_table()
160                   ->Insert({session_->session_id, trace_set_id,
161                             static_cast<int64_t>(trace.size())})
162                   .id;
163     StorageHandle(context_).StoreTrace(id, std::move(trace));
164   }
165   session_.reset();
166 }
167 
StartChunkedTrace()168 void EtmV4Stream::StartChunkedTrace() {
169   PERFETTO_CHECK(buffer_.empty());
170 }
171 
WriteChunkedTrace(const uint8_t * src,uint32_t size)172 void EtmV4Stream::WriteChunkedTrace(const uint8_t* src, uint32_t size) {
173   buffer_.insert(buffer_.end(), src, src + size);
174 }
175 
EndChunkedTrace()176 void EtmV4Stream::EndChunkedTrace() {
177   if (buffer_.empty()) {
178     return;
179   }
180   AddTrace(TraceBlobView(TraceBlob::CopyFrom(buffer_.data(), buffer_.size())));
181   buffer_.clear();
182 }
183 
184 }  // namespace perfetto::trace_processor::etm
185