blob: 8cbdfaed37e53aaa04f71db82a2cc6020f6dc4de [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstdint>
#include <functional>
#include <memory>
#include "perfetto/ext/base/hash.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/protozero/field.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/ftrace/virtio_video_tracker.h"
#include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
#include "protos/perfetto/trace/ftrace/virtio_video.pbzero.h"
#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
namespace trace_processor {
namespace {
using protos::pbzero::FtraceEvent;
using protos::pbzero::VirtioVideoCmdDoneFtraceEvent;
using protos::pbzero::VirtioVideoCmdFtraceEvent;
using protos::pbzero::VirtioVideoResourceQueueDoneFtraceEvent;
using protos::pbzero::VirtioVideoResourceQueueFtraceEvent;
using protozero::ConstBytes;
using TrackSetId = AsyncTrackSetTracker::TrackSetId;
/* VIRTIO_VIDEO_QUEUE_TYPE_INPUT */
constexpr uint64_t kVirtioVideoQueueTypeInput = 0x100;
/* VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT */
constexpr uint64_t kVirtioVideoQueueTypeOutput = 0x101;
constexpr int64_t kVirtioVideoCmdDuration = 100000;
} // namespace
VirtioVideoTracker::VirtioVideoTracker(TraceProcessorContext* context)
: context_(context),
unknown_id_(context->storage->InternString("Unknown")),
input_queue_id_(context->storage->InternString("INPUT")),
output_queue_id_(context->storage->InternString("OUTPUT")),
fields_string_ids_(*context->storage) {
TraceStorage& storage = *context_->storage;
command_names_.Insert(0x100, storage.InternString("QUERY_CAPABILITY"));
command_names_.Insert(0x101, storage.InternString("STREAM_CREATE"));
command_names_.Insert(0x102, storage.InternString("STREAM_DESTROY"));
command_names_.Insert(0x103, storage.InternString("STREAM_DRAIN"));
command_names_.Insert(0x104, storage.InternString("RESOURCE_CREATE"));
command_names_.Insert(0x105, storage.InternString("RESOURCE_QUEUE"));
command_names_.Insert(0x106, storage.InternString("RESOURCE_DESTROY_ALL"));
command_names_.Insert(0x107, storage.InternString("QUEUE_CLEAR"));
command_names_.Insert(0x108, storage.InternString("GET_PARAMS"));
command_names_.Insert(0x109, storage.InternString("SET_PARAMS"));
command_names_.Insert(0x10a, storage.InternString("QUERY_CONTROL"));
command_names_.Insert(0x10b, storage.InternString("GET_CONTROL"));
command_names_.Insert(0x10c, storage.InternString("SET_CONTROL"));
command_names_.Insert(0x10d, storage.InternString("GET_PARAMS_EXT"));
command_names_.Insert(0x10e, storage.InternString("SET_PARAMS_EXT"));
}
VirtioVideoTracker::~VirtioVideoTracker() = default;
void VirtioVideoTracker::ParseVirtioVideoEvent(uint64_t fld_id,
int64_t timestamp,
const ConstBytes& blob) {
switch (fld_id) {
case FtraceEvent::kVirtioVideoResourceQueueFieldNumber: {
VirtioVideoResourceQueueFtraceEvent::Decoder pb_evt(blob.data, blob.size);
uint64_t hash = base::Hasher::Combine(
pb_evt.stream_id(), pb_evt.resource_id(), pb_evt.queue_type());
base::StackString<64> name("Resource #%" PRIu32, pb_evt.resource_id());
StringId name_id = context_->storage->InternString(name.string_view());
TrackSetId track_set_id =
InternOrCreateBufferTrack(pb_evt.stream_id(), pb_evt.queue_type());
TrackId begin_id = context_->async_track_set_tracker->Begin(
track_set_id, static_cast<int64_t>(hash));
context_->slice_tracker->Begin(timestamp, begin_id, kNullStringId,
name_id);
break;
}
case FtraceEvent::kVirtioVideoResourceQueueDoneFieldNumber: {
VirtioVideoResourceQueueDoneFtraceEvent::Decoder pb_evt(blob.data,
blob.size);
uint64_t hash = base::Hasher::Combine(
pb_evt.stream_id(), pb_evt.resource_id(), pb_evt.queue_type());
TrackSetId track_set_id =
InternOrCreateBufferTrack(pb_evt.stream_id(), pb_evt.queue_type());
TrackId end_id = context_->async_track_set_tracker->End(
track_set_id, static_cast<int64_t>(hash));
context_->slice_tracker->End(
timestamp, end_id, {}, {},
[this, &pb_evt](ArgsTracker::BoundInserter* args) {
this->AddCommandSliceArgs(&pb_evt, args);
});
break;
}
case FtraceEvent::kVirtioVideoCmdFieldNumber: {
VirtioVideoCmdFtraceEvent::Decoder pb_evt(blob.data, blob.size);
AddCommandSlice(timestamp, pb_evt.stream_id(), pb_evt.type(), false);
break;
}
case FtraceEvent::kVirtioVideoCmdDoneFieldNumber: {
VirtioVideoCmdDoneFtraceEvent::Decoder pb_evt(blob.data, blob.size);
AddCommandSlice(timestamp, pb_evt.stream_id(), pb_evt.type(), true);
break;
}
}
}
VirtioVideoTracker::FieldsStringIds::FieldsStringIds(TraceStorage& storage)
: stream_id(storage.InternString("stream_id")),
resource_id(storage.InternString("resource_id")),
queue_type(storage.InternString("queue_type")),
data_size0(storage.InternString("data_size0")),
data_size1(storage.InternString("data_size1")),
data_size2(storage.InternString("data_size2")),
data_size3(storage.InternString("data_size3")),
timestamp(storage.InternString("timestamp")) {}
TrackSetId VirtioVideoTracker::InternOrCreateBufferTrack(int32_t stream_id,
uint32_t queue_type) {
const char* queue_name;
switch (queue_type) {
case kVirtioVideoQueueTypeInput: {
queue_name = "INPUT";
break;
}
case kVirtioVideoQueueTypeOutput: {
queue_name = "OUTPUT";
break;
}
default: {
queue_name = "Unknown";
break;
}
}
base::StackString<64> track_name("virtio_video stream #%" PRId32 " %s",
stream_id, queue_name);
StringId track_name_id =
context_->storage->InternString(track_name.string_view());
return context_->async_track_set_tracker->InternGlobalTrackSet(track_name_id);
}
void VirtioVideoTracker::AddCommandSlice(int64_t timestamp,
uint32_t stream_id,
uint64_t type,
bool response) {
const StringId* cmd_name_id = command_names_.Find(type);
if (!cmd_name_id) {
cmd_name_id = &unknown_id_;
}
const char* suffix = response ? "Responses" : "Requests";
base::StackString<64> track_name("virtio_video stream #%" PRId32 " %s",
stream_id, suffix);
StringId track_name_id =
context_->storage->InternString(track_name.string_view());
TrackSetId track_set_id =
context_->async_track_set_tracker->InternGlobalTrackSet(track_name_id);
TrackId track_id = context_->async_track_set_tracker->Scoped(
track_set_id, timestamp, kVirtioVideoCmdDuration);
context_->slice_tracker->Scoped(timestamp, track_id, kNullStringId,
*cmd_name_id, kVirtioVideoCmdDuration);
}
void VirtioVideoTracker::AddCommandSliceArgs(
protos::pbzero::VirtioVideoResourceQueueDoneFtraceEvent::Decoder* pb_evt,
ArgsTracker::BoundInserter* args) {
StringId queue_type_id;
switch (pb_evt->queue_type()) {
case kVirtioVideoQueueTypeInput: {
queue_type_id = input_queue_id_;
break;
}
case kVirtioVideoQueueTypeOutput: {
queue_type_id = output_queue_id_;
break;
}
default: {
queue_type_id = unknown_id_;
break;
}
}
args->AddArg(fields_string_ids_.stream_id,
Variadic::Integer(pb_evt->stream_id()));
args->AddArg(fields_string_ids_.resource_id,
Variadic::Integer(pb_evt->resource_id()));
args->AddArg(fields_string_ids_.queue_type, Variadic::String(queue_type_id));
args->AddArg(fields_string_ids_.data_size0,
Variadic::Integer(pb_evt->data_size0()));
args->AddArg(fields_string_ids_.data_size1,
Variadic::Integer(pb_evt->data_size1()));
args->AddArg(fields_string_ids_.data_size2,
Variadic::Integer(pb_evt->data_size2()));
args->AddArg(fields_string_ids_.data_size3,
Variadic::Integer(pb_evt->data_size3()));
args->AddArg(fields_string_ids_.timestamp,
Variadic::UnsignedInteger(pb_evt->timestamp()));
}
} // namespace trace_processor
} // namespace perfetto