Add memory snapshot processing to Perfetto TP
The trace processor parses the proto-encoded memory dump, converts it into the GlobalNodeGraph using GraphProcessor and emits rows into the tables. See crbug.com/1116359 for more details.
Bug: 1116359
Change-Id: I95e6af67265f68022ba5b244ca098ae594333b7b
diff --git a/Android.bp b/Android.bp
index 7f117c7..4a52aad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -7366,6 +7366,8 @@
"src/trace_processor/importers/proto/args_table_utils.cc",
"src/trace_processor/importers/proto/async_track_set_tracker.cc",
"src/trace_processor/importers/proto/heap_profile_tracker.cc",
+ "src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
+ "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
"src/trace_processor/importers/proto/metadata_tracker.cc",
"src/trace_processor/importers/proto/packet_sequence_state.cc",
"src/trace_processor/importers/proto/profile_module.cc",
@@ -8572,6 +8574,7 @@
":perfetto_include_perfetto_base_base",
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_trace_processor_export_json",
+ ":perfetto_include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
":perfetto_include_perfetto_ext_traced_sys_stats_counters",
":perfetto_include_perfetto_protozero_protozero",
":perfetto_include_perfetto_trace_processor_basic_types",
@@ -8615,6 +8618,7 @@
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_ftrace_descriptors",
":perfetto_src_trace_processor_importers_common",
+ ":perfetto_src_trace_processor_importers_memory_tracker_graph_processor",
":perfetto_src_trace_processor_lib",
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_lib",
@@ -8704,6 +8708,7 @@
":perfetto_include_perfetto_base_base",
":perfetto_include_perfetto_ext_base_base",
":perfetto_include_perfetto_ext_trace_processor_export_json",
+ ":perfetto_include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
":perfetto_include_perfetto_ext_traced_sys_stats_counters",
":perfetto_include_perfetto_profiling_deobfuscator",
":perfetto_include_perfetto_profiling_pprof_builder",
@@ -8751,6 +8756,7 @@
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_ftrace_descriptors",
":perfetto_src_trace_processor_importers_common",
+ ":perfetto_src_trace_processor_importers_memory_tracker_graph_processor",
":perfetto_src_trace_processor_lib",
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_lib",
diff --git a/BUILD b/BUILD
index da6b0ae..5dd6713 100644
--- a/BUILD
+++ b/BUILD
@@ -339,6 +339,19 @@
],
)
+# GN target: //include/perfetto/ext/trace_processor/importers/memory_tracker:memory_tracker
+filegroup(
+ name = "include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
+ srcs = [
+ "include/perfetto/ext/trace_processor/importers/memory_tracker/graph.h",
+ "include/perfetto/ext/trace_processor/importers/memory_tracker/graph_processor.h",
+ "include/perfetto/ext/trace_processor/importers/memory_tracker/memory_allocator_node_id.h",
+ "include/perfetto/ext/trace_processor/importers/memory_tracker/memory_graph_edge.h",
+ "include/perfetto/ext/trace_processor/importers/memory_tracker/raw_memory_graph_node.h",
+ "include/perfetto/ext/trace_processor/importers/memory_tracker/raw_process_memory_node.h",
+ ],
+)
+
# GN target: //include/perfetto/ext/trace_processor:export_json
filegroup(
name = "include_perfetto_ext_trace_processor_export_json",
@@ -754,6 +767,18 @@
],
)
+# GN target: //src/trace_processor/importers/memory_tracker:graph_processor
+filegroup(
+ name = "src_trace_processor_importers_memory_tracker_graph_processor",
+ srcs = [
+ "src/trace_processor/importers/memory_tracker/graph.cc",
+ "src/trace_processor/importers/memory_tracker/graph_processor.cc",
+ "src/trace_processor/importers/memory_tracker/memory_allocator_node_id.cc",
+ "src/trace_processor/importers/memory_tracker/raw_memory_graph_node.cc",
+ "src/trace_processor/importers/memory_tracker/raw_process_memory_node.cc",
+ ],
+)
+
# GN target: //src/trace_processor/importers:common
filegroup(
name = "src_trace_processor_importers_common",
@@ -1166,6 +1191,10 @@
"src/trace_processor/importers/proto/async_track_set_tracker.h",
"src/trace_processor/importers/proto/heap_profile_tracker.cc",
"src/trace_processor/importers/proto/heap_profile_tracker.h",
+ "src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc",
+ "src/trace_processor/importers/proto/memory_tracker_snapshot_module.h",
+ "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc",
+ "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h",
"src/trace_processor/importers/proto/metadata_tracker.cc",
"src/trace_processor/importers/proto/metadata_tracker.h",
"src/trace_processor/importers/proto/packet_sequence_state.cc",
@@ -3061,6 +3090,7 @@
":src_trace_processor_export_json",
":src_trace_processor_ftrace_descriptors",
":src_trace_processor_importers_common",
+ ":src_trace_processor_importers_memory_tracker_graph_processor",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_lib",
@@ -3079,6 +3109,7 @@
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
":include_perfetto_ext_trace_processor_export_json",
+ ":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
":include_perfetto_ext_traced_sys_stats_counters",
":include_perfetto_protozero_protozero",
":include_perfetto_trace_processor_basic_types",
@@ -3141,6 +3172,7 @@
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
":include_perfetto_ext_trace_processor_export_json",
+ ":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
":include_perfetto_ext_traced_sys_stats_counters",
":include_perfetto_protozero_protozero",
":include_perfetto_trace_processor_basic_types",
@@ -3154,6 +3186,7 @@
":src_trace_processor_export_json",
":src_trace_processor_ftrace_descriptors",
":src_trace_processor_importers_common",
+ ":src_trace_processor_importers_memory_tracker_graph_processor",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_lib",
@@ -3310,6 +3343,7 @@
":include_perfetto_base_base",
":include_perfetto_ext_base_base",
":include_perfetto_ext_trace_processor_export_json",
+ ":include_perfetto_ext_trace_processor_importers_memory_tracker_memory_tracker",
":include_perfetto_ext_traced_sys_stats_counters",
":include_perfetto_profiling_deobfuscator",
":include_perfetto_profiling_pprof_builder",
@@ -3326,6 +3360,7 @@
":src_trace_processor_export_json",
":src_trace_processor_ftrace_descriptors",
":src_trace_processor_importers_common",
+ ":src_trace_processor_importers_memory_tracker_graph_processor",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_lib",
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 448e482..b6641ab 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -92,6 +92,10 @@
"importers/proto/async_track_set_tracker.h",
"importers/proto/heap_profile_tracker.cc",
"importers/proto/heap_profile_tracker.h",
+ "importers/proto/memory_tracker_snapshot_module.cc",
+ "importers/proto/memory_tracker_snapshot_module.h",
+ "importers/proto/memory_tracker_snapshot_parser.cc",
+ "importers/proto/memory_tracker_snapshot_parser.h",
"importers/proto/metadata_tracker.cc",
"importers/proto/metadata_tracker.h",
"importers/proto/packet_sequence_state.cc",
@@ -139,6 +143,7 @@
"../protozero",
"containers",
"importers:common",
+ "importers/memory_tracker:graph_processor",
"storage",
"tables",
"types",
diff --git a/src/trace_processor/importers/common/args_tracker.h b/src/trace_processor/importers/common/args_tracker.h
index 7b051a2..4b17787 100644
--- a/src/trace_processor/importers/common/args_tracker.h
+++ b/src/trace_processor/importers/common/args_tracker.h
@@ -112,7 +112,7 @@
return AddArgsTo(context_->storage->mutable_flow_table(), id);
}
- BoundInserter AddArgsTo(SnapshotNodeId id) {
+ BoundInserter AddArgsTo(tables::MemorySnapshotNodeTable::Id id) {
return AddArgsTo(context_->storage->mutable_memory_snapshot_node_table(),
id);
}
diff --git a/src/trace_processor/importers/default_modules.cc b/src/trace_processor/importers/default_modules.cc
index 2704478..88fa696 100644
--- a/src/trace_processor/importers/default_modules.cc
+++ b/src/trace_processor/importers/default_modules.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/importers/default_modules.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
+#include "src/trace_processor/importers/proto/memory_tracker_snapshot_module.h"
#include "src/trace_processor/importers/proto/profile_module.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/importers/proto/track_event_module.h"
@@ -30,6 +31,7 @@
context->ftrace_module =
static_cast<FtraceModule*>(context->modules.back().get());
+ context->modules.emplace_back(new MemoryTrackerSnapshotModule(context));
context->modules.emplace_back(new TrackEventModule(context));
context->modules.emplace_back(new ProfileModule(context));
}
diff --git a/src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc b/src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc
new file mode 100644
index 0000000..cd4dde2
--- /dev/null
+++ b/src/trace_processor/importers/proto/memory_tracker_snapshot_module.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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/memory_tracker_snapshot_module.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+using perfetto::protos::pbzero::TracePacket;
+
+MemoryTrackerSnapshotModule::MemoryTrackerSnapshotModule(
+ TraceProcessorContext* context)
+ : parser_(context) {
+ RegisterForField(TracePacket::kMemoryTrackerSnapshotFieldNumber, context);
+}
+
+MemoryTrackerSnapshotModule::~MemoryTrackerSnapshotModule() = default;
+
+void MemoryTrackerSnapshotModule::ParsePacket(
+ const TracePacket::Decoder& decoder,
+ const TimestampedTracePiece& ttp,
+ uint32_t field_id) {
+ switch (field_id) {
+ case TracePacket::kMemoryTrackerSnapshotFieldNumber:
+ parser_.ParseMemoryTrackerSnapshot(ttp.timestamp,
+ decoder.memory_tracker_snapshot());
+ return;
+ }
+}
+
+void MemoryTrackerSnapshotModule::NotifyEndOfFile() {
+ parser_.NotifyEndOfFile();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/memory_tracker_snapshot_module.h b/src/trace_processor/importers/proto/memory_tracker_snapshot_module.h
new file mode 100644
index 0000000..730b7e3
--- /dev/null
+++ b/src/trace_processor/importers/proto/memory_tracker_snapshot_module.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MEMORY_TRACKER_SNAPSHOT_MODULE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MEMORY_TRACKER_SNAPSHOT_MODULE_H_
+
+#include "src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h"
+#include "src/trace_processor/importers/proto/proto_importer_module.h"
+#include "src/trace_processor/timestamped_trace_piece.h"
+
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class MemoryTrackerSnapshotModule : public ProtoImporterModule {
+ public:
+ explicit MemoryTrackerSnapshotModule(TraceProcessorContext* context);
+
+ ~MemoryTrackerSnapshotModule() override;
+
+ void ParsePacket(const protos::pbzero::TracePacket::Decoder&,
+ const TimestampedTracePiece&,
+ uint32_t field_id) override;
+
+ void NotifyEndOfFile() override;
+
+ private:
+ MemoryTrackerSnapshotParser parser_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MEMORY_TRACKER_SNAPSHOT_MODULE_H_
diff --git a/src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc b/src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc
new file mode 100644
index 0000000..6c735f9
--- /dev/null
+++ b/src/trace_processor/importers/proto/memory_tracker_snapshot_parser.cc
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2020 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/memory_tracker_snapshot_parser.h"
+
+#include "perfetto/ext/base/string_view.h"
+#include "protos/perfetto/trace/memory_graph.pbzero.h"
+#include "src/trace_processor/containers/string_pool.h"
+#include "src/trace_processor/importers/common/args_tracker.h"
+#include "src/trace_processor/tables/memory_tables.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+MemoryTrackerSnapshotParser::MemoryTrackerSnapshotParser(
+ TraceProcessorContext* context)
+ : context_(context),
+ level_of_detail_ids_{{context_->storage->InternString("detailed"),
+ context_->storage->InternString("light"),
+ context_->storage->InternString("background")}},
+ unit_ids_{{context_->storage->InternString("objects"),
+ context_->storage->InternString("bytes")}},
+ aggregate_raw_nodes_(),
+ last_snapshot_timestamp_(-1),
+ last_snapshot_level_of_detail_(LevelOfDetail::kFirst) {}
+
+void MemoryTrackerSnapshotParser::ParseMemoryTrackerSnapshot(int64_t ts,
+ ConstBytes blob) {
+ PERFETTO_DCHECK(last_snapshot_timestamp_ <= ts);
+ if (!aggregate_raw_nodes_.empty() && ts != last_snapshot_timestamp_) {
+ GenerateGraphFromRawNodesAndEmitRows();
+ }
+ ReadProtoSnapshot(blob, aggregate_raw_nodes_, last_snapshot_level_of_detail_);
+ last_snapshot_timestamp_ = ts;
+}
+
+void MemoryTrackerSnapshotParser::NotifyEndOfFile() {
+ if (!aggregate_raw_nodes_.empty()) {
+ GenerateGraphFromRawNodesAndEmitRows();
+ }
+}
+
+void MemoryTrackerSnapshotParser::ReadProtoSnapshot(
+ ConstBytes blob,
+ RawMemoryNodeMap& raw_nodes,
+ LevelOfDetail& level_of_detail) {
+ protos::pbzero::MemoryTrackerSnapshot::Decoder snapshot(blob.data, blob.size);
+ level_of_detail = LevelOfDetail::kDetailed;
+
+ switch (snapshot.level_of_detail()) {
+ case 0: // FULL
+ level_of_detail = LevelOfDetail::kDetailed;
+ break;
+ case 1: // LIGHT
+ level_of_detail = LevelOfDetail::kLight;
+ break;
+ case 2: // BACKGROUND
+ level_of_detail = LevelOfDetail::kBackground;
+ break;
+ }
+
+ for (auto process_it = snapshot.process_memory_dumps(); process_it;
+ ++process_it) {
+ protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::Decoder
+ process_memory_dump(*process_it);
+
+ base::PlatformProcessId pid =
+ static_cast<base::PlatformProcessId>(process_memory_dump.pid());
+
+ RawProcessMemoryNode::MemoryNodesMap nodes_map;
+ RawProcessMemoryNode::AllocatorNodeEdgesMap edges_map;
+
+ for (auto node_it = process_memory_dump.allocator_dumps(); node_it;
+ ++node_it) {
+ protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::MemoryNode::
+ Decoder node(*node_it);
+
+ MemoryAllocatorNodeId node_id(node.id());
+ const std::string absolute_name = node.absolute_name().ToStdString();
+ int flags;
+ if (node.weak()) {
+ flags = RawMemoryGraphNode::kWeak;
+ } else {
+ flags = RawMemoryGraphNode::kDefault;
+ }
+
+ std::vector<RawMemoryGraphNode::MemoryNodeEntry> entries;
+
+ if (node.has_size_bytes()) {
+ entries.emplace_back("size", RawMemoryGraphNode::kUnitsBytes,
+ node.size_bytes());
+ }
+
+ for (auto entry_it = node.entries(); entry_it; ++entry_it) {
+ protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::MemoryNode::
+ MemoryNodeEntry::Decoder entry(*entry_it);
+
+ std::string unit;
+
+ switch (entry.units()) {
+ case 1: // BYTES
+ unit = RawMemoryGraphNode::kUnitsBytes;
+ break;
+ case 2: // COUNT
+ unit = RawMemoryGraphNode::kUnitsObjects;
+ break;
+ }
+ if (entry.has_value_uint64()) {
+ entries.emplace_back(entry.name().ToStdString(), unit,
+ entry.value_uint64());
+ } else if (entry.has_value_string()) {
+ entries.emplace_back(entry.name().ToStdString(), unit,
+ entry.value_string().ToStdString());
+ } else {
+ context_->storage->IncrementStats(
+ stats::memory_snapshot_parser_failure);
+ }
+ }
+ std::unique_ptr<RawMemoryGraphNode> raw_graph_node(new RawMemoryGraphNode(
+ absolute_name, level_of_detail, node_id, std::move(entries)));
+ raw_graph_node->set_flags(flags);
+ nodes_map.emplace(
+ std::make_pair(absolute_name, std::move(raw_graph_node)));
+ }
+
+ for (auto edge_it = process_memory_dump.memory_edges(); edge_it;
+ ++edge_it) {
+ protos::pbzero::MemoryTrackerSnapshot::ProcessSnapshot::MemoryEdge::
+ Decoder edge(*edge_it);
+
+ std::unique_ptr<MemoryGraphEdge> graph_edge(new MemoryGraphEdge(
+ MemoryAllocatorNodeId(edge.source_id()),
+ MemoryAllocatorNodeId(edge.target_id()),
+ static_cast<int>(edge.importance()), edge.overridable()));
+
+ edges_map.emplace(std::make_pair(MemoryAllocatorNodeId(edge.source_id()),
+ std::move(graph_edge)));
+ }
+ raw_nodes.emplace(
+ pid, new RawProcessMemoryNode(level_of_detail, std::move(edges_map),
+ std::move(nodes_map)));
+ }
+}
+
+std::unique_ptr<GlobalNodeGraph> MemoryTrackerSnapshotParser::GenerateGraph(
+ RawMemoryNodeMap& raw_nodes) {
+ auto graph = GraphProcessor::CreateMemoryGraph(raw_nodes);
+ GraphProcessor::CalculateSizesForGraph(graph.get());
+ return graph;
+}
+
+void MemoryTrackerSnapshotParser::EmitRows(int64_t ts,
+ GlobalNodeGraph& graph,
+ LevelOfDetail level_of_detail) {
+ IdNodeMap id_node_table;
+
+ // For now, we use the existing global instant event track for chrome events,
+ // since memory dumps are global.
+ TrackId track_id =
+ context_->track_tracker->GetOrCreateLegacyChromeGlobalInstantTrack();
+
+ tables::MemorySnapshotTable::Row snapshot_row(
+ ts, track_id, level_of_detail_ids_[static_cast<size_t>(level_of_detail)]);
+ tables::MemorySnapshotTable::Id snapshot_row_id =
+ context_->storage->mutable_memory_snapshot_table()
+ ->Insert(snapshot_row)
+ .id;
+
+ for (auto const& it_process : graph.process_node_graphs()) {
+ tables::ProcessMemorySnapshotTable::Row process_row;
+ process_row.upid = context_->process_tracker->GetOrCreateProcess(
+ static_cast<uint32_t>(it_process.first));
+ process_row.snapshot_id = snapshot_row_id;
+ tables::ProcessMemorySnapshotTable::Id proc_snapshot_row_id =
+ context_->storage->mutable_process_memory_snapshot_table()
+ ->Insert(process_row)
+ .id;
+ EmitMemorySnapshotNodeRows(*(it_process.second->root()),
+ proc_snapshot_row_id, id_node_table);
+ }
+
+ // For each snapshot nodes from shared_memory_graph will be associated
+ // with a fabricated process_memory_snapshot entry whose pid == 0.
+ // TODO(mobica-google-contributors@mobica.com): Track the shared memory graph
+ // in a separate table.
+ tables::ProcessMemorySnapshotTable::Row fake_process_row;
+ fake_process_row.upid = context_->process_tracker->GetOrCreateProcess(0u);
+ fake_process_row.snapshot_id = snapshot_row_id;
+ tables::ProcessMemorySnapshotTable::Id fake_proc_snapshot_row_id =
+ context_->storage->mutable_process_memory_snapshot_table()
+ ->Insert(fake_process_row)
+ .id;
+ EmitMemorySnapshotNodeRows(*(graph.shared_memory_graph()->root()),
+ fake_proc_snapshot_row_id, id_node_table);
+
+ for (const auto& it_edge : graph.edges()) {
+ tables::MemorySnapshotEdgeTable::Row edge_row;
+ edge_row.source_node_id = static_cast<tables::MemorySnapshotNodeTable::Id>(
+ id_node_table.find(it_edge.source()->id())->second);
+ edge_row.target_node_id = static_cast<tables::MemorySnapshotNodeTable::Id>(
+ id_node_table.find(it_edge.target()->id())->second);
+ edge_row.importance = static_cast<uint32_t>(it_edge.priority());
+ context_->storage->mutable_memory_snapshot_edge_table()->Insert(edge_row);
+ }
+}
+
+void MemoryTrackerSnapshotParser::EmitMemorySnapshotNodeRows(
+ GlobalNodeGraph::Node& root_node_graph,
+ ProcessMemorySnapshotId& proc_snapshot_row_id,
+ IdNodeMap& id_node_map) {
+ EmitMemorySnapshotNodeRowsRecursively(root_node_graph, std::string(),
+ base::nullopt, proc_snapshot_row_id,
+ id_node_map);
+}
+
+void MemoryTrackerSnapshotParser::EmitMemorySnapshotNodeRowsRecursively(
+ GlobalNodeGraph::Node& node,
+ const std::string& path,
+ base::Optional<tables::MemorySnapshotNodeTable::Id> parent_node_row_id,
+ ProcessMemorySnapshotId& proc_snapshot_row_id,
+ IdNodeMap& id_node_map) {
+ base::Optional<tables::MemorySnapshotNodeTable::Id> node_id;
+ // Skip emitting the root node into the tables - it is not a real node.
+ if (!path.empty()) {
+ node_id = EmitNode(node, path, parent_node_row_id, proc_snapshot_row_id,
+ id_node_map);
+ }
+
+ for (const auto& name_and_child : *node.children()) {
+ std::string child_path = path;
+ if (!child_path.empty())
+ child_path += "/";
+ child_path += name_and_child.first;
+
+ EmitMemorySnapshotNodeRowsRecursively(*(name_and_child.second), child_path,
+ /*parent_node_id=*/node_id,
+ proc_snapshot_row_id, id_node_map);
+ }
+}
+
+base::Optional<tables::MemorySnapshotNodeTable::Id>
+MemoryTrackerSnapshotParser::EmitNode(
+ const GlobalNodeGraph::Node& node,
+ const std::string& path,
+ base::Optional<tables::MemorySnapshotNodeTable::Id> parent_node_row_id,
+ ProcessMemorySnapshotId& proc_snapshot_row_id,
+ IdNodeMap& id_node_map) {
+ tables::MemorySnapshotNodeTable::Row node_row;
+ node_row.process_snapshot_id = proc_snapshot_row_id;
+ node_row.parent_node_id = parent_node_row_id;
+ node_row.path = context_->storage->InternString(base::StringView(path));
+
+ tables::MemorySnapshotNodeTable::Id node_row_id =
+ context_->storage->mutable_memory_snapshot_node_table()
+ ->Insert(node_row)
+ .id;
+
+ auto* node_table = context_->storage->mutable_memory_snapshot_node_table();
+ uint32_t node_row_index =
+ static_cast<uint32_t>(*node_table->id().IndexOf(node_row_id));
+ ArgsTracker::BoundInserter args =
+ context_->args_tracker->AddArgsTo(node_row_id);
+
+ for (const auto& entry : node.const_entries()) {
+ switch (entry.second.type) {
+ case GlobalNodeGraph::Node::Entry::Type::kUInt64: {
+ int64_t value_int = static_cast<int64_t>(entry.second.value_uint64);
+
+ if (entry.first == "size") {
+ node_table->mutable_size()->Set(node_row_index, value_int);
+ } else if (entry.first == "effective_size") {
+ node_table->mutable_effective_size()->Set(node_row_index, value_int);
+ } else {
+ args.AddArg(context_->storage->InternString(
+ base::StringView(entry.first + ".value")),
+ Variadic::Integer(value_int));
+ if (entry.second.units < unit_ids_.size()) {
+ args.AddArg(context_->storage->InternString(
+ base::StringView(entry.first + ".unit")),
+ Variadic::String(unit_ids_[entry.second.units]));
+ }
+ }
+ break;
+ }
+ case GlobalNodeGraph::Node::Entry::Type::kString: {
+ args.AddArg(context_->storage->InternString(
+ base::StringView(entry.first + ".value")),
+ Variadic::String(context_->storage->InternString(
+ base::StringView(entry.second.value_string))));
+ break;
+ }
+ }
+ }
+ id_node_map.emplace(std::make_pair(node.id(), node_row_id));
+ return node_row_id;
+}
+
+void MemoryTrackerSnapshotParser::GenerateGraphFromRawNodesAndEmitRows() {
+ std::unique_ptr<GlobalNodeGraph> graph = GenerateGraph(aggregate_raw_nodes_);
+ EmitRows(last_snapshot_timestamp_, *(graph.get()),
+ last_snapshot_level_of_detail_);
+ aggregate_raw_nodes_.clear();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h b/src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h
new file mode 100644
index 0000000..32119c2
--- /dev/null
+++ b/src/trace_processor/importers/proto/memory_tracker_snapshot_parser.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MEMORY_TRACKER_SNAPSHOT_PARSER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MEMORY_TRACKER_SNAPSHOT_PARSER_H_
+
+#include "perfetto/ext/trace_processor/importers/memory_tracker/graph_processor.h"
+#include "protos/perfetto/trace/memory_graph.pbzero.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+class MemoryTrackerSnapshotParser {
+ public:
+ explicit MemoryTrackerSnapshotParser(TraceProcessorContext* context);
+ void ParseMemoryTrackerSnapshot(int64_t ts, protozero::ConstBytes blob);
+
+ void NotifyEndOfFile();
+
+ private:
+ using RawMemoryNodeMap =
+ std::map<base::PlatformProcessId, std::unique_ptr<RawProcessMemoryNode>>;
+ using IdNodeMap =
+ std::map<MemoryAllocatorNodeId, tables::MemorySnapshotNodeTable::Id>;
+ using ConstBytes = protozero::ConstBytes;
+
+ class ChildNode {
+ public:
+ ChildNode() : table_index_(-1) {}
+ GlobalNodeGraph::Node* node_;
+ std::string path_;
+ uint64_t size_;
+ uint64_t effective_size_;
+ int32_t table_index_;
+ };
+
+ // Reads the proto-encoded memory snapshot of a process (message
+ // MemoryTrackerSnapshot) in given |blob| in order to get:
+ // - map of RawProcessMemoryNode containers |raw_nodes|. It
+ // is need to generates GlobalNodeGraph via GraphProcessor.
+ // - level of detail of the memory graph |level_of_detail|.
+ void ReadProtoSnapshot(ConstBytes blob,
+ RawMemoryNodeMap& raw_nodes,
+ LevelOfDetail& level_of_detail);
+
+ // Generates GlobalNodeGraph via GraphProcessor for given map |raw_nodes|.
+ std::unique_ptr<GlobalNodeGraph> GenerateGraph(RawMemoryNodeMap& raw_nodes);
+
+ // Fills out MemorySnapshotTable, ProcessMemorySnapshotTable,
+ // MemorySnapshotNodeTable, MemorySnapshotEdgeTable with given
+ // timestamp |ts|, |graph|, |level_of_detail|.
+ void EmitRows(int64_t ts,
+ GlobalNodeGraph& graph,
+ LevelOfDetail level_of_detail);
+
+ // Fills out MemorySnapshotNodeTable for given root node
+ // |root_node_graph| and ProcessMemorySnapshotId |proc_snapshot_row_id|.
+ // Generates map of MemoryAllocatorNodeId and MemorySnapshotNodeTable::Id
+ // |id_node_map| which is used at time of filling out of
+ // MemorySnapshotEdgeTable.
+ void EmitMemorySnapshotNodeRows(GlobalNodeGraph::Node& root_node_graph,
+ ProcessMemorySnapshotId& proc_snapshot_row_id,
+ IdNodeMap& id_node_map);
+
+ // Recursively traverses through list of children of |node| to generate full
+ // |path| to every node in MemorySnapshotNodeTable for given
+ // ProcessMemorySnapshotId |proc_snapshot_row_id|.
+ // Generates map of MemoryAllocatorNodeId and MemorySnapshotNodeTable::Id
+ // |id_node_map| which is used at time of filling out of
+ // MemorySnapshotEdgeTable.
+ void EmitMemorySnapshotNodeRowsRecursively(
+ GlobalNodeGraph::Node& node,
+ const std::string&,
+ base::Optional<tables::MemorySnapshotNodeTable::Id> parent_node_row_id,
+ ProcessMemorySnapshotId& proc_snapshot_row_id,
+ IdNodeMap& id_node_map);
+
+ // Fills out MemorySnapshotNodeTable for given Node
+ // |node|, |path|, MemorySnapshotNodeTable::Id |parent_node_row_id| and
+ // ProcessMemorySnapshotId |proc_snapshot_row_id|. Generates map of
+ // MemoryAllocatorNodeId and MemorySnapshotNodeTable::Id |id_node_map| which
+ // is used at time of filling out of MemorySnapshotEdgeTable.
+ base::Optional<tables::MemorySnapshotNodeTable::Id> EmitNode(
+ const GlobalNodeGraph::Node& node,
+ const std::string& path,
+ base::Optional<tables::MemorySnapshotNodeTable::Id> parent_node_row_id,
+ ProcessMemorySnapshotId& proc_snapshot_row_id,
+ IdNodeMap& id_node_map);
+
+ void GenerateGraphFromRawNodesAndEmitRows();
+
+ TraceProcessorContext* context_;
+ std::array<StringId, 3> level_of_detail_ids_;
+ std::array<StringId, 2> unit_ids_;
+ RawMemoryNodeMap aggregate_raw_nodes_;
+ int64_t last_snapshot_timestamp_;
+ LevelOfDetail last_snapshot_level_of_detail_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_MEMORY_TRACKER_SNAPSHOT_PARSER_H_
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index 3a08c4a..b93af99 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -798,7 +798,6 @@
context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
continue;
}
-
}
}
@@ -833,7 +832,18 @@
{upid, ts, context_->storage->InternString(e.path()),
static_cast<int64_t>(e.size_kb()),
static_cast<int64_t>(e.private_dirty_kb()),
- static_cast<int64_t>(e.swap_kb())});
+ static_cast<int64_t>(e.swap_kb()),
+ context_->storage->InternString(e.file_name()),
+ static_cast<int64_t>(e.start_address()),
+ static_cast<int64_t>(e.module_timestamp()),
+ context_->storage->InternString(e.module_debugid()),
+ context_->storage->InternString(e.module_debug_path()),
+ static_cast<int32_t>(e.protection_flags()),
+ static_cast<int64_t>(e.private_clean_resident_kb()),
+ static_cast<int64_t>(e.shared_dirty_resident_kb()),
+ static_cast<int64_t>(e.shared_clean_resident_kb()),
+ static_cast<int64_t>(e.locked_kb()),
+ static_cast<int64_t>(e.proportional_resident_kb())});
}
}
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 96b14ec..d81e335 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -69,6 +69,12 @@
cpu_times_softirq_ns_id_(
context->storage->InternString("cpu.times.softirq_ns")),
oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
+ is_peak_rss_resettable_id_(
+ context->storage->InternString("is_peak_rss_resettable")),
+ chrome_private_footprint_kb_(
+ context->storage->InternString("chrome.private_footprint_kb")),
+ chrome_peak_resident_set_kb_(
+ context->storage->InternString("chrome.peak_resident_set_kb")),
thread_time_in_state_id_(context->storage->InternString("time_in_state")),
thread_time_in_state_cpu_id_(
context_->storage->InternString("time_in_state_cpu_id")),
@@ -99,6 +105,12 @@
context->storage->InternString("mem.rss.watermark");
proc_stats_process_names_[ProcessStats::Process::kOomScoreAdjFieldNumber] =
oom_score_adj_id_;
+ proc_stats_process_names_
+ [ProcessStats::Process::kChromePrivateFootprintKbFieldNumber] =
+ chrome_private_footprint_kb_;
+ proc_stats_process_names_
+ [ProcessStats::Process::kChromePeakResidentSetKbFieldNumber] =
+ chrome_peak_resident_set_kb_;
}
void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
@@ -281,11 +293,19 @@
protozero::ProtoDecoder proc(*it);
uint32_t pid = 0;
+ bool is_peak_rss_resettable = false;
+ bool has_peak_rrs_resettable = false;
for (auto fld = proc.ReadField(); fld.valid(); fld = proc.ReadField()) {
if (fld.id() == protos::pbzero::ProcessStats::Process::kPidFieldNumber) {
pid = fld.as_uint32();
continue;
}
+ if (fld.id() == protos::pbzero::ProcessStats::Process::
+ kIsPeakRssResettableFieldNumber) {
+ is_peak_rss_resettable = fld.as_bool();
+ has_peak_rrs_resettable = true;
+ continue;
+ }
if (fld.id() ==
protos::pbzero::ProcessStats::Process::kThreadsFieldNumber) {
if (PERFETTO_UNLIKELY(ms_per_tick_ == 0 ||
@@ -311,18 +331,27 @@
}
}
+ if (has_peak_rrs_resettable) {
+ UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
+ context_->process_tracker->AddArgsTo(upid).AddArg(
+ is_peak_rss_resettable_id_,
+ Variadic::Boolean(is_peak_rss_resettable));
+ }
// Skip field_id 0 (invalid) and 1 (pid).
for (size_t field_id = 2; field_id < counter_values.size(); field_id++) {
- if (!has_counter[field_id])
+ if (!has_counter[field_id] || field_id ==
+ protos::pbzero::ProcessStats::Process::
+ kIsPeakRssResettableFieldNumber) {
continue;
+ }
// Lookup the interned string id from the field name using the
// pre-cached |proc_stats_process_names_| map.
StringId name = proc_stats_process_names_[field_id];
- int64_t value = counter_values[field_id];
UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
TrackId track =
context_->track_tracker->InternProcessCounterTrack(name, upid);
+ int64_t value = counter_values[field_id];
context_->event_tracker->PushCounter(ts, static_cast<double>(value),
track);
}
diff --git a/src/trace_processor/importers/proto/system_probes_parser.h b/src/trace_processor/importers/proto/system_probes_parser.h
index 5485b36..b604b6c 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.h
+++ b/src/trace_processor/importers/proto/system_probes_parser.h
@@ -60,6 +60,9 @@
const StringId cpu_times_irq_ns_id_;
const StringId cpu_times_softirq_ns_id_;
const StringId oom_score_adj_id_;
+ const StringId is_peak_rss_resettable_id_;
+ const StringId chrome_private_footprint_kb_;
+ const StringId chrome_peak_resident_set_kb_;
const StringId thread_time_in_state_id_;
const StringId thread_time_in_state_cpu_id_;
const StringId cpu_freq_id_;
@@ -69,7 +72,7 @@
// Maps a proto field number for memcounters in ProcessStats::Process to
// their StringId. Keep kProcStatsProcessSize equal to 1 + max proto field
// id of ProcessStats::Process.
- static constexpr size_t kProcStatsProcessSize = 11;
+ static constexpr size_t kProcStatsProcessSize = 15;
std::array<StringId, kProcStatsProcessSize> proc_stats_process_names_{};
uint64_t ms_per_tick_ = 0;
diff --git a/src/trace_processor/storage/stats.h b/src/trace_processor/storage/stats.h
index 062d287..8514b42 100644
--- a/src/trace_processor/storage/stats.h
+++ b/src/trace_processor/storage/stats.h
@@ -155,6 +155,7 @@
F(ninja_parse_errors, kSingle, kError, kTrace, ""), \
F(perf_samples_skipped, kSingle, kInfo, kTrace, ""), \
F(perf_samples_skipped_dataloss, kSingle, kDataLoss, kTrace, ""), \
+ F(memory_snapshot_parser_failure, kSingle, kError, kAnalysis, ""), \
F(thread_time_in_state_out_of_order, kSingle, kError, kAnalysis, ""), \
F(thread_time_in_state_unknown_cpu_freq, \
kSingle, kError, kAnalysis, ""), \
diff --git a/src/trace_processor/storage/trace_storage.h b/src/trace_processor/storage/trace_storage.h
index 604b026..6c42178 100644
--- a/src/trace_processor/storage/trace_storage.h
+++ b/src/trace_processor/storage/trace_storage.h
@@ -91,6 +91,8 @@
using VulkanAllocId = tables::VulkanMemoryAllocationsTable::Id;
+using ProcessMemorySnapshotId = tables::ProcessMemorySnapshotTable::Id;
+
using SnapshotNodeId = tables::MemorySnapshotNodeTable::Id;
// TODO(lalitm): this is a temporary hack while migrating the counters table and
diff --git a/src/trace_processor/tables/memory_tables.h b/src/trace_processor/tables/memory_tables.h
index 6678a73..510426f 100644
--- a/src/trace_processor/tables/memory_tables.h
+++ b/src/trace_processor/tables/memory_tables.h
@@ -44,14 +44,14 @@
PERFETTO_TP_TABLE(PERFETTO_TP_PROCESS_MEMORY_SNAPSHOT_DEF);
// @tablegroup
-#define PERFETTO_TP_MEMORY_SNAPSHOT_NODE_DEF(NAME, PARENT, C) \
- NAME(MemorySnapshotNodeTable, "memory_snapshot_node") \
- PERFETTO_TP_ROOT_TABLE(PARENT, C) \
- C(ProcessMemorySnapshotTable::Id, process_snapshot_id) \
- C(MemorySnapshotNodeTable::Id, parent_node_id) \
- C(StringPool::Id, path) \
- C(int64_t, size) \
- C(int64_t, effective_size) \
+#define PERFETTO_TP_MEMORY_SNAPSHOT_NODE_DEF(NAME, PARENT, C) \
+ NAME(MemorySnapshotNodeTable, "memory_snapshot_node") \
+ PERFETTO_TP_ROOT_TABLE(PARENT, C) \
+ C(ProcessMemorySnapshotTable::Id, process_snapshot_id) \
+ C(base::Optional<MemorySnapshotNodeTable::Id>, parent_node_id) \
+ C(StringPool::Id, path) \
+ C(int64_t, size) \
+ C(int64_t, effective_size) \
C(base::Optional<uint32_t>, arg_set_id)
PERFETTO_TP_TABLE(PERFETTO_TP_MEMORY_SNAPSHOT_NODE_DEF);
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index ae1f9cc..ff9cee6 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -97,6 +97,7 @@
for (std::unique_ptr<ProtoImporterModule>& module : context_.modules) {
module->NotifyEndOfFile();
}
+ context_.args_tracker->Flush();
}
} // namespace trace_processor
diff --git a/test/trace_processor/chrome/index b/test/trace_processor/chrome/index
index a1d9c54..1c821ac 100644
--- a/test/trace_processor/chrome/index
+++ b/test/trace_processor/chrome/index
@@ -12,3 +12,12 @@
../../data/chrome_scroll_without_vsync.pftrace scroll_jank_cause_queuing_delay_general_validation.sql scroll_jank_cause_queuing_delay_general_validation.out
../../data/chrome_scroll_without_vsync.pftrace chrome_thread_slice_with_cpu_time.sql chrome_thread_slice_with_cpu_time.out
../track_event/track_event_counters.textproto chrome_thread_slice_with_cpu_time_repeated.sql chrome_thread_slice_with_cpu_time_repeated.out
+
+# Chrome memory snapshots.
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_general_validation.sql memory_snapshot_general_validation.out
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_os_dump_events.sql memory_snapshot_os_dump_events.out
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_chrome_dump_events.sql memory_snapshot_chrome_dump_events.out
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_nodes.sql memory_snapshot_nodes.out
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_edges.sql memory_snapshot_edges.out
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_node_args.sql memory_snapshot_node_args.out
+../../data/chrome_memory_snapshot.pftrace memory_snapshot_smaps.sql memory_snapshot_smaps.out
diff --git a/test/trace_processor/chrome/memory_snapshot_chrome_dump_events.out b/test/trace_processor/chrome/memory_snapshot_chrome_dump_events.out
new file mode 100644
index 0000000..1d07a47
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_chrome_dump_events.out
@@ -0,0 +1,19 @@
+"process_snapshot_id","upid","snapshot_id","timestamp","detail_level"
+0,1,0,111027205123000,"background"
+1,2,0,111027205123000,"background"
+2,3,0,111027205123000,"background"
+3,5,0,111027205123000,"background"
+4,4,0,111027205123000,"background"
+5,8,0,111027205123000,"background"
+6,6,0,111027205123000,"background"
+7,7,0,111027205123000,"background"
+8,0,0,111027205123000,"background"
+9,1,1,111037187565000,"background"
+10,2,1,111037187565000,"background"
+11,3,1,111037187565000,"background"
+12,5,1,111037187565000,"background"
+13,4,1,111037187565000,"background"
+14,8,1,111037187565000,"background"
+15,6,1,111037187565000,"background"
+16,7,1,111037187565000,"background"
+17,0,1,111037187565000,"background"
diff --git a/test/trace_processor/chrome/memory_snapshot_chrome_dump_events.sql b/test/trace_processor/chrome/memory_snapshot_chrome_dump_events.sql
new file mode 100644
index 0000000..67fbf86
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_chrome_dump_events.sql
@@ -0,0 +1,25 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+--
+
+SELECT
+ pms.id AS process_snapshot_id,
+ upid,
+ snapshot_id,
+ timestamp,
+ detail_level
+FROM memory_snapshot ms
+LEFT JOIN process_memory_snapshot pms
+ ON ms.id = pms.snapshot_id
diff --git a/test/trace_processor/chrome/memory_snapshot_edges.out b/test/trace_processor/chrome/memory_snapshot_edges.out
new file mode 100644
index 0000000..15bb371
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_edges.out
@@ -0,0 +1,21 @@
+"id","source_node_id","target_node_id","importance"
+0,1734,1863,0
+1,1728,1839,0
+2,1732,1772,0
+3,1729,1786,0
+4,1730,1805,0
+5,1735,1859,0
+6,1733,1844,0
+7,1727,1840,0
+8,1731,1850,0
+9,1726,1849,0
+10,1636,1639,0
+11,1681,1846,0
+12,1683,1744,0
+13,1680,1849,0
+14,1682,1859,0
+15,1707,1621,0
+16,1634,1638,0
+17,1399,1193,0
+18,1083,1795,2
+19,1358,1846,0
diff --git a/test/trace_processor/chrome/memory_snapshot_edges.sql b/test/trace_processor/chrome/memory_snapshot_edges.sql
new file mode 100644
index 0000000..63307ad
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_edges.sql
@@ -0,0 +1,23 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+--
+
+SELECT
+ id,
+ source_node_id,
+ target_node_id,
+ importance
+FROM memory_snapshot_edge
+LIMIT 20
diff --git a/test/trace_processor/chrome/memory_snapshot_general_validation.out b/test/trace_processor/chrome/memory_snapshot_general_validation.out
new file mode 100644
index 0000000..cb203ee
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_general_validation.out
@@ -0,0 +1,2 @@
+"total_snapshots","total_processes","total_process_snapshots","total_nodes","total_edges","total_node_args","total_smaps"
+2,9,18,3584,788,5014,33979
diff --git a/test/trace_processor/chrome/memory_snapshot_general_validation.sql b/test/trace_processor/chrome/memory_snapshot_general_validation.sql
new file mode 100644
index 0000000..4075041
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_general_validation.sql
@@ -0,0 +1,41 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+
+SELECT
+ (
+ SELECT COUNT(*) FROM memory_snapshot
+ ) AS total_snapshots,
+ (
+ SELECT COUNT(*) FROM process
+ ) AS total_processes,
+ (
+ SELECT COUNT(*) FROM process_memory_snapshot
+ ) AS total_process_snapshots,
+ (
+ SELECT COUNT(*) FROM memory_snapshot_node
+ ) AS total_nodes,
+ (
+ SELECT COUNT(*) FROM memory_snapshot_edge
+ ) AS total_edges,
+ (
+ SELECT COUNT(DISTINCT args.id)
+ FROM args
+ INNER JOIN memory_snapshot_node
+ ON args.arg_set_id = memory_snapshot_node.arg_set_id
+ ) AS total_node_args,
+ (
+ SELECT COUNT(*) FROM profiler_smaps
+ INNER JOIN memory_snapshot ON timestamp = ts
+ ) AS total_smaps
diff --git a/test/trace_processor/chrome/memory_snapshot_node_args.out b/test/trace_processor/chrome/memory_snapshot_node_args.out
new file mode 100644
index 0000000..c6adffe
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_node_args.out
@@ -0,0 +1,21 @@
+"node_id","key","value_type","int_value","string_value"
+20,"id.value","string","[NULL]","C7BC3FD59A40689345EB9CB08570641B"
+20,"locked_size.value","int",0,"[NULL]"
+20,"locked_size.unit","string","[NULL]","bytes"
+20,"virtual_size.value","int",961,"[NULL]"
+20,"virtual_size.unit","string","[NULL]","bytes"
+21,"id.value","string","[NULL]","AF621E3BE175B9B618BAADF9138E5598"
+21,"locked_size.value","int",0,"[NULL]"
+21,"locked_size.unit","string","[NULL]","bytes"
+21,"virtual_size.value","int",529,"[NULL]"
+21,"virtual_size.unit","string","[NULL]","bytes"
+30,"free_size.value","int",1048576,"[NULL]"
+30,"free_size.unit","string","[NULL]","bytes"
+32,"free_size.value","int",65472,"[NULL]"
+32,"free_size.unit","string","[NULL]","bytes"
+54,"name.value","string","[NULL]","/home/toki/.config/chromium/Default/Site Characteristics Database"
+57,"name.value","string","[NULL]","/home/toki/.config/chromium/Default/Sync Data/LevelDB"
+60,"name.value","string","[NULL]","/home/toki/.config/chromium/Default/shared_proto_db/metadata"
+63,"name.value","string","[NULL]","/home/toki/.config/chromium/Default/GCM Store/Encryption"
+66,"name.value","string","[NULL]","/home/toki/.config/chromium/Default/Service Worker/Database"
+69,"name.value","string","[NULL]","/home/toki/.config/chromium/Default/Extension Rules"
diff --git a/test/trace_processor/chrome/memory_snapshot_node_args.sql b/test/trace_processor/chrome/memory_snapshot_node_args.sql
new file mode 100644
index 0000000..03df9e9
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_node_args.sql
@@ -0,0 +1,25 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+--
+
+SELECT
+ node.id AS node_id,
+ key,
+ value_type,
+ int_value,
+ string_value
+FROM memory_snapshot_node node
+INNER JOIN args ON node.arg_set_id = args.arg_set_id
+LIMIT 20
diff --git a/test/trace_processor/chrome/memory_snapshot_nodes.out b/test/trace_processor/chrome/memory_snapshot_nodes.out
new file mode 100644
index 0000000..39a8108
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_nodes.out
@@ -0,0 +1,21 @@
+"id","process_snapshot_id","parent_node_id","path","size","effective_size"
+0,0,"[NULL]","cc",2899968,2899968
+1,0,0,"cc/tile_memory",2899968,2899968
+2,0,1,"cc/tile_memory/provider_0",2899968,2899968
+3,0,2,"cc/tile_memory/provider_0/resource_10",262144,262144
+4,0,2,"cc/tile_memory/provider_0/resource_11",131072,131072
+5,0,2,"cc/tile_memory/provider_0/resource_14",262144,262144
+6,0,2,"cc/tile_memory/provider_0/resource_15",131072,131072
+7,0,2,"cc/tile_memory/provider_0/resource_21",262144,262144
+8,0,2,"cc/tile_memory/provider_0/resource_23",262144,262144
+9,0,2,"cc/tile_memory/provider_0/resource_26",131072,131072
+10,0,2,"cc/tile_memory/provider_0/resource_3",262144,262144
+11,0,2,"cc/tile_memory/provider_0/resource_31",131072,131072
+12,0,2,"cc/tile_memory/provider_0/resource_36",262144,262144
+13,0,2,"cc/tile_memory/provider_0/resource_4",131072,131072
+14,0,2,"cc/tile_memory/provider_0/resource_41",16384,16384
+15,0,2,"cc/tile_memory/provider_0/resource_42",262144,262144
+16,0,2,"cc/tile_memory/provider_0/resource_7",262144,262144
+17,0,2,"cc/tile_memory/provider_0/resource_8",131072,131072
+18,0,"[NULL]","discardable",16384,16384
+19,0,18,"discardable/process_ffffffff",16384,16384
diff --git a/test/trace_processor/chrome/memory_snapshot_nodes.sql b/test/trace_processor/chrome/memory_snapshot_nodes.sql
new file mode 100644
index 0000000..0c014d3
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_nodes.sql
@@ -0,0 +1,25 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+--
+
+SELECT
+ id,
+ process_snapshot_id,
+ parent_node_id,
+ path,
+ size,
+ effective_size
+FROM memory_snapshot_node
+LIMIT 20
diff --git a/test/trace_processor/chrome/memory_snapshot_os_dump_events.out b/test/trace_processor/chrome/memory_snapshot_os_dump_events.out
new file mode 100644
index 0000000..b21de21
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_os_dump_events.out
@@ -0,0 +1,19 @@
+"upid","pid","name","timestamp","detail_level","private_footprint_kb","peak_resident_set_kb","is_peak_rss_resettable"
+0,0,"[NULL]",111027205123000,"background","[NULL]","[NULL]","[NULL]"
+1,29694,"Browser",111027205123000,"background",76656640.000000,479354880.000000,1
+2,29725,"GPU Process",111027205123000,"background",62836736.000000,280952832.000000,1
+3,29728,"Service: network.mojom.NetworkService",111027205123000,"background",35360768.000000,229261312.000000,1
+4,29764,"Service: data_decoder.mojom.DataDecoderService",111027205123000,"background",30576640.000000,201347072.000000,1
+5,29737,"Service: storage.mojom.StorageService",111027205123000,"background",30617600.000000,207138816.000000,1
+6,29833,"Renderer",111027205123000,"background",36802560.000000,264036352.000000,1
+7,29877,"Service: tracing.mojom.TracingService",111027205123000,"background",31002624.000000,199208960.000000,1
+8,29807,"Renderer",111027205123000,"background",87248896.000000,451424256.000000,1
+0,0,"[NULL]",111037187565000,"background","[NULL]","[NULL]","[NULL]"
+1,29694,"Browser",111037187565000,"background",85942272.000000,491671552.000000,1
+2,29725,"GPU Process",111037187565000,"background",62754816.000000,275906560.000000,1
+3,29728,"Service: network.mojom.NetworkService",111037187565000,"background",35495936.000000,229351424.000000,1
+4,29764,"Service: data_decoder.mojom.DataDecoderService",111037187565000,"background",30679040.000000,201424896.000000,1
+5,29737,"Service: storage.mojom.StorageService",111037187565000,"background",30650368.000000,205791232.000000,1
+6,29833,"Renderer",111037187565000,"background",36950016.000000,264843264.000000,1
+7,29877,"Service: tracing.mojom.TracingService",111037187565000,"background",33386496.000000,204554240.000000,1
+8,29807,"Renderer",111037187565000,"background",76832768.000000,445292544.000000,1
diff --git a/test/trace_processor/chrome/memory_snapshot_os_dump_events.sql b/test/trace_processor/chrome/memory_snapshot_os_dump_events.sql
new file mode 100644
index 0000000..b266773
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_os_dump_events.sql
@@ -0,0 +1,42 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+--
+
+SELECT
+ p.upid,
+ pid,
+ p.name,
+ timestamp,
+ detail_level,
+ pf.value AS private_footprint_kb,
+ prs.value AS peak_resident_set_kb,
+ EXTRACT_ARG(p.arg_set_id, 'is_peak_rss_resettable') AS is_peak_rss_resettable
+FROM process p
+LEFT JOIN memory_snapshot
+LEFT JOIN (
+ SELECT id, upid
+ FROM process_counter_track
+ WHERE name IS 'chrome.private_footprint_kb'
+ ) AS pct_pf
+ ON p.upid = pct_pf.upid
+LEFT JOIN counter pf ON timestamp = pf.ts AND pct_pf.id = pf.track_id
+LEFT JOIN (
+ SELECT id, upid
+ FROM process_counter_track
+ WHERE name IS 'chrome.peak_resident_set_kb'
+ ) AS pct_prs
+ ON p.upid = pct_prs.upid
+LEFT JOIN counter prs ON timestamp = prs.ts AND pct_prs.id = prs.track_id
+ORDER BY timestamp
diff --git a/test/trace_processor/chrome/memory_snapshot_smaps.out b/test/trace_processor/chrome/memory_snapshot_smaps.out
new file mode 100644
index 0000000..255526d
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_smaps.out
@@ -0,0 +1,21 @@
+"upid","name","ts","path","size_kb","private_dirty_kb","swap_kb","file_name","start_address","module_timestamp","module_debugid","module_debug_path","protection_flags","private_clean_resident_kb","shared_dirty_resident_kb","shared_clean_resident_kb","locked_kb","proportional_resident_kb"
+1,"Browser",111027205123000,"[NULL]",4,0,0,"",14051238432768,0,"[NULL]","[NULL]",0,0,0,0,0,0
+1,"Browser",111027205123000,"[NULL]",40956,40464,0,"",14051238436864,0,"[NULL]","[NULL]",6,0,0,0,0,40464
+1,"Browser",111027205123000,"[NULL]",4,0,0,"",14051280375808,0,"[NULL]","[NULL]",0,0,0,0,0,0
+1,"Browser",111027205123000,"[NULL]",11860,8620,0,"",14051280379904,0,"[NULL]","[NULL]",6,0,0,0,0,8620
+1,"Browser",111027205123000,"[NULL]",67896,4,0,"/home/toki/chromium/src/out/Default/chrome",94168098267136,0,"[NULL]","[NULL]",4,6824,0,14812,0,8788
+1,"Browser",111027205123000,"[NULL]",123784,4,0,"/home/toki/chromium/src/out/Default/chrome",94168167792640,0,"[NULL]","[NULL]",5,62584,0,28044,0,70896
+1,"Browser",111027205123000,"[NULL]",3036,3036,0,"/home/toki/chromium/src/out/Default/chrome",94168294547456,0,"[NULL]","[NULL]",4,0,0,0,0,3036
+1,"Browser",111027205123000,"[NULL]",148,136,0,"/home/toki/chromium/src/out/Default/chrome",94168297656320,0,"[NULL]","[NULL]",6,0,0,12,0,137
+1,"Browser",111027205123000,"[NULL]",404,240,0,"",94168297807872,0,"[NULL]","[NULL]",6,0,0,0,0,240
+1,"Browser",111027205123000,"[NULL]",2048,0,0,"/dev/shm/.org.chromium.Chromium.Doo3XC (deleted)",140632555954176,0,"[NULL]","[NULL]",134,0,4,0,0,2
+1,"Browser",111027205123000,"[NULL]",2048,0,0,"/dev/shm/.org.chromium.Chromium.PxFFQm (deleted)",140632558575616,0,"[NULL]","[NULL]",134,0,4,0,0,2
+1,"Browser",111027205123000,"[NULL]",428,0,0,"/usr/lib/x86_64-linux-gnu/nss/libnssckbi.so",140632563163136,0,"[NULL]","[NULL]",5,128,0,136,0,196
+1,"Browser",111027205123000,"[NULL]",2044,0,0,"/usr/lib/x86_64-linux-gnu/nss/libnssckbi.so",140632563601408,0,"[NULL]","[NULL]",0,0,0,0,0,0
+1,"Browser",111027205123000,"[NULL]",68,68,0,"/usr/lib/x86_64-linux-gnu/nss/libnssckbi.so",140632565694464,0,"[NULL]","[NULL]",4,0,0,0,0,68
+1,"Browser",111027205123000,"[NULL]",40,40,0,"/usr/lib/x86_64-linux-gnu/nss/libnssckbi.so",140632565764096,0,"[NULL]","[NULL]",6,0,0,0,0,40
+1,"Browser",111027205123000,"[NULL]",668,0,0,"/usr/lib/x86_64-linux-gnu/nss/libfreeblpriv3.so",140632565805056,0,"[NULL]","[NULL]",5,340,0,16,0,344
+1,"Browser",111027205123000,"[NULL]",2048,0,0,"/usr/lib/x86_64-linux-gnu/nss/libfreeblpriv3.so",140632566489088,0,"[NULL]","[NULL]",0,0,0,0,0,0
+1,"Browser",111027205123000,"[NULL]",8,8,0,"/usr/lib/x86_64-linux-gnu/nss/libfreeblpriv3.so",140632568586240,0,"[NULL]","[NULL]",4,0,0,0,0,8
+1,"Browser",111027205123000,"[NULL]",4,4,0,"/usr/lib/x86_64-linux-gnu/nss/libfreeblpriv3.so",140632568594432,0,"[NULL]","[NULL]",6,0,0,0,0,4
+1,"Browser",111027205123000,"[NULL]",16,16,0,"",140632568598528,0,"[NULL]","[NULL]",6,0,0,0,0,16
diff --git a/test/trace_processor/chrome/memory_snapshot_smaps.sql b/test/trace_processor/chrome/memory_snapshot_smaps.sql
new file mode 100644
index 0000000..dfd1fce
--- /dev/null
+++ b/test/trace_processor/chrome/memory_snapshot_smaps.sql
@@ -0,0 +1,39 @@
+--
+-- Copyright 2020 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
+--
+-- https://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.
+--
+
+SELECT
+ process.upid,
+ process.name,
+ smap.ts,
+ path,
+ size_kb,
+ private_dirty_kb,
+ swap_kb,
+ file_name,
+ start_address,
+ module_timestamp,
+ module_debugid,
+ module_debug_path,
+ protection_flags,
+ private_clean_resident_kb,
+ shared_dirty_resident_kb,
+ shared_clean_resident_kb,
+ locked_kb,
+ proportional_resident_kb
+FROM process
+INNER JOIN profiler_smaps smap ON process.upid = smap.upid
+INNER JOIN memory_snapshot ms ON ms.timestamp = smap.ts
+LIMIT 20