• 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/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(index_ <= std::numeric_limits<decltype(index_)>::max() -
75                                data_block_size);
76   index_ += data_block_size;
77 
78   ASSIGN_OR_RETURN(keep_going, frame_decoder_->TraceDataIn(
79                                    OCSD_OP_EOT, index_, 0, nullptr, nullptr));
80   PERFETTO_CHECK(keep_going);
81   return base::OkStatus();
82 }
83 
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)84 ocsd_datapath_resp_t EtmV4Stream::TraceDataIn(const ocsd_datapath_op_t op,
85                                               const ocsd_trc_index_t,
86                                               const uint32_t size,
87                                               const uint8_t* data,
88                                               uint32_t* num_bytes_processed) {
89   switch (op) {
90     case OCSD_OP_RESET:
91       StartChunkedTrace();
92       break;
93 
94     case OCSD_OP_DATA:
95       WriteChunkedTrace(data, size);
96       *num_bytes_processed = size;
97       break;
98 
99     case OCSD_OP_FLUSH:
100       PERFETTO_FATAL("Unreachable");
101       break;
102 
103     case OCSD_OP_EOT:
104       EndChunkedTrace();
105   }
106   return OCSD_RESP_CONT;
107 }
108 
OnDataLoss(uint64_t num_bytes)109 void EtmV4Stream::OnDataLoss(uint64_t num_bytes) {
110   index_ += num_bytes;
111   // No need to do anything else as we treat every AuxData as a new trace, or
112   // in the case of non raw data, the decoder is reset for each AuxData
113 }
114 
NotifyEndOfStream()115 base::Status EtmV4Stream::NotifyEndOfStream() {
116   PERFETTO_CHECK(stream_active_);
117   if (session_.has_value()) {
118     EndSession();
119   }
120   stream_active_ = false;
121   return base::OkStatus();
122 }
123 
OnItraceStartRecord(perf_importer::ItraceStartRecord start)124 base::Status EtmV4Stream::OnItraceStartRecord(
125     perf_importer::ItraceStartRecord start) {
126   std::optional<int64_t> start_ts;
127   if (start.time().has_value()) {
128     ASSIGN_OR_RETURN(start_ts, context_->clock_tracker->ToTraceTime(
129                                    start.attr->clock_id(),
130                                    static_cast<int64_t>(*start.time())));
131   }
132   if (session_.has_value()) {
133     EndSession();
134   }
135   StartSession(start_ts);
136   return base::OkStatus();
137 }
138 
StartSession(std::optional<int64_t> start_ts)139 void EtmV4Stream::StartSession(std::optional<int64_t> start_ts) {
140   PERFETTO_CHECK(stream_active_);
141   PERFETTO_CHECK(!session_.has_value());
142   session_.emplace(context_->storage->mutable_etm_v4_session_table()
143                        ->Insert({config_id_, start_ts})
144                        .id);
145 }
146 
AddTrace(TraceBlobView trace)147 void EtmV4Stream::AddTrace(TraceBlobView trace) {
148   PERFETTO_CHECK(session_.has_value());
149   session_->traces_.push_back(std::move(trace));
150 }
151 
EndSession()152 void EtmV4Stream::EndSession() {
153   PERFETTO_CHECK(session_.has_value());
154   // There should be no inflight framed data.
155   PERFETTO_CHECK(buffer_.empty());
156   uint32_t trace_set_id = context_->storage->etm_v4_trace_table().row_count();
157   for (auto& trace : session_->traces_) {
158     if (trace.size() == 0) {
159       continue;
160     }
161     auto id = context_->storage->mutable_etm_v4_trace_table()
162                   ->Insert({session_->session_id, trace_set_id,
163                             static_cast<int64_t>(trace.size())})
164                   .id;
165     StorageHandle(context_).StoreTrace(id, std::move(trace));
166   }
167   session_.reset();
168 }
169 
StartChunkedTrace()170 void EtmV4Stream::StartChunkedTrace() {
171   PERFETTO_CHECK(buffer_.empty());
172 }
173 
WriteChunkedTrace(const uint8_t * src,uint32_t size)174 void EtmV4Stream::WriteChunkedTrace(const uint8_t* src, uint32_t size) {
175   buffer_.insert(buffer_.end(), src, src + size);
176 }
177 
EndChunkedTrace()178 void EtmV4Stream::EndChunkedTrace() {
179   if (buffer_.empty()) {
180     return;
181   }
182   AddTrace(TraceBlobView(TraceBlob::CopyFrom(buffer_.data(), buffer_.size())));
183   buffer_.clear();
184 }
185 
186 }  // namespace perfetto::trace_processor::etm
187