Reapply "tp: fix build in Google3"
Reapply "Refactor StackProfile related classes."
This reverts commits
be8c9b247dd59ebc0d2b8555b4a063ba0e711743
and
037c128f85a73ab7fbe854ffbef792f7ac77a0c6.
+ Adds fixes for various test failures. (See diff patchset 1 and 2)
Bug: b/283794416
Change-Id: Ifcbe212250647c5f6ece0d0971ee97fe1d6188e3
diff --git a/Android.bp b/Android.bp
index 4267433..0ea862b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2375,6 +2375,7 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
+ ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
@@ -11078,6 +11079,7 @@
"src/trace_processor/importers/common/process_tracker.cc",
"src/trace_processor/importers/common/slice_tracker.cc",
"src/trace_processor/importers/common/slice_translation_table.cc",
+ "src/trace_processor/importers/common/stack_profile_tracker.cc",
"src/trace_processor/importers/common/system_info_tracker.cc",
"src/trace_processor/importers/common/trace_parser.cc",
"src/trace_processor/importers/common/track_tracker.cc",
@@ -11397,7 +11399,6 @@
"src/trace_processor/importers/proto/chrome_system_probes_module.cc",
"src/trace_processor/importers/proto/chrome_system_probes_parser.cc",
"src/trace_processor/importers/proto/default_modules.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_minimal_module.cc",
@@ -11406,12 +11407,12 @@
"src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
"src/trace_processor/importers/proto/perf_sample_tracker.cc",
"src/trace_processor/importers/proto/profile_module.cc",
+ "src/trace_processor/importers/proto/profile_packet_sequence_state.cc",
"src/trace_processor/importers/proto/profile_packet_utils.cc",
- "src/trace_processor/importers/proto/profiler_util.cc",
"src/trace_processor/importers/proto/proto_trace_parser.cc",
"src/trace_processor/importers/proto/proto_trace_reader.cc",
"src/trace_processor/importers/proto/proto_trace_tokenizer.cc",
- "src/trace_processor/importers/proto/stack_profile_tracker.cc",
+ "src/trace_processor/importers/proto/stack_profile_sequence_state.cc",
"src/trace_processor/importers/proto/track_event_module.cc",
"src/trace_processor/importers/proto/track_event_parser.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.cc",
@@ -11438,9 +11439,9 @@
srcs: [
"src/trace_processor/importers/proto/active_chrome_processes_tracker_unittest.cc",
"src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc",
- "src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc",
"src/trace_processor/importers/proto/network_trace_module_unittest.cc",
"src/trace_processor/importers/proto/perf_sample_tracker_unittest.cc",
+ "src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc",
"src/trace_processor/importers/proto/proto_trace_parser_unittest.cc",
"src/trace_processor/importers/proto/string_encoding_utils_unittests.cc",
],
@@ -12320,6 +12321,14 @@
],
}
+// GN: //src/trace_processor/util:profiler_util
+filegroup {
+ name: "perfetto_src_trace_processor_util_profiler_util",
+ srcs: [
+ "src/trace_processor/util/profiler_util.cc",
+ ],
+}
+
// GN: //src/trace_processor/util:proto_profiler
filegroup {
name: "perfetto_src_trace_processor_util_proto_profiler",
@@ -13871,6 +13880,7 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
+ ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
@@ -14568,6 +14578,7 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
+ ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
@@ -14800,6 +14811,7 @@
":perfetto_src_trace_processor_util_gzip",
":perfetto_src_trace_processor_util_interned_message_view",
":perfetto_src_trace_processor_util_profile_builder",
+ ":perfetto_src_trace_processor_util_profiler_util",
":perfetto_src_trace_processor_util_proto_profiler",
":perfetto_src_trace_processor_util_proto_to_args_parser",
":perfetto_src_trace_processor_util_protozero_to_json",
diff --git a/BUILD b/BUILD
index e6649d9..09ab8b4 100644
--- a/BUILD
+++ b/BUILD
@@ -272,6 +272,7 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
+ ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
@@ -1473,6 +1474,8 @@
"src/trace_processor/importers/common/slice_tracker.h",
"src/trace_processor/importers/common/slice_translation_table.cc",
"src/trace_processor/importers/common/slice_translation_table.h",
+ "src/trace_processor/importers/common/stack_profile_tracker.cc",
+ "src/trace_processor/importers/common/stack_profile_tracker.h",
"src/trace_processor/importers/common/system_info_tracker.cc",
"src/trace_processor/importers/common/system_info_tracker.h",
"src/trace_processor/importers/common/trace_parser.cc",
@@ -1821,8 +1824,6 @@
"src/trace_processor/importers/proto/chrome_system_probes_parser.h",
"src/trace_processor/importers/proto/default_modules.cc",
"src/trace_processor/importers/proto/default_modules.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",
@@ -1839,10 +1840,10 @@
"src/trace_processor/importers/proto/perf_sample_tracker.h",
"src/trace_processor/importers/proto/profile_module.cc",
"src/trace_processor/importers/proto/profile_module.h",
+ "src/trace_processor/importers/proto/profile_packet_sequence_state.cc",
+ "src/trace_processor/importers/proto/profile_packet_sequence_state.h",
"src/trace_processor/importers/proto/profile_packet_utils.cc",
"src/trace_processor/importers/proto/profile_packet_utils.h",
- "src/trace_processor/importers/proto/profiler_util.cc",
- "src/trace_processor/importers/proto/profiler_util.h",
"src/trace_processor/importers/proto/proto_incremental_state.h",
"src/trace_processor/importers/proto/proto_trace_parser.cc",
"src/trace_processor/importers/proto/proto_trace_parser.h",
@@ -1850,8 +1851,8 @@
"src/trace_processor/importers/proto/proto_trace_reader.h",
"src/trace_processor/importers/proto/proto_trace_tokenizer.cc",
"src/trace_processor/importers/proto/proto_trace_tokenizer.h",
- "src/trace_processor/importers/proto/stack_profile_tracker.cc",
- "src/trace_processor/importers/proto/stack_profile_tracker.h",
+ "src/trace_processor/importers/proto/stack_profile_sequence_state.cc",
+ "src/trace_processor/importers/proto/stack_profile_sequence_state.h",
"src/trace_processor/importers/proto/track_event_module.cc",
"src/trace_processor/importers/proto/track_event_module.h",
"src/trace_processor/importers/proto/track_event_parser.cc",
@@ -2713,6 +2714,15 @@
],
)
+# GN target: //src/trace_processor/util:profiler_util
+perfetto_filegroup(
+ name = "src_trace_processor_util_profiler_util",
+ srcs = [
+ "src/trace_processor/util/profiler_util.cc",
+ "src/trace_processor/util/profiler_util.h",
+ ],
+)
+
# GN target: //src/trace_processor/util:proto_profiler
perfetto_filegroup(
name = "src_trace_processor_util_proto_profiler",
@@ -5590,6 +5600,7 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
+ ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
@@ -5759,6 +5770,7 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
+ ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
@@ -5980,6 +5992,7 @@
":src_trace_processor_util_gzip",
":src_trace_processor_util_interned_message_view",
":src_trace_processor_util_profile_builder",
+ ":src_trace_processor_util_profiler_util",
":src_trace_processor_util_proto_profiler",
":src_trace_processor_util_proto_to_args_parser",
":src_trace_processor_util_protozero_to_json",
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index dac6e41..823edd8 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -44,6 +44,8 @@
"slice_tracker.h",
"slice_translation_table.cc",
"slice_translation_table.h",
+ "stack_profile_tracker.cc",
+ "stack_profile_tracker.h",
"system_info_tracker.cc",
"system_info_tracker.h",
"trace_parser.cc",
@@ -66,7 +68,10 @@
"../../../base",
"../../db:minimal",
"../../storage",
+ "../../tables:tables",
"../../types",
+ "../../util:profiler_util",
+ "../../util:stack_traces_util",
"../fuchsia:fuchsia_record",
"../systrace:systrace_line",
]
diff --git a/src/trace_processor/importers/common/stack_profile_tracker.cc b/src/trace_processor/importers/common/stack_profile_tracker.cc
new file mode 100644
index 0000000..ad57523
--- /dev/null
+++ b/src/trace_processor/importers/common/stack_profile_tracker.cc
@@ -0,0 +1,160 @@
+/*
+ * 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/common/stack_profile_tracker.h"
+
+#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_view.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/tables/profiler_tables_py.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/profiler_util.h"
+#include "src/trace_processor/util/stack_traces_util.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+namespace {
+std::string CleanBuildId(base::StringView build_id) {
+ if (build_id.empty()) {
+ return build_id.ToStdString();
+ }
+ // If the build_id is 33 characters long, we assume it's a Breakpad debug
+ // identifier which is already in Hex and doesn't need conversion.
+ // TODO(b/148109467): Remove workaround once all active Chrome versions
+ // write raw bytes instead of a string as build_id.
+ if (util::IsHexModuleId(build_id)) {
+ return build_id.ToStdString();
+ }
+
+ return base::ToHex(build_id.data(), build_id.size());
+}
+
+} // namespace
+
+std::vector<FrameId> StackProfileTracker::JavaFramesForName(
+ NameInPackage name) const {
+ if (const auto* frames = java_frames_for_name_.Find(name); frames) {
+ return *frames;
+ }
+ return {};
+}
+
+std::vector<MappingId> StackProfileTracker::FindMappingRow(
+ StringId name,
+ StringId build_id) const {
+ if (const auto* mappings =
+ mappings_by_name_and_build_id_.Find(std::make_pair(name, build_id));
+ mappings) {
+ return *mappings;
+ }
+ return {};
+}
+
+std::vector<FrameId> StackProfileTracker::FindFrameIds(MappingId mapping_id,
+ uint64_t rel_pc) const {
+ if (const auto* frames =
+ frame_by_mapping_and_rel_pc_.Find(std::make_pair(mapping_id, rel_pc));
+ frames) {
+ return *frames;
+ }
+ return {};
+}
+
+MappingId StackProfileTracker::InternMapping(
+ const CreateMappingParams& params) {
+ tables::StackProfileMappingTable::Row row;
+ row.build_id = InternBuildId(params.build_id);
+ row.exact_offset = static_cast<int64_t>(params.exact_offset);
+ row.start_offset = static_cast<int64_t>(params.start_offset);
+ row.start = static_cast<int64_t>(params.start);
+ row.end = static_cast<int64_t>(params.end);
+ row.load_bias = static_cast<int64_t>(params.load_bias);
+ row.name = context_->storage->InternString(params.name);
+
+ if (MappingId* id = mapping_unique_row_index_.Find(row); id) {
+ return *id;
+ }
+
+ MappingId mapping_id =
+ context_->storage->mutable_stack_profile_mapping_table()->Insert(row).id;
+ mapping_unique_row_index_.Insert(row, mapping_id);
+ mappings_by_name_and_build_id_[{row.name, row.build_id}].push_back(
+ mapping_id);
+ return mapping_id;
+}
+
+CallsiteId StackProfileTracker::InternCallsite(
+ std::optional<CallsiteId> parent_callsite_id,
+ FrameId frame_id,
+ uint32_t depth) {
+ tables::StackProfileCallsiteTable::Row row{depth, parent_callsite_id,
+ frame_id};
+ if (CallsiteId* id = callsite_unique_row_index_.Find(row); id) {
+ return *id;
+ }
+
+ CallsiteId callsite_id =
+ context_->storage->mutable_stack_profile_callsite_table()->Insert(row).id;
+ callsite_unique_row_index_.Insert(row, callsite_id);
+ return callsite_id;
+}
+
+FrameId StackProfileTracker::InternFrame(MappingId mapping_id,
+ uint64_t rel_pc,
+ base::StringView function_name) {
+ tables::StackProfileFrameTable::Row row;
+ row.mapping = mapping_id;
+ row.rel_pc = static_cast<int64_t>(rel_pc);
+ row.name = context_->storage->InternString(function_name);
+
+ if (FrameId* id = frame_unique_row_index_.Find(row); id) {
+ return *id;
+ }
+
+ FrameId frame_id =
+ context_->storage->mutable_stack_profile_frame_table()->Insert(row).id;
+ frame_unique_row_index_.Insert(row, frame_id);
+ frame_by_mapping_and_rel_pc_[{mapping_id, rel_pc}].push_back(frame_id);
+
+ if (function_name.find('.') != base::StringView::npos) {
+ // Java frames always contain a '.'
+ base::StringView mapping_name = context_->storage->GetString(
+ context_->storage->stack_profile_mapping_table()
+ .FindById(mapping_id)
+ ->name());
+ std::optional<std::string> package =
+ PackageFromLocation(context_->storage.get(), mapping_name);
+ if (package) {
+ NameInPackage nip{row.name, context_->storage->InternString(
+ base::StringView(*package))};
+ java_frames_for_name_[nip].push_back(frame_id);
+ } else if (mapping_name.find("/memfd:") == 0) {
+ NameInPackage nip{row.name, context_->storage->InternString("memfd")};
+ java_frames_for_name_[nip].push_back(frame_id);
+ }
+ }
+
+ return frame_id;
+}
+
+StringId StackProfileTracker::InternBuildId(base::StringView build_id) {
+ return context_->storage->InternString(
+ base::StringView(CleanBuildId(build_id)));
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/common/stack_profile_tracker.h b/src/trace_processor/importers/common/stack_profile_tracker.h
new file mode 100644
index 0000000..a1067b8
--- /dev/null
+++ b/src/trace_processor/importers/common/stack_profile_tracker.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_STACK_PROFILE_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_STACK_PROFILE_TRACKER_H_
+
+#include <cstdint>
+#include <optional>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/hash.h"
+#include "perfetto/ext/base/string_view.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/tables/profiler_tables_py.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+struct NameInPackage {
+ StringId name;
+ StringId package;
+
+ bool operator==(const NameInPackage& b) const {
+ return std::tie(name, package) == std::tie(b.name, b.package);
+ }
+
+ struct Hasher {
+ size_t operator()(const NameInPackage& o) const {
+ return static_cast<size_t>(
+ base::Hasher::Combine(o.name.raw_id(), o.package.raw_id()));
+ }
+ };
+};
+
+class TraceProcessorContext;
+
+class StackProfileTracker {
+ public:
+ struct CreateMappingParams {
+ base::StringView build_id;
+ uint64_t exact_offset;
+ uint64_t start_offset;
+ uint64_t start;
+ uint64_t end;
+ uint64_t load_bias;
+ base::StringView name;
+ };
+
+ explicit StackProfileTracker(TraceProcessorContext* context)
+ : context_(context) {}
+
+ std::vector<FrameId> JavaFramesForName(NameInPackage name) const;
+ std::vector<MappingId> FindMappingRow(StringId name, StringId build_id) const;
+ std::vector<FrameId> FindFrameIds(MappingId mapping_id,
+ uint64_t rel_pc) const;
+
+ MappingId InternMapping(const CreateMappingParams& params);
+ CallsiteId InternCallsite(std::optional<CallsiteId> parent_callsite_id,
+ FrameId frame_id,
+ uint32_t depth);
+ FrameId InternFrame(MappingId mapping_id,
+ uint64_t rel_pc,
+ base::StringView function_name);
+
+ private:
+ StringId InternBuildId(base::StringView build_id);
+
+ TraceProcessorContext* const context_;
+ base::FlatHashMap<tables::StackProfileMappingTable::Row, MappingId>
+ mapping_unique_row_index_;
+ base::FlatHashMap<tables::StackProfileCallsiteTable::Row, CallsiteId>
+ callsite_unique_row_index_;
+ base::FlatHashMap<tables::StackProfileFrameTable::Row, FrameId>
+ frame_unique_row_index_;
+
+ struct MappingHasher {
+ size_t operator()(const std::pair<StringId, StringId>& o) const {
+ return static_cast<size_t>(
+ base::Hasher::Combine(o.first.raw_id(), o.second.raw_id()));
+ }
+ };
+ base::FlatHashMap<std::pair<StringId, StringId>,
+ std::vector<MappingId>,
+ MappingHasher>
+ mappings_by_name_and_build_id_;
+
+ struct FrameHasher {
+ size_t operator()(const std::pair<MappingId, uint64_t>& o) const {
+ return static_cast<size_t>(
+ base::Hasher::Combine(o.first.value, o.second));
+ }
+ };
+ base::FlatHashMap<std::pair<MappingId, uint64_t>,
+ std::vector<FrameId>,
+ FrameHasher>
+ frame_by_mapping_and_rel_pc_;
+
+ base::FlatHashMap<NameInPackage, std::vector<FrameId>, NameInPackage::Hasher>
+ java_frames_for_name_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_STACK_PROFILE_TRACKER_H_
diff --git a/src/trace_processor/importers/ftrace/BUILD.gn b/src/trace_processor/importers/ftrace/BUILD.gn
index 8065a41..c618978 100644
--- a/src/trace_processor/importers/ftrace/BUILD.gn
+++ b/src/trace_processor/importers/ftrace/BUILD.gn
@@ -68,6 +68,7 @@
"../../../../protos/perfetto/trace:zero",
"../../../../protos/perfetto/trace/ftrace:zero",
"../../../../protos/perfetto/trace/interned_data:zero",
+ "../../../../protos/perfetto/trace/profiling:zero",
"../../../protozero",
"../../sorter",
"../../storage",
@@ -76,6 +77,7 @@
"../common:parser_types",
"../i2c:full",
"../proto:minimal",
+ "../proto:packet_sequence_state_generation_hdr",
"../syscalls:full",
"../systrace:systrace_parser",
]
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index cfed1d1..951c03d 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -32,7 +32,7 @@
#include "src/trace_processor/importers/ftrace/v4l2_tracker.h"
#include "src/trace_processor/importers/ftrace/virtio_video_tracker.h"
#include "src/trace_processor/importers/i2c/i2c_tracker.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/importers/syscalls/syscall_tracker.h"
#include "src/trace_processor/importers/systrace/systrace_parser.h"
#include "src/trace_processor/storage/stats.h"
@@ -85,6 +85,7 @@
#include "protos/perfetto/trace/ftrace/vmscan.pbzero.h"
#include "protos/perfetto/trace/ftrace/workqueue.pbzero.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
index e61a137..d644742 100644
--- a/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
+++ b/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc
@@ -29,12 +29,12 @@
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/default_modules.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/metadata.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -236,8 +236,7 @@
context_.track_tracker.reset(new TrackTracker(&context_));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
- context_.global_stack_profile_tracker.reset(
- new GlobalStackProfileTracker());
+ context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
context_.args_tracker.reset(new ArgsTracker(&context_));
context_.args_translation_table.reset(new ArgsTranslationTable(storage_));
context_.metadata_tracker.reset(
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index a901ae1..2eaa5fe 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -26,8 +26,6 @@
"chrome_system_probes_parser.h",
"default_modules.cc",
"default_modules.h",
- "heap_profile_tracker.cc",
- "heap_profile_tracker.h",
"memory_tracker_snapshot_module.cc",
"memory_tracker_snapshot_module.h",
"memory_tracker_snapshot_parser.cc",
@@ -44,10 +42,10 @@
"perf_sample_tracker.h",
"profile_module.cc",
"profile_module.h",
+ "profile_packet_sequence_state.cc",
+ "profile_packet_sequence_state.h",
"profile_packet_utils.cc",
"profile_packet_utils.h",
- "profiler_util.cc",
- "profiler_util.h",
"proto_incremental_state.h",
"proto_trace_parser.cc",
"proto_trace_parser.h",
@@ -55,8 +53,8 @@
"proto_trace_reader.h",
"proto_trace_tokenizer.cc",
"proto_trace_tokenizer.h",
- "stack_profile_tracker.cc",
- "stack_profile_tracker.h",
+ "stack_profile_sequence_state.cc",
+ "stack_profile_sequence_state.h",
"track_event_module.cc",
"track_event_module.h",
"track_event_parser.cc",
@@ -94,6 +92,7 @@
"../../tables",
"../../types",
"../../util:gzip",
+ "../../util:profiler_util",
"../../util:stack_traces_util",
"../common",
"../common:parser_types",
@@ -155,6 +154,7 @@
":gen_cc_statsd_atoms_descriptor",
":gen_cc_trace_descriptor",
":minimal",
+ ":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
"../../../../include/perfetto/ext/traced:sys_stats_counters",
"../../../../protos/perfetto/common:zero",
@@ -178,8 +178,10 @@
"../../tables",
"../../types",
"../../util:descriptors",
+ "../../util:profiler_util",
"../../util:proto_profiler",
"../../util:proto_to_args_parser",
+ "../../util:stack_traces_util",
"../common",
"../common:parser_types",
"../etw:full",
@@ -243,9 +245,9 @@
sources = [
"active_chrome_processes_tracker_unittest.cc",
"heap_graph_tracker_unittest.cc",
- "heap_profile_tracker_unittest.cc",
"network_trace_module_unittest.cc",
"perf_sample_tracker_unittest.cc",
+ "profile_packet_sequence_state_unittest.cc",
"proto_trace_parser_unittest.cc",
"string_encoding_utils_unittests.cc",
]
@@ -273,6 +275,8 @@
"../../storage",
"../../types",
"../../util:descriptors",
+ "../../util:profiler_util",
+ "../../util:stack_traces_util",
"../common",
"../ftrace:full",
]
diff --git a/src/trace_processor/importers/proto/heap_graph_module.cc b/src/trace_processor/importers/proto/heap_graph_module.cc
index cc1d7ad..93fd468 100644
--- a/src/trace_processor/importers/proto/heap_graph_module.cc
+++ b/src/trace_processor/importers/proto/heap_graph_module.cc
@@ -19,9 +19,9 @@
#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
-#include "src/trace_processor/importers/proto/profiler_util.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/profiler_util.h"
#include "protos/perfetto/trace/profiling/deobfuscation.pbzero.h"
#include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index fcbd054..2e95889 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -22,8 +22,8 @@
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
#include "protos/perfetto/trace/profiling/heap_graph.pbzero.h"
-#include "src/trace_processor/importers/proto/profiler_util.h"
#include "src/trace_processor/tables/profiler_tables_py.h"
+#include "src/trace_processor/util/profiler_util.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc b/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
index 70c7398..ebc2a5e 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
@@ -18,7 +18,7 @@
#include "perfetto/base/logging.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/proto/profiler_util.h"
+#include "src/trace_processor/util/profiler_util.h"
#include "test/gtest_and_gmock.h"
namespace perfetto {
diff --git a/src/trace_processor/importers/proto/heap_profile_tracker.cc b/src/trace_processor/importers/proto/heap_profile_tracker.cc
deleted file mode 100644
index ea20108..0000000
--- a/src/trace_processor/importers/proto/heap_profile_tracker.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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_profile_tracker.h"
-
-#include "perfetto/base/logging.h"
-#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-HeapProfileTracker::HeapProfileTracker(TraceProcessorContext* context)
- : context_(context),
- empty_(context_->storage->InternString({"", 0})),
- art_heap_(context_->storage->InternString("com.android.art")) {}
-
-HeapProfileTracker::~HeapProfileTracker() = default;
-
-void HeapProfileTracker::SetProfilePacketIndex(uint32_t seq_id,
- uint64_t index) {
- SequenceState& sequence_state = sequence_state_[seq_id];
- bool dropped_packet = false;
- // heapprofd starts counting at index = 0.
- if (!sequence_state.prev_index && index != 0) {
- dropped_packet = true;
- }
-
- if (sequence_state.prev_index && *sequence_state.prev_index + 1 != index) {
- dropped_packet = true;
- }
-
- if (dropped_packet) {
- if (sequence_state.prev_index) {
- PERFETTO_ELOG("Missing packets between %" PRIu64 " and %" PRIu64,
- *sequence_state.prev_index, index);
- } else {
- PERFETTO_ELOG("Invalid first packet index %" PRIu64 " (!= 0)", index);
- }
-
- context_->storage->IncrementStats(stats::heapprofd_missing_packet);
- }
- sequence_state.prev_index = index;
-}
-
-void HeapProfileTracker::AddAllocation(
- uint32_t seq_id,
- SequenceStackProfileTracker* sequence_stack_profile_tracker,
- const SourceAllocation& alloc,
- const SequenceStackProfileTracker::InternLookup* intern_lookup) {
- SequenceState& sequence_state = sequence_state_[seq_id];
-
- auto opt_callstack_id = sequence_stack_profile_tracker->FindOrInsertCallstack(
- alloc.callstack_id, intern_lookup);
- if (!opt_callstack_id)
- return;
-
- CallsiteId callstack_id = *opt_callstack_id;
-
- UniquePid upid = context_->process_tracker->GetOrCreateProcess(
- static_cast<uint32_t>(alloc.pid));
-
- tables::HeapProfileAllocationTable::Row alloc_row{
- alloc.timestamp,
- upid,
- alloc.heap_name,
- callstack_id,
- static_cast<int64_t>(alloc.alloc_count),
- static_cast<int64_t>(alloc.self_allocated)};
-
- tables::HeapProfileAllocationTable::Row free_row{
- alloc.timestamp,
- upid,
- alloc.heap_name,
- callstack_id,
- -static_cast<int64_t>(alloc.free_count),
- -static_cast<int64_t>(alloc.self_freed)};
-
- auto prev_alloc_it = sequence_state.prev_alloc.find({upid, callstack_id});
- if (prev_alloc_it == sequence_state.prev_alloc.end()) {
- std::tie(prev_alloc_it, std::ignore) = sequence_state.prev_alloc.emplace(
- std::make_pair(upid, callstack_id),
- tables::HeapProfileAllocationTable::Row{});
- }
-
- tables::HeapProfileAllocationTable::Row& prev_alloc = prev_alloc_it->second;
-
- auto prev_free_it = sequence_state.prev_free.find({upid, callstack_id});
- if (prev_free_it == sequence_state.prev_free.end()) {
- std::tie(prev_free_it, std::ignore) = sequence_state.prev_free.emplace(
- std::make_pair(upid, callstack_id),
- tables::HeapProfileAllocationTable::Row{});
- }
-
- tables::HeapProfileAllocationTable::Row& prev_free = prev_free_it->second;
-
- std::set<CallsiteId>& callstacks_for_source_callstack_id =
- sequence_state.seen_callstacks[SourceAllocationIndex{
- upid, alloc.callstack_id, alloc.heap_name}];
- bool new_callstack;
- std::tie(std::ignore, new_callstack) =
- callstacks_for_source_callstack_id.emplace(callstack_id);
-
- if (new_callstack) {
- sequence_state.alloc_correction[alloc.callstack_id] = prev_alloc;
- sequence_state.free_correction[alloc.callstack_id] = prev_free;
- }
-
- auto alloc_correction_it =
- sequence_state.alloc_correction.find(alloc.callstack_id);
- if (alloc_correction_it != sequence_state.alloc_correction.end()) {
- const auto& alloc_correction = alloc_correction_it->second;
- alloc_row.count += alloc_correction.count;
- alloc_row.size += alloc_correction.size;
- }
-
- auto free_correction_it =
- sequence_state.free_correction.find(alloc.callstack_id);
- if (free_correction_it != sequence_state.free_correction.end()) {
- const auto& free_correction = free_correction_it->second;
- free_row.count += free_correction.count;
- free_row.size += free_correction.size;
- }
-
- tables::HeapProfileAllocationTable::Row alloc_delta = alloc_row;
- tables::HeapProfileAllocationTable::Row free_delta = free_row;
-
- alloc_delta.count -= prev_alloc.count;
- alloc_delta.size -= prev_alloc.size;
-
- free_delta.count -= prev_free.count;
- free_delta.size -= prev_free.size;
-
- if (alloc_delta.count < 0 || alloc_delta.size < 0 || free_delta.count > 0 ||
- free_delta.size > 0) {
- PERFETTO_DLOG("Non-monotonous allocation.");
- context_->storage->IncrementIndexedStats(stats::heapprofd_malformed_packet,
- static_cast<int>(upid));
- return;
- }
-
- // Dump at max profiles do not have .count set.
- if (alloc_delta.count || alloc_delta.size) {
- context_->storage->mutable_heap_profile_allocation_table()->Insert(
- alloc_delta);
- }
-
- // ART only reports allocations, and not frees. This throws off our logic
- // that assumes that if a new object was allocated with the same address,
- // the old one has to have been freed in the meantime.
- // See HeapTracker::RecordMalloc in bookkeeping.cc.
- if (alloc.heap_name != art_heap_ && (free_delta.count || free_delta.size)) {
- context_->storage->mutable_heap_profile_allocation_table()->Insert(
- free_delta);
- }
-
- prev_alloc = alloc_row;
- prev_free = free_row;
-}
-
-void HeapProfileTracker::StoreAllocation(uint32_t seq_id,
- SourceAllocation alloc) {
- SequenceState& sequence_state = sequence_state_[seq_id];
- sequence_state.pending_allocs.emplace_back(std::move(alloc));
-}
-
-void HeapProfileTracker::CommitAllocations(
- uint32_t seq_id,
- SequenceStackProfileTracker* sequence_stack_profile_tracker,
- const SequenceStackProfileTracker::InternLookup* intern_lookup) {
- SequenceState& sequence_state = sequence_state_[seq_id];
- for (const auto& p : sequence_state.pending_allocs)
- AddAllocation(seq_id, sequence_stack_profile_tracker, p, intern_lookup);
- sequence_state.pending_allocs.clear();
-}
-
-void HeapProfileTracker::FinalizeProfile(
- uint32_t seq_id,
- SequenceStackProfileTracker* sequence_stack_profile_tracker,
- const SequenceStackProfileTracker::InternLookup* intern_lookup) {
- CommitAllocations(seq_id, sequence_stack_profile_tracker, intern_lookup);
- sequence_stack_profile_tracker->ClearIndices();
-}
-
-void HeapProfileTracker::NotifyEndOfFile() {
- for (const auto& key_and_sequence_state : sequence_state_) {
- const SequenceState& sequence_state = key_and_sequence_state.second;
- if (!sequence_state.pending_allocs.empty()) {
- context_->storage->IncrementStats(stats::heapprofd_non_finalized_profile);
- }
- }
-}
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/heap_profile_tracker.h b/src/trace_processor/importers/proto/heap_profile_tracker.h
deleted file mode 100644
index 5ed5394..0000000
--- a/src/trace_processor/importers/proto/heap_profile_tracker.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_
-
-#include <optional>
-#include <set>
-#include <unordered_map>
-
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
-#include "src/trace_processor/storage/trace_storage.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class TraceProcessorContext;
-
-class HeapProfileTracker {
- public:
- struct SourceAllocation {
- uint64_t pid = 0;
- // This is int64_t, because we get this from the TraceSorter which also
- // converts this for us.
- int64_t timestamp = 0;
- StringPool::Id heap_name;
- SequenceStackProfileTracker::SourceCallstackId callstack_id = 0;
- uint64_t self_allocated = 0;
- uint64_t self_freed = 0;
- uint64_t alloc_count = 0;
- uint64_t free_count = 0;
- };
-
- void SetProfilePacketIndex(uint32_t seq_id, uint64_t id);
-
- explicit HeapProfileTracker(TraceProcessorContext* context);
-
- void StoreAllocation(uint32_t seq_id, SourceAllocation);
-
- // Call after the last profile packet of a dump to commit the allocations
- // that had been stored using StoreAllocation and clear internal indices
- // for that dump.
- void FinalizeProfile(
- uint32_t seq_id,
- SequenceStackProfileTracker* sequence_stack_profile_tracker,
- const SequenceStackProfileTracker::InternLookup* lookup);
-
- // Only commit the allocations that had been stored using StoreAllocations.
- // This is only needed in tests, use FinalizeProfile instead.
- void CommitAllocations(
- uint32_t seq_id,
- SequenceStackProfileTracker* sequence_stack_profile_tracker,
- const SequenceStackProfileTracker::InternLookup* lookup);
-
- void NotifyEndOfFile();
-
- ~HeapProfileTracker();
-
- private:
- void AddAllocation(
- uint32_t seq_id,
- SequenceStackProfileTracker* sequence_stack_profile_tracker,
- const SourceAllocation&,
- const SequenceStackProfileTracker::InternLookup* intern_lookup = nullptr);
- struct SourceAllocationIndex {
- UniquePid upid;
- SequenceStackProfileTracker::SourceCallstackId src_callstack_id;
- StringPool::Id heap_name;
- bool operator<(const SourceAllocationIndex& o) const {
- return std::tie(upid, src_callstack_id, heap_name) <
- std::tie(o.upid, o.src_callstack_id, o.heap_name);
- }
- };
- struct SequenceState {
- std::vector<SourceAllocation> pending_allocs;
-
- std::unordered_map<std::pair<UniquePid, CallsiteId>,
- tables::HeapProfileAllocationTable::Row>
- prev_alloc;
- std::unordered_map<std::pair<UniquePid, CallsiteId>,
- tables::HeapProfileAllocationTable::Row>
- prev_free;
-
- // For continuous dumps, we only store the delta in the data-base. To do
- // this, we subtract the previous dump's value. Sometimes, we should not
- // do that subtraction, because heapprofd garbage collects stacks that
- // have no unfreed allocations. If the application then allocations again
- // at that stack, it gets recreated and initialized to zero.
- //
- // To correct for this, we add the previous' stacks value to the current
- // one, and then handle it as normal. If it is the first time we see a
- // SourceCallstackId for a CallsiteId, we put the previous value into
- // the correction maps below.
- std::map<SourceAllocationIndex, std::set<CallsiteId>> seen_callstacks;
- std::map<SequenceStackProfileTracker::SourceCallstackId,
- tables::HeapProfileAllocationTable::Row>
- alloc_correction;
- std::map<SequenceStackProfileTracker::SourceCallstackId,
- tables::HeapProfileAllocationTable::Row>
- free_correction;
-
- std::optional<uint64_t> prev_index;
- };
- std::map<uint32_t, SequenceState> sequence_state_;
- TraceProcessorContext* const context_;
- const StringId empty_;
- const StringId art_heap_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_HEAP_PROFILE_TRACKER_H_
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
index 8c29222..2ad0c7b 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state.h
@@ -19,13 +19,12 @@
#include <stdint.h>
-#include <unordered_map>
+#include <memory>
+#include <type_traits>
#include <vector>
#include "perfetto/base/compiler.h"
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
-#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/interned_message_view.h"
@@ -34,19 +33,8 @@
class PacketSequenceState {
public:
- // Helper to keep per sequence state. These are not reset when the generation
- // changes.
- // Trackers or parsers can add their custom per sequence state here instead of
- // keeping a map from seq_id to some internal state.
- // TODO(carlscab): We should come up with a nicer API that allows extensions
- // to be notified of generation changes.
- // TODO(carlscab): There is some existing code that could use this. Migrate.
- struct ExtensibleSequenceState {
- std::unique_ptr<Destructible> v8_sequence_state;
- };
-
explicit PacketSequenceState(TraceProcessorContext* context)
- : context_(context), sequence_stack_profile_tracker_(context) {
+ : context_(context) {
current_generation_.reset(
new PacketSequenceStateGeneration(this, generation_index_++));
}
@@ -87,7 +75,7 @@
// sequence. Add a new generation with the updated defaults but the
// current generation's interned data state.
current_generation_.reset(new PacketSequenceStateGeneration(
- this, generation_index_++, current_generation_->interned_data_,
+ this, generation_index_++, current_generation_.get(),
std::move(defaults)));
}
@@ -119,14 +107,6 @@
bool IsIncrementalStateValid() const { return !packet_loss_; }
- SequenceStackProfileTracker& sequence_stack_profile_tracker() {
- return sequence_stack_profile_tracker_;
- }
-
- ExtensibleSequenceState& extensible_sequence_state() {
- return extensible_sequence_state_;
- }
-
// Returns a ref-counted ptr to the current generation.
RefPtr<PacketSequenceStateGeneration> current_generation() const {
return current_generation_;
@@ -174,20 +154,8 @@
int64_t track_event_thread_instruction_count_ = 0;
RefPtr<PacketSequenceStateGeneration> current_generation_;
- SequenceStackProfileTracker sequence_stack_profile_tracker_;
- ExtensibleSequenceState extensible_sequence_state_;
};
-template <uint32_t FieldId, typename MessageType>
-typename MessageType::Decoder*
-PacketSequenceStateGeneration::LookupInternedMessage(uint64_t iid) {
- auto* interned_message_view = GetInternedMessageView(FieldId, iid);
- if (!interned_message_view)
- return nullptr;
-
- return interned_message_view->template GetOrCreateDecoder<MessageType>();
-}
-
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
index 6e8e98d..1e89096 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
@@ -15,12 +15,38 @@
*/
#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include <cstddef>
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
namespace trace_processor {
+PacketSequenceStateGeneration::PacketSequenceStateGeneration(
+ PacketSequenceState* state,
+ size_t generation_index,
+ PacketSequenceStateGeneration* prev_gen,
+ TraceBlobView defaults)
+ : state_(state),
+ generation_index_(generation_index),
+ interned_data_(prev_gen->interned_data_),
+ trace_packet_defaults_(InternedMessageView(std::move(defaults))),
+ trackers_(prev_gen->trackers_) {
+ for (auto& t : trackers_) {
+ if (t.get() != nullptr) {
+ t->set_generation(this);
+ }
+ }
+}
+
+PacketSequenceStateGeneration::InternedDataTracker::~InternedDataTracker() =
+ default;
+
+TraceProcessorContext* PacketSequenceStateGeneration::GetContext() const {
+ return state_->context();
+}
+
void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
TraceBlobView message) {
constexpr auto kIidFieldNumber = 1;
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_generation.h b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
index 9c7aa5a..1f05d5c 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
@@ -17,10 +17,17 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
+#include <array>
+#include <cstddef>
+#include <memory>
#include <optional>
+#include <tuple>
+#include <type_traits>
#include <unordered_map>
+#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/ref_counted.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/util/interned_message_view.h"
#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
@@ -35,9 +42,65 @@
std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
class PacketSequenceState;
+class TraceProcessorContext;
+
+class StackProfileSequenceState;
+class ProfilePacketSequenceState;
+class V8SequenceState;
+
+using InternedDataTrackers = std::tuple<StackProfileSequenceState,
+ ProfilePacketSequenceState,
+ V8SequenceState>;
class PacketSequenceStateGeneration : public RefCounted {
public:
+ // Base class to add custom sequence state. This state is keep per sequence
+ // and per incremental state interval, that is, each time incremental state is
+ // reset a new instance is created but not each time `TracePacketDefaults` are
+ // updated. Note that this means that different
+ // `PacketSequenceStateGeneration` instances might point to the same
+ // `InternedDataTracker` (because they only differ in their
+ // `TracePacketDefaults`).
+ //
+ // ATTENTION: You should not create instances of these classes yourself but
+ // use the `PacketSequenceStateGeneration::GetOrCreate<>' method instead.
+ class InternedDataTracker : public RefCounted {
+ public:
+ virtual ~InternedDataTracker();
+
+ protected:
+ template <uint32_t FieldId, typename MessageType>
+ typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
+ return generation_->LookupInternedMessage<FieldId, MessageType>(iid);
+ }
+
+ InternedMessageView* GetInternedMessageView(uint32_t field_id,
+ uint64_t iid) {
+ return generation_->GetInternedMessageView(field_id, iid);
+ }
+
+ template <typename T>
+ std::remove_cv_t<T>* GetOrCreate() {
+ return generation_->GetOrCreate<T>();
+ }
+
+ private:
+ friend PacketSequenceStateGeneration;
+ // Called when the a new generation is created as a result of
+ // `TracePacketDefaults` being updated.
+ void set_generation(PacketSequenceStateGeneration* generation) {
+ generation_ = generation;
+ }
+
+ // Note: A `InternedDataTracker` instance can be linked to multiple
+ // `PacketSequenceStateGeneration` instances (when there are multiple
+ // `TracePacketDefaults` in the same interning context). `generation_` will
+ // point to the latest one. We keep this member private to prevent misuse /
+ // confusion around this fact. Instead subclasses should access the public
+ // methods of this class to get any interned data.
+ PacketSequenceStateGeneration* generation_ = nullptr;
+ };
+
// Returns |nullptr| if the message with the given |iid| was not found (also
// records a stat in this case).
template <uint32_t FieldId, typename MessageType>
@@ -79,21 +142,47 @@
PacketSequenceState* state() const { return state_; }
size_t generation_index() const { return generation_index_; }
+ // Extension point for custom sequence state. To add new per sequence state
+ // just subclass ´PacketSequenceStateGeneration´ and get your sequence bound
+ // instance by calling this method.
+ template <typename T>
+ std::remove_cv_t<T>* GetOrCreate();
+
private:
friend class PacketSequenceState;
+ // Helper to find the index in a tuple of a given type. Lookups are done
+ // ignoring cv qualifiers. If no index is found size of the tuple is returned.
+ //
+ // ATTENTION: Duplicate types in the tuple will trigger a compiler error.
+ template <typename Tuple, typename Type, size_t index = 0>
+ static constexpr size_t FindUniqueType() {
+ constexpr size_t kSize = std::tuple_size_v<Tuple>;
+ if constexpr (index < kSize) {
+ using TypeAtIndex = typename std::tuple_element<index, Tuple>::type;
+ if constexpr (std::is_same_v<std::remove_cv_t<Type>,
+ std::remove_cv_t<TypeAtIndex>>) {
+ static_assert(FindUniqueType<Tuple, Type, index + 1>() == kSize,
+ "Duplicate types.");
+ return index;
+ } else {
+ return FindUniqueType<Tuple, Type, index + 1>();
+ }
+ } else {
+ return kSize;
+ }
+ }
+
PacketSequenceStateGeneration(PacketSequenceState* state,
size_t generation_index)
: state_(state), generation_index_(generation_index) {}
PacketSequenceStateGeneration(PacketSequenceState* state,
size_t generation_index,
- InternedFieldMap interned_data,
- TraceBlobView defaults)
- : state_(state),
- generation_index_(generation_index),
- interned_data_(interned_data),
- trace_packet_defaults_(InternedMessageView(std::move(defaults))) {}
+ PacketSequenceStateGeneration* prev_gen,
+ TraceBlobView defaults);
+
+ TraceProcessorContext* GetContext() const;
void InternMessage(uint32_t field_id, TraceBlobView message);
@@ -107,8 +196,34 @@
size_t generation_index_;
InternedFieldMap interned_data_;
std::optional<InternedMessageView> trace_packet_defaults_;
+ std::array<RefPtr<InternedDataTracker>,
+ std::tuple_size_v<InternedDataTrackers>>
+ trackers_;
};
+template <typename T>
+std::remove_cv_t<T>* PacketSequenceStateGeneration::GetOrCreate() {
+ constexpr size_t index = FindUniqueType<InternedDataTrackers, T>();
+ static_assert(index < std::tuple_size_v<InternedDataTrackers>, "Not found");
+ auto& ptr = trackers_[index];
+ if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
+ ptr.reset(new T(GetContext()));
+ ptr->set_generation(this);
+ }
+
+ return static_cast<std::remove_cv_t<T>*>(ptr.get());
+}
+
+template <uint32_t FieldId, typename MessageType>
+typename MessageType::Decoder*
+PacketSequenceStateGeneration::LookupInternedMessage(uint64_t iid) {
+ auto* interned_message_view = GetInternedMessageView(FieldId, iid);
+ if (!interned_message_view)
+ return nullptr;
+
+ return interned_message_view->template GetOrCreateDecoder<MessageType>();
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_module.cc b/src/trace_processor/importers/proto/profile_module.cc
index c337869..61596d3 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -25,17 +25,18 @@
#include "src/trace_processor/importers/common/deobfuscation_mapping_table.h"
#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
+#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
-#include "src/trace_processor/importers/proto/profiler_util.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
+#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/stats.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/profiler_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/profiler_util.h"
#include "src/trace_processor/util/stack_traces_util.h"
#include "protos/perfetto/common/builtin_clock.pbzero.h"
@@ -91,8 +92,7 @@
ParsePerfSample(ts, data.sequence_state.get(), decoder);
return;
case TracePacket::kProfilePacketFieldNumber:
- ParseProfilePacket(ts, data.sequence_state.get(),
- decoder.trusted_packet_sequence_id(),
+ ParseProfilePacket(ts, data.sequence_state->state(),
decoder.profile_packet());
return;
case TracePacket::kModuleSymbolsFieldNumber:
@@ -152,9 +152,8 @@
ProcessTracker* procs = context_->process_tracker.get();
TraceStorage* storage = context_->storage.get();
- SequenceStackProfileTracker& sequence_stack_profile_tracker =
- sequence_state->state()->sequence_stack_profile_tracker();
- ProfilePacketInternLookup intern_lookup(sequence_state);
+ StackProfileSequenceState& stack_profile_sequence_state =
+ *sequence_state->GetOrCreate<StackProfileSequenceState>();
uint32_t pid = static_cast<uint32_t>(sequence_state->state()->pid());
uint32_t tid = static_cast<uint32_t>(sequence_state->state()->tid());
@@ -171,8 +170,8 @@
break;
}
- auto opt_cs_id = sequence_stack_profile_tracker.FindOrInsertCallstack(
- *callstack_it, &intern_lookup);
+ auto opt_cs_id =
+ stack_profile_sequence_state.FindOrInsertCallstack(*callstack_it);
if (!opt_cs_id) {
context_->storage->IncrementStats(stats::stackprofile_parser_error);
continue;
@@ -247,12 +246,11 @@
ts, static_cast<double>(sample.timebase_count()),
sampling_stream.timebase_track_id);
- SequenceStackProfileTracker& stack_tracker =
- sequence_state->state()->sequence_stack_profile_tracker();
- ProfilePacketInternLookup intern_lookup(sequence_state);
+ StackProfileSequenceState& stack_profile_sequence_state =
+ *sequence_state->GetOrCreate<StackProfileSequenceState>();
uint64_t callstack_iid = sample.callstack_iid();
std::optional<CallsiteId> cs_id =
- stack_tracker.FindOrInsertCallstack(callstack_iid, &intern_lookup);
+ stack_profile_sequence_state.FindOrInsertCallstack(callstack_iid);
// A failed lookup of the interned callstack can mean either:
// (a) This is a counter-only profile without callstacks. Due to an
@@ -298,45 +296,38 @@
context_->storage->mutable_perf_sample_table()->Insert(sample_row);
}
-void ProfileModule::ParseProfilePacket(
- int64_t ts,
- PacketSequenceStateGeneration* sequence_state,
- uint32_t seq_id,
- ConstBytes blob) {
+void ProfileModule::ParseProfilePacket(int64_t ts,
+ PacketSequenceState* sequence_state,
+ ConstBytes blob) {
+ ProfilePacketSequenceState& profile_packet_sequence_state =
+ *sequence_state->current_generation()
+ ->GetOrCreate<ProfilePacketSequenceState>();
protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
- context_->heap_profile_tracker->SetProfilePacketIndex(seq_id, packet.index());
+ profile_packet_sequence_state.SetProfilePacketIndex(packet.index());
for (auto it = packet.strings(); 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);
- sequence_state->state()->sequence_stack_profile_tracker().AddString(
- entry.iid(), str_view);
+ profile_packet_sequence_state.AddString(entry.iid(), str_view);
}
for (auto it = packet.mappings(); it; ++it) {
protos::pbzero::Mapping::Decoder entry(*it);
- SequenceStackProfileTracker::SourceMapping src_mapping =
- ProfilePacketUtils::MakeSourceMapping(entry);
- sequence_state->state()->sequence_stack_profile_tracker().AddMapping(
- entry.iid(), src_mapping);
+ profile_packet_sequence_state.AddMapping(
+ entry.iid(), ProfilePacketUtils::MakeSourceMapping(entry));
}
for (auto it = packet.frames(); it; ++it) {
protos::pbzero::Frame::Decoder entry(*it);
- SequenceStackProfileTracker::SourceFrame src_frame =
- ProfilePacketUtils::MakeSourceFrame(entry);
- sequence_state->state()->sequence_stack_profile_tracker().AddFrame(
- entry.iid(), src_frame);
+ profile_packet_sequence_state.AddFrame(
+ entry.iid(), ProfilePacketUtils::MakeSourceFrame(entry));
}
for (auto it = packet.callstacks(); it; ++it) {
protos::pbzero::Callstack::Decoder entry(*it);
- SequenceStackProfileTracker::SourceCallstack src_callstack =
- ProfilePacketUtils::MakeSourceCallstack(entry);
- sequence_state->state()->sequence_stack_profile_tracker().AddCallstack(
- entry.iid(), src_callstack);
+ profile_packet_sequence_state.AddCallstack(
+ entry.iid(), ProfilePacketUtils::MakeSourceCallstack(entry));
}
for (auto it = packet.process_dumps(); it; ++it) {
@@ -406,7 +397,7 @@
for (auto sample_it = entry.samples(); sample_it; ++sample_it) {
protos::pbzero::ProfilePacket::HeapSample::Decoder sample(*sample_it);
- HeapProfileTracker::SourceAllocation src_allocation;
+ ProfilePacketSequenceState::SourceAllocation src_allocation;
src_allocation.pid = entry.pid();
if (entry.heap_name().size != 0) {
src_allocation.heap_name =
@@ -427,15 +418,11 @@
src_allocation.free_count = sample.free_count();
}
- context_->heap_profile_tracker->StoreAllocation(seq_id, src_allocation);
+ profile_packet_sequence_state.StoreAllocation(src_allocation);
}
}
if (!packet.continued()) {
- PERFETTO_CHECK(sequence_state);
- ProfilePacketInternLookup intern_lookup(sequence_state);
- context_->heap_profile_tracker->FinalizeProfile(
- seq_id, &sequence_state->state()->sequence_stack_profile_tracker(),
- &intern_lookup);
+ profile_packet_sequence_state.FinalizeProfile();
}
}
@@ -451,7 +438,7 @@
module_symbols.build_id().data, module_symbols.build_id().size)));
}
- auto mapping_ids = context_->global_stack_profile_tracker->FindMappingRow(
+ auto mapping_ids = context_->stack_profile_tracker->FindMappingRow(
context_->storage->InternString(module_symbols.path()), build_id);
if (mapping_ids.empty()) {
context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
@@ -484,7 +471,7 @@
context_->args_translation_table->AddNativeSymbolTranslationRule(
mapping_id, address_symbols.address(), last_location);
std::vector<FrameId> frame_ids =
- context_->global_stack_profile_tracker->FindFrameIds(
+ context_->stack_profile_tracker->FindFrameIds(
mapping_id, address_symbols.address());
for (const FrameId frame_id : frame_ids) {
@@ -536,21 +523,16 @@
std::vector<tables::StackProfileFrameTable::Id> frames;
if (opt_package_name_id) {
- const std::vector<tables::StackProfileFrameTable::Id>* pkg_frames =
- context_->global_stack_profile_tracker->JavaFramesForName(
+ const std::vector<tables::StackProfileFrameTable::Id> pkg_frames =
+ context_->stack_profile_tracker->JavaFramesForName(
{*merged_obfuscated_id, *opt_package_name_id});
- if (pkg_frames) {
- frames.insert(frames.end(), pkg_frames->begin(), pkg_frames->end());
- }
+ frames.insert(frames.end(), pkg_frames.begin(), pkg_frames.end());
}
if (opt_memfd_id) {
- const std::vector<tables::StackProfileFrameTable::Id>* memfd_frames =
- context_->global_stack_profile_tracker->JavaFramesForName(
+ const std::vector<tables::StackProfileFrameTable::Id> memfd_frames =
+ context_->stack_profile_tracker->JavaFramesForName(
{*merged_obfuscated_id, *opt_memfd_id});
- if (memfd_frames) {
- frames.insert(frames.end(), memfd_frames->begin(),
- memfd_frames->end());
- }
+ frames.insert(frames.end(), memfd_frames.begin(), memfd_frames.end());
}
for (tables::StackProfileFrameTable::Id frame_id : frames) {
diff --git a/src/trace_processor/importers/proto/profile_module.h b/src/trace_processor/importers/proto/profile_module.h
index e6674d7..883fb7a 100644
--- a/src/trace_processor/importers/proto/profile_module.h
+++ b/src/trace_processor/importers/proto/profile_module.h
@@ -65,8 +65,7 @@
// heap profiling:
void ParseProfilePacket(int64_t ts,
- PacketSequenceStateGeneration*,
- uint32_t seq_id,
+ PacketSequenceState*,
protozero::ConstBytes);
void ParseDeobfuscationMapping(int64_t ts,
PacketSequenceStateGeneration*,
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
new file mode 100644
index 0000000..9d889ef
--- /dev/null
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
@@ -0,0 +1,287 @@
+/*
+ * 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/profile_packet_sequence_state.h"
+
+#include "perfetto/base/flat_set.h"
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_view.h"
+#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/profile_packet_utils.h"
+#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
+#include "src/trace_processor/storage/stats.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+const char kArtHeapName[] = "com.android.art";
+}
+
+ProfilePacketSequenceState::ProfilePacketSequenceState(
+ TraceProcessorContext* context)
+ : context_(context) {
+ strings_.Insert(0, "");
+}
+
+ProfilePacketSequenceState::~ProfilePacketSequenceState() = default;
+
+void ProfilePacketSequenceState::SetProfilePacketIndex(uint64_t index) {
+ bool dropped_packet = false;
+ // heapprofd starts counting at index = 0.
+ if (!prev_index.has_value() && index != 0) {
+ dropped_packet = true;
+ }
+
+ if (prev_index.has_value() && *prev_index + 1 != index) {
+ dropped_packet = true;
+ }
+
+ if (dropped_packet) {
+ context_->storage->IncrementStats(stats::heapprofd_missing_packet);
+ }
+ prev_index = index;
+}
+
+void ProfilePacketSequenceState::AddString(SourceStringId id,
+ base::StringView str) {
+ PERFETTO_CHECK(id != 0 || str.empty());
+ strings_.Insert(id, str.ToStdString());
+}
+
+void ProfilePacketSequenceState::AddMapping(SourceMappingId id,
+ const SourceMapping& mapping) {
+ StackProfileTracker::CreateMappingParams params;
+ if (std::string* str = strings_.Find(mapping.build_id); str) {
+ params.build_id = base::StringView(*str);
+ } else {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ return;
+ }
+ params.exact_offset = mapping.exact_offset;
+ params.start_offset = mapping.start_offset;
+ params.start = mapping.start;
+ params.end = mapping.end;
+ params.load_bias = mapping.load_bias;
+
+ std::vector<base::StringView> path_components;
+ path_components.reserve(mapping.name_ids.size());
+ for (SourceStringId string_id : mapping.name_ids) {
+ if (std::string* str = strings_.Find(string_id); str) {
+ path_components.push_back(base::StringView(*str));
+ } else {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ // For backward compatibility reasons we do not return an error but
+ // instead stop adding path components.
+ break;
+ }
+ }
+ std::string path = ProfilePacketUtils::MakeMappingName(path_components);
+ params.name = base::StringView(path);
+ MappingId mapping_id = context_->stack_profile_tracker->InternMapping(params);
+ mappings_.Insert(id, mapping_id);
+}
+
+void ProfilePacketSequenceState::AddFrame(SourceFrameId id,
+ const SourceFrame& frame) {
+ MappingId* mapping_id = mappings_.Find(frame.mapping_id);
+ if (!mapping_id) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
+ return;
+ }
+
+ std::string* function_name = strings_.Find(frame.name_id);
+ if (!function_name) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ return;
+ }
+
+ FrameId frame_id = context_->stack_profile_tracker->InternFrame(
+ *mapping_id, frame.rel_pc, base::StringView(*function_name));
+
+ frames_.Insert(id, frame_id);
+}
+
+void ProfilePacketSequenceState::AddCallstack(
+ SourceCallstackId id,
+ const SourceCallstack& callstack) {
+ std::optional<CallsiteId> parent_callsite_id;
+ uint32_t depth = 0;
+ for (SourceFrameId source_frame_id : callstack) {
+ FrameId* frame_id = frames_.Find(source_frame_id);
+ if (!frame_id) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
+ return;
+ }
+ parent_callsite_id = context_->stack_profile_tracker->InternCallsite(
+ parent_callsite_id, *frame_id, depth);
+ ++depth;
+ }
+
+ if (!parent_callsite_id) {
+ context_->storage->IncrementStats(stats::stackprofile_empty_callstack);
+ return;
+ }
+
+ callstacks_.Insert(id, *parent_callsite_id);
+}
+
+void ProfilePacketSequenceState::StoreAllocation(
+ const SourceAllocation& alloc) {
+ pending_allocs_.push_back(std::move(alloc));
+}
+
+void ProfilePacketSequenceState::CommitAllocations() {
+ for (const SourceAllocation& alloc : pending_allocs_)
+ AddAllocation(alloc);
+ pending_allocs_.clear();
+}
+
+void ProfilePacketSequenceState::FinalizeProfile() {
+ CommitAllocations();
+ strings_.Clear();
+ mappings_.Clear();
+ frames_.Clear();
+ callstacks_.Clear();
+}
+
+FrameId ProfilePacketSequenceState::GetDatabaseFrameIdForTesting(
+ SourceFrameId source_frame_id) {
+ FrameId* frame_id = frames_.Find(source_frame_id);
+ if (!frame_id) {
+ PERFETTO_DLOG("Invalid frame.");
+ return {};
+ }
+ return *frame_id;
+}
+
+void ProfilePacketSequenceState::AddAllocation(const SourceAllocation& alloc) {
+ auto opt_callstack_id = FindOrInsertCallstack(alloc.callstack_id);
+ if (!opt_callstack_id)
+ return;
+
+ CallsiteId callstack_id = *opt_callstack_id;
+
+ UniquePid upid = context_->process_tracker->GetOrCreateProcess(
+ static_cast<uint32_t>(alloc.pid));
+
+ tables::HeapProfileAllocationTable::Row alloc_row{
+ alloc.timestamp,
+ upid,
+ alloc.heap_name,
+ callstack_id,
+ static_cast<int64_t>(alloc.alloc_count),
+ static_cast<int64_t>(alloc.self_allocated)};
+
+ tables::HeapProfileAllocationTable::Row free_row{
+ alloc.timestamp,
+ upid,
+ alloc.heap_name,
+ callstack_id,
+ -static_cast<int64_t>(alloc.free_count),
+ -static_cast<int64_t>(alloc.self_freed)};
+
+ auto* prev_alloc = prev_alloc_.Find({upid, callstack_id});
+ if (!prev_alloc) {
+ prev_alloc = prev_alloc_
+ .Insert(std::make_pair(upid, callstack_id),
+ tables::HeapProfileAllocationTable::Row{})
+ .first;
+ }
+
+ auto* prev_free = prev_free_.Find({upid, callstack_id});
+ if (!prev_free) {
+ prev_free = prev_free_
+ .Insert(std::make_pair(upid, callstack_id),
+ tables::HeapProfileAllocationTable::Row{})
+ .first;
+ }
+
+ base::FlatSet<CallsiteId>& callstacks_for_source_callstack_id =
+ seen_callstacks_[SourceAllocationIndex{upid, alloc.callstack_id,
+ alloc.heap_name}];
+ bool new_callstack;
+ std::tie(std::ignore, new_callstack) =
+ callstacks_for_source_callstack_id.insert(callstack_id);
+
+ if (new_callstack) {
+ alloc_correction_[alloc.callstack_id] = *prev_alloc;
+ free_correction_[alloc.callstack_id] = *prev_free;
+ }
+
+ const auto* alloc_correction = alloc_correction_.Find(alloc.callstack_id);
+ if (alloc_correction) {
+ alloc_row.count += alloc_correction->count;
+ alloc_row.size += alloc_correction->size;
+ }
+
+ const auto* free_correction = free_correction_.Find(alloc.callstack_id);
+ if (free_correction) {
+ free_row.count += free_correction->count;
+ free_row.size += free_correction->size;
+ }
+
+ tables::HeapProfileAllocationTable::Row alloc_delta = alloc_row;
+ tables::HeapProfileAllocationTable::Row free_delta = free_row;
+
+ alloc_delta.count -= prev_alloc->count;
+ alloc_delta.size -= prev_alloc->size;
+
+ free_delta.count -= prev_free->count;
+ free_delta.size -= prev_free->size;
+
+ if (alloc_delta.count < 0 || alloc_delta.size < 0 || free_delta.count > 0 ||
+ free_delta.size > 0) {
+ PERFETTO_DLOG("Non-monotonous allocation.");
+ context_->storage->IncrementIndexedStats(stats::heapprofd_malformed_packet,
+ static_cast<int>(upid));
+ return;
+ }
+
+ // Dump at max profiles do not have .count set.
+ if (alloc_delta.count || alloc_delta.size) {
+ context_->storage->mutable_heap_profile_allocation_table()->Insert(
+ alloc_delta);
+ }
+
+ // ART only reports allocations, and not frees. This throws off our logic
+ // that assumes that if a new object was allocated with the same address,
+ // the old one has to have been freed in the meantime.
+ // See HeapTracker::RecordMalloc in bookkeeping.cc.
+ if (context_->storage->GetString(alloc.heap_name) != kArtHeapName &&
+ (free_delta.count || free_delta.size)) {
+ context_->storage->mutable_heap_profile_allocation_table()->Insert(
+ free_delta);
+ }
+
+ *prev_alloc = alloc_row;
+ *prev_free = free_row;
+}
+
+std::optional<CallsiteId> ProfilePacketSequenceState::FindOrInsertCallstack(
+ uint64_t iid) {
+ if (CallsiteId* id = callstacks_.Find(iid); id) {
+ return *id;
+ }
+ return GetOrCreate<StackProfileSequenceState>()->FindOrInsertCallstack(iid);
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.h b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
new file mode 100644
index 0000000..678aab2
--- /dev/null
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_
+
+#include <cstdint>
+#include "perfetto/base/flat_set.h"
+#include "perfetto/ext/base/flat_hash_map.h"
+
+#include "perfetto/ext/base/hash.h"
+#include "perfetto/ext/base/string_view.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Keeps sequence specific state for profile packets.
+class ProfilePacketSequenceState final
+ : public PacketSequenceStateGeneration::InternedDataTracker {
+ public:
+ using SourceStringId = uint64_t;
+
+ struct SourceMapping {
+ SourceStringId build_id = 0;
+ uint64_t exact_offset = 0;
+ uint64_t start_offset = 0;
+ uint64_t start = 0;
+ uint64_t end = 0;
+ uint64_t load_bias = 0;
+ std::vector<SourceStringId> name_ids;
+ };
+ using SourceMappingId = uint64_t;
+
+ struct SourceFrame {
+ SourceStringId name_id = 0;
+ SourceMappingId mapping_id = 0;
+ uint64_t rel_pc = 0;
+ };
+ using SourceFrameId = uint64_t;
+
+ using SourceCallstack = std::vector<SourceFrameId>;
+ using SourceCallstackId = uint64_t;
+ struct SourceAllocation {
+ uint64_t pid = 0;
+ // This is int64_t, because we get this from the TraceSorter which also
+ // converts this for us.
+ int64_t timestamp = 0;
+ StringId heap_name;
+ uint64_t callstack_id = 0;
+ uint64_t self_allocated = 0;
+ uint64_t self_freed = 0;
+ uint64_t alloc_count = 0;
+ uint64_t free_count = 0;
+ };
+
+ explicit ProfilePacketSequenceState(TraceProcessorContext* context);
+ virtual ~ProfilePacketSequenceState() override;
+
+ // Profile packets keep track of a index to detect packet loss. Call this
+ // method to update this index with the latest seen value.
+ void SetProfilePacketIndex(uint64_t index);
+
+ // In Android version Q we did not intern Mappings, Frames nor Callstacks,
+ // instead the profile packed "interned these". The following methods are used
+ // to support this old use case. They add the given object to a sequence local
+ // index for them to be retrieved later (see Find* Lookup* methods).
+ void AddString(SourceStringId id, base::StringView str);
+ void AddMapping(SourceMappingId id, const SourceMapping& mapping);
+ void AddFrame(SourceFrameId id, const SourceFrame& frame);
+ void AddCallstack(SourceCallstackId id, const SourceCallstack& callstack);
+
+ void StoreAllocation(const SourceAllocation& allocation);
+ void FinalizeProfile();
+ void CommitAllocations();
+
+ FrameId GetDatabaseFrameIdForTesting(SourceFrameId);
+
+ private:
+ struct SourceAllocationIndex {
+ UniquePid upid;
+ SourceCallstackId src_callstack_id;
+ StringPool::Id heap_name;
+ bool operator==(const SourceAllocationIndex& o) const {
+ return std::tie(upid, src_callstack_id, heap_name) ==
+ std::tie(o.upid, o.src_callstack_id, o.heap_name);
+ }
+ struct Hasher {
+ size_t operator()(const SourceAllocationIndex& o) const {
+ return static_cast<size_t>(base::Hasher::Combine(
+ o.upid, o.src_callstack_id, o.heap_name.raw_id()));
+ }
+ };
+ };
+
+ void AddAllocation(const SourceAllocation& alloc);
+
+ // The following methods deal with interned data. In Android version Q we did
+ // not intern Mappings, Frames nor Callstacks, instead the profile packed
+ // "interned these" and this class keeps those ina sequence local index. In
+ // newer versions, these objects are in InternedData (see
+ // protos/perfetto/trace/interned_data) and are shared across multiple
+ // ProfilePackets. For backwards compatibility, the following methods first
+ // look up interned data in the private sequence local index (for values added
+ // via the Add* methods), and then, if this lookup fails, in the InternedData
+ // instead.
+ std::optional<MappingId> FindOrInsertMapping(uint64_t iid);
+ std::optional<CallsiteId> FindOrInsertCallstack(uint64_t iid);
+
+ TraceProcessorContext* const context_;
+
+ base::FlatHashMap<SourceStringId, std::string> strings_;
+ base::FlatHashMap<SourceMappingId, MappingId> mappings_;
+ base::FlatHashMap<SourceFrameId, FrameId> frames_;
+ base::FlatHashMap<SourceCallstackId, CallsiteId> callstacks_;
+
+ std::vector<SourceAllocation> pending_allocs_;
+
+ struct Hasher {
+ size_t operator()(const std::pair<UniquePid, CallsiteId>& p) const {
+ return static_cast<size_t>(
+ base::Hasher::Combine(p.first, p.second.value));
+ }
+ };
+ base::FlatHashMap<std::pair<UniquePid, CallsiteId>,
+ tables::HeapProfileAllocationTable::Row,
+ Hasher>
+ prev_alloc_;
+ base::FlatHashMap<std::pair<UniquePid, CallsiteId>,
+ tables::HeapProfileAllocationTable::Row,
+ Hasher>
+ prev_free_;
+
+ // For continuous dumps, we only store the delta in the data-base. To do
+ // this, we subtract the previous dump's value. Sometimes, we should not
+ // do that subtraction, because heapprofd garbage collects stacks that
+ // have no unfreed allocations. If the application then allocations again
+ // at that stack, it gets recreated and initialized to zero.
+ //
+ // To correct for this, we add the previous' stacks value to the current
+ // one, and then handle it as normal. If it is the first time we see a
+ // SourceCallstackId for a CallsiteId, we put the previous value into
+ // the correction maps below.
+ base::FlatHashMap<SourceAllocationIndex,
+ base::FlatSet<CallsiteId>,
+ SourceAllocationIndex::Hasher>
+ seen_callstacks_;
+ base::FlatHashMap<SourceCallstackId, tables::HeapProfileAllocationTable::Row>
+ alloc_correction_;
+ base::FlatHashMap<SourceCallstackId, tables::HeapProfileAllocationTable::Row>
+ free_correction_;
+
+ std::optional<uint64_t> prev_index;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILE_PACKET_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
similarity index 74%
rename from src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc
rename to src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
index 558ad91..ab947fa 100644
--- a/src/trace_processor/importers/proto/heap_profile_tracker_unittest.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
@@ -14,9 +14,12 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
+#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
+#include <memory>
+
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -40,7 +43,6 @@
constexpr auto kMappingStart = 234;
constexpr auto kMappingEnd = 345;
constexpr auto kMappingLoadBias = 456;
-constexpr auto kDefaultSequence = 1;
// heapprofd on Android Q has large callstack ideas, explicitly test large
// values.
@@ -56,10 +58,8 @@
public:
HeapProfileTrackerDupTest() {
context.storage.reset(new TraceStorage());
- context.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
- sequence_stack_profile_tracker.reset(
- new SequenceStackProfileTracker(&context));
- context.heap_profile_tracker.reset(new HeapProfileTracker(&context));
+ context.stack_profile_tracker.reset(new StackProfileTracker(&context));
+ packet_sequence_state.reset(new PacketSequenceState(&context));
mapping_name = context.storage->InternString("[mapping]");
fully_qualified_mapping_name = context.storage->InternString("/[mapping]");
@@ -68,13 +68,17 @@
}
protected:
+ ProfilePacketSequenceState& profile_packet_sequence_state() {
+ return *packet_sequence_state->current_generation()
+ ->GetOrCreate<ProfilePacketSequenceState>();
+ }
void InsertMapping(const Packet& packet) {
- sequence_stack_profile_tracker->AddString(packet.mapping_name_id,
+ profile_packet_sequence_state().AddString(packet.mapping_name_id,
"[mapping]");
- sequence_stack_profile_tracker->AddString(packet.build_id, kBuildIDName);
+ profile_packet_sequence_state().AddString(packet.build_id, kBuildIDName);
- SequenceStackProfileTracker::SourceMapping first_frame;
+ ProfilePacketSequenceState::SourceMapping first_frame;
first_frame.build_id = packet.build_id;
first_frame.exact_offset = kMappingExactOffset;
first_frame.start_offset = kMappingStartOffset;
@@ -83,27 +87,27 @@
first_frame.load_bias = kMappingLoadBias;
first_frame.name_ids = {packet.mapping_name_id};
- sequence_stack_profile_tracker->AddMapping(packet.mapping_id, first_frame);
+ profile_packet_sequence_state().AddMapping(packet.mapping_id, first_frame);
}
void InsertFrame(const Packet& packet) {
InsertMapping(packet);
- sequence_stack_profile_tracker->AddString(packet.frame_name_id, "[frame]");
+ profile_packet_sequence_state().AddString(packet.frame_name_id, "[frame]");
- SequenceStackProfileTracker::SourceFrame first_frame;
+ ProfilePacketSequenceState::SourceFrame first_frame;
first_frame.name_id = packet.frame_name_id;
first_frame.mapping_id = packet.mapping_id;
first_frame.rel_pc = kFrameRelPc;
- sequence_stack_profile_tracker->AddFrame(packet.frame_id, first_frame);
+ profile_packet_sequence_state().AddFrame(packet.frame_id, first_frame);
}
void InsertCallsite(const Packet& packet) {
InsertFrame(packet);
- SequenceStackProfileTracker::SourceCallstack first_callsite = {
+ ProfilePacketSequenceState::SourceCallstack first_callsite = {
packet.frame_id, packet.frame_id};
- sequence_stack_profile_tracker->AddCallstack(kCallstackId, first_callsite);
+ profile_packet_sequence_state().AddCallstack(kCallstackId, first_callsite);
}
StringId mapping_name;
@@ -111,18 +115,16 @@
StringId build;
StringId frame_name;
TraceProcessorContext context;
- std::unique_ptr<SequenceStackProfileTracker> sequence_stack_profile_tracker;
+ std::unique_ptr<PacketSequenceState> packet_sequence_state;
};
// Insert the same mapping from two different packets, with different strings
// interned, and assert we only store one.
TEST_F(HeapProfileTrackerDupTest, Mapping) {
InsertMapping(kFirstPacket);
- context.heap_profile_tracker->FinalizeProfile(
- kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
+ profile_packet_sequence_state().FinalizeProfile();
InsertMapping(kSecondPacket);
- context.heap_profile_tracker->FinalizeProfile(
- kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
+ profile_packet_sequence_state().FinalizeProfile();
EXPECT_THAT(context.storage->stack_profile_mapping_table().build_id()[0],
context.storage->InternString({kBuildIDHexName}));
@@ -144,11 +146,9 @@
// interned, and assert we only store one.
TEST_F(HeapProfileTrackerDupTest, Frame) {
InsertFrame(kFirstPacket);
- context.heap_profile_tracker->FinalizeProfile(
- kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
+ profile_packet_sequence_state().FinalizeProfile();
InsertFrame(kSecondPacket);
- context.heap_profile_tracker->FinalizeProfile(
- kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
+ profile_packet_sequence_state().FinalizeProfile();
const auto& frames = context.storage->stack_profile_frame_table();
EXPECT_THAT(frames.name()[0], frame_name);
@@ -160,11 +160,9 @@
// stored once.
TEST_F(HeapProfileTrackerDupTest, Callstack) {
InsertCallsite(kFirstPacket);
- context.heap_profile_tracker->FinalizeProfile(
- kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
+ profile_packet_sequence_state().FinalizeProfile();
InsertCallsite(kSecondPacket);
- context.heap_profile_tracker->FinalizeProfile(
- kDefaultSequence, sequence_stack_profile_tracker.get(), nullptr);
+ profile_packet_sequence_state().FinalizeProfile();
const auto& callsite_table = context.storage->stack_profile_callsite_table();
const auto& depth = callsite_table.depth();
@@ -198,22 +196,20 @@
TEST(HeapProfileTrackerTest, SourceMappingPath) {
TraceProcessorContext context;
context.storage.reset(new TraceStorage());
- context.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
- context.heap_profile_tracker.reset(new HeapProfileTracker(&context));
-
- HeapProfileTracker* hpt = context.heap_profile_tracker.get();
- std::unique_ptr<SequenceStackProfileTracker> spt(
- new SequenceStackProfileTracker(&context));
+ context.stack_profile_tracker.reset(new StackProfileTracker(&context));
+ PacketSequenceState pss(&context);
+ ProfilePacketSequenceState& ppss =
+ *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
constexpr auto kBuildId = 1u;
constexpr auto kMappingNameId1 = 2u;
constexpr auto kMappingNameId2 = 3u;
- spt->AddString(kBuildId, "buildid");
- spt->AddString(kMappingNameId1, "foo");
- spt->AddString(kMappingNameId2, "bar");
+ ppss.AddString(kBuildId, "buildid");
+ ppss.AddString(kMappingNameId1, "foo");
+ ppss.AddString(kMappingNameId2, "bar");
- SequenceStackProfileTracker::SourceMapping mapping;
+ ProfilePacketSequenceState::SourceMapping mapping;
mapping.build_id = kBuildId;
mapping.exact_offset = 1;
mapping.start_offset = 1;
@@ -221,8 +217,8 @@
mapping.end = 3;
mapping.load_bias = 0;
mapping.name_ids = {kMappingNameId1, kMappingNameId2};
- spt->AddMapping(0, mapping);
- hpt->CommitAllocations(kDefaultSequence, spt.get(), nullptr);
+ ppss.AddMapping(0, mapping);
+ ppss.CommitAllocations();
auto foo_bar_id = context.storage->string_pool().GetId("/foo/bar");
ASSERT_NE(foo_bar_id, std::nullopt);
EXPECT_THAT(context.storage->stack_profile_mapping_table().name()[0],
@@ -233,12 +229,11 @@
TEST(HeapProfileTrackerTest, Functional) {
TraceProcessorContext context;
context.storage.reset(new TraceStorage());
- context.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
- context.heap_profile_tracker.reset(new HeapProfileTracker(&context));
+ context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- HeapProfileTracker* hpt = context.heap_profile_tracker.get();
- std::unique_ptr<SequenceStackProfileTracker> spt(
- new SequenceStackProfileTracker(&context));
+ PacketSequenceState pss(&context);
+ ProfilePacketSequenceState& ppss =
+ *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
uint32_t next_string_intern_id = 1;
@@ -252,7 +247,7 @@
for (size_t i = 0; i < base::ArraySize(mapping_names); ++i)
mapping_name_ids[i] = next_string_intern_id++;
- SequenceStackProfileTracker::SourceMapping
+ ProfilePacketSequenceState::SourceMapping
mappings[base::ArraySize(mapping_names)] = {};
mappings[0].build_id = build_id_ids[0];
mappings[0].exact_offset = 1;
@@ -283,7 +278,7 @@
for (size_t i = 0; i < base::ArraySize(function_names); ++i)
function_name_ids[i] = next_string_intern_id++;
- SequenceStackProfileTracker::SourceFrame
+ ProfilePacketSequenceState::SourceFrame
frames[base::ArraySize(function_names)];
frames[0].name_id = function_name_ids[0];
frames[0].mapping_id = 0;
@@ -301,41 +296,41 @@
frames[3].mapping_id = 2;
frames[3].rel_pc = 123;
- SequenceStackProfileTracker::SourceCallstack callstacks[3];
+ ProfilePacketSequenceState::SourceCallstack callstacks[3];
callstacks[0] = {2, 1, 0};
callstacks[1] = {2, 1, 0, 1, 0};
callstacks[2] = {0, 2, 0, 1, 2};
for (size_t i = 0; i < base::ArraySize(build_ids); ++i) {
auto interned = base::StringView(build_ids[i].data(), build_ids[i].size());
- spt->AddString(build_id_ids[i], interned);
+ ppss.AddString(build_id_ids[i], interned);
}
for (size_t i = 0; i < base::ArraySize(mapping_names); ++i) {
auto interned =
base::StringView(mapping_names[i].data(), mapping_names[i].size());
- spt->AddString(mapping_name_ids[i], interned);
+ ppss.AddString(mapping_name_ids[i], interned);
}
for (size_t i = 0; i < base::ArraySize(function_names); ++i) {
auto interned =
base::StringView(function_names[i].data(), function_names[i].size());
- spt->AddString(function_name_ids[i], interned);
+ ppss.AddString(function_name_ids[i], interned);
}
for (uint32_t i = 0; i < base::ArraySize(mappings); ++i)
- spt->AddMapping(i, mappings[i]);
+ ppss.AddMapping(i, mappings[i]);
for (uint32_t i = 0; i < base::ArraySize(frames); ++i)
- spt->AddFrame(i, frames[i]);
+ ppss.AddFrame(i, frames[i]);
for (uint32_t i = 0; i < base::ArraySize(callstacks); ++i)
- spt->AddCallstack(i, callstacks[i]);
+ ppss.AddCallstack(i, callstacks[i]);
- hpt->CommitAllocations(kDefaultSequence, spt.get(), nullptr);
+ ppss.CommitAllocations();
for (size_t i = 0; i < base::ArraySize(callstacks); ++i) {
std::optional<CallsiteId> parent;
- const SequenceStackProfileTracker::SourceCallstack& callstack =
+ const ProfilePacketSequenceState::SourceCallstack& callstack =
callstacks[i];
for (size_t depth = 0; depth < callstack.size(); ++depth) {
- auto frame_id = spt->GetDatabaseFrameIdForTesting(callstack[depth]);
+ auto frame_id = ppss.GetDatabaseFrameIdForTesting(callstack[depth]);
std::optional<CallsiteId> self = FindCallstack(
*context.storage, static_cast<int64_t>(depth), parent, frame_id);
ASSERT_TRUE(self.has_value());
@@ -343,7 +338,7 @@
}
}
- hpt->FinalizeProfile(kDefaultSequence, spt.get(), nullptr);
+ ppss.FinalizeProfile();
}
} // namespace
diff --git a/src/trace_processor/importers/proto/profile_packet_utils.cc b/src/trace_processor/importers/proto/profile_packet_utils.cc
index 9478db9..3cc5dc1 100644
--- a/src/trace_processor/importers/proto/profile_packet_utils.cc
+++ b/src/trace_processor/importers/proto/profile_packet_utils.cc
@@ -15,11 +15,27 @@
*/
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
+#include "perfetto/ext/base/string_utils.h"
namespace perfetto {
namespace trace_processor {
-ProfilePacketInternLookup::~ProfilePacketInternLookup() = default;
+// static
+std::string ProfilePacketUtils::MakeMappingName(
+ const std::vector<base::StringView>& path_components) {
+ std::string name;
+ for (base::StringView p : path_components) {
+ name.push_back('/');
+ name.append(p.data(), p.size());
+ }
+
+ // When path strings just have single full path(like Chrome does), the mapping
+ // path gets an extra '/' prepended, strip the extra '/'.
+ if (base::StartsWith(name, "//")) {
+ name = name.substr(1);
+ }
+ return name;
+}
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/profile_packet_utils.h b/src/trace_processor/importers/proto/profile_packet_utils.h
index 64b2c50..a9ea0e6 100644
--- a/src/trace_processor/importers/proto/profile_packet_utils.h
+++ b/src/trace_processor/importers/proto/profile_packet_utils.h
@@ -20,7 +20,7 @@
#include "perfetto/ext/base/string_view.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
+#include "src/trace_processor/importers/proto/profile_packet_sequence_state.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
@@ -31,9 +31,12 @@
class ProfilePacketUtils {
public:
- static SequenceStackProfileTracker::SourceMapping MakeSourceMapping(
+ static std::string MakeMappingName(
+ const std::vector<base::StringView>& path_components);
+
+ static ProfilePacketSequenceState::SourceMapping MakeSourceMapping(
const protos::pbzero::Mapping::Decoder& entry) {
- SequenceStackProfileTracker::SourceMapping src_mapping{};
+ ProfilePacketSequenceState::SourceMapping src_mapping{};
src_mapping.build_id = entry.build_id();
src_mapping.exact_offset = entry.exact_offset();
src_mapping.start_offset = entry.start_offset();
@@ -47,18 +50,18 @@
return src_mapping;
}
- static SequenceStackProfileTracker::SourceFrame MakeSourceFrame(
+ static ProfilePacketSequenceState::SourceFrame MakeSourceFrame(
const protos::pbzero::Frame::Decoder& entry) {
- SequenceStackProfileTracker::SourceFrame src_frame;
+ ProfilePacketSequenceState::SourceFrame src_frame;
src_frame.name_id = entry.function_name_id();
src_frame.mapping_id = entry.mapping_id();
src_frame.rel_pc = entry.rel_pc();
return src_frame;
}
- static SequenceStackProfileTracker::SourceCallstack MakeSourceCallstack(
+ static ProfilePacketSequenceState::SourceCallstack MakeSourceCallstack(
const protos::pbzero::Callstack::Decoder& entry) {
- SequenceStackProfileTracker::SourceCallstack src_callstack;
+ ProfilePacketSequenceState::SourceCallstack src_callstack;
for (auto frame_it = entry.frame_ids(); frame_it; ++frame_it)
src_callstack.emplace_back(*frame_it);
return src_callstack;
@@ -126,76 +129,6 @@
}
};
-class ProfilePacketInternLookup
- : public SequenceStackProfileTracker::InternLookup {
- public:
- explicit ProfilePacketInternLookup(PacketSequenceStateGeneration* seq_state)
- : seq_state_(seq_state) {}
- ~ProfilePacketInternLookup() override;
-
- std::optional<base::StringView> GetString(
- SequenceStackProfileTracker::SourceStringId iid,
- SequenceStackProfileTracker::InternedStringType type) const override {
- protos::pbzero::InternedString::Decoder* decoder = nullptr;
- switch (type) {
- case SequenceStackProfileTracker::InternedStringType::kBuildId:
- decoder = seq_state_->LookupInternedMessage<
- protos::pbzero::InternedData::kBuildIdsFieldNumber,
- protos::pbzero::InternedString>(iid);
- break;
- case SequenceStackProfileTracker::InternedStringType::kFunctionName:
- decoder = seq_state_->LookupInternedMessage<
- protos::pbzero::InternedData::kFunctionNamesFieldNumber,
- protos::pbzero::InternedString>(iid);
- break;
- case SequenceStackProfileTracker::InternedStringType::kMappingPath:
- decoder = seq_state_->LookupInternedMessage<
- protos::pbzero::InternedData::kMappingPathsFieldNumber,
- protos::pbzero::InternedString>(iid);
- break;
- }
- if (!decoder)
- return std::nullopt;
- return base::StringView(reinterpret_cast<const char*>(decoder->str().data),
- decoder->str().size);
- }
-
- std::optional<SequenceStackProfileTracker::SourceMapping> GetMapping(
- SequenceStackProfileTracker::SourceMappingId iid) const override {
- auto* decoder = seq_state_->LookupInternedMessage<
- protos::pbzero::InternedData::kMappingsFieldNumber,
- protos::pbzero::Mapping>(iid);
- if (!decoder)
- return std::nullopt;
- return ProfilePacketUtils::MakeSourceMapping(*decoder);
- }
-
- std::optional<SequenceStackProfileTracker::SourceFrame> GetFrame(
- SequenceStackProfileTracker::SourceFrameId iid) const override {
- auto* decoder = seq_state_->LookupInternedMessage<
- protos::pbzero::InternedData::kFramesFieldNumber,
- protos::pbzero::Frame>(iid);
- if (!decoder)
- return std::nullopt;
- return ProfilePacketUtils::MakeSourceFrame(*decoder);
- }
-
- std::optional<SequenceStackProfileTracker::SourceCallstack> GetCallstack(
- SequenceStackProfileTracker::SourceCallstackId iid) const override {
- auto* interned_message_view = seq_state_->GetInternedMessageView(
- protos::pbzero::InternedData::kCallstacksFieldNumber, iid);
- if (!interned_message_view)
- return std::nullopt;
- protos::pbzero::Callstack::Decoder decoder(
- interned_message_view->message().data(),
- interned_message_view->message().length());
- return ProfilePacketUtils::MakeSourceCallstack(std::move(decoder));
- }
-
- private:
- PacketSequenceStateGeneration* seq_state_;
-};
-
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
index af96d34..148bf60 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser_unittest.cc
@@ -28,12 +28,12 @@
#include "src/trace_processor/importers/common/metadata_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/default_modules.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/metadata.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -55,6 +55,7 @@
#include "protos/perfetto/trace/ftrace/sched.pbzero.h"
#include "protos/perfetto/trace/ftrace/task.pbzero.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
#include "protos/perfetto/trace/ps/process_tree.pbzero.h"
#include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
@@ -251,8 +252,7 @@
context_.track_tracker.reset(new TrackTracker(&context_));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
- context_.global_stack_profile_tracker.reset(
- new GlobalStackProfileTracker());
+ context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
context_.args_tracker.reset(new ArgsTracker(&context_));
context_.args_translation_table.reset(new ArgsTranslationTable(storage_));
context_.metadata_tracker.reset(
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 1c554a6..8afc40c 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -24,6 +24,7 @@
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
+#include "src/trace_processor/storage/trace_storage.h"
namespace protozero {
struct ConstBytes;
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.cc b/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
new file mode 100644
index 0000000..e503a09
--- /dev/null
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.cc
@@ -0,0 +1,220 @@
+/*
+ * 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/stack_profile_sequence_state.h"
+
+#include <optional>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_view.h"
+#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/profile_packet_utils.h"
+#include "src/trace_processor/storage/stats.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+base::StringView ToStringView(protozero::ConstBytes bytes) {
+ return base::StringView(reinterpret_cast<const char*>(bytes.data),
+ bytes.size);
+}
+} // namespace
+
+StackProfileSequenceState::StackProfileSequenceState(
+ TraceProcessorContext* context)
+ : context_(context) {}
+
+StackProfileSequenceState::~StackProfileSequenceState() = default;
+
+std::optional<MappingId> StackProfileSequenceState::FindOrInsertMapping(
+ uint64_t iid) {
+ if (MappingId* id = cached_mappings_.Find(iid); id) {
+ return *id;
+ }
+ auto* decoder =
+ LookupInternedMessage<protos::pbzero::InternedData::kMappingsFieldNumber,
+ protos::pbzero::Mapping>(iid);
+ if (!decoder) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
+ return std::nullopt;
+ }
+
+ std::optional<base::StringView> build_id =
+ LookupInternedBuildId(decoder->build_id());
+ if (!build_id) {
+ return std::nullopt;
+ }
+
+ std::vector<base::StringView> path_components;
+ for (auto it = decoder->path_string_ids(); it; ++it) {
+ std::optional<base::StringView> str = LookupInternedMappingPath(*it);
+ if (!str) {
+ // For backward compatibility reasons we do not return an error but
+ // instead stop adding path components.
+ break;
+ }
+ path_components.push_back(*str);
+ }
+ std::string path = ProfilePacketUtils::MakeMappingName(path_components);
+
+ StackProfileTracker::CreateMappingParams params;
+ params.build_id = *build_id;
+ params.exact_offset = decoder->exact_offset();
+ params.start_offset = decoder->start_offset();
+ params.start = decoder->start();
+ params.end = decoder->end();
+ params.load_bias = decoder->load_bias();
+ params.name = base::StringView(path);
+ MappingId mapping_id = context_->stack_profile_tracker->InternMapping(params);
+ cached_mappings_.Insert(iid, mapping_id);
+ return mapping_id;
+}
+
+std::optional<base::StringView>
+StackProfileSequenceState::LookupInternedBuildId(uint64_t iid) {
+ // This should really be an error (value not set) or at the very least return
+ // a null string, but for backward compatibility use an empty string instead.
+ if (iid == 0) {
+ return "";
+ }
+ auto* decoder =
+ LookupInternedMessage<protos::pbzero::InternedData::kBuildIdsFieldNumber,
+ protos::pbzero::InternedString>(iid);
+ if (!decoder) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ return std::nullopt;
+ }
+
+ return ToStringView(decoder->str());
+}
+
+std::optional<base::StringView>
+StackProfileSequenceState::LookupInternedMappingPath(uint64_t iid) {
+ // This should really be an error (value not set) or at the very least return
+ // a null string, but for backward compatibility use an empty string instead.
+ if (iid == 0) {
+ return "";
+ }
+ auto* decoder = LookupInternedMessage<
+ protos::pbzero::InternedData::kMappingPathsFieldNumber,
+ protos::pbzero::InternedString>(iid);
+ if (!decoder) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ return std::nullopt;
+ }
+
+ return ToStringView(decoder->str());
+}
+
+std::optional<CallsiteId> StackProfileSequenceState::FindOrInsertCallstack(
+ uint64_t iid) {
+ if (CallsiteId* id = cached_callstacks_.Find(iid); id) {
+ return *id;
+ }
+ auto* decoder = LookupInternedMessage<
+ protos::pbzero::InternedData::kCallstacksFieldNumber,
+ protos::pbzero::Callstack>(iid);
+ if (!decoder) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
+ return std::nullopt;
+ }
+
+ std::optional<CallsiteId> parent_callsite_id;
+ uint32_t depth = 0;
+ for (auto it = decoder->frame_ids(); it; ++it) {
+ std::optional<FrameId> frame_id = FindOrInsertFrame(*it);
+ if (!frame_id) {
+ return std::nullopt;
+ }
+ parent_callsite_id = context_->stack_profile_tracker->InternCallsite(
+ parent_callsite_id, *frame_id, depth);
+ ++depth;
+ }
+
+ if (!parent_callsite_id) {
+ context_->storage->IncrementStats(stats::stackprofile_empty_callstack);
+ return std::nullopt;
+ }
+
+ cached_callstacks_.Insert(iid, *parent_callsite_id);
+
+ return *parent_callsite_id;
+}
+
+std::optional<FrameId> StackProfileSequenceState::FindOrInsertFrame(
+ uint64_t iid) {
+ if (FrameId* id = cached_frames_.Find(iid); id) {
+ return *id;
+ }
+ auto* decoder =
+ LookupInternedMessage<protos::pbzero::InternedData::kFramesFieldNumber,
+ protos::pbzero::Frame>(iid);
+ if (!decoder) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
+ return std::nullopt;
+ }
+
+ std::optional<MappingId> mapping_id =
+ FindOrInsertMapping(decoder->mapping_id());
+ if (!mapping_id) {
+ return std::nullopt;
+ }
+
+ base::StringView function_name;
+ if (decoder->function_name_id() != 0) {
+ std::optional<base::StringView> func =
+ LookupInternedFunctionName(decoder->function_name_id());
+ if (!func) {
+ return std::nullopt;
+ }
+ function_name = *func;
+ }
+
+ FrameId frame_id = context_->stack_profile_tracker->InternFrame(
+ *mapping_id, decoder->rel_pc(), function_name);
+
+ cached_frames_.Insert(iid, frame_id);
+
+ return frame_id;
+}
+
+std::optional<base::StringView>
+StackProfileSequenceState::LookupInternedFunctionName(uint64_t iid) {
+ // This should really be an error (value not set) or at the very least return
+ // a null string, but for backward compatibility use an empty string instead.
+ if (iid == 0) {
+ return "";
+ }
+ auto* decoder = LookupInternedMessage<
+ protos::pbzero::InternedData::kFunctionNamesFieldNumber,
+ protos::pbzero::InternedString>(iid);
+ if (!decoder) {
+ context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
+ return std::nullopt;
+ }
+
+ return ToStringView(decoder->str());
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.h b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
new file mode 100644
index 0000000..7a7879a
--- /dev/null
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_SEQUENCE_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_SEQUENCE_STATE_H_
+
+#include <cstdint>
+#include <optional>
+
+#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/string_view.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.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 StackProfileSequenceState final
+ : public PacketSequenceStateGeneration::InternedDataTracker {
+ public:
+ explicit StackProfileSequenceState(TraceProcessorContext* context);
+
+ StackProfileSequenceState(const StackProfileSequenceState&);
+
+ virtual ~StackProfileSequenceState() override;
+
+ std::optional<MappingId> FindOrInsertMapping(uint64_t iid);
+ std::optional<CallsiteId> FindOrInsertCallstack(uint64_t iid);
+
+ private:
+ std::optional<base::StringView> LookupInternedBuildId(uint64_t iid);
+ std::optional<base::StringView> LookupInternedMappingPath(uint64_t iid);
+ std::optional<base::StringView> LookupInternedFunctionName(uint64_t iid);
+ std::optional<FrameId> FindOrInsertFrame(uint64_t iid);
+
+ TraceProcessorContext* const context_;
+ base::FlatHashMap<uint64_t, MappingId> cached_mappings_;
+ base::FlatHashMap<uint64_t, CallsiteId> cached_callstacks_;
+ base::FlatHashMap<uint64_t, FrameId> cached_frames_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/stack_profile_tracker.cc b/src/trace_processor/importers/proto/stack_profile_tracker.cc
deleted file mode 100644
index d00f287..0000000
--- a/src/trace_processor/importers/proto/stack_profile_tracker.cc
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * 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/stack_profile_tracker.h"
-
-#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/string_utils.h"
-#include "src/trace_processor/importers/proto/profiler_util.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-#include "src/trace_processor/util/stack_traces_util.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-SequenceStackProfileTracker::InternLookup::~InternLookup() = default;
-
-SequenceStackProfileTracker::SequenceStackProfileTracker(
- TraceProcessorContext* context)
- : context_(context), empty_(kNullStringId) {}
-
-SequenceStackProfileTracker::~SequenceStackProfileTracker() = default;
-
-StringId SequenceStackProfileTracker::GetEmptyStringId() {
- if (empty_ == kNullStringId) {
- empty_ = context_->storage->InternString({"", 0});
- }
-
- return empty_;
-}
-
-void SequenceStackProfileTracker::AddString(SourceStringId id,
- base::StringView str) {
- string_map_.emplace(id, str.ToStdString());
-}
-
-std::optional<MappingId> SequenceStackProfileTracker::AddMapping(
- SourceMappingId id,
- const SourceMapping& mapping,
- const InternLookup* intern_lookup) {
- std::string path;
- for (SourceStringId str_id : mapping.name_ids) {
- auto opt_str = FindOrInsertString(str_id, intern_lookup,
- InternedStringType::kMappingPath);
- if (!opt_str)
- break;
- path += "/" + *opt_str;
- }
- // When path strings just have single full path(like Chrome does), the mapping
- // path gets an extra '/' prepended, strip the extra '/'.
- if (base::StartsWith(path, "//")) {
- path = path.substr(1);
- }
-
- auto opt_build_id = FindAndInternString(mapping.build_id, intern_lookup,
- InternedStringType::kBuildId);
- if (!opt_build_id) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- PERFETTO_DLOG("Invalid string.");
- return std::nullopt;
- }
- const StringId raw_build_id = opt_build_id.value();
- NullTermStringView raw_build_id_str =
- context_->storage->GetString(raw_build_id);
- StringId build_id = GetEmptyStringId();
- if (!raw_build_id_str.empty()) {
- // If the build_id is 33 characters long, we assume it's a Breakpad debug
- // identifier which is already in Hex and doesn't need conversion.
- // TODO(b/148109467): Remove workaround once all active Chrome versions
- // write raw bytes instead of a string as build_id.
- if (util::IsHexModuleId(raw_build_id_str)) {
- build_id = raw_build_id;
- } else {
- std::string hex_build_id =
- base::ToHex(raw_build_id_str.c_str(), raw_build_id_str.size());
- build_id =
- context_->storage->InternString(base::StringView(hex_build_id));
- }
- }
-
- tables::StackProfileMappingTable::Row row{
- build_id,
- static_cast<int64_t>(mapping.exact_offset),
- static_cast<int64_t>(mapping.start_offset),
- static_cast<int64_t>(mapping.start),
- static_cast<int64_t>(mapping.end),
- static_cast<int64_t>(mapping.load_bias),
- context_->storage->InternString(base::StringView(path))};
-
- tables::StackProfileMappingTable* mappings =
- context_->storage->mutable_stack_profile_mapping_table();
- std::optional<MappingId> cur_id;
- auto it = mapping_idx_.find(row);
- if (it != mapping_idx_.end()) {
- cur_id = it->second;
- } else {
- std::vector<MappingId> db_mappings =
- context_->global_stack_profile_tracker->FindMappingRow(row.name,
- row.build_id);
- for (const MappingId preexisting_mapping : db_mappings) {
- uint32_t preexisting_row = *mappings->id().IndexOf(preexisting_mapping);
- tables::StackProfileMappingTable::Row preexisting_data{
- mappings->build_id()[preexisting_row],
- mappings->exact_offset()[preexisting_row],
- mappings->start_offset()[preexisting_row],
- mappings->start()[preexisting_row],
- mappings->end()[preexisting_row],
- mappings->load_bias()[preexisting_row],
- mappings->name()[preexisting_row]};
-
- if (row == preexisting_data) {
- cur_id = preexisting_mapping;
- }
- }
- if (!cur_id) {
- MappingId mapping_id = mappings->Insert(row).id;
- context_->global_stack_profile_tracker->InsertMappingId(
- row.name, row.build_id, mapping_id);
- cur_id = mapping_id;
- }
- mapping_idx_.emplace(row, *cur_id);
- }
- mapping_ids_.emplace(id, *cur_id);
- return cur_id;
-}
-
-std::optional<FrameId> SequenceStackProfileTracker::AddFrame(
- SourceFrameId id,
- const SourceFrame& frame,
- const InternLookup* intern_lookup) {
- std::optional<std::string> opt_name = FindOrInsertString(
- frame.name_id, intern_lookup, InternedStringType::kFunctionName);
- if (!opt_name) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
- PERFETTO_DLOG("Invalid string.");
- return std::nullopt;
- }
- const std::string& name = *opt_name;
- const StringId str_id =
- context_->storage->InternString(base::StringView(name));
-
- auto opt_mapping = FindOrInsertMapping(frame.mapping_id, intern_lookup);
- if (!opt_mapping) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
- return std::nullopt;
- }
- MappingId mapping_id = *opt_mapping;
- const auto& mappings = context_->storage->stack_profile_mapping_table();
- StringId mapping_name_id =
- mappings.name()[*mappings.id().IndexOf(mapping_id)];
- auto mapping_name = context_->storage->GetString(mapping_name_id);
-
- tables::StackProfileFrameTable::Row row{str_id, mapping_id,
- static_cast<int64_t>(frame.rel_pc)};
-
- auto* frames = context_->storage->mutable_stack_profile_frame_table();
-
- std::optional<FrameId> cur_id;
- auto it = frame_idx_.find(row);
- if (it != frame_idx_.end()) {
- cur_id = it->second;
- } else {
- std::vector<FrameId> db_frames =
- context_->global_stack_profile_tracker->FindFrameIds(mapping_id,
- frame.rel_pc);
- for (const FrameId preexisting_frame : db_frames) {
- uint32_t preexisting_row_id = *frames->id().IndexOf(preexisting_frame);
- tables::StackProfileFrameTable::Row preexisting_row{
- frames->name()[preexisting_row_id],
- frames->mapping()[preexisting_row_id],
- frames->rel_pc()[preexisting_row_id]};
-
- if (row == preexisting_row) {
- cur_id = preexisting_frame;
- }
- }
- if (!cur_id) {
- cur_id = frames->Insert(row).id;
- context_->global_stack_profile_tracker->InsertFrameRow(
- mapping_id, static_cast<uint64_t>(row.rel_pc), *cur_id);
- if (base::Contains(name, '.')) {
- // Java frames always contain a '.'
- std::optional<std::string> package =
- PackageFromLocation(context_->storage.get(), mapping_name);
- if (package) {
- NameInPackage nip{str_id, context_->storage->InternString(
- base::StringView(*package))};
- context_->global_stack_profile_tracker->InsertJavaFrameForName(
- nip, *cur_id);
- } else if (mapping_name.find("/memfd:") == 0) {
- NameInPackage nip{str_id, context_->storage->InternString("memfd")};
- context_->global_stack_profile_tracker->InsertJavaFrameForName(
- nip, *cur_id);
- }
- }
- }
- frame_idx_.emplace(row, *cur_id);
- }
- frame_ids_.emplace(id, *cur_id);
- return cur_id;
-}
-
-std::optional<CallsiteId> SequenceStackProfileTracker::AddCallstack(
- SourceCallstackId id,
- const SourceCallstack& frame_ids,
- const InternLookup* intern_lookup) {
- if (frame_ids.empty())
- return std::nullopt;
-
- std::optional<CallsiteId> parent_id;
- for (uint32_t depth = 0; depth < frame_ids.size(); ++depth) {
- auto opt_frame_id = FindOrInsertFrame(frame_ids[depth], intern_lookup);
- if (!opt_frame_id) {
- context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
- return std::nullopt;
- }
- FrameId frame_id = *opt_frame_id;
-
- tables::StackProfileCallsiteTable::Row row{depth, parent_id, frame_id};
- CallsiteId self_id;
- auto callsite_it = callsite_idx_.find(row);
- if (callsite_it != callsite_idx_.end()) {
- self_id = callsite_it->second;
- } else {
- auto* callsite =
- context_->storage->mutable_stack_profile_callsite_table();
- self_id = callsite->Insert(row).id;
- callsite_idx_.emplace(row, self_id);
- }
- parent_id = self_id;
- }
- PERFETTO_DCHECK(parent_id); // The loop ran at least once.
- callstack_ids_.emplace(id, *parent_id);
- return parent_id;
-}
-
-FrameId SequenceStackProfileTracker::GetDatabaseFrameIdForTesting(
- SourceFrameId frame_id) {
- auto it = frame_ids_.find(frame_id);
- if (it == frame_ids_.end()) {
- PERFETTO_DLOG("Invalid frame.");
- return {};
- }
- return it->second;
-}
-
-std::optional<StringId> SequenceStackProfileTracker::FindAndInternString(
- SourceStringId id,
- const InternLookup* intern_lookup,
- SequenceStackProfileTracker::InternedStringType type) {
- if (id == 0)
- return GetEmptyStringId();
-
- auto opt_str = FindOrInsertString(id, intern_lookup, type);
- if (!opt_str)
- return GetEmptyStringId();
-
- return context_->storage->InternString(base::StringView(*opt_str));
-}
-
-std::optional<std::string> SequenceStackProfileTracker::FindOrInsertString(
- SourceStringId id,
- const InternLookup* intern_lookup,
- SequenceStackProfileTracker::InternedStringType type) {
- if (id == 0)
- return "";
-
- auto it = string_map_.find(id);
- if (it == string_map_.end()) {
- if (intern_lookup) {
- auto str = intern_lookup->GetString(id, type);
- if (!str) {
- context_->storage->IncrementStats(
- stats::stackprofile_invalid_string_id);
- PERFETTO_DLOG("Invalid string.");
- return std::nullopt;
- }
- return str->ToStdString();
- }
- return std::nullopt;
- }
-
- return it->second;
-}
-
-std::optional<MappingId> SequenceStackProfileTracker::FindOrInsertMapping(
- SourceMappingId mapping_id,
- const InternLookup* intern_lookup) {
- std::optional<MappingId> res;
- auto it = mapping_ids_.find(mapping_id);
- if (it == mapping_ids_.end()) {
- if (intern_lookup) {
- auto interned_mapping = intern_lookup->GetMapping(mapping_id);
- if (interned_mapping) {
- res = AddMapping(mapping_id, *interned_mapping, intern_lookup);
- return res;
- }
- }
- context_->storage->IncrementStats(stats::stackprofile_invalid_mapping_id);
- return res;
- }
- res = it->second;
- return res;
-}
-
-std::optional<FrameId> SequenceStackProfileTracker::FindOrInsertFrame(
- SourceFrameId frame_id,
- const InternLookup* intern_lookup) {
- std::optional<FrameId> res;
- auto it = frame_ids_.find(frame_id);
- if (it == frame_ids_.end()) {
- if (intern_lookup) {
- auto interned_frame = intern_lookup->GetFrame(frame_id);
- if (interned_frame) {
- res = AddFrame(frame_id, *interned_frame, intern_lookup);
- return res;
- }
- }
- context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
- PERFETTO_DLOG("Unknown frame %" PRIu64 " : %zu", frame_id,
- frame_ids_.size());
- return res;
- }
- res = it->second;
- return res;
-}
-
-std::optional<CallsiteId> SequenceStackProfileTracker::FindOrInsertCallstack(
- SourceCallstackId callstack_id,
- const InternLookup* intern_lookup) {
- std::optional<CallsiteId> res;
- auto it = callstack_ids_.find(callstack_id);
- if (it == callstack_ids_.end()) {
- auto interned_callstack = intern_lookup->GetCallstack(callstack_id);
- if (interned_callstack) {
- res = AddCallstack(callstack_id, *interned_callstack, intern_lookup);
- return res;
- }
- context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
- PERFETTO_DLOG("Unknown callstack %" PRIu64 " : %zu", callstack_id,
- callstack_ids_.size());
- return res;
- }
- res = it->second;
- return res;
-}
-
-void SequenceStackProfileTracker::ClearIndices() {
- string_map_.clear();
- mapping_ids_.clear();
- callstack_ids_.clear();
- frame_ids_.clear();
-}
-
-} // namespace trace_processor
-} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/stack_profile_tracker.h b/src/trace_processor/importers/proto/stack_profile_tracker.h
deleted file mode 100644
index a29d3c1..0000000
--- a/src/trace_processor/importers/proto/stack_profile_tracker.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_TRACKER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_TRACKER_H_
-
-#include <deque>
-#include <optional>
-#include <unordered_map>
-
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/profiler_tables_py.h"
-
-#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
-#include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
-
-template <>
-struct std::hash<std::pair<uint32_t, int64_t>> {
- using argument_type = std::pair<uint32_t, int64_t>;
- using result_type = size_t;
-
- result_type operator()(const argument_type& p) const {
- return std::hash<uint32_t>{}(p.first) ^ std::hash<int64_t>{}(p.second);
- }
-};
-
-template <>
-struct std::hash<std::pair<uint32_t, perfetto::trace_processor::CallsiteId>> {
- using argument_type =
- std::pair<uint32_t, perfetto::trace_processor::CallsiteId>;
- using result_type = size_t;
-
- result_type operator()(const argument_type& p) const {
- return std::hash<uint32_t>{}(p.first) ^
- std::hash<uint32_t>{}(p.second.value);
- }
-};
-
-template <>
-struct std::hash<std::pair<uint32_t, perfetto::trace_processor::MappingId>> {
- using argument_type =
- std::pair<uint32_t, perfetto::trace_processor::MappingId>;
- using result_type = size_t;
-
- result_type operator()(const argument_type& p) const {
- return std::hash<uint32_t>{}(p.first) ^
- std::hash<uint32_t>{}(p.second.value);
- }
-};
-
-template <>
-struct std::hash<std::pair<uint32_t, perfetto::trace_processor::FrameId>> {
- using argument_type = std::pair<uint32_t, perfetto::trace_processor::FrameId>;
- using result_type = size_t;
-
- result_type operator()(const argument_type& p) const {
- return std::hash<uint32_t>{}(p.first) ^
- std::hash<uint32_t>{}(p.second.value);
- }
-};
-
-template <>
-struct std::hash<std::vector<uint64_t>> {
- using argument_type = std::vector<uint64_t>;
- using result_type = size_t;
-
- result_type operator()(const argument_type& p) const {
- size_t h = 0u;
- for (auto v : p)
- h = h ^ std::hash<uint64_t>{}(v);
- return h;
- }
-};
-
-namespace perfetto {
-namespace trace_processor {
-
-struct NameInPackage {
- StringId name;
- StringId package;
-
- bool operator<(const NameInPackage& b) const {
- return std::tie(name, package) < std::tie(b.name, b.package);
- }
-};
-
-class TraceProcessorContext;
-
-class GlobalStackProfileTracker {
- public:
- std::vector<MappingId> FindMappingRow(StringId name,
- StringId build_id) const {
- auto it = stack_profile_mapping_index_.find(std::make_pair(name, build_id));
- if (it == stack_profile_mapping_index_.end())
- return {};
- return it->second;
- }
-
- void InsertMappingId(StringId name, StringId build_id, MappingId row) {
- auto pair = std::make_pair(name, build_id);
- stack_profile_mapping_index_[pair].emplace_back(row);
- }
-
- std::vector<FrameId> FindFrameIds(MappingId mapping_row,
- uint64_t rel_pc) const {
- auto it =
- stack_profile_frame_index_.find(std::make_pair(mapping_row, rel_pc));
- if (it == stack_profile_frame_index_.end())
- return {};
- return it->second;
- }
-
- void InsertFrameRow(MappingId mapping_row, uint64_t rel_pc, FrameId row) {
- auto pair = std::make_pair(mapping_row, rel_pc);
- stack_profile_frame_index_[pair].emplace_back(row);
- }
-
- const std::vector<tables::StackProfileFrameTable::Id>* JavaFramesForName(
- NameInPackage name) {
- auto it = java_frames_for_name_.find(name);
- if (it == java_frames_for_name_.end())
- return nullptr;
- return &it->second;
- }
-
- void InsertJavaFrameForName(NameInPackage name,
- tables::StackProfileFrameTable::Id id) {
- java_frames_for_name_[name].push_back(id);
- }
-
- private:
- using MappingKey = std::pair<StringId /* name */, StringId /* build id */>;
- std::map<MappingKey, std::vector<MappingId>> stack_profile_mapping_index_;
-
- using FrameKey = std::pair<MappingId, uint64_t /* rel_pc */>;
- std::map<FrameKey, std::vector<FrameId>> stack_profile_frame_index_;
-
- std::map<NameInPackage, std::vector<tables::StackProfileFrameTable::Id>>
- java_frames_for_name_;
-};
-
-// TODO(lalitm): Overhaul this class to make row vs id consistent and use
-// base::Optional instead of int64_t.
-class SequenceStackProfileTracker {
- public:
- using SourceStringId = uint64_t;
-
- enum class InternedStringType {
- kMappingPath,
- kBuildId,
- kFunctionName,
- };
-
- struct SourceMapping {
- SourceStringId build_id = 0;
- uint64_t exact_offset = 0;
- uint64_t start_offset = 0;
- uint64_t start = 0;
- uint64_t end = 0;
- uint64_t load_bias = 0;
- std::vector<SourceStringId> name_ids;
- };
- using SourceMappingId = uint64_t;
-
- struct SourceFrame {
- SourceStringId name_id = 0;
- SourceMappingId mapping_id = 0;
- uint64_t rel_pc = 0;
- };
- using SourceFrameId = uint64_t;
-
- using SourceCallstack = std::vector<SourceFrameId>;
- using SourceCallstackId = uint64_t;
-
- struct SourceAllocation {
- uint64_t pid = 0;
- // This is int64_t, because we get this from the TraceSorter which also
- // converts this for us.
- int64_t timestamp = 0;
- SourceCallstackId callstack_id = 0;
- uint64_t self_allocated = 0;
- uint64_t self_freed = 0;
- uint64_t alloc_count = 0;
- uint64_t free_count = 0;
- };
-
- class InternLookup {
- public:
- virtual ~InternLookup();
-
- virtual std::optional<base::StringView> GetString(
- SourceStringId,
- InternedStringType) const = 0;
- virtual std::optional<SourceMapping> GetMapping(SourceMappingId) const = 0;
- virtual std::optional<SourceFrame> GetFrame(SourceFrameId) const = 0;
- virtual std::optional<SourceCallstack> GetCallstack(
- SourceCallstackId) const = 0;
- };
-
- explicit SequenceStackProfileTracker(TraceProcessorContext* context);
- ~SequenceStackProfileTracker();
-
- void AddString(SourceStringId, base::StringView);
- std::optional<MappingId> AddMapping(
- SourceMappingId,
- const SourceMapping&,
- const InternLookup* intern_lookup = nullptr);
- std::optional<FrameId> AddFrame(SourceFrameId,
- const SourceFrame&,
- const InternLookup* intern_lookup = nullptr);
- std::optional<CallsiteId> AddCallstack(
- SourceCallstackId,
- const SourceCallstack&,
- const InternLookup* intern_lookup = nullptr);
-
- FrameId GetDatabaseFrameIdForTesting(SourceFrameId);
-
- // Gets the row number of string / mapping / frame / callstack previously
- // added through AddString / AddMapping/ AddFrame / AddCallstack.
- //
- // If it is not found, look up the string / mapping / frame / callstack in
- // the global InternedData state, and if found, add to the database, if not
- // already added before.
- //
- // This is to support both ProfilePackets that contain the interned data
- // (for Android Q) and where the interned data is kept globally in
- // InternedData (for versions newer than Q).
- std::optional<StringId> FindAndInternString(SourceStringId,
- const InternLookup* intern_lookup,
- InternedStringType type);
- std::optional<std::string> FindOrInsertString(
- SourceStringId,
- const InternLookup* intern_lookup,
- InternedStringType type);
- std::optional<MappingId> FindOrInsertMapping(
- SourceMappingId,
- const InternLookup* intern_lookup);
- std::optional<FrameId> FindOrInsertFrame(SourceFrameId,
- const InternLookup* intern_lookup);
-
- std::optional<CallsiteId> FindOrInsertCallstack(
- SourceCallstackId,
- const InternLookup* intern_lookup);
-
- // Clear indices when they're no longer needed.
- void ClearIndices();
-
- private:
- StringId GetEmptyStringId();
-
- std::unordered_map<SourceStringId, std::string> string_map_;
-
- // Mapping from ID of mapping / frame / callstack in original trace and the
- // index in the respective table it was inserted into.
- std::unordered_map<SourceMappingId, MappingId> mapping_ids_;
- std::unordered_map<SourceFrameId, FrameId> frame_ids_;
- std::unordered_map<SourceCallstackId, CallsiteId> callstack_ids_;
-
- // TODO(oysteine): Share these indices between the StackProfileTrackers,
- // since they're not sequence-specific.
- //
- // Mapping from content of database row to the index of the raw.
- std::unordered_map<tables::StackProfileMappingTable::Row, MappingId>
- mapping_idx_;
- std::unordered_map<tables::StackProfileFrameTable::Row, FrameId> frame_idx_;
- std::unordered_map<tables::StackProfileCallsiteTable::Row, CallsiteId>
- callsite_idx_;
-
- TraceProcessorContext* const context_;
- StringId empty_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_STACK_PROFILE_TRACKER_H_
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 06e5c39..00bf52e 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -34,6 +34,7 @@
#include "src/trace_processor/importers/proto/packet_analyzer.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
+#include "src/trace_processor/importers/proto/stack_profile_sequence_state.h"
#include "src/trace_processor/importers/proto/track_event_tracker.h"
#include "src/trace_processor/util/debug_annotation_parser.h"
#include "src/trace_processor/util/proto_to_args_parser.h"
@@ -195,12 +196,9 @@
}
// Interned mapping_id loses it's meaning when the sequence ends. So we need
// to get an id from stack_profile_mapping table.
- ProfilePacketInternLookup intern_lookup(delegate.seq_state());
- auto mapping_id =
- delegate.seq_state()
- ->state()
- ->sequence_stack_profile_tracker()
- .FindOrInsertMapping(decoder->mapping_id(), &intern_lookup);
+ auto mapping_id = delegate.seq_state()
+ ->GetOrCreate<StackProfileSequenceState>()
+ ->FindOrInsertMapping(decoder->mapping_id());
if (!mapping_id) {
return std::nullopt;
}
diff --git a/src/trace_processor/importers/proto/v8_module.cc b/src/trace_processor/importers/proto/v8_module.cc
index ac2086a..94684e3 100644
--- a/src/trace_processor/importers/proto/v8_module.cc
+++ b/src/trace_processor/importers/proto/v8_module.cc
@@ -88,8 +88,7 @@
void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state =
- *V8SequenceState::GetOrCreate(data.sequence_state->state());
+ V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
V8JsCode::Decoder code(bytes);
@@ -110,8 +109,7 @@
void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state =
- *V8SequenceState::GetOrCreate(data.sequence_state->state());
+ V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
V8InternalCode::Decoder code(bytes);
@@ -126,8 +124,7 @@
void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state =
- *V8SequenceState::GetOrCreate(data.sequence_state->state());
+ V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
V8WasmCode::Decoder code(bytes);
@@ -148,8 +145,7 @@
void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state =
- *V8SequenceState::GetOrCreate(data.sequence_state->state());
+ V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
V8RegExpCode::Decoder code(bytes);
@@ -164,8 +160,7 @@
void V8Module::ParseV8CodeMove(protozero::ConstBytes bytes,
int64_t,
const TracePacketData& data) {
- V8SequenceState& state =
- *V8SequenceState::GetOrCreate(data.sequence_state->state());
+ V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
protos::pbzero::V8CodeMove::Decoder v8_code_move(bytes);
std::optional<tables::V8IsolateTable::Id> isolate_id =
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.cc b/src/trace_processor/importers/proto/v8_sequence_state.cc
index 946ab22..33abb24 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.cc
+++ b/src/trace_processor/importers/proto/v8_sequence_state.cc
@@ -17,10 +17,10 @@
#include "src/trace_processor/importers/proto/v8_sequence_state.h"
#include <optional>
-#include "perfetto/ext/base/string_utils.h"
#include "protos/perfetto/trace/chrome/v8.pbzero.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/importers/proto/string_encoding_utils.h"
#include "src/trace_processor/importers/proto/v8_tracker.h"
#include "src/trace_processor/storage/stats.h"
@@ -41,9 +41,8 @@
} // namespace
-V8SequenceState::V8SequenceState(PacketSequenceState* sequence_state)
- : sequence_state_(sequence_state),
- v8_tracker_(V8Tracker::GetOrCreate(sequence_state->context())) {}
+V8SequenceState::V8SequenceState(TraceProcessorContext* context)
+ : context_(context), v8_tracker_(V8Tracker::GetOrCreate(context_)) {}
V8SequenceState::~V8SequenceState() = default;
@@ -53,11 +52,9 @@
return *id;
}
- auto* view = sequence_state_->current_generation()->GetInternedMessageView(
- InternedData::kV8IsolateFieldNumber, iid);
+ auto* view = GetInternedMessageView(InternedData::kV8IsolateFieldNumber, iid);
if (!view) {
- sequence_state_->context()->storage->IncrementStats(
- stats::v8_intern_errors);
+ context_->storage->IncrementStats(stats::v8_intern_errors);
return std::nullopt;
}
@@ -73,11 +70,10 @@
return *id;
}
- auto* view = sequence_state_->current_generation()->GetInternedMessageView(
- InternedData::kV8JsFunctionFieldNumber, iid);
+ auto* view =
+ GetInternedMessageView(InternedData::kV8JsFunctionFieldNumber, iid);
if (!view) {
- sequence_state_->context()->storage->IncrementStats(
- stats::v8_intern_errors);
+ context_->storage->IncrementStats(stats::v8_intern_errors);
return std::nullopt;
}
@@ -107,11 +103,10 @@
if (auto* id = wasm_scripts_.Find(iid); id != nullptr) {
return *id;
}
- auto* view = sequence_state_->current_generation()->GetInternedMessageView(
- InternedData::kV8WasmScriptFieldNumber, iid);
+ auto* view =
+ GetInternedMessageView(InternedData::kV8WasmScriptFieldNumber, iid);
if (!view) {
- sequence_state_->context()->storage->IncrementStats(
- stats::v8_intern_errors);
+ context_->storage->IncrementStats(stats::v8_intern_errors);
return std::nullopt;
}
@@ -127,11 +122,10 @@
if (auto* id = js_scripts_.Find(iid); id != nullptr) {
return *id;
}
- auto* view = sequence_state_->current_generation()->GetInternedMessageView(
- InternedData::kV8JsScriptFieldNumber, iid);
+ auto* view =
+ GetInternedMessageView(InternedData::kV8JsScriptFieldNumber, iid);
if (!view) {
- sequence_state_->context()->storage->IncrementStats(
- stats::v8_intern_errors);
+ context_->storage->IncrementStats(stats::v8_intern_errors);
return std::nullopt;
}
@@ -147,17 +141,16 @@
return *id;
}
- auto* view = sequence_state_->current_generation()->GetInternedMessageView(
- InternedData::kV8JsFunctionNameFieldNumber, iid);
+ auto* view =
+ GetInternedMessageView(InternedData::kV8JsFunctionNameFieldNumber, iid);
if (!view) {
- sequence_state_->context()->storage->IncrementStats(
- stats::v8_intern_errors);
+ context_->storage->IncrementStats(stats::v8_intern_errors);
return std::nullopt;
}
InternedV8String::Decoder function_name(ToConstBytes(view->message()));
- auto& storage = *sequence_state_->context()->storage;
+ auto& storage = *context_->storage;
StringId id;
if (function_name.has_latin1()) {
id = storage.InternString(
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.h b/src/trace_processor/importers/proto/v8_sequence_state.h
index 781960d..d2e008a 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.h
+++ b/src/trace_processor/importers/proto/v8_sequence_state.h
@@ -21,7 +21,7 @@
#include <optional>
#include "perfetto/ext/base/flat_hash_map.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/v8_tables_py.h"
#include "src/trace_processor/types/destructible.h"
@@ -29,19 +29,14 @@
namespace perfetto {
namespace trace_processor {
+class TraceProcessorContext;
class V8Tracker;
// Helper class to deal with V8 related interned data.
-class V8SequenceState : public Destructible {
+class V8SequenceState final
+ : public PacketSequenceStateGeneration::InternedDataTracker {
public:
- static V8SequenceState* GetOrCreate(PacketSequenceState* sequence_state) {
- auto& v8_sequence_state =
- sequence_state->extensible_sequence_state().v8_sequence_state;
- if (!v8_sequence_state) {
- v8_sequence_state.reset(new V8SequenceState(sequence_state));
- }
- return static_cast<V8SequenceState*>(v8_sequence_state.get());
- }
+ explicit V8SequenceState(TraceProcessorContext* context);
~V8SequenceState() override;
@@ -54,13 +49,12 @@
tables::V8IsolateTable::Id isolate_id);
private:
- explicit V8SequenceState(PacketSequenceState* sequence_state);
std::optional<tables::V8JsScriptTable::Id> GetOrInsertJsScript(
uint64_t iid,
tables::V8IsolateTable::Id isolate_id);
std::optional<StringId> GetOrInsertJsFunctionName(uint64_t iid);
- PacketSequenceState* const sequence_state_;
+ TraceProcessorContext* const context_;
V8Tracker* const v8_tracker_;
using InterningId = uint64_t;
diff --git a/src/trace_processor/importers/proto/vulkan_memory_tracker.h b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
index 1457923..9d1afc5 100644
--- a/src/trace_processor/importers/proto/vulkan_memory_tracker.h
+++ b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
@@ -17,6 +17,7 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_VULKAN_MEMORY_TRACKER_H_
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/winscope/protolog_parser.h b/src/trace_processor/importers/proto/winscope/protolog_parser.h
index fbcf9d9..97d9183 100644
--- a/src/trace_processor/importers/proto/winscope/protolog_parser.h
+++ b/src/trace_processor/importers/proto/winscope/protolog_parser.h
@@ -19,6 +19,7 @@
#include "protos/perfetto/trace/android/protolog.pbzero.h"
#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/util/descriptors.h"
#include "src/trace_processor/util/proto_to_args_parser.h"
diff --git a/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc b/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc
index fde9046..b4d76cf 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_flamegraph.cc
@@ -31,8 +31,8 @@
#include "src/trace_processor/db/column/types.h"
#include "src/trace_processor/db/table.h"
#include "src/trace_processor/importers/proto/heap_graph_tracker.h"
-#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/flamegraph_construction_algorithms.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/profiler_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
diff --git a/src/trace_processor/storage/stats.h b/src/trace_processor/storage/stats.h
index 66a524e..ec72287 100644
--- a/src/trace_processor/storage/stats.h
+++ b/src/trace_processor/storage/stats.h
@@ -115,6 +115,8 @@
F(flow_end_without_start, kSingle, kInfo, kTrace, ""), \
F(flow_invalid_id, kSingle, kError, kTrace, ""), \
F(flow_without_direction, kSingle, kError, kTrace, ""), \
+ F(stackprofile_empty_callstack, kSingle, kError, kTrace, \
+ "Callstack had no frames. Ignored"), \
F(stackprofile_invalid_string_id, kSingle, kError, kTrace, ""), \
F(stackprofile_invalid_mapping_id, kSingle, kError, kTrace, ""), \
F(stackprofile_invalid_frame_id, kSingle, kError, kTrace, ""), \
diff --git a/src/trace_processor/trace_processor_context.cc b/src/trace_processor/trace_processor_context.cc
index 34da487..c7cea38 100644
--- a/src/trace_processor/trace_processor_context.cc
+++ b/src/trace_processor/trace_processor_context.cc
@@ -31,13 +31,12 @@
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
-#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/importers/proto/proto_trace_parser.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/importers/proto/track_event_module.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/types/destructible.h"
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index f24a1fc..05b88c0 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -30,15 +30,14 @@
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
#include "src/trace_processor/importers/common/slice_translation_table.h"
+#include "src/trace_processor/importers/common/stack_profile_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/proto/chrome_track_event.descriptor.h"
#include "src/trace_processor/importers/proto/default_modules.h"
-#include "src/trace_processor/importers/proto/heap_profile_tracker.h"
#include "src/trace_processor/importers/proto/packet_analyzer.h"
#include "src/trace_processor/importers/proto/perf_sample_tracker.h"
#include "src/trace_processor/importers/proto/proto_importer_module.h"
#include "src/trace_processor/importers/proto/proto_trace_reader.h"
-#include "src/trace_processor/importers/proto/stack_profile_tracker.h"
#include "src/trace_processor/importers/proto/track_event.descriptor.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/util/descriptors.h"
@@ -63,9 +62,8 @@
context_.process_tracker.reset(new ProcessTracker(&context_));
context_.clock_tracker.reset(new ClockTracker(&context_));
context_.clock_converter.reset(new ClockConverter(&context_));
- context_.heap_profile_tracker.reset(new HeapProfileTracker(&context_));
context_.perf_sample_tracker.reset(new PerfSampleTracker(&context_));
- context_.global_stack_profile_tracker.reset(new GlobalStackProfileTracker());
+ context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
context_.metadata_tracker.reset(new MetadataTracker(context_.storage.get()));
context_.global_args_tracker.reset(
new GlobalArgsTracker(context_.storage.get()));
@@ -143,7 +141,6 @@
}
context_.event_tracker->FlushPendingEvents();
context_.slice_tracker->FlushPendingSlices();
- context_.heap_profile_tracker->NotifyEndOfFile();
context_.args_tracker->Flush();
context_.process_tracker->NotifyEndOfFile();
}
diff --git a/src/trace_processor/types/trace_processor_context.h b/src/trace_processor/types/trace_processor_context.h
index 25f129b..ad4e148 100644
--- a/src/trace_processor/types/trace_processor_context.h
+++ b/src/trace_processor/types/trace_processor_context.h
@@ -52,9 +52,8 @@
class ForwardingTraceParser;
class FtraceModule;
class GlobalArgsTracker;
-class GlobalStackProfileTracker;
+class StackProfileTracker;
class HeapGraphTracker;
-class HeapProfileTracker;
class PerfSampleTracker;
class MetadataTracker;
class PacketAnalyzer;
@@ -101,9 +100,8 @@
std::unique_ptr<EventTracker> event_tracker;
std::unique_ptr<ClockTracker> clock_tracker;
std::unique_ptr<ClockConverter> clock_converter;
- std::unique_ptr<HeapProfileTracker> heap_profile_tracker;
std::unique_ptr<PerfSampleTracker> perf_sample_tracker;
- std::unique_ptr<GlobalStackProfileTracker> global_stack_profile_tracker;
+ std::unique_ptr<StackProfileTracker> stack_profile_tracker;
std::unique_ptr<MetadataTracker> metadata_tracker;
// These fields are stored as pointers to Destructible objects rather than
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index c717d3e..8420a06 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -61,6 +61,19 @@
}
}
+source_set("profiler_util") {
+ sources = [
+ "profiler_util.cc",
+ "profiler_util.h",
+ ]
+ deps = [
+ "../../../gn:default_deps",
+ "../../../include/perfetto/ext/base:base",
+ "../../../protos/perfetto/trace/profiling:zero",
+ "../storage:storage",
+ ]
+}
+
source_set("stack_traces_util") {
sources = [
"stack_traces_util.cc",
@@ -69,6 +82,7 @@
deps = [
"../../../gn:default_deps",
"../../../include/perfetto/ext/base:base",
+ "../../../protos/perfetto/trace/profiling:zero",
]
}
diff --git a/src/trace_processor/importers/proto/profiler_util.cc b/src/trace_processor/util/profiler_util.cc
similarity index 98%
rename from src/trace_processor/importers/proto/profiler_util.cc
rename to src/trace_processor/util/profiler_util.cc
index 79a5448..71c3c25 100644
--- a/src/trace_processor/importers/proto/profiler_util.cc
+++ b/src/trace_processor/util/profiler_util.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/proto/profiler_util.h"
+#include "src/trace_processor/util/profiler_util.h"
#include <optional>
#include "perfetto/ext/base/string_utils.h"
diff --git a/src/trace_processor/importers/proto/profiler_util.h b/src/trace_processor/util/profiler_util.h
similarity index 86%
rename from src/trace_processor/importers/proto/profiler_util.h
rename to src/trace_processor/util/profiler_util.h
index cbf8ad1..3af3606 100644
--- a/src/trace_processor/importers/proto/profiler_util.h
+++ b/src/trace_processor/util/profiler_util.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILER_UTIL_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILER_UTIL_H_
+#ifndef SRC_TRACE_PROCESSOR_UTIL_PROFILER_UTIL_H_
+#define SRC_TRACE_PROCESSOR_UTIL_PROFILER_UTIL_H_
#include <optional>
#include <string>
@@ -38,4 +38,4 @@
} // namespace trace_processor
} // namespace perfetto
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROFILER_UTIL_H_
+#endif // SRC_TRACE_PROCESSOR_UTIL_PROFILER_UTIL_H_