1
2 /*
3 * Copyright (C) 2022 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <cstdint>
19 #include <functional>
20 #include <memory>
21
22 #include "perfetto/ext/base/hash.h"
23 #include "perfetto/ext/base/string_utils.h"
24 #include "perfetto/protozero/field.h"
25 #include "src/trace_processor/importers/common/args_tracker.h"
26 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
27 #include "src/trace_processor/importers/common/slice_tracker.h"
28 #include "src/trace_processor/importers/ftrace/virtio_video_tracker.h"
29
30 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
31 #include "protos/perfetto/trace/ftrace/virtio_video.pbzero.h"
32 #include "src/trace_processor/storage/trace_storage.h"
33
34 namespace perfetto {
35 namespace trace_processor {
36
37 namespace {
38 using protos::pbzero::FtraceEvent;
39 using protos::pbzero::VirtioVideoCmdDoneFtraceEvent;
40 using protos::pbzero::VirtioVideoCmdFtraceEvent;
41 using protos::pbzero::VirtioVideoResourceQueueDoneFtraceEvent;
42 using protos::pbzero::VirtioVideoResourceQueueFtraceEvent;
43 using protozero::ConstBytes;
44 using TrackSetId = AsyncTrackSetTracker::TrackSetId;
45
46 /* VIRTIO_VIDEO_QUEUE_TYPE_INPUT */
47 constexpr uint64_t kVirtioVideoQueueTypeInput = 0x100;
48
49 /* VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT */
50 constexpr uint64_t kVirtioVideoQueueTypeOutput = 0x101;
51
52 constexpr int64_t kVirtioVideoCmdDuration = 100000;
53 } // namespace
54
VirtioVideoTracker(TraceProcessorContext * context)55 VirtioVideoTracker::VirtioVideoTracker(TraceProcessorContext* context)
56 : context_(context),
57 unknown_id_(context->storage->InternString("Unknown")),
58 input_queue_id_(context->storage->InternString("INPUT")),
59 output_queue_id_(context->storage->InternString("OUTPUT")),
60 fields_string_ids_(*context->storage) {
61 TraceStorage& storage = *context_->storage;
62
63 command_names_.Insert(0x100, storage.InternString("QUERY_CAPABILITY"));
64 command_names_.Insert(0x101, storage.InternString("STREAM_CREATE"));
65 command_names_.Insert(0x102, storage.InternString("STREAM_DESTROY"));
66 command_names_.Insert(0x103, storage.InternString("STREAM_DRAIN"));
67 command_names_.Insert(0x104, storage.InternString("RESOURCE_CREATE"));
68 command_names_.Insert(0x105, storage.InternString("RESOURCE_QUEUE"));
69 command_names_.Insert(0x106, storage.InternString("RESOURCE_DESTROY_ALL"));
70 command_names_.Insert(0x107, storage.InternString("QUEUE_CLEAR"));
71 command_names_.Insert(0x108, storage.InternString("GET_PARAMS"));
72 command_names_.Insert(0x109, storage.InternString("SET_PARAMS"));
73 command_names_.Insert(0x10a, storage.InternString("QUERY_CONTROL"));
74 command_names_.Insert(0x10b, storage.InternString("GET_CONTROL"));
75 command_names_.Insert(0x10c, storage.InternString("SET_CONTROL"));
76 command_names_.Insert(0x10d, storage.InternString("GET_PARAMS_EXT"));
77 command_names_.Insert(0x10e, storage.InternString("SET_PARAMS_EXT"));
78 }
79
80 VirtioVideoTracker::~VirtioVideoTracker() = default;
81
ParseVirtioVideoEvent(uint64_t fld_id,int64_t timestamp,const ConstBytes & blob)82 void VirtioVideoTracker::ParseVirtioVideoEvent(uint64_t fld_id,
83 int64_t timestamp,
84 const ConstBytes& blob) {
85 switch (fld_id) {
86 case FtraceEvent::kVirtioVideoResourceQueueFieldNumber: {
87 VirtioVideoResourceQueueFtraceEvent::Decoder pb_evt(blob.data, blob.size);
88
89 uint64_t hash = base::Hasher::Combine(
90 pb_evt.stream_id(), pb_evt.resource_id(), pb_evt.queue_type());
91
92 base::StackString<64> name("Resource #%" PRIu32, pb_evt.resource_id());
93 StringId name_id = context_->storage->InternString(name.string_view());
94
95 TrackSetId track_set_id =
96 InternOrCreateBufferTrack(pb_evt.stream_id(), pb_evt.queue_type());
97 TrackId begin_id = context_->async_track_set_tracker->Begin(
98 track_set_id, static_cast<int64_t>(hash));
99 context_->slice_tracker->Begin(timestamp, begin_id, kNullStringId,
100 name_id);
101 break;
102 }
103 case FtraceEvent::kVirtioVideoResourceQueueDoneFieldNumber: {
104 VirtioVideoResourceQueueDoneFtraceEvent::Decoder pb_evt(blob.data,
105 blob.size);
106
107 uint64_t hash = base::Hasher::Combine(
108 pb_evt.stream_id(), pb_evt.resource_id(), pb_evt.queue_type());
109
110 TrackSetId track_set_id =
111 InternOrCreateBufferTrack(pb_evt.stream_id(), pb_evt.queue_type());
112
113 TrackId end_id = context_->async_track_set_tracker->End(
114 track_set_id, static_cast<int64_t>(hash));
115 context_->slice_tracker->End(
116 timestamp, end_id, {}, {},
117 [this, &pb_evt](ArgsTracker::BoundInserter* args) {
118 this->AddCommandSliceArgs(&pb_evt, args);
119 });
120 break;
121 }
122 case FtraceEvent::kVirtioVideoCmdFieldNumber: {
123 VirtioVideoCmdFtraceEvent::Decoder pb_evt(blob.data, blob.size);
124 AddCommandSlice(timestamp, pb_evt.stream_id(), pb_evt.type(), false);
125 break;
126 }
127 case FtraceEvent::kVirtioVideoCmdDoneFieldNumber: {
128 VirtioVideoCmdDoneFtraceEvent::Decoder pb_evt(blob.data, blob.size);
129 AddCommandSlice(timestamp, pb_evt.stream_id(), pb_evt.type(), true);
130 break;
131 }
132 }
133 }
134
FieldsStringIds(TraceStorage & storage)135 VirtioVideoTracker::FieldsStringIds::FieldsStringIds(TraceStorage& storage)
136 : stream_id(storage.InternString("stream_id")),
137 resource_id(storage.InternString("resource_id")),
138 queue_type(storage.InternString("queue_type")),
139 data_size0(storage.InternString("data_size0")),
140 data_size1(storage.InternString("data_size1")),
141 data_size2(storage.InternString("data_size2")),
142 data_size3(storage.InternString("data_size3")),
143 timestamp(storage.InternString("timestamp")) {}
144
InternOrCreateBufferTrack(int32_t stream_id,uint32_t queue_type)145 TrackSetId VirtioVideoTracker::InternOrCreateBufferTrack(int32_t stream_id,
146 uint32_t queue_type) {
147 const char* queue_name;
148
149 switch (queue_type) {
150 case kVirtioVideoQueueTypeInput: {
151 queue_name = "INPUT";
152 break;
153 }
154 case kVirtioVideoQueueTypeOutput: {
155 queue_name = "OUTPUT";
156 break;
157 }
158 default: {
159 queue_name = "Unknown";
160 break;
161 }
162 }
163
164 base::StackString<64> track_name("virtio_video stream #%" PRId32 " %s",
165 stream_id, queue_name);
166 StringId track_name_id =
167 context_->storage->InternString(track_name.string_view());
168 return context_->async_track_set_tracker->InternGlobalTrackSet(track_name_id);
169 }
170
AddCommandSlice(int64_t timestamp,uint32_t stream_id,uint64_t type,bool response)171 void VirtioVideoTracker::AddCommandSlice(int64_t timestamp,
172 uint32_t stream_id,
173 uint64_t type,
174 bool response) {
175 const StringId* cmd_name_id = command_names_.Find(type);
176 if (!cmd_name_id) {
177 cmd_name_id = &unknown_id_;
178 }
179
180 const char* suffix = response ? "Responses" : "Requests";
181
182 base::StackString<64> track_name("virtio_video stream #%" PRId32 " %s",
183 stream_id, suffix);
184 StringId track_name_id =
185 context_->storage->InternString(track_name.string_view());
186
187 TrackSetId track_set_id =
188 context_->async_track_set_tracker->InternGlobalTrackSet(track_name_id);
189
190 TrackId track_id = context_->async_track_set_tracker->Scoped(
191 track_set_id, timestamp, kVirtioVideoCmdDuration);
192
193 context_->slice_tracker->Scoped(timestamp, track_id, kNullStringId,
194 *cmd_name_id, kVirtioVideoCmdDuration);
195 }
196
AddCommandSliceArgs(protos::pbzero::VirtioVideoResourceQueueDoneFtraceEvent::Decoder * pb_evt,ArgsTracker::BoundInserter * args)197 void VirtioVideoTracker::AddCommandSliceArgs(
198 protos::pbzero::VirtioVideoResourceQueueDoneFtraceEvent::Decoder* pb_evt,
199 ArgsTracker::BoundInserter* args) {
200 StringId queue_type_id;
201 switch (pb_evt->queue_type()) {
202 case kVirtioVideoQueueTypeInput: {
203 queue_type_id = input_queue_id_;
204 break;
205 }
206 case kVirtioVideoQueueTypeOutput: {
207 queue_type_id = output_queue_id_;
208 break;
209 }
210 default: {
211 queue_type_id = unknown_id_;
212 break;
213 }
214 }
215
216 args->AddArg(fields_string_ids_.stream_id,
217 Variadic::Integer(pb_evt->stream_id()));
218 args->AddArg(fields_string_ids_.resource_id,
219 Variadic::Integer(pb_evt->resource_id()));
220 args->AddArg(fields_string_ids_.queue_type, Variadic::String(queue_type_id));
221 args->AddArg(fields_string_ids_.data_size0,
222 Variadic::Integer(pb_evt->data_size0()));
223 args->AddArg(fields_string_ids_.data_size1,
224 Variadic::Integer(pb_evt->data_size1()));
225 args->AddArg(fields_string_ids_.data_size2,
226 Variadic::Integer(pb_evt->data_size2()));
227 args->AddArg(fields_string_ids_.data_size3,
228 Variadic::Integer(pb_evt->data_size3()));
229 args->AddArg(fields_string_ids_.timestamp,
230 Variadic::UnsignedInteger(pb_evt->timestamp()));
231 }
232
233 } // namespace trace_processor
234 } // namespace perfetto
235