blob: 50bba4555a527868e13e77a2814a194f2870000e [file] [log] [blame]
/*
* Copyright (C) 2019 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/heap_graph_module.h"
#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_storage.h"
#include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
namespace perfetto {
namespace trace_processor {
namespace {
const char* HeapGraphRootTypeToString(int32_t type) {
switch (type) {
case protos::pbzero::HeapGraphRoot::ROOT_UNKNOWN:
return "ROOT_UNKNOWN";
case protos::pbzero::HeapGraphRoot::ROOT_JNI_GLOBAL:
return "ROOT_JNI_GLOBAL";
case protos::pbzero::HeapGraphRoot::ROOT_JNI_LOCAL:
return "ROOT_JNI_LOCAL";
case protos::pbzero::HeapGraphRoot::ROOT_JAVA_FRAME:
return "ROOT_JAVA_FRAME";
case protos::pbzero::HeapGraphRoot::ROOT_NATIVE_STACK:
return "ROOT_NATIVE_STACK";
case protos::pbzero::HeapGraphRoot::ROOT_STICKY_CLASS:
return "ROOT_STICKY_CLASS";
case protos::pbzero::HeapGraphRoot::ROOT_THREAD_BLOCK:
return "ROOT_THREAD_BLOCK";
case protos::pbzero::HeapGraphRoot::ROOT_MONITOR_USED:
return "ROOT_MONITOR_USED";
case protos::pbzero::HeapGraphRoot::ROOT_THREAD_OBJECT:
return "ROOT_THREAD_OBJECT";
case protos::pbzero::HeapGraphRoot::ROOT_INTERNED_STRING:
return "ROOT_INTERNED_STRING";
case protos::pbzero::HeapGraphRoot::ROOT_FINALIZING:
return "ROOT_FINALIZING";
case protos::pbzero::HeapGraphRoot::ROOT_DEBUGGER:
return "ROOT_DEBUGGER";
case protos::pbzero::HeapGraphRoot::ROOT_REFERENCE_CLEANUP:
return "ROOT_REFERENCE_CLEANUP";
case protos::pbzero::HeapGraphRoot::ROOT_VM_INTERNAL:
return "ROOT_VM_INTERNAL";
case protos::pbzero::HeapGraphRoot::ROOT_JNI_MONITOR:
return "ROOT_JNI_MONITOR";
default:
return "ROOT_UNKNOWN";
}
}
} // namespace
void HeapGraphModule::ParseHeapGraph(int64_t ts, protozero::ConstBytes blob) {
protos::pbzero::HeapGraph::Decoder heap_graph(blob.data, blob.size);
UniquePid upid = context_->process_tracker->GetOrCreateProcess(
static_cast<uint32_t>(heap_graph.pid()));
context_->heap_graph_tracker->SetPacketIndex(heap_graph.index());
for (auto it = heap_graph.objects(); it; ++it) {
protos::pbzero::HeapGraphObject::Decoder object(*it);
HeapGraphTracker::SourceObject obj;
obj.object_id = object.id();
obj.self_size = object.self_size();
obj.type_id = object.type_id();
auto ref_field_ids_it = object.reference_field_id();
auto ref_object_ids_it = object.reference_object_id();
for (; ref_field_ids_it && ref_object_ids_it;
++ref_field_ids_it, ++ref_object_ids_it) {
HeapGraphTracker::SourceObject::Reference ref;
ref.field_name_id = *ref_field_ids_it;
ref.owned_object_id = *ref_object_ids_it;
obj.references.emplace_back(std::move(ref));
}
if (ref_field_ids_it || ref_object_ids_it) {
context_->storage->IncrementIndexedStats(stats::heap_graph_missing_packet,
static_cast<int>(upid));
continue;
}
context_->heap_graph_tracker->AddObject(upid, ts, std::move(obj));
}
for (auto it = heap_graph.type_names(); it; ++it) {
protos::pbzero::InternedString::Decoder entry(*it);
const char* str = reinterpret_cast<const char*>(entry.str().data);
auto str_view = base::StringView(str, entry.str().size);
context_->heap_graph_tracker->AddInternedTypeName(
entry.iid(), context_->storage->InternString(str_view));
}
for (auto it = heap_graph.field_names(); it; ++it) {
protos::pbzero::InternedString::Decoder entry(*it);
const char* str = reinterpret_cast<const char*>(entry.str().data);
auto str_view = base::StringView(str, entry.str().size);
context_->heap_graph_tracker->AddInternedFieldName(
entry.iid(), context_->storage->InternString(str_view));
}
for (auto it = heap_graph.roots(); it; ++it) {
protos::pbzero::HeapGraphRoot::Decoder entry(*it);
const char* str = HeapGraphRootTypeToString(entry.root_type());
auto str_view = base::StringView(str);
HeapGraphTracker::SourceRoot src_root;
src_root.root_type = context_->storage->InternString(str_view);
for (auto obj_it = entry.object_ids(); obj_it; ++obj_it)
src_root.object_ids.emplace_back(*obj_it);
context_->heap_graph_tracker->AddRoot(upid, ts, std::move(src_root));
}
if (!heap_graph.continued()) {
context_->heap_graph_tracker->FinalizeProfile();
}
}
} // namespace trace_processor
} // namespace perfetto