blob: 0123c44d9b1093e5e4f532239380e19208776d0e [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 "src/trace_processor/importers/proto/content_analyzer.h"
#include "perfetto/ext/base/string_utils.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/proto/content_analyzer.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/importers/proto/trace.descriptor.h"
namespace perfetto {
namespace trace_processor {
ProtoContentAnalyzer::ProtoContentAnalyzer(TraceProcessorContext* context)
: context_(context),
pool_([]() {
DescriptorPool pool;
base::Status status = pool.AddFromFileDescriptorSet(
kTraceDescriptor.data(), kTraceDescriptor.size());
if (!status.ok()) {
PERFETTO_ELOG("Could not add TracePacket proto descriptor %s",
status.c_message());
}
return pool;
}()),
computer_(&pool_, ".perfetto.protos.TracePacket") {}
ProtoContentAnalyzer::~ProtoContentAnalyzer() = default;
void ProtoContentAnalyzer::ProcessPacket(
const TraceBlobView& packet,
const SampleAnnotation& packet_annotations) {
auto& map = aggregated_samples_[packet_annotations];
computer_.Reset(packet.data(), packet.length());
for (auto sample = computer_.GetNext(); sample.has_value();
sample = computer_.GetNext()) {
auto* value = map.Find(computer_.GetPath());
if (value) {
value->size += *sample;
++value->count;
} else {
map.Insert(computer_.GetPath(), Sample{*sample, 1});
}
}
}
void ProtoContentAnalyzer::NotifyEndOfFile() {
// TODO(kraskevich): consider generating a flamegraph-compatable table once
// Perfetto UI supports custom flamegraphs (b/227644078).
for (auto annotated_map = aggregated_samples_.GetIterator(); annotated_map;
++annotated_map) {
base::FlatHashMap<util::SizeProfileComputer::FieldPath,
tables::ExperimentalProtoPathTable::Id,
util::SizeProfileComputer::FieldPathHasher>
path_ids;
for (auto sample = annotated_map.value().GetIterator(); sample; ++sample) {
std::string path_string;
std::optional<tables::ExperimentalProtoPathTable::Id> previous_path_id;
util::SizeProfileComputer::FieldPath path;
for (const auto& field : sample.key()) {
if (field.has_field_name()) {
if (!path_string.empty()) {
path_string += '.';
}
path_string.append(field.field_name());
}
if (!path_string.empty()) {
path_string += '.';
}
path_string.append(field.type_name());
path.push_back(field);
// Reuses existing path from |path_ids| if possible.
{
auto* path_id = path_ids.Find(path);
if (path_id) {
previous_path_id = *path_id;
continue;
}
}
// Create a new row in experimental_proto_path.
tables::ExperimentalProtoPathTable::Row path_row;
if (field.has_field_name()) {
path_row.field_name = context_->storage->InternString(
base::StringView(field.field_name()));
}
path_row.field_type = context_->storage->InternString(
base::StringView(field.type_name()));
if (previous_path_id.has_value())
path_row.parent_id = *previous_path_id;
auto path_id =
context_->storage->mutable_experimental_proto_path_table()
->Insert(path_row)
.id;
if (!previous_path_id.has_value()) {
// Add annotations to the current row as an args set.
auto inserter = context_->args_tracker->AddArgsTo(path_id);
for (auto& annotation : annotated_map.key()) {
inserter.AddArg(annotation.first,
Variadic::String(annotation.second));
}
}
previous_path_id = path_id;
path_ids[path] = path_id;
}
// Add a content row referring to |previous_path_id|.
tables::ExperimentalProtoContentTable::Row content_row;
content_row.path =
context_->storage->InternString(base::StringView(path_string));
content_row.path_id = *previous_path_id;
content_row.total_size = static_cast<int64_t>(sample.value().size);
content_row.size = static_cast<int64_t>(sample.value().size);
content_row.count = static_cast<int64_t>(sample.value().count);
context_->storage->mutable_experimental_proto_content_table()->Insert(
content_row);
}
}
aggregated_samples_.Clear();
}
} // namespace trace_processor
} // namespace perfetto