aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-16 01:07:35 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-16 01:07:35 +0000
commit3bd36db1d857a4e73a264abd2c0f51b171ea3fc4 (patch)
tree50cf23766bec31a01e2087f02b34856c56272e06
parent491f58e520146ad9deb6e8aa5c7a4707bbe70628 (diff)
parent92c019c4e0a5e0a3c3ee9078992050cf95a0bf2a (diff)
downloadperfetto-sdk-release.tar.gz
Snap for 11847757 from 92c019c4e0a5e0a3c3ee9078992050cf95a0bf2a to sdk-releasesdk-release
Change-Id: Iad1aa7b5b9ef2a5127db8d35c184ea60307c1ee3
-rw-r--r--Android.bp2
-rw-r--r--BUILD6
-rw-r--r--CHANGELOG3
-rw-r--r--buildtools/BUILD.gn30
-rw-r--r--buildtools/libcxx_config/__assertion_handler16
-rw-r--r--buildtools/libcxx_config/__config_site52
-rw-r--r--gn/perfetto.gni4
-rw-r--r--include/perfetto/ext/base/small_set.h4
-rw-r--r--include/perfetto/profiling/parse_smaps.h1
-rw-r--r--include/perfetto/public/data_source.h8
-rw-r--r--include/perfetto/tracing/string_helpers.h5
-rw-r--r--include/perfetto/tracing/track.h116
-rw-r--r--protos/perfetto/metrics/android/startup_metric.proto31
-rw-r--r--protos/perfetto/metrics/perfetto_merged_metrics.proto31
-rw-r--r--protos/perfetto/trace/perfetto_trace.proto9
-rw-r--r--protos/perfetto/trace/track_event/track_descriptor.proto9
-rw-r--r--python/generators/diff_tests/testing.py4
-rw-r--r--python/perfetto/trace_processor/metrics.descriptor10
-rw-r--r--src/trace_processor/containers/BUILD.gn2
-rw-r--r--src/trace_processor/containers/interval_tree.h135
-rw-r--r--src/trace_processor/containers/interval_tree_unittest.cc165
-rw-r--r--src/trace_processor/importers/ftrace/ftrace_parser.cc146
-rw-r--r--src/trace_processor/importers/ftrace/ftrace_parser.h13
-rw-r--r--src/trace_processor/importers/proto/BUILD.gn13
-rw-r--r--src/trace_processor/importers/proto/frame_timeline_event_parser.h1
-rw-r--r--src/trace_processor/importers/proto/gpu_event_parser.h1
-rw-r--r--src/trace_processor/importers/proto/graphics_frame_event_parser.h1
-rw-r--r--src/trace_processor/importers/proto/packet_sequence_state.h157
-rw-r--r--src/trace_processor/importers/proto/packet_sequence_state_builder.h82
-rw-r--r--src/trace_processor/importers/proto/packet_sequence_state_generation.cc147
-rw-r--r--src/trace_processor/importers/proto/packet_sequence_state_generation.h215
-rw-r--r--src/trace_processor/importers/proto/profile_module.cc6
-rw-r--r--src/trace_processor/importers/proto/profile_packet_sequence_state.cc4
-rw-r--r--src/trace_processor/importers/proto/profile_packet_sequence_state.h2
-rw-r--r--src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc17
-rw-r--r--src/trace_processor/importers/proto/proto_incremental_state.h59
-rw-r--r--src/trace_processor/importers/proto/proto_trace_reader.cc2
-rw-r--r--src/trace_processor/importers/proto/proto_trace_reader.h23
-rw-r--r--src/trace_processor/importers/proto/stack_profile_sequence_state.h3
-rw-r--r--src/trace_processor/importers/proto/track_event_parser.cc8
-rw-r--r--src/trace_processor/importers/proto/track_event_sequence_state.cc37
-rw-r--r--src/trace_processor/importers/proto/track_event_sequence_state.h99
-rw-r--r--src/trace_processor/importers/proto/track_event_tokenizer.cc7
-rw-r--r--src/trace_processor/importers/proto/v8_module.cc15
-rw-r--r--src/trace_processor/importers/proto/v8_sequence_state.h3
-rw-r--r--src/trace_processor/importers/proto/vulkan_memory_tracker.h7
-rw-r--r--src/trace_processor/metrics/sql/android/android_startup.sql14
-rw-r--r--src/trace_processor/perfetto_sql/stdlib/android/startup/time_to_display.sql4
-rw-r--r--src/trace_processor/sorter/BUILD.gn2
-rw-r--r--src/trace_processor/sorter/trace_sorter.h1
-rw-r--r--src/trace_processor/sorter/trace_sorter_unittest.cc74
-rw-r--r--src/trace_processor/sorter/trace_token_buffer_unittest.cc52
-rw-r--r--src/trace_processor/util/BUILD.gn1
-rw-r--r--src/trace_processor/util/debug_annotation_parser_unittest.cc26
-rw-r--r--src/trace_processor/util/interned_message_view.h2
-rw-r--r--src/traced/probes/packages_list/packages_list_parser.cc2
-rw-r--r--src/tracing/internal/tracing_muxer_impl.cc5
-rw-r--r--src/tracing/test/api_integrationtest.cc11
-rw-r--r--src/tracing/track.cc7
-rw-r--r--src/tracing/track_event_state_tracker.cc6
-rw-r--r--test/trace_processor/diff_tests/metrics/startup/tests.py6
-rw-r--r--test/trace_processor/diff_tests/metrics/startup/ttid_and_ttfd.out98
-rw-r--r--test/trace_processor/diff_tests/parser/profiling/tests.py2
-rw-r--r--test/trace_processor/diff_tests/stdlib/android/startups_tests.py12
-rw-r--r--test/trace_processor/diff_tests/stdlib/prelude/pprof_functions_tests.py2
-rwxr-xr-xtools/install-build-deps10
-rw-r--r--ui/release/channels.json2
-rw-r--r--ui/src/common/state.ts22
-rw-r--r--ui/src/controller/trace_controller.ts2
69 files changed, 1449 insertions, 625 deletions
diff --git a/Android.bp b/Android.bp
index b379ef77c..14e7ab9b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11871,6 +11871,7 @@ filegroup {
srcs: [
"src/trace_processor/containers/bit_vector_unittest.cc",
"src/trace_processor/containers/implicit_segment_forest_unittest.cc",
+ "src/trace_processor/containers/interval_tree_unittest.cc",
"src/trace_processor/containers/null_term_string_view_unittest.cc",
"src/trace_processor/containers/row_map_unittest.cc",
"src/trace_processor/containers/string_pool_unittest.cc",
@@ -12393,6 +12394,7 @@ filegroup {
"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_sequence_state.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.cc",
"src/trace_processor/importers/proto/track_event_tracker.cc",
],
diff --git a/BUILD b/BUILD
index bf86ecc44..3437d7c16 100644
--- a/BUILD
+++ b/BUILD
@@ -1375,6 +1375,7 @@ perfetto_cc_library(
":include_perfetto_public_protozero",
"src/trace_processor/containers/bit_vector.h",
"src/trace_processor/containers/implicit_segment_forest.h",
+ "src/trace_processor/containers/interval_tree.h",
"src/trace_processor/containers/null_term_string_view.h",
"src/trace_processor/containers/row_map.h",
"src/trace_processor/containers/row_map_algorithms.h",
@@ -1896,7 +1897,7 @@ perfetto_filegroup(
"src/trace_processor/importers/proto/network_trace_module.h",
"src/trace_processor/importers/proto/packet_analyzer.cc",
"src/trace_processor/importers/proto/packet_analyzer.h",
- "src/trace_processor/importers/proto/packet_sequence_state.h",
+ "src/trace_processor/importers/proto/packet_sequence_state_builder.h",
"src/trace_processor/importers/proto/packet_sequence_state_generation.cc",
"src/trace_processor/importers/proto/perf_sample_tracker.cc",
"src/trace_processor/importers/proto/perf_sample_tracker.h",
@@ -1906,7 +1907,6 @@ perfetto_filegroup(
"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/proto_incremental_state.h",
"src/trace_processor/importers/proto/proto_trace_parser_impl.cc",
"src/trace_processor/importers/proto/proto_trace_parser_impl.h",
"src/trace_processor/importers/proto/proto_trace_reader.cc",
@@ -1919,6 +1919,7 @@ perfetto_filegroup(
"src/trace_processor/importers/proto/track_event_module.h",
"src/trace_processor/importers/proto/track_event_parser.cc",
"src/trace_processor/importers/proto/track_event_parser.h",
+ "src/trace_processor/importers/proto/track_event_sequence_state.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.cc",
"src/trace_processor/importers/proto/track_event_tokenizer.h",
"src/trace_processor/importers/proto/track_event_tracker.cc",
@@ -1931,6 +1932,7 @@ perfetto_filegroup(
name = "src_trace_processor_importers_proto_packet_sequence_state_generation_hdr",
srcs = [
"src/trace_processor/importers/proto/packet_sequence_state_generation.h",
+ "src/trace_processor/importers/proto/track_event_sequence_state.h",
],
)
diff --git a/CHANGELOG b/CHANGELOG
index 278d2f44d..d117e7d34 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,7 +2,8 @@ Unreleased:
Tracing service and probes:
*
Trace Processor:
- *
+ * Added "time to initial display" and "time to full display" metrics to
+ the Android startup metric.
UI:
*
SDK:
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index 07c6e217e..ae25789a6 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -876,7 +876,10 @@ if (use_custom_libcxx) {
libs = [ "atomic" ]
}
- inputs = [ "libcxx_config/__config_site" ]
+ inputs = [
+ "libcxx_config/__assertion_handler",
+ "libcxx_config/__config_site",
+ ]
sources = [
"libcxx/src/algorithm.cpp",
@@ -884,12 +887,17 @@ if (use_custom_libcxx) {
"libcxx/src/atomic.cpp",
"libcxx/src/barrier.cpp",
"libcxx/src/bind.cpp",
+ "libcxx/src/call_once.cpp",
"libcxx/src/charconv.cpp",
"libcxx/src/chrono.cpp",
"libcxx/src/condition_variable.cpp",
"libcxx/src/condition_variable_destructor.cpp",
+ "libcxx/src/error_category.cpp",
"libcxx/src/exception.cpp",
- "libcxx/src/format.cpp",
+ "libcxx/src/filesystem/directory_iterator.cpp",
+ "libcxx/src/filesystem/filesystem_error.cpp",
+ "libcxx/src/filesystem/operations.cpp",
+ "libcxx/src/filesystem/path.cpp",
"libcxx/src/functional.cpp",
"libcxx/src/future.cpp",
"libcxx/src/hash.cpp",
@@ -901,7 +909,8 @@ if (use_custom_libcxx) {
"libcxx/src/memory.cpp",
"libcxx/src/mutex.cpp",
"libcxx/src/mutex_destructor.cpp",
- "libcxx/src/new.cpp",
+ "libcxx/src/new_handler.cpp",
+ "libcxx/src/new_helpers.cpp",
"libcxx/src/optional.cpp",
"libcxx/src/random.cpp",
"libcxx/src/random_shuffle.cpp",
@@ -916,12 +925,23 @@ if (use_custom_libcxx) {
"libcxx/src/system_error.cpp",
"libcxx/src/thread.cpp",
"libcxx/src/typeinfo.cpp",
- "libcxx/src/utility.cpp",
"libcxx/src/valarray.cpp",
"libcxx/src/variant.cpp",
"libcxx/src/vector.cpp",
"libcxx/src/verbose_abort.cpp",
]
+ if (!using_sanitizer) {
+ # In {a,t,m}san configurations, operator new and operator delete will be
+ # provided by the sanitizer runtime library. Since libc++ defines these
+ # symbols with weak linkage, and the *san runtime uses strong linkage, it
+ # should technically be OK to include this file, but it's removed to be
+ # explicit.
+ # We need using_sanitizer rather than is_asan || is_msan ... because in
+ # perfetto, when cross-compiling, we build only targets with sanitizers,
+ # but not host artifacts, and using_sanitizer is only true for the
+ # target toolchain, while is_asan is globally true on all toolchains.
+ sources += [ "libcxx/src/new.cpp" ]
+ }
include_dirs = [ "libcxx/src" ]
if (is_win) {
@@ -1543,7 +1563,7 @@ source_set("llvm_demangle") {
"llvm-project/llvm/include/llvm/Demangle/ItaniumDemangle.h",
"llvm-project/llvm/include/llvm/Demangle/MicrosoftDemangle.h",
"llvm-project/llvm/include/llvm/Demangle/MicrosoftDemangleNodes.h",
- "llvm-project/llvm/include/llvm/Demangle/StringView.h",
+ "llvm-project/llvm/include/llvm/Demangle/StringViewExtras.h",
"llvm-project/llvm/include/llvm/Demangle/Utility.h",
"llvm-project/llvm/lib/Demangle/DLangDemangle.cpp",
"llvm-project/llvm/lib/Demangle/Demangle.cpp",
diff --git a/buildtools/libcxx_config/__assertion_handler b/buildtools/libcxx_config/__assertion_handler
new file mode 100644
index 000000000..5d997d0b6
--- /dev/null
+++ b/buildtools/libcxx_config/__assertion_handler
@@ -0,0 +1,16 @@
+// From chromium's buildtools/third_party/libc++/__assertion_handler
+
+#ifndef _LIBCPP___ASSERTION_HANDLER
+#define _LIBCPP___ASSERTION_HANDLER
+
+#include <__config>
+#include <__verbose_abort>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+// TODO(hardening): in production, trap rather than abort.
+#define _LIBCPP_ASSERTION_HANDLER(message) _LIBCPP_VERBOSE_ABORT("%s", message)
+
+#endif // _LIBCPP___ASSERTION_HANDLER
diff --git a/buildtools/libcxx_config/__config_site b/buildtools/libcxx_config/__config_site
index 2df8632ec..dd396f0a7 100644
--- a/buildtools/libcxx_config/__config_site
+++ b/buildtools/libcxx_config/__config_site
@@ -1,3 +1,5 @@
+// From chromium's buildtools/third_party/libc++/__config_site
+
#ifndef _LIBCPP_CONFIG_SITE
#define _LIBCPP_CONFIG_SITE
@@ -11,7 +13,8 @@
// on Windows, the increase is great enough that we go above the 4GB size
// limit for PDBs (https://crbug.com/1327710#c5). To fix this, we set
// _LIBCPP_ABI_NAMESPACE to a shorter value.
-#define _LIBCPP_ABI_NAMESPACE Cr
+#define _LIBCPP_ABI_NAMESPACE __Cr
+
#define _LIBCPP_ABI_VERSION 2
/* #undef _LIBCPP_ABI_FORCE_ITANIUM */
@@ -27,12 +30,37 @@
#define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS
/* #undef _LIBCPP_NO_VCRUNTIME */
/* #undef _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION */
-/* #undef _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY */
+/* #undef _LIBCPP_HAS_NO_FILESYSTEM */
/* #undef _LIBCPP_HAS_PARALLEL_ALGORITHMS */
/* #undef _LIBCPP_HAS_NO_RANDOM_DEVICE */
/* #undef _LIBCPP_HAS_NO_LOCALIZATION */
/* #undef _LIBCPP_HAS_NO_WIDE_CHARACTERS */
+// TODO(thakis): Is this right?
+/* #undef _LIBCPP_HAS_NO_STD_MODULES */
+
+// TODO(thakis): Is this right?
+/* #undef _LIBCPP_HAS_NO_TIME_ZONE_DATABASE */
+
+#define _LIBCPP_INSTRUMENTED_WITH_ASAN
+
+// PSTL backends
+/* #undef _LIBCPP_PSTL_BACKEND_SERIAL */
+#if defined(__APPLE__)
+#define _LIBCPP_PSTL_BACKEND_LIBDISPATCH
+#else
+#define _LIBCPP_PSTL_BACKEND_STD_THREAD
+#endif
+
+// PSTL backends, old spelling
+// TODO(thakis): Remove these after the next libc++ roll is in.
+/* #undef _LIBCPP_PSTL_CPU_BACKEND_SERIAL */
+#if defined(__APPLE__)
+#define _LIBCPP_PSTL_CPU_BACKEND_LIBDISPATCH
+#else
+#define _LIBCPP_PSTL_CPU_BACKEND_THREAD
+#endif
+
// Settings below aren't part of __config_site upstream.
// We set them here since we want them to take effect everywhere,
// unconditionally.
@@ -45,4 +73,24 @@
#define _LIBCPP_REMOVE_TRANSITIVE_INCLUDES
+// Don't add ABI tags to libc++ symbols. ABI tags increase mangled name sizes.
+// This only exists to allow multiple // libc++ versions to be linked into a
+// binary, which Chrome doesn't do.
+#define _LIBCPP_NO_ABI_TAG
+
+// Explicitly define _LIBCPP_VERBOSE_ABORT(...) to call the termination
+// function because by default, this macro will does not call the verbose
+// termination function on Apple platforms.
+#define _LIBCPP_VERBOSE_ABORT(...) ::std::__libcpp_verbose_abort(__VA_ARGS__)
+
+// TODO(crbug.com/40272953) Link against compiler-rt's builtins library to
+// enable 128-arithmetic.
+#if defined(_WIN32)
+#define _LIBCPP_HAS_NO_INT128
+#endif
+
+// TODO(thakis): Remove this after LLVM 19's libc++ is rolled in.
+#define _LIBCPP_CHAR_TRAITS_REMOVE_BASE_SPECIALIZATION
+
+#define _LIBCPP_HARDENING_MODE_DEFAULT _LIBCPP_HARDENING_MODE_NONE
#endif // _LIBCPP_CONFIG_SITE
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index 8cd9b086c..c0aed1cd0 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -312,8 +312,10 @@ declare_args() {
# Enables function name demangling using sources from llvm. Otherwise
# trace_processor falls back onto using the c++ runtime demangler, which
# typically handles only itanium mangling.
+ # llvm-demangle is incompatible with GCC and can be used only when building
+ # with clang.
enable_perfetto_llvm_demangle =
- enable_perfetto_trace_processor && perfetto_build_standalone
+ is_clang && enable_perfetto_trace_processor && perfetto_build_standalone
# Enables gRPC in the Perfetto codebase. gRPC significantly increases build
# times and the general footprint of Perfetto. As it only required for
diff --git a/include/perfetto/ext/base/small_set.h b/include/perfetto/ext/base/small_set.h
index db057a0e8..5d8d8bcf1 100644
--- a/include/perfetto/ext/base/small_set.h
+++ b/include/perfetto/ext/base/small_set.h
@@ -49,7 +49,9 @@ class SmallSet {
}
const_iterator begin() const { return arr_.cbegin(); }
- const_iterator end() const { return arr_.cbegin() + filled_; }
+ const_iterator end() const {
+ return arr_.cbegin() + static_cast<ssize_t>(filled_);
+ }
size_t size() const { return filled_; }
private:
diff --git a/include/perfetto/profiling/parse_smaps.h b/include/perfetto/profiling/parse_smaps.h
index 9623c3810..80e7e6cf0 100644
--- a/include/perfetto/profiling/parse_smaps.h
+++ b/include/perfetto/profiling/parse_smaps.h
@@ -23,6 +23,7 @@
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
diff --git a/include/perfetto/public/data_source.h b/include/perfetto/public/data_source.h
index 23fba9250..83fb52792 100644
--- a/include/perfetto/public/data_source.h
+++ b/include/perfetto/public/data_source.h
@@ -75,6 +75,10 @@ struct PerfettoDsParams {
// How to behave when running out of shared memory buffer space.
enum PerfettoDsBufferExhaustedPolicy buffer_exhausted_policy;
+
+ // When true the data source is expected to ack the stop request through the
+ // NotifyDataSourceStopped() IPC.
+ bool will_notify_on_stop;
};
static inline struct PerfettoDsParams PerfettoDsParamsDefault(void) {
@@ -88,7 +92,8 @@ static inline struct PerfettoDsParams PerfettoDsParamsDefault(void) {
PERFETTO_NULL,
PERFETTO_NULL,
PERFETTO_NULL,
- PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP};
+ PERFETTO_DS_BUFFER_EXHAUSTED_POLICY_DROP,
+ true};
return ret;
}
@@ -112,6 +117,7 @@ static inline bool PerfettoDsRegister(struct PerfettoDs* ds,
PerfettoPbMsgInit(&desc.msg, &writer);
perfetto_protos_DataSourceDescriptor_set_cstr_name(&desc, data_source_name);
+ perfetto_protos_DataSourceDescriptor_set_will_notify_on_stop(&desc, params.will_notify_on_stop);
desc_size = PerfettoStreamWriterGetWrittenSize(&writer.writer);
desc_buf = malloc(desc_size);
diff --git a/include/perfetto/tracing/string_helpers.h b/include/perfetto/tracing/string_helpers.h
index 0d2819a99..03fa9e4d7 100644
--- a/include/perfetto/tracing/string_helpers.h
+++ b/include/perfetto/tracing/string_helpers.h
@@ -38,6 +38,8 @@ class PERFETTO_EXPORT_COMPONENT StaticString {
constexpr explicit StaticString(const char* str) : value(str) {}
+ operator bool() const { return !!value; }
+
const char* value;
};
@@ -52,6 +54,9 @@ class PERFETTO_EXPORT_COMPONENT DynamicString {
length = strlen(str);
}
DynamicString(const char* str, size_t len) : value(str), length(len) {}
+ constexpr DynamicString() : value(nullptr), length(0) {}
+
+ operator bool() const { return !!value; }
const char* value;
size_t length;
diff --git a/include/perfetto/tracing/track.h b/include/perfetto/tracing/track.h
index 37f02e585..831c29074 100644
--- a/include/perfetto/tracing/track.h
+++ b/include/perfetto/tracing/track.h
@@ -25,6 +25,7 @@
#include "perfetto/tracing/internal/fnv1a.h"
#include "perfetto/tracing/internal/tracing_muxer.h"
#include "perfetto/tracing/platform.h"
+#include "perfetto/tracing/string_helpers.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
#include "protos/perfetto/trace/track_event/counter_descriptor.pbzero.h"
@@ -201,71 +202,92 @@ class PERFETTO_EXPORT_COMPONENT CounterTrack : public Track {
perfetto::protos::gen::CounterDescriptor::BuiltinCounterType;
// |name| must outlive this object.
- constexpr explicit CounterTrack(const char* name,
+ constexpr explicit CounterTrack(StaticString name,
Track parent = MakeProcessTrack())
- : Track(internal::Fnv1a(name) ^ kCounterMagic, parent),
- name_(name),
- category_(nullptr) {}
+ : CounterTrack(
+ name,
+ perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED,
+ nullptr,
+ parent) {}
+
+ explicit CounterTrack(DynamicString name, Track parent = MakeProcessTrack())
+ : CounterTrack(
+ name,
+ perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED,
+ nullptr,
+ parent) {}
// |unit_name| is a free-form description of the unit used by this counter. It
// must outlive this object.
- constexpr CounterTrack(const char* name,
+ template <class TrackEventName>
+ constexpr CounterTrack(TrackEventName&& name,
const char* unit_name,
Track parent = MakeProcessTrack())
- : Track(internal::Fnv1a(name) ^ kCounterMagic, parent),
- name_(name),
- category_(nullptr),
- unit_name_(unit_name) {}
-
- constexpr CounterTrack(const char* name,
+ : CounterTrack(
+ std::forward<TrackEventName>(name),
+ perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED,
+ unit_name,
+ parent) {}
+
+ template <class TrackEventName>
+ constexpr CounterTrack(TrackEventName&& name,
Unit unit,
Track parent = MakeProcessTrack())
- : Track(internal::Fnv1a(name) ^ kCounterMagic, parent),
- name_(name),
- category_(nullptr),
- unit_(unit) {}
+ : CounterTrack(std::forward<TrackEventName>(name),
+ unit,
+ nullptr,
+ parent) {}
- static constexpr CounterTrack Global(const char* name,
+ template <class TrackEventName>
+ static constexpr CounterTrack Global(TrackEventName&& name,
const char* unit_name) {
- return CounterTrack(name, unit_name, Track());
+ return CounterTrack(std::forward<TrackEventName>(name), unit_name, Track());
}
- static constexpr CounterTrack Global(const char* name, Unit unit) {
- return CounterTrack(name, unit, Track());
+ template <class TrackEventName>
+ static constexpr CounterTrack Global(TrackEventName&& name, Unit unit) {
+ return CounterTrack(std::forward<TrackEventName>(name), unit, Track());
}
- static constexpr CounterTrack Global(const char* name) {
- return Global(name, nullptr);
+ template <class TrackEventName>
+ static constexpr CounterTrack Global(TrackEventName&& name) {
+ return Global(std::forward<TrackEventName>(name), nullptr);
}
constexpr CounterTrack set_unit(Unit unit) const {
- return CounterTrack(uuid, parent_uuid, name_, category_, unit, unit_name_,
- unit_multiplier_, is_incremental_, type_);
+ return CounterTrack(uuid, parent_uuid, static_name_, dynamic_name_,
+ category_, unit, unit_name_, unit_multiplier_,
+ is_incremental_, type_);
}
constexpr CounterTrack set_type(CounterType type) const {
- return CounterTrack(uuid, parent_uuid, name_, category_, unit_, unit_name_,
- unit_multiplier_, is_incremental_, type);
+ return CounterTrack(uuid, parent_uuid, static_name_, dynamic_name_,
+ category_, unit_, unit_name_, unit_multiplier_,
+ is_incremental_, type);
}
constexpr CounterTrack set_unit_name(const char* unit_name) const {
- return CounterTrack(uuid, parent_uuid, name_, category_, unit_, unit_name,
- unit_multiplier_, is_incremental_, type_);
+ return CounterTrack(uuid, parent_uuid, static_name_, dynamic_name_,
+ category_, unit_, unit_name, unit_multiplier_,
+ is_incremental_, type_);
}
constexpr CounterTrack set_unit_multiplier(int64_t unit_multiplier) const {
- return CounterTrack(uuid, parent_uuid, name_, category_, unit_, unit_name_,
- unit_multiplier, is_incremental_, type_);
+ return CounterTrack(uuid, parent_uuid, static_name_, dynamic_name_,
+ category_, unit_, unit_name_, unit_multiplier,
+ is_incremental_, type_);
}
constexpr CounterTrack set_category(const char* category) const {
- return CounterTrack(uuid, parent_uuid, name_, category, unit_, unit_name_,
- unit_multiplier_, is_incremental_, type_);
+ return CounterTrack(uuid, parent_uuid, static_name_, dynamic_name_,
+ category, unit_, unit_name_, unit_multiplier_,
+ is_incremental_, type_);
}
constexpr CounterTrack set_is_incremental(bool is_incremental = true) const {
- return CounterTrack(uuid, parent_uuid, name_, category_, unit_, unit_name_,
- unit_multiplier_, is_incremental, type_);
+ return CounterTrack(uuid, parent_uuid, static_name_, dynamic_name_,
+ category_, unit_, unit_name_, unit_multiplier_,
+ is_incremental, type_);
}
constexpr bool is_incremental() const { return is_incremental_; }
@@ -274,9 +296,29 @@ class PERFETTO_EXPORT_COMPONENT CounterTrack : public Track {
protos::gen::TrackDescriptor Serialize() const;
private:
+ constexpr CounterTrack(StaticString name,
+ Unit unit,
+ const char* unit_name,
+ Track parent)
+ : Track(internal::Fnv1a(name.value) ^ kCounterMagic, parent),
+ static_name_(name),
+ category_(nullptr),
+ unit_(unit),
+ unit_name_(unit_name) {}
+ CounterTrack(DynamicString name,
+ Unit unit,
+ const char* unit_name,
+ Track parent)
+ : Track(internal::Fnv1a(name.value, name.length) ^ kCounterMagic, parent),
+ static_name_(nullptr),
+ dynamic_name_(name),
+ category_(nullptr),
+ unit_(unit),
+ unit_name_(unit_name) {}
constexpr CounterTrack(uint64_t uuid_,
uint64_t parent_uuid_,
- const char* name,
+ StaticString static_name,
+ DynamicString dynamic_name,
const char* category,
Unit unit,
const char* unit_name,
@@ -284,7 +326,8 @@ class PERFETTO_EXPORT_COMPONENT CounterTrack : public Track {
bool is_incremental,
CounterType type)
: Track(uuid_, parent_uuid_),
- name_(name),
+ static_name_(static_name),
+ dynamic_name_(dynamic_name),
category_(category),
unit_(unit),
unit_name_(unit_name),
@@ -292,7 +335,8 @@ class PERFETTO_EXPORT_COMPONENT CounterTrack : public Track {
is_incremental_(is_incremental),
type_(type) {}
- const char* const name_;
+ StaticString static_name_;
+ DynamicString dynamic_name_;
const char* const category_;
Unit unit_ = perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED;
const char* const unit_name_ = nullptr;
diff --git a/protos/perfetto/metrics/android/startup_metric.proto b/protos/perfetto/metrics/android/startup_metric.proto
index 16a0c3ec6..66f01ec4b 100644
--- a/protos/perfetto/metrics/android/startup_metric.proto
+++ b/protos/perfetto/metrics/android/startup_metric.proto
@@ -86,7 +86,8 @@ message AndroidStartupMetric {
// The actual duration of the process start (based on the zygote slice).
optional Slice time_during_start_process = 11;
- // The duration from launch to first running state thread of startup process.
+ // The duration from launch to first running state thread of startup
+ // process.
optional Slice time_to_running_state = 35;
optional Slice to_post_fork = 18;
@@ -200,11 +201,11 @@ message AndroidStartupMetric {
message SystemState {
// Whether the dex2oat64 process was running concurrent to the startup.
// Deprecated as of 10/2022.
- optional bool dex2oat_running = 1 [deprecated=true];
+ optional bool dex2oat_running = 1 [deprecated = true];
// Whether the installd process was running concurrent to the startup.
// Deprecated as of 10/2022.
- optional bool installd_running = 2 [deprecated=true];
+ optional bool installd_running = 2 [deprecated = true];
// The number of broadcasts dispatched by the system during the app
// launch.
@@ -279,7 +280,8 @@ message AndroidStartupMetric {
optional int64 launch_dur = 5;
// Sum of durations of slices and thread states in trace_slices_or_threads.
- // Can be used to decide if a couple of top slices or threads caused the issue.
+ // Can be used to decide if a couple of top slices or threads caused the
+ // issue.
optional int64 duration = 6;
// Information of a subset of slice and thread sections to focused on,
@@ -295,7 +297,7 @@ message AndroidStartupMetric {
message ThresholdValue {
// Expected value. 1 for true and 0 for false for booleans.
- optional int64 value = 1;
+ optional int64 value = 1;
// Expected value unit. Enum, e.g. "ns", "%"
enum ThresholdUnit {
@@ -333,14 +335,14 @@ message AndroidStartupMetric {
// Contains information for a section of a thread.
message TraceThreadSection {
- optional int64 start_timestamp = 1;
+ optional int64 start_timestamp = 1;
- optional int64 end_timestamp = 2;
+ optional int64 end_timestamp = 2;
- optional uint32 thread_utid = 3;
+ optional uint32 thread_utid = 3;
}
- // Next id: 22
+ // Next id: 24
message Startup {
// Random id uniquely identifying an app startup in this trace.
optional uint32 startup_id = 1;
@@ -370,6 +372,17 @@ message AndroidStartupMetric {
// it.
optional uint32 activity_hosting_process_count = 6;
+ // Time it takes to display the first frame of the app`s UI.
+ // Details:
+ // https://developer.android.com/topic/performance/vitals/launch-time#time-initial
+ optional int64 time_to_initial_display = 22;
+
+ // Time to full display (TTFD) is the time ittakes for an app to become
+ // interactive for the user.
+ // Datails:
+ // https://developer.android.com/topic/performance/vitals/launch-time#time-full
+ optional int64 time_to_full_display = 23;
+
// Contains timestamps of important events which happened during
// the startup.
optional EventTimestamps event_timestamps = 13;
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 1db8a09c1..bffca26fe 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -2202,7 +2202,8 @@ message AndroidStartupMetric {
// The actual duration of the process start (based on the zygote slice).
optional Slice time_during_start_process = 11;
- // The duration from launch to first running state thread of startup process.
+ // The duration from launch to first running state thread of startup
+ // process.
optional Slice time_to_running_state = 35;
optional Slice to_post_fork = 18;
@@ -2316,11 +2317,11 @@ message AndroidStartupMetric {
message SystemState {
// Whether the dex2oat64 process was running concurrent to the startup.
// Deprecated as of 10/2022.
- optional bool dex2oat_running = 1 [deprecated=true];
+ optional bool dex2oat_running = 1 [deprecated = true];
// Whether the installd process was running concurrent to the startup.
// Deprecated as of 10/2022.
- optional bool installd_running = 2 [deprecated=true];
+ optional bool installd_running = 2 [deprecated = true];
// The number of broadcasts dispatched by the system during the app
// launch.
@@ -2395,7 +2396,8 @@ message AndroidStartupMetric {
optional int64 launch_dur = 5;
// Sum of durations of slices and thread states in trace_slices_or_threads.
- // Can be used to decide if a couple of top slices or threads caused the issue.
+ // Can be used to decide if a couple of top slices or threads caused the
+ // issue.
optional int64 duration = 6;
// Information of a subset of slice and thread sections to focused on,
@@ -2411,7 +2413,7 @@ message AndroidStartupMetric {
message ThresholdValue {
// Expected value. 1 for true and 0 for false for booleans.
- optional int64 value = 1;
+ optional int64 value = 1;
// Expected value unit. Enum, e.g. "ns", "%"
enum ThresholdUnit {
@@ -2449,14 +2451,14 @@ message AndroidStartupMetric {
// Contains information for a section of a thread.
message TraceThreadSection {
- optional int64 start_timestamp = 1;
+ optional int64 start_timestamp = 1;
- optional int64 end_timestamp = 2;
+ optional int64 end_timestamp = 2;
- optional uint32 thread_utid = 3;
+ optional uint32 thread_utid = 3;
}
- // Next id: 22
+ // Next id: 24
message Startup {
// Random id uniquely identifying an app startup in this trace.
optional uint32 startup_id = 1;
@@ -2486,6 +2488,17 @@ message AndroidStartupMetric {
// it.
optional uint32 activity_hosting_process_count = 6;
+ // Time it takes to display the first frame of the app`s UI.
+ // Details:
+ // https://developer.android.com/topic/performance/vitals/launch-time#time-initial
+ optional int64 time_to_initial_display = 22;
+
+ // Time to full display (TTFD) is the time ittakes for an app to become
+ // interactive for the user.
+ // Datails:
+ // https://developer.android.com/topic/performance/vitals/launch-time#time-full
+ optional int64 time_to_full_display = 23;
+
// Contains timestamps of important events which happened during
// the startup.
optional EventTimestamps event_timestamps = 13;
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 960f8c301..5df533909 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -14675,7 +14675,7 @@ message CounterDescriptor {
// |TrackEvent::track_uuid|. It is possible but not necessary to emit a
// TrackDescriptor for this implicit track.
//
-// Next id: 10.
+// Next id: 11.
message TrackDescriptor {
// Unique ID that identifies this track. This ID is global to the whole trace.
// Producers should ensure that it is unlikely to clash with IDs emitted by
@@ -14695,7 +14695,12 @@ message TrackDescriptor {
// Name of the track. Optional - if unspecified, it may be derived from the
// process/thread name (process/thread tracks), the first event's name (async
// tracks), or counter name (counter tracks).
- optional string name = 2;
+ oneof static_or_dynamic_name {
+ string name = 2;
+ // This field is only set by the SDK when perfetto::StaticString is
+ // provided.
+ string static_name = 10;
+ }
// Associate the track with a process, making it the process-global track.
// There should only be one such track per process (usually for instant
diff --git a/protos/perfetto/trace/track_event/track_descriptor.proto b/protos/perfetto/trace/track_event/track_descriptor.proto
index d6db23396..76890f2fc 100644
--- a/protos/perfetto/trace/track_event/track_descriptor.proto
+++ b/protos/perfetto/trace/track_event/track_descriptor.proto
@@ -37,7 +37,7 @@ package perfetto.protos;
// |TrackEvent::track_uuid|. It is possible but not necessary to emit a
// TrackDescriptor for this implicit track.
//
-// Next id: 10.
+// Next id: 11.
message TrackDescriptor {
// Unique ID that identifies this track. This ID is global to the whole trace.
// Producers should ensure that it is unlikely to clash with IDs emitted by
@@ -57,7 +57,12 @@ message TrackDescriptor {
// Name of the track. Optional - if unspecified, it may be derived from the
// process/thread name (process/thread tracks), the first event's name (async
// tracks), or counter name (counter tracks).
- optional string name = 2;
+ oneof static_or_dynamic_name {
+ string name = 2;
+ // This field is only set by the SDK when perfetto::StaticString is
+ // provided.
+ string static_name = 10;
+ }
// Associate the track with a process, making it the process-global track.
// There should only be one such track per process (usually for instant
diff --git a/python/generators/diff_tests/testing.py b/python/generators/diff_tests/testing.py
index 515f95641..b90e4cd4a 100644
--- a/python/generators/diff_tests/testing.py
+++ b/python/generators/diff_tests/testing.py
@@ -270,12 +270,14 @@ def PrintProfileProto(profile):
locations = {l.id: l for l in profile.location}
functions = {f.id: f for f in profile.function}
samples = []
+ # Strips trailing annotations like (.__uniq.1657) from the function name.
+ filter_fname = lambda x: re.sub(' [(\[].*?uniq.*?[)\]]$', '', x)
for s in profile.sample:
stack = []
for location in [locations[id] for id in s.location_id]:
for function in [functions[l.function_id] for l in location.line]:
stack.append("{name} ({address})".format(
- name=profile.string_table[function.name],
+ name=filter_fname(profile.string_table[function.name]),
address=hex(location.address)))
if len(location.line) == 0:
stack.append("({address})".format(address=hex(location.address)))
diff --git a/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
index 4b307a8d3..ef138160e 100644
--- a/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
@@ -992,8 +992,8 @@ maxRuntime$
name ( RnameY
threads ( 2?.perfetto.protos.AndroidSimpleperfMetric.PerfEventMetric.ThreadRthreads
total (Rtotal
-¡A
-4protos/perfetto/metrics/android/startup_metric.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"Ÿ@
+‰B
+4protos/perfetto/metrics/android/startup_metric.protoperfetto.protos6protos/perfetto/metrics/android/process_metadata.proto"‡A
AndroidStartupMetricG
startup ( 2-.perfetto.protos.AndroidStartupMetric.StartupRstartupó
TaskStateBreakdown$
@@ -1144,7 +1144,7 @@ PERCENTAGE
start_timestamp (RstartTimestamp#
end_timestamp (R endTimestamp
thread_utid ( R
-threadUtidŒ
+threadUtidô
Startup
startup_id ( R startupId!
@@ -1156,7 +1156,9 @@ activities ( 2..perfetto.protos.AndroidStartupMetric.ActivityR
activitiesq
long_binder_transactions ( 27.perfetto.protos.AndroidStartupMetric.BinderTransactionRlongBinderTransactions,
zygote_new_process (RzygoteNewProcessC
-activity_hosting_process_count ( RactivityHostingProcessCount`
+activity_hosting_process_count ( RactivityHostingProcessCount5
+time_to_initial_display (RtimeToInitialDisplay/
+time_to_full_display (RtimeToFullDisplay`
event_timestamps ( 25.perfetto.protos.AndroidStartupMetric.EventTimestampsReventTimestampsX
to_first_frame ( 22.perfetto.protos.AndroidStartupMetric.ToFirstFrameR toFirstFrameA
process ( 2'.perfetto.protos.AndroidProcessMetadataRprocessB
diff --git a/src/trace_processor/containers/BUILD.gn b/src/trace_processor/containers/BUILD.gn
index c724df867..797400353 100644
--- a/src/trace_processor/containers/BUILD.gn
+++ b/src/trace_processor/containers/BUILD.gn
@@ -23,6 +23,7 @@ perfetto_component("containers") {
public = [
"bit_vector.h",
"implicit_segment_forest.h",
+ "interval_tree.h",
"null_term_string_view.h",
"row_map.h",
"row_map_algorithms.h",
@@ -46,6 +47,7 @@ perfetto_unittest_source_set("unittests") {
sources = [
"bit_vector_unittest.cc",
"implicit_segment_forest_unittest.cc",
+ "interval_tree_unittest.cc",
"null_term_string_view_unittest.cc",
"row_map_unittest.cc",
"string_pool_unittest.cc",
diff --git a/src/trace_processor/containers/interval_tree.h b/src/trace_processor/containers/interval_tree.h
new file mode 100644
index 000000000..c083da053
--- /dev/null
+++ b/src/trace_processor/containers/interval_tree.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 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_CONTAINERS_INTERVAL_TREE_H_
+#define SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_
+
+#include <cstdint>
+#include <limits>
+#include <memory>
+#include <vector>
+
+namespace perfetto::trace_processor {
+
+// An implementation of an interval tree data structure, designed to efficiently
+// perform overlap queries on a set of intervals. Used by `interval_intersect`,
+// where one set of intervals (generally the bigger one) has interval tree
+// created based on it, as another queries `FindOverlaps` function for each
+// interval.
+// As interval tree is build on sorted (by `start`) set of N intervals, the
+// complexity of creating a tree goes down from O(N*logN) to O(N) and the
+// created tree is optimally balanced. Each call to `FindOverlaps` is O(logN).
+class IntervalTree {
+ public:
+ struct Interval {
+ uint32_t start;
+ uint32_t end;
+ uint32_t id;
+ };
+
+ // Takes vector of sorted intervals.
+ explicit IntervalTree(std::vector<Interval>& sorted_intervals) {
+ tree_root_ = BuildFromSortedIntervals(
+ sorted_intervals, 0, static_cast<int32_t>(sorted_intervals.size() - 1));
+ }
+
+ // Modifies |overlaps| to contain ids of all intervals in the interval tree
+ // that overlap with |interval|.
+ void FindOverlaps(Interval interval, std::vector<uint32_t>& overlaps) const {
+ if (tree_root_) {
+ FindOverlaps(*tree_root_, interval, overlaps);
+ }
+ }
+
+ private:
+ struct Node {
+ Interval interval;
+ uint32_t max;
+ std::unique_ptr<Node> left;
+ std::unique_ptr<Node> right;
+
+ explicit Node(Interval i) : interval(i), max(i.end) {}
+ };
+
+ static std::unique_ptr<Node> Insert(std::unique_ptr<Node> root, Interval i) {
+ if (root == nullptr) {
+ return std::make_unique<Node>(i);
+ }
+
+ if (i.start < root->interval.start) {
+ root->left = Insert(std::move(root->left), i);
+ } else {
+ root->right = Insert(std::move(root->right), i);
+ }
+
+ if (root->max < i.end) {
+ root->max = i.end;
+ }
+
+ return root;
+ }
+
+ static std::unique_ptr<Node> BuildFromSortedIntervals(
+ const std::vector<Interval>& is,
+ int32_t start,
+ int32_t end) {
+ // |start == end| happens if there is one element so we need to check for
+ // |start > end| that happens in the next recursive call.
+ if (start > end) {
+ return nullptr;
+ }
+
+ int32_t mid = start + (end - start) / 2;
+ auto node = std::make_unique<Node>(is[static_cast<uint32_t>(mid)]);
+
+ node->left = BuildFromSortedIntervals(is, start, mid - 1);
+ node->right = BuildFromSortedIntervals(is, mid + 1, end);
+
+ uint32_t max_from_children = std::max(
+ node->left ? node->left->max : std::numeric_limits<uint32_t>::min(),
+ node->right ? node->right->max : std::numeric_limits<uint32_t>::min());
+
+ node->max = std::max(node->interval.end, max_from_children);
+
+ return node;
+ }
+
+ static void FindOverlaps(const Node& node,
+ const Interval& i,
+ std::vector<uint32_t>& overlaps) {
+ // Intervals overlap if one starts before the other ends and ends after it
+ // starts.
+ if (node.interval.start < i.end && node.interval.end > i.start) {
+ overlaps.push_back(node.interval.id);
+ }
+
+ // Try to find overlaps with left.
+ if (i.start <= node.interval.start && node.left) {
+ FindOverlaps(*node.left, i, overlaps);
+ }
+
+ // Try to find overlaps with right.
+ if (i.start < node.max && node.right) {
+ FindOverlaps(*node.right, i, overlaps);
+ }
+ }
+
+ std::unique_ptr<Node> tree_root_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_TREE_H_
diff --git a/src/trace_processor/containers/interval_tree_unittest.cc b/src/trace_processor/containers/interval_tree_unittest.cc
new file mode 100644
index 000000000..61023d422
--- /dev/null
+++ b/src/trace_processor/containers/interval_tree_unittest.cc
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 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/containers/interval_tree.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <numeric>
+#include <random>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/compiler.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto::trace_processor {
+
+inline bool operator==(const IntervalTree::Interval& a,
+ const IntervalTree::Interval& b) {
+ return std::tie(a.start, a.end, a.id) == std::tie(b.start, b.end, b.id);
+}
+
+namespace {
+
+using Interval = IntervalTree::Interval;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
+
+std::vector<Interval> CreateIntervals(
+ std::vector<std::pair<uint32_t, uint32_t>> periods) {
+ std::vector<Interval> res;
+ uint32_t id = 0;
+ for (auto period : periods) {
+ res.push_back({period.first, period.second, id++});
+ }
+ return res;
+}
+
+TEST(IntervalTree, Trivial) {
+ std::vector<Interval> interval({{10, 20, 5}});
+ IntervalTree tree(interval);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps({5, 30, 0}, overlaps);
+
+ ASSERT_THAT(overlaps, UnorderedElementsAre(5));
+}
+
+TEST(IntervalTree, Simple) {
+ auto intervals = CreateIntervals({{0, 10}, {5, 20}, {30, 40}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps({4, 30, 0}, overlaps);
+
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+}
+
+TEST(IntervalTree, SinglePointOverlap) {
+ auto intervals = CreateIntervals({{10, 20}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+
+ // Overlaps at the start point only
+ tree.FindOverlaps({10, 10, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+
+ overlaps.clear();
+
+ // Overlaps at the end point only
+ tree.FindOverlaps({20, 20, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+}
+
+TEST(IntervalTree, NoOverlaps) {
+ auto intervals = CreateIntervals({{10, 20}, {30, 40}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+
+ // Before all intervals
+ tree.FindOverlaps({5, 9, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+ overlaps.clear();
+
+ // Between intervals
+ tree.FindOverlaps({21, 29, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+ overlaps.clear();
+
+ // After all intervals
+ tree.FindOverlaps({41, 50, 0}, overlaps);
+ ASSERT_THAT(overlaps, IsEmpty());
+}
+
+TEST(IntervalTree, IdenticalIntervals) {
+ auto intervals = CreateIntervals({{10, 20}, {10, 20}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps({10, 20, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+}
+
+TEST(IntervalTree, MultipleOverlapsVariousPositions) {
+ auto intervals = CreateIntervals({{5, 15}, {10, 20}, {12, 22}, {25, 35}});
+ IntervalTree tree(intervals);
+
+ std::vector<uint32_t> overlaps;
+ /// Starts before, ends within
+ tree.FindOverlaps({9, 11, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+
+ overlaps.clear();
+ // Starts within, ends within
+ tree.FindOverlaps({13, 21, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(1, 2));
+
+ overlaps.clear();
+ // Starts within, ends after
+ tree.FindOverlaps({18, 26, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(1, 2, 3));
+}
+
+TEST(IntervalTree, OverlappingEndpoints) {
+ auto intervals = CreateIntervals({{10, 20}, {20, 30}});
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+
+ tree.FindOverlaps({19, 21, 0}, overlaps);
+ ASSERT_THAT(overlaps, UnorderedElementsAre(0, 1));
+}
+
+TEST(IntervalTree, Stress) {
+ static constexpr size_t kCount = 9249;
+ std::minstd_rand0 rng(42);
+
+ std::vector<std::pair<uint32_t, uint32_t>> periods;
+ uint32_t prev_max = 0;
+ for (uint32_t i = 0; i < kCount; ++i) {
+ prev_max += static_cast<uint32_t>(rng()) % 100;
+ periods.push_back(
+ {prev_max, prev_max + (static_cast<uint32_t>(rng()) % 100)});
+ }
+ auto intervals = CreateIntervals(periods);
+ Interval query_i{periods.front().first, periods.back().first + 1, 5};
+ IntervalTree tree(intervals);
+ std::vector<uint32_t> overlaps;
+ tree.FindOverlaps(query_i, overlaps);
+
+ EXPECT_EQ(overlaps.size(), kCount);
+}
+
+} // namespace
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index a46002f12..406f30199 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -232,6 +232,75 @@ enum RpmStatus {
RPM_SUSPENDED,
RPM_SUSPENDING,
};
+
+// Obtain the string corresponding to the event code (`event` field) in the
+// `device_pm_callback_start` tracepoint.
+std::string GetDpmCallbackEventString(int64_t event) {
+ // This mapping order is obtained directly from the Linux kernel code.
+ switch (event) {
+ case 0x2:
+ return "suspend";
+ case 0x10:
+ return "resume";
+ case 0x1:
+ return "freeze";
+ case 0x8:
+ return "quiesce";
+ case 0x4:
+ return "hibernate";
+ case 0x20:
+ return "thaw";
+ case 0x40:
+ return "restore";
+ case 0x80:
+ return "recover";
+ default:
+ return "(unknown PM event)";
+ }
+}
+
+bool StrStartsWith(const std::string& str, const std::string& prefix) {
+ return str.size() >= prefix.size() &&
+ str.compare(0, prefix.size(), prefix) == 0;
+}
+
+// Constructs the display string for device PM callback slices.
+//
+// Format: "<driver name> <device name> <event type>[:<callback phase>]"
+//
+// Note: The optional `<callback phase>` is extracted from the `pm_ops` field
+// of the `device_pm_callback_start` tracepoint.
+std::string ConstructDpmCallbackSliceName(const std::string& driver_name,
+ const std::string& device_name,
+ const std::string& pm_ops,
+ const std::string& event_type) {
+ std::string slice_name_base =
+ driver_name + " " + device_name + " " + event_type;
+
+ // The Linux kernel has a limitation where the `pm_ops` field in the
+ // tracepoint is left empty if the phase is either prepare/complete.
+ if (pm_ops == "") {
+ if (event_type == "suspend")
+ return slice_name_base + ":prepare";
+ else if (event_type == "resume")
+ return slice_name_base + ":complete";
+ }
+
+ // Extract callback phase (if present) for slice display name.
+ //
+ // The `pm_ops` string may contain both callback phase and callback type, but
+ // only phase is needed. A prefix match is used due to potential absence of
+ // either/both phase or type in `pm_ops`.
+ const std::vector<std::string> valid_phases = {"early", "late", "noirq"};
+ for (const std::string& valid_phase : valid_phases) {
+ if (StrStartsWith(pm_ops, valid_phase)) {
+ return slice_name_base + ":" + valid_phase;
+ }
+ }
+
+ return slice_name_base;
+}
+
} // namespace
FtraceParser::FtraceParser(TraceProcessorContext* context)
@@ -1169,6 +1238,14 @@ base::Status FtraceParser::ParseFtraceEvent(uint32_t cpu,
ParseGoogleIrmEvent(ts, fld_bytes);
break;
}
+ case FtraceEvent::kDevicePmCallbackStartFieldNumber: {
+ ParseDevicePmCallbackStart(ts, fld_bytes);
+ break;
+ }
+ case FtraceEvent::kDevicePmCallbackEndFieldNumber: {
+ ParseDevicePmCallbackEnd(ts, fld_bytes);
+ break;
+ }
default:
break;
}
@@ -3127,6 +3204,14 @@ void FtraceParser::ParseSuspendResume(int64_t timestamp,
// processor_id and device could enter suspend/resume from different
// processor.
auto val = (action_name == "timekeeping_freeze") ? 0 : evt.val();
+ std::string cookie_key = std::to_string(val);
+ int64_t cookie = 0;
+ if (suspend_resume_cookie_map_.Find(cookie_key) == nullptr) {
+ cookie = static_cast<int64_t>(suspend_resume_cookie_map_.size());
+ suspend_resume_cookie_map_[cookie_key] = cookie;
+ } else {
+ cookie = suspend_resume_cookie_map_[cookie_key];
+ }
base::StackString<64> str("%s(%" PRIu32 ")", action_name.c_str(), val);
std::string current_action = str.ToStdString();
@@ -3134,8 +3219,8 @@ void FtraceParser::ParseSuspendResume(int64_t timestamp,
StringId slice_name_id = context_->storage->InternString(str.string_view());
if (!evt.start()) {
- TrackId end_id = context_->async_track_set_tracker->End(
- async_track, static_cast<int64_t>(val));
+ TrackId end_id =
+ context_->async_track_set_tracker->End(async_track, cookie);
context_->slice_tracker->End(timestamp, end_id);
ongoing_suspend_resume_actions[current_action] = false;
return;
@@ -3143,8 +3228,8 @@ void FtraceParser::ParseSuspendResume(int64_t timestamp,
// Complete the previous action before starting a new one.
if (ongoing_suspend_resume_actions[current_action]) {
- TrackId end_id = context_->async_track_set_tracker->End(
- async_track, static_cast<int64_t>(val));
+ TrackId end_id =
+ context_->async_track_set_tracker->End(async_track, cookie);
auto args_inserter = [this](ArgsTracker::BoundInserter* inserter) {
inserter->AddArg(replica_slice_id_, Variadic::Boolean(true));
};
@@ -3152,8 +3237,8 @@ void FtraceParser::ParseSuspendResume(int64_t timestamp,
kNullStringId, args_inserter);
}
- TrackId start_id = context_->async_track_set_tracker->Begin(
- async_track, static_cast<int64_t>(val));
+ TrackId start_id =
+ context_->async_track_set_tracker->Begin(async_track, cookie);
context_->slice_tracker->Begin(timestamp, start_id, suspend_resume_name_id_,
slice_name_id);
ongoing_suspend_resume_actions[current_action] = true;
@@ -3370,6 +3455,55 @@ void FtraceParser::ParseRpmStatus(int64_t ts, protozero::ConstBytes blob) {
devices_with_active_rpm_slice_.insert(device_name);
}
+// Parses `device_pm_callback_start` events and begins corresponding slices in
+// the suspend / resume latency UI track.
+void FtraceParser::ParseDevicePmCallbackStart(int64_t ts,
+ protozero::ConstBytes blob) {
+ protos::pbzero::DevicePmCallbackStartFtraceEvent::Decoder dpm_event(
+ blob.data, blob.size);
+
+ // Device here refers to anything managed by a Linux kernel driver.
+ std::string device_name = dpm_event.device().ToStdString();
+ int64_t cookie;
+
+ if (suspend_resume_cookie_map_.Find(device_name) == nullptr) {
+ cookie = static_cast<int64_t>(suspend_resume_cookie_map_.size());
+ suspend_resume_cookie_map_[device_name] = cookie;
+ } else {
+ cookie = suspend_resume_cookie_map_[device_name];
+ }
+
+ std::string slice_name = ConstructDpmCallbackSliceName(
+ dpm_event.driver().ToStdString(), device_name,
+ dpm_event.pm_ops().ToStdString(),
+ GetDpmCallbackEventString(dpm_event.event()));
+ StringId slice_name_id = context_->storage->InternString(slice_name.c_str());
+
+ auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet(
+ suspend_resume_name_id_);
+ TrackId track_id =
+ context_->async_track_set_tracker->Begin(async_track, cookie);
+ context_->slice_tracker->Begin(ts, track_id, suspend_resume_name_id_,
+ slice_name_id);
+}
+
+// Parses `device_pm_callback_end` events and ends corresponding slices in the
+// suspend / resume latency UI track.
+void FtraceParser::ParseDevicePmCallbackEnd(int64_t ts,
+ protozero::ConstBytes blob) {
+ protos::pbzero::DevicePmCallbackEndFtraceEvent::Decoder dpm_event(blob.data,
+ blob.size);
+
+ // Device here refers to anything managed by a Linux kernel driver.
+ std::string device_name = dpm_event.device().ToStdString();
+
+ auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet(
+ suspend_resume_name_id_);
+ TrackId track_id = context_->async_track_set_tracker->End(
+ async_track, suspend_resume_cookie_map_[device_name]);
+ context_->slice_tracker->End(ts, track_id);
+}
+
void FtraceParser::ParsePanelWriteGeneric(int64_t timestamp,
uint32_t pid,
ConstBytes blob) {
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index 86c7114b5..d8bafde94 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -297,6 +297,8 @@ class FtraceParser {
protozero::ConstBytes);
StringId GetRpmStatusStringId(int32_t rpm_status_val);
void ParseRpmStatus(int64_t ts, protozero::ConstBytes);
+ void ParseDevicePmCallbackStart(int64_t ts, protozero::ConstBytes);
+ void ParseDevicePmCallbackEnd(int64_t ts, protozero::ConstBytes);
void ParsePanelWriteGeneric(int64_t timestamp,
uint32_t pid,
protozero::ConstBytes);
@@ -469,6 +471,17 @@ class FtraceParser {
// slices.
std::unordered_set<std::string> devices_with_active_rpm_slice_;
+ // Tracks unique identifiers ("cookies") to create separate async tracks for
+ // the Suspend/Resume UI track. The separation prevents unnestable slices from
+ // overlapping on a single trace processor track.
+ //
+ // For `suspend_resume` ftrace events, the key for this map is derived from
+ // the `val` field in the trace object.
+ //
+ // For `device_pm_callback_[start|end]` ftrace events, the key for this map is
+ // derived from the device name.
+ base::FlatHashMap<std::string, int64_t> suspend_resume_cookie_map_;
+
struct PairHash {
std::size_t operator()(const std::pair<uint64_t, int64_t>& p) const {
base::Hasher hasher;
diff --git a/src/trace_processor/importers/proto/BUILD.gn b/src/trace_processor/importers/proto/BUILD.gn
index 18a617af5..dde995cd9 100644
--- a/src/trace_processor/importers/proto/BUILD.gn
+++ b/src/trace_processor/importers/proto/BUILD.gn
@@ -40,7 +40,7 @@ source_set("minimal") {
"network_trace_module.h",
"packet_analyzer.cc",
"packet_analyzer.h",
- "packet_sequence_state.h",
+ "packet_sequence_state_builder.h",
"packet_sequence_state_generation.cc",
"perf_sample_tracker.cc",
"perf_sample_tracker.h",
@@ -50,7 +50,6 @@ source_set("minimal") {
"profile_packet_sequence_state.h",
"profile_packet_utils.cc",
"profile_packet_utils.h",
- "proto_incremental_state.h",
"proto_trace_parser_impl.cc",
"proto_trace_parser_impl.h",
"proto_trace_reader.cc",
@@ -63,6 +62,7 @@ source_set("minimal") {
"track_event_module.h",
"track_event_parser.cc",
"track_event_parser.h",
+ "track_event_sequence_state.cc",
"track_event_tokenizer.cc",
"track_event_tokenizer.h",
"track_event_tracker.cc",
@@ -70,7 +70,6 @@ source_set("minimal") {
]
public_deps = [ ":proto_importer_module" ]
deps = [
- ":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
"../../../../include/perfetto/trace_processor:trace_processor",
"../../../../protos/perfetto/common:zero",
@@ -201,6 +200,7 @@ source_set("proto_importer_module") {
"proto_importer_module.cc",
"proto_importer_module.h",
]
+ public_deps = [ ":packet_sequence_state_generation_hdr" ]
deps = [
":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
@@ -212,12 +212,16 @@ source_set("proto_importer_module") {
}
source_set("packet_sequence_state_generation_hdr") {
- sources = [ "packet_sequence_state_generation.h" ]
+ sources = [
+ "packet_sequence_state_generation.h",
+ "track_event_sequence_state.h",
+ ]
deps = [
"../../../../gn:default_deps",
"../../../../include/perfetto/ext/base",
"../../../../protos/perfetto/trace:non_minimal_zero",
"../../../../protos/perfetto/trace/track_event:zero",
+ "../../types:types",
"../../util:interned_message_view",
]
}
@@ -262,6 +266,7 @@ source_set("unittests") {
deps = [
":full",
":minimal",
+ ":packet_sequence_state_generation_hdr",
"../../../../gn:default_deps",
"../../../../gn:gtest_and_gmock",
"../../../../protos/perfetto/common:cpp",
diff --git a/src/trace_processor/importers/proto/frame_timeline_event_parser.h b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
index 596f415ed..b1c1e1297 100644
--- a/src/trace_processor/importers/proto/frame_timeline_event_parser.h
+++ b/src/trace_processor/importers/proto/frame_timeline_event_parser.h
@@ -20,7 +20,6 @@
#include "perfetto/protozero/field.h"
#include "src/trace_processor/importers/common/args_tracker.h"
#include "src/trace_processor/importers/common/async_track_set_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "protos/perfetto/trace/android/frame_timeline_event.pbzero.h"
diff --git a/src/trace_processor/importers/proto/gpu_event_parser.h b/src/trace_processor/importers/proto/gpu_event_parser.h
index e2eaac87c..6ca65270e 100644
--- a/src/trace_processor/importers/proto/gpu_event_parser.h
+++ b/src/trace_processor/importers/proto/gpu_event_parser.h
@@ -25,7 +25,6 @@
#include "protos/perfetto/trace/android/gpu_mem_event.pbzero.h"
#include "protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.h"
#include "src/trace_processor/importers/common/args_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/graphics_frame_event_parser.h b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
index 2d376126f..146d12690 100644
--- a/src/trace_processor/importers/proto/graphics_frame_event_parser.h
+++ b/src/trace_processor/importers/proto/graphics_frame_event_parser.h
@@ -23,7 +23,6 @@
#include "perfetto/ext/base/string_writer.h"
#include "perfetto/protozero/field.h"
#include "src/trace_processor/importers/common/args_tracker.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
#include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
#include "src/trace_processor/storage/trace_storage.h"
diff --git a/src/trace_processor/importers/proto/packet_sequence_state.h b/src/trace_processor/importers/proto/packet_sequence_state.h
deleted file mode 100644
index b50af207b..000000000
--- a/src/trace_processor/importers/proto/packet_sequence_state.h
+++ /dev/null
@@ -1,157 +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_PACKET_SEQUENCE_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
-
-#include <stdint.h>
-
-#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/types/trace_processor_context.h"
-#include "src/trace_processor/util/interned_message_view.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class PacketSequenceState {
- public:
- explicit PacketSequenceState(TraceProcessorContext* context)
- : context_(context) {
- current_generation_.reset(new PacketSequenceStateGeneration(this));
- }
-
- int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_timestamp_ns_ += delta_ns;
- return track_event_timestamp_ns_;
- }
-
- int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_thread_timestamp_ns_ += delta_ns;
- return track_event_thread_timestamp_ns_;
- }
-
- int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
- PERFETTO_DCHECK(track_event_timestamps_valid());
- track_event_thread_instruction_count_ += delta;
- return track_event_thread_instruction_count_;
- }
-
- // Intern a message into the current generation.
- void InternMessage(uint32_t field_id, TraceBlobView message) {
- current_generation_->InternMessage(field_id, std::move(message));
- }
-
- // Set the trace packet defaults for the current generation. If the current
- // generation already has defaults set, starts a new generation without
- // invalidating other incremental state (such as interned data).
- void UpdateTracePacketDefaults(TraceBlobView defaults) {
- if (!current_generation_->GetTracePacketDefaultsView()) {
- current_generation_->SetTracePacketDefaults(std::move(defaults));
- return;
- }
-
- // The new defaults should only apply to subsequent messages on the
- // sequence. Add a new generation with the updated defaults but the
- // current generation's interned data state.
- current_generation_.reset(new PacketSequenceStateGeneration(
- this, current_generation_.get(), std::move(defaults)));
- }
-
- void SetThreadDescriptor(int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count) {
- track_event_timestamps_valid_ = true;
- pid_and_tid_valid_ = true;
- pid_ = pid;
- tid_ = tid;
- track_event_timestamp_ns_ = timestamp_ns;
- track_event_thread_timestamp_ns_ = thread_timestamp_ns;
- track_event_thread_instruction_count_ = thread_instruction_count;
- }
-
- void OnPacketLoss() {
- packet_loss_ = true;
- track_event_timestamps_valid_ = false;
- }
-
- // Starts a new generation with clean-slate incremental state and defaults.
- void OnIncrementalStateCleared() {
- packet_loss_ = false;
- current_generation_.reset(new PacketSequenceStateGeneration(this));
- }
-
- bool IsIncrementalStateValid() const { return !packet_loss_; }
-
- // Returns a ref-counted ptr to the current generation.
- RefPtr<PacketSequenceStateGeneration> current_generation() const {
- return current_generation_;
- }
-
- bool track_event_timestamps_valid() const {
- return track_event_timestamps_valid_;
- }
-
- bool pid_and_tid_valid() const { return pid_and_tid_valid_; }
-
- int32_t pid() const { return pid_; }
- int32_t tid() const { return tid_; }
-
- TraceProcessorContext* context() const { return context_; }
-
- private:
- TraceProcessorContext* context_;
-
- // If true, incremental state on the sequence is considered invalid until we
- // see the next packet with incremental_state_cleared. We assume that we
- // missed some packets at the beginning of the trace.
- bool packet_loss_ = true;
-
- // We can only consider TrackEvent delta timestamps to be correct after we
- // have observed a thread descriptor (since the last packet loss).
- bool track_event_timestamps_valid_ = false;
-
- // |pid_| and |tid_| are only valid after we parsed at least one
- // ThreadDescriptor packet on the sequence.
- bool pid_and_tid_valid_ = false;
-
- // Process/thread ID of the packet sequence set by a ThreadDescriptor
- // packet. Used as default values for TrackEvents that don't specify a
- // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
- int32_t pid_ = 0;
- int32_t tid_ = 0;
-
- // Current wall/thread timestamps/counters used as reference for the next
- // TrackEvent delta timestamp.
- int64_t track_event_timestamp_ns_ = 0;
- int64_t track_event_thread_timestamp_ns_ = 0;
- int64_t track_event_thread_instruction_count_ = 0;
-
- RefPtr<PacketSequenceStateGeneration> current_generation_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/packet_sequence_state_builder.h b/src/trace_processor/importers/proto/packet_sequence_state_builder.h
new file mode 100644
index 000000000..599b03d2a
--- /dev/null
+++ b/src/trace_processor/importers/proto/packet_sequence_state_builder.h
@@ -0,0 +1,82 @@
+/*
+ * 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_PACKET_SEQUENCE_STATE_BUILDER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
+
+#include <cstdint>
+
+#include "perfetto/trace_processor/ref_counted.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+// Helper class to generate a stream of PacketSequenceStateGeneration as we
+// receive packets for a sequence. This class deals with various events that
+// incrementally build up state that can be accessed by packet handling code
+// (tokenization nad parsing). An example of such state are interned messages or
+// trace packet defaults.
+class PacketSequenceStateBuilder {
+ public:
+ explicit PacketSequenceStateBuilder(TraceProcessorContext* context) {
+ generation_ = PacketSequenceStateGeneration::CreateFirst(context);
+ }
+
+ // Intern a message into the current generation.
+ void InternMessage(uint32_t field_id, TraceBlobView message) {
+ generation_->InternMessage(field_id, std::move(message));
+ }
+
+ // Set the trace packet defaults for the current generation. If the current
+ // generation already has defaults set, starts a new generation without
+ // invalidating other incremental state (such as interned data).
+ void UpdateTracePacketDefaults(TraceBlobView defaults) {
+ generation_ = generation_->OnNewTracePacketDefaults(std::move(defaults));
+ }
+
+ void OnPacketLoss() {
+ generation_ = generation_->OnPacketLoss();
+ packet_loss_ = true;
+ }
+
+ // Starts a new generation with clean-slate incremental state and defaults.
+ void OnIncrementalStateCleared() {
+ packet_loss_ = false;
+ generation_ = generation_->OnIncrementalStateCleared();
+ }
+
+ bool IsIncrementalStateValid() const { return !packet_loss_; }
+
+ // Returns a ref-counted ptr to the current generation.
+ RefPtr<PacketSequenceStateGeneration> current_generation() const {
+ return generation_;
+ }
+
+ private:
+ // If true, incremental state on the sequence is considered invalid until we
+ // see the next packet with incremental_state_cleared. We assume that we
+ // missed some packets at the beginning of the trace.
+ bool packet_loss_ = true;
+
+ RefPtr<PacketSequenceStateGeneration> generation_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_BUILDER_H_
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 c520e9259..711bb64e5 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.cc
@@ -17,42 +17,89 @@
#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/importers/proto/track_event_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 perfetto::trace_processor {
+
+PacketSequenceStateGeneration::CustomState::~CustomState() = default;
+
+// static
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::CreateFirst(TraceProcessorContext* context) {
+ return RefPtr<PacketSequenceStateGeneration>(
+ new PacketSequenceStateGeneration(
+ context, TrackEventSequenceState::CreateFirst(), false));
+}
PacketSequenceStateGeneration::PacketSequenceStateGeneration(
- PacketSequenceState* state,
- PacketSequenceStateGeneration* prev_gen,
- TraceBlobView defaults)
- : state_(state),
- 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);
+ TraceProcessorContext* context,
+ InternedFieldMap interned_data,
+ TrackEventSequenceState track_event_sequence_state,
+ CustomStateArray custom_state,
+ TraceBlobView trace_packet_defaults,
+ bool is_incremental_state_valid)
+ : context_(context),
+ interned_data_(std::move(interned_data)),
+ track_event_sequence_state_(std::move(track_event_sequence_state)),
+ custom_state_(std::move(custom_state)),
+ trace_packet_defaults_(std::move(trace_packet_defaults)),
+ is_incremental_state_valid_(is_incremental_state_valid) {
+ for (auto& s : custom_state_) {
+ if (s.get() != nullptr) {
+ s->set_generation(this);
}
}
}
-PacketSequenceStateGeneration::InternedDataTracker::~InternedDataTracker() =
- default;
-
-bool PacketSequenceStateGeneration::pid_and_tid_valid() const {
- return state_->pid_and_tid_valid();
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnPacketLoss() {
+ // No need to increment the generation. If any future packet depends on
+ // previous messages to update the incremental state its packet (if the
+ // DataSource is behaving correctly) would have the
+ // SEQ_NEEDS_INCREMENTAL_STATE bit set and such a packet will be dropped by
+ // the ProtoTraceReader and never make it far enough to update any incremental
+ // state.
+ track_event_sequence_state_.OnPacketLoss();
+ is_incremental_state_valid_ = false;
+ return RefPtr<PacketSequenceStateGeneration>(this);
}
-int32_t PacketSequenceStateGeneration::pid() const {
- return state_->pid();
+
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnIncrementalStateCleared() {
+ return RefPtr<PacketSequenceStateGeneration>(
+ new PacketSequenceStateGeneration(
+ context_, track_event_sequence_state_.OnIncrementalStateCleared(),
+ true));
}
-int32_t PacketSequenceStateGeneration::tid() const {
- return state_->tid();
+
+RefPtr<PacketSequenceStateGeneration>
+PacketSequenceStateGeneration::OnNewTracePacketDefaults(
+ TraceBlobView trace_packet_defaults) {
+ return RefPtr<PacketSequenceStateGeneration>(
+ new PacketSequenceStateGeneration(
+ context_, interned_data_,
+ track_event_sequence_state_.OnIncrementalStateCleared(),
+ custom_state_, std::move(trace_packet_defaults),
+ is_incremental_state_valid_));
}
-TraceProcessorContext* PacketSequenceStateGeneration::GetContext() const {
- return state_->context();
+InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
+ uint32_t field_id,
+ uint64_t iid) {
+ auto field_it = interned_data_.find(field_id);
+ if (field_it != interned_data_.end()) {
+ auto* message_map = &field_it->second;
+ auto it = message_map->find(iid);
+ if (it != message_map->end()) {
+ return &it->second;
+ }
+ }
+
+ context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
+ return nullptr;
}
void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
@@ -67,8 +114,7 @@ void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
auto field = decoder.FindField(kIidFieldNumber);
if (PERFETTO_UNLIKELY(!field)) {
PERFETTO_DLOG("Interned message without interning_id");
- state_->context()->storage->IncrementStats(
- stats::interned_data_tokenizer_errors);
+ context_->storage->IncrementStats(stats::interned_data_tokenizer_errors);
return;
}
iid = field.as_uint64();
@@ -87,51 +133,4 @@ void PacketSequenceStateGeneration::InternMessage(uint32_t field_id,
message_size) == 0));
}
-InternedMessageView* PacketSequenceStateGeneration::GetInternedMessageView(
- uint32_t field_id,
- uint64_t iid) {
- auto field_it = interned_data_.find(field_id);
- if (field_it != interned_data_.end()) {
- auto* message_map = &field_it->second;
- auto it = message_map->find(iid);
- if (it != message_map->end()) {
- return &it->second;
- }
- }
- state_->context()->storage->IncrementStats(
- stats::interned_data_tokenizer_errors);
- return nullptr;
-}
-
-int64_t PacketSequenceStateGeneration::IncrementAndGetTrackEventTimeNs(
- int64_t delta_ns) {
- return state_->IncrementAndGetTrackEventTimeNs(delta_ns);
-}
-int64_t PacketSequenceStateGeneration::IncrementAndGetTrackEventThreadTimeNs(
- int64_t delta_ns) {
- return state_->IncrementAndGetTrackEventThreadTimeNs(delta_ns);
-}
-int64_t
-PacketSequenceStateGeneration::IncrementAndGetTrackEventThreadInstructionCount(
- int64_t delta) {
- return state_->IncrementAndGetTrackEventThreadInstructionCount(delta);
-}
-bool PacketSequenceStateGeneration::track_event_timestamps_valid() const {
- return state_->track_event_timestamps_valid();
-}
-void PacketSequenceStateGeneration::SetThreadDescriptor(
- int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count) {
- state_->SetThreadDescriptor(pid, tid, timestamp_ns, thread_timestamp_ns,
- thread_instruction_count);
-}
-
-bool PacketSequenceStateGeneration::IsIncrementalStateValid() const {
- return state_->IsIncrementalStateValid();
-}
-
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
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 6b60b596d..82e225253 100644
--- a/src/trace_processor/importers/proto/packet_sequence_state_generation.h
+++ b/src/trace_processor/importers/proto/packet_sequence_state_generation.h
@@ -17,21 +17,16 @@
#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 <cstdint>
-#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/importers/proto/track_event_sequence_state.h"
#include "src/trace_processor/util/interned_message_view.h"
#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace perfetto {
@@ -42,32 +37,36 @@ using InternedMessageMap =
using InternedFieldMap =
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>;
+using CustomStateClasses = std::tuple<StackProfileSequenceState,
+ ProfilePacketSequenceState,
+ V8SequenceState>;
+// This is the public API exposed to packet tokenizers and parsers to access
+// state attached to a packet sequence. This state evolves as packets are
+// processed in sequence order. A packet that requires sequence state to be
+// properly parsed should snapshot this state by taking a copy of the RefPtr to
+// the currently active generation and passing it along with parsing specific
+// data to the sorting stage.
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
+ // Base class to attach custom state to the 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`).
+ // `CustomState` (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 {
+ // use the `PacketSequenceStateGeneration::GetCustomState<>' method instead.
+ class CustomState : public RefCounted {
public:
- virtual ~InternedDataTracker();
+ virtual ~CustomState();
protected:
template <uint32_t FieldId, typename MessageType>
@@ -81,8 +80,8 @@ class PacketSequenceStateGeneration : public RefCounted {
}
template <typename T>
- std::remove_cv_t<T>* GetOrCreate() {
- return generation_->GetOrCreate<T>();
+ std::remove_cv_t<T>* GetCustomState() {
+ return generation_->GetCustomState<T>();
}
bool pid_and_tid_valid() const { return generation_->pid_and_tid_valid(); }
@@ -103,32 +102,57 @@ class PacketSequenceStateGeneration : public RefCounted {
// 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.
+ // TODO(carlscab): Given that CustomState is ref counted this pointer might
+ // become invalid. CustomState should not be ref pointed and instead be
+ // owned by the `PacketSequenceStateGeneration` instance pointed at by
+ // `generation_`.
PacketSequenceStateGeneration* generation_ = nullptr;
};
- bool pid_and_tid_valid() const;
- int32_t pid() const;
- int32_t tid() const;
+ static RefPtr<PacketSequenceStateGeneration> CreateFirst(
+ TraceProcessorContext* context);
+
+ RefPtr<PacketSequenceStateGeneration> OnPacketLoss();
+
+ RefPtr<PacketSequenceStateGeneration> OnIncrementalStateCleared();
+
+ RefPtr<PacketSequenceStateGeneration> OnNewTracePacketDefaults(
+ TraceBlobView trace_packet_defaults);
+
+ bool pid_and_tid_valid() const {
+ return track_event_sequence_state_.pid_and_tid_valid();
+ }
+ int32_t pid() const { return track_event_sequence_state_.pid(); }
+ int32_t tid() const { return track_event_sequence_state_.tid(); }
// 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>
- typename MessageType::Decoder* LookupInternedMessage(uint64_t iid);
+ typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
+ auto* interned_message_view = GetInternedMessageView(FieldId, iid);
+ if (!interned_message_view)
+ return nullptr;
+
+ return interned_message_view->template GetOrCreateDecoder<MessageType>();
+ }
InternedMessageView* GetInternedMessageView(uint32_t field_id, uint64_t iid);
// Returns |nullptr| if no defaults were set.
InternedMessageView* GetTracePacketDefaultsView() {
- if (!trace_packet_defaults_)
+ if (!trace_packet_defaults_.has_value()) {
return nullptr;
- return &trace_packet_defaults_.value();
+ }
+
+ return &*trace_packet_defaults_;
}
// Returns |nullptr| if no defaults were set.
protos::pbzero::TracePacketDefaults::Decoder* GetTracePacketDefaults() {
- InternedMessageView* view = GetTracePacketDefaultsView();
- if (!view)
+ if (!trace_packet_defaults_.has_value()) {
return nullptr;
- return view->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
+ }
+ return trace_packet_defaults_
+ ->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
}
// Returns |nullptr| if no TrackEventDefaults were set.
@@ -148,30 +172,57 @@ class PacketSequenceStateGeneration : public RefCounted {
return nullptr;
}
- // 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.
+ // Extension point for custom incremental state. Custom state classes need to
+ // inherit from `CustomState`.
+ //
+ // A common use case for this custom state is to store cache mappings between
+ // interning ids (iid) and TraceProcessor objects (e.g. table row). When we
+ // see an iid we need to access the InternedMessageView for that iid, and
+ // possibly do some computations, the result of all of this could then be
+ // cached so that next time we encounter the same iid we could reuse this
+ // cached value. This caching is only valid until incremental state is
+ // cleared, from then on subsequent iid values on the sequence will no longer
+ // refer to the same entities as the iid values before the clear. Custom state
+ // classes no not need to explicitly handle this: they are attached to an
+ // `IncrementalState` instance, and a new one is created when the state is
+ // cleared, so iid values after the clear will be processed by a new (empty)
+ // custom state instance.
template <typename T>
- std::remove_cv_t<T>* GetOrCreate();
-
- // TODO(carlscab): All this should be tracked in a dedicated class
- // TrackEventSequenceState or something attached to the "incremental state".
- int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns);
- int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns);
- int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta);
- bool track_event_timestamps_valid() const;
- void SetThreadDescriptor(int32_t pid,
- int32_t tid,
- int64_t timestamp_ns,
- int64_t thread_timestamp_ns,
- int64_t thread_instruction_count);
+ std::remove_cv_t<T>* GetCustomState();
+
+ int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+ return track_event_sequence_state_.IncrementAndGetTrackEventTimeNs(
+ delta_ns);
+ }
+
+ int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+ return track_event_sequence_state_.IncrementAndGetTrackEventThreadTimeNs(
+ delta_ns);
+ }
+
+ int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+ return track_event_sequence_state_
+ .IncrementAndGetTrackEventThreadInstructionCount(delta);
+ }
+
+ bool track_event_timestamps_valid() const {
+ return track_event_sequence_state_.timestamps_valid();
+ }
+
+ void SetThreadDescriptor(
+ const protos::pbzero::ThreadDescriptor::Decoder& descriptor) {
+ track_event_sequence_state_.SetThreadDescriptor(descriptor);
+ }
// TODO(carlscab): Nobody other than `ProtoTraceReader` should care about
// this. Remove.
- bool IsIncrementalStateValid() const;
+ bool IsIncrementalStateValid() const { return is_incremental_state_valid_; }
private:
- friend class PacketSequenceState;
+ friend class PacketSequenceStateBuilder;
+
+ using CustomStateArray =
+ std::array<RefPtr<CustomState>, std::tuple_size_v<CustomStateClasses>>;
// 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.
@@ -195,56 +246,50 @@ class PacketSequenceStateGeneration : public RefCounted {
}
}
- explicit PacketSequenceStateGeneration(PacketSequenceState* state)
- : state_(state) {}
-
- PacketSequenceStateGeneration(PacketSequenceState* state,
- PacketSequenceStateGeneration* prev_gen,
- TraceBlobView defaults);
-
- TraceProcessorContext* GetContext() const;
-
+ PacketSequenceStateGeneration(TraceProcessorContext* context,
+ TrackEventSequenceState track_state,
+ bool is_incremental_state_valid)
+ : context_(context),
+ track_event_sequence_state_(std::move(track_state)),
+ is_incremental_state_valid_(is_incremental_state_valid) {}
+
+ PacketSequenceStateGeneration(
+ TraceProcessorContext* context,
+ InternedFieldMap interned_data,
+ TrackEventSequenceState track_event_sequence_state,
+ CustomStateArray custom_state,
+ TraceBlobView trace_packet_defaults,
+ bool is_incremental_state_valid);
+
+ // Add an interned message to this incremental state view. This can only be
+ // called by `PacketSequenceStateBuilder' (which is a friend) as packet
+ // tokenizers and parsers should never deal directly with reading interned
+ // data out of trace packets.
void InternMessage(uint32_t field_id, TraceBlobView message);
- void SetTracePacketDefaults(TraceBlobView defaults) {
- // Defaults should only be set once per generation.
- PERFETTO_DCHECK(!trace_packet_defaults_);
- trace_packet_defaults_ = InternedMessageView(std::move(defaults));
- }
-
- // TODO(carlscab): This is dangerous given that PacketSequenceStateGeneration
- // is refcounted and PacketSequenceState is not.
- PacketSequenceState* state_;
+ TraceProcessorContext* const context_;
InternedFieldMap interned_data_;
+ TrackEventSequenceState track_event_sequence_state_;
+ CustomStateArray custom_state_;
std::optional<InternedMessageView> trace_packet_defaults_;
- std::array<RefPtr<InternedDataTracker>,
- std::tuple_size_v<InternedDataTrackers>>
- trackers_;
+ // TODO(carlscab): Should not be needed as clients of this class should not
+ // care about validity.
+ bool is_incremental_state_valid_ = true;
};
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];
+std::remove_cv_t<T>* PacketSequenceStateGeneration::GetCustomState() {
+ constexpr size_t index = FindUniqueType<CustomStateClasses, T>();
+ static_assert(index < std::tuple_size_v<CustomStateClasses>, "Not found");
+ auto& ptr = custom_state_[index];
if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
- ptr.reset(new T(GetContext()));
+ ptr.reset(new T(context_));
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 2bfb78a02..55e3547bd 100644
--- a/src/trace_processor/importers/proto/profile_module.cc
+++ b/src/trace_processor/importers/proto/profile_module.cc
@@ -155,7 +155,7 @@ void ProfileModule::ParseStreamingProfilePacket(
ProcessTracker* procs = context_->process_tracker.get();
TraceStorage* storage = context_->storage.get();
StackProfileSequenceState& stack_profile_sequence_state =
- *sequence_state->GetOrCreate<StackProfileSequenceState>();
+ *sequence_state->GetCustomState<StackProfileSequenceState>();
uint32_t pid = static_cast<uint32_t>(sequence_state->pid());
uint32_t tid = static_cast<uint32_t>(sequence_state->tid());
@@ -255,7 +255,7 @@ void ProfileModule::ParsePerfSample(
context_->process_tracker->GetOrCreateProcess(sample.pid());
StackProfileSequenceState& stack_profile_sequence_state =
- *sequence_state->GetOrCreate<StackProfileSequenceState>();
+ *sequence_state->GetCustomState<StackProfileSequenceState>();
uint64_t callstack_iid = sample.callstack_iid();
std::optional<CallsiteId> cs_id =
stack_profile_sequence_state.FindOrInsertCallstack(upid, callstack_iid);
@@ -306,7 +306,7 @@ void ProfileModule::ParseProfilePacket(
PacketSequenceStateGeneration* sequence_state,
ConstBytes blob) {
ProfilePacketSequenceState& profile_packet_sequence_state =
- *sequence_state->GetOrCreate<ProfilePacketSequenceState>();
+ *sequence_state->GetCustomState<ProfilePacketSequenceState>();
protos::pbzero::ProfilePacket::Decoder packet(blob.data, blob.size);
profile_packet_sequence_state.SetProfilePacketIndex(packet.index());
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
index b5cdb704b..f0858e3ac 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.cc
@@ -283,8 +283,8 @@ std::optional<CallsiteId> ProfilePacketSequenceState::FindOrInsertCallstack(
if (CallsiteId* id = callstacks_.Find(iid); id) {
return *id;
}
- return GetOrCreate<StackProfileSequenceState>()->FindOrInsertCallstack(upid,
- iid);
+ return GetCustomState<StackProfileSequenceState>()->FindOrInsertCallstack(
+ upid, iid);
}
} // namespace trace_processor
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state.h b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
index 3fb8dcdd4..728265774 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state.h
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state.h
@@ -34,7 +34,7 @@ class VirtualMemoryMapping;
// Keeps sequence specific state for profile packets.
class ProfilePacketSequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+ : public PacketSequenceStateGeneration::CustomState {
public:
using SourceStringId = uint64_t;
diff --git a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
index c9cd6e365..ddaaa8522 100644
--- a/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
+++ b/src/trace_processor/importers/proto/profile_packet_sequence_state_unittest.cc
@@ -20,7 +20,7 @@
#include "src/trace_processor/importers/common/mapping_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/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -61,7 +61,7 @@ class HeapProfileTrackerDupTest : public ::testing::Test {
context.storage.reset(new TraceStorage());
context.mapping_tracker.reset(new MappingTracker(&context));
context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- packet_sequence_state.reset(new PacketSequenceState(&context));
+ sequence_state = PacketSequenceStateGeneration::CreateFirst(&context);
mapping_name = context.storage->InternString("[mapping]");
fully_qualified_mapping_name = context.storage->InternString("/[mapping]");
@@ -71,8 +71,7 @@ class HeapProfileTrackerDupTest : public ::testing::Test {
protected:
ProfilePacketSequenceState& profile_packet_sequence_state() {
- return *packet_sequence_state->current_generation()
- ->GetOrCreate<ProfilePacketSequenceState>();
+ return *sequence_state->GetCustomState<ProfilePacketSequenceState>();
}
void InsertMapping(const Packet& packet) {
profile_packet_sequence_state().AddString(packet.mapping_name_id,
@@ -117,7 +116,7 @@ class HeapProfileTrackerDupTest : public ::testing::Test {
StringId build;
StringId frame_name;
TraceProcessorContext context;
- std::unique_ptr<PacketSequenceState> packet_sequence_state;
+ RefPtr<PacketSequenceStateGeneration> sequence_state;
};
// Insert the same mapping from two different packets, with different strings
@@ -200,9 +199,9 @@ TEST(HeapProfileTrackerTest, SourceMappingPath) {
context.storage.reset(new TraceStorage());
context.mapping_tracker.reset(new MappingTracker(&context));
context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- PacketSequenceState pss(&context);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context);
ProfilePacketSequenceState& ppss =
- *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+ *state->GetCustomState<ProfilePacketSequenceState>();
constexpr auto kBuildId = 1u;
constexpr auto kMappingNameId1 = 2u;
@@ -235,9 +234,9 @@ TEST(HeapProfileTrackerTest, Functional) {
context.mapping_tracker.reset(new MappingTracker(&context));
context.stack_profile_tracker.reset(new StackProfileTracker(&context));
- PacketSequenceState pss(&context);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context);
ProfilePacketSequenceState& ppss =
- *pss.current_generation()->GetOrCreate<ProfilePacketSequenceState>();
+ *state->GetCustomState<ProfilePacketSequenceState>();
uint32_t next_string_intern_id = 1;
diff --git a/src/trace_processor/importers/proto/proto_incremental_state.h b/src/trace_processor/importers/proto/proto_incremental_state.h
deleted file mode 100644
index aaac42fdf..000000000
--- a/src/trace_processor/importers/proto/proto_incremental_state.h
+++ /dev/null
@@ -1,59 +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_PROTO_INCREMENTAL_STATE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
-
-#include <stdint.h>
-
-#include <map>
-
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-
-namespace perfetto {
-namespace trace_processor {
-
-class TraceProcessorContext;
-
-// Stores per-packet-sequence incremental state during trace parsing, such as
-// reference timestamps for delta timestamp calculation and interned messages.
-class ProtoIncrementalState {
- public:
- ProtoIncrementalState(TraceProcessorContext* context) : context_(context) {}
-
- // Returns the PacketSequenceState for the packet sequence with the given id.
- // If this is a new sequence which we haven't tracked before, initializes and
- // inserts a new PacketSequenceState into the state map.
- PacketSequenceState* GetOrCreateStateForPacketSequence(uint32_t sequence_id) {
- auto& ptr = packet_sequence_states_[sequence_id];
- if (!ptr)
- ptr.reset(new PacketSequenceState(context_));
- return ptr.get();
- }
-
- private:
- // Stores unique_ptrs to ensure that pointers to a PacketSequenceState remain
- // valid even if the map rehashes.
- std::map<uint32_t, std::unique_ptr<PacketSequenceState>>
- packet_sequence_states_;
-
- TraceProcessorContext* context_;
-};
-
-} // namespace trace_processor
-} // namespace perfetto
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PROTO_INCREMENTAL_STATE_H_
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index e139cbe0e..2e50f0cc3 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -34,8 +34,6 @@
#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/importers/ftrace/ftrace_module.h"
#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/proto_incremental_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"
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.h b/src/trace_processor/importers/proto/proto_trace_reader.h
index 1243b976e..a93ad9881 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.h
+++ b/src/trace_processor/importers/proto/proto_trace_reader.h
@@ -19,11 +19,13 @@
#include <stdint.h>
-#include <memory>
+#include <tuple>
+#include <utility>
+#include "perfetto/ext/base/flat_hash_map.h"
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
#include "src/trace_processor/importers/proto/multi_machine_trace_manager.h"
-#include "src/trace_processor/importers/proto/proto_incremental_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
#include "src/trace_processor/storage/trace_storage.h"
@@ -79,11 +81,15 @@ class ProtoTraceReader : public ChunkedTraceReader {
std::optional<StringId> GetBuiltinClockNameOrNull(int64_t clock_id);
- PacketSequenceState* GetIncrementalStateForPacketSequence(
+ PacketSequenceStateBuilder* GetIncrementalStateForPacketSequence(
uint32_t sequence_id) {
- if (!incremental_state)
- incremental_state.reset(new ProtoIncrementalState(context_));
- return incremental_state->GetOrCreateStateForPacketSequence(sequence_id);
+ auto* builder = packet_sequence_state_builders_.Find(sequence_id);
+ if (builder == nullptr) {
+ builder = packet_sequence_state_builders_
+ .Insert(sequence_id, PacketSequenceStateBuilder(context_))
+ .first;
+ }
+ return builder;
}
util::Status ParseExtensionDescriptor(ConstBytes descriptor);
@@ -95,9 +101,8 @@ class ProtoTraceReader : public ChunkedTraceReader {
// timestamp given is latest_timestamp_.
int64_t latest_timestamp_ = 0;
- // Stores incremental state and references to interned data, e.g. for track
- // event protos.
- std::unique_ptr<ProtoIncrementalState> incremental_state;
+ base::FlatHashMap<uint32_t, PacketSequenceStateBuilder>
+ packet_sequence_state_builders_;
StringId skipped_packet_key_id_;
StringId invalid_incremental_state_key_id_;
diff --git a/src/trace_processor/importers/proto/stack_profile_sequence_state.h b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
index 518388df3..e946e8dce 100644
--- a/src/trace_processor/importers/proto/stack_profile_sequence_state.h
+++ b/src/trace_processor/importers/proto/stack_profile_sequence_state.h
@@ -23,7 +23,6 @@
#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/importers/common/mapping_tracker.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"
@@ -35,7 +34,7 @@ class TraceProcessorContext;
class VirtualMemoryMapping;
class StackProfileSequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+ : public PacketSequenceStateGeneration::CustomState {
public:
explicit StackProfileSequenceState(TraceProcessorContext* context);
diff --git a/src/trace_processor/importers/proto/track_event_parser.cc b/src/trace_processor/importers/proto/track_event_parser.cc
index 09ef47433..585463049 100644
--- a/src/trace_processor/importers/proto/track_event_parser.cc
+++ b/src/trace_processor/importers/proto/track_event_parser.cc
@@ -31,6 +31,7 @@
#include "src/trace_processor/importers/common/machine_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/importers/common/virtual_memory_mapping.h"
#include "src/trace_processor/importers/json/json_utils.h"
#include "src/trace_processor/importers/proto/packet_analyzer.h"
#include "src/trace_processor/importers/proto/profile_packet_utils.h"
@@ -197,7 +198,7 @@ std::optional<base::Status> MaybeParseUnsymbolizedSourceLocation(
// Interned mapping_id loses it's meaning when the sequence ends. So we need
// to get an id from stack_profile_mapping table.
auto mapping = delegate.seq_state()
- ->GetOrCreate<StackProfileSequenceState>()
+ ->GetCustomState<StackProfileSequenceState>()
->FindOrInsertMapping(decoder->mapping_id());
if (!mapping) {
return std::nullopt;
@@ -1621,9 +1622,10 @@ void TrackEventParser::ParseTrackDescriptor(
}
// Override the name with the most recent name seen (after sorting by ts).
- if (decoder.has_name()) {
+ if (decoder.has_name() || decoder.has_static_name()) {
auto* tracks = context_->storage->mutable_track_table();
- StringId name_id = context_->storage->InternString(decoder.name());
+ StringId name_id = context_->storage->InternString(
+ decoder.has_name() ? decoder.name() : decoder.static_name());
tracks->mutable_name()->Set(*tracks->id().IndexOf(track_id), name_id);
}
}
diff --git a/src/trace_processor/importers/proto/track_event_sequence_state.cc b/src/trace_processor/importers/proto/track_event_sequence_state.cc
new file mode 100644
index 000000000..99bc93ee0
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_sequence_state.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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/track_event_sequence_state.h"
+
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+void TrackEventSequenceState::SetThreadDescriptor(
+ const protos::pbzero::ThreadDescriptor::Decoder& decoder) {
+ persistent_state_.pid_and_tid_valid = true;
+ persistent_state_.pid = decoder.pid();
+ persistent_state_.tid = decoder.tid();
+
+ timestamps_valid_ = true;
+ timestamp_ns_ = decoder.reference_timestamp_us() * 1000;
+ thread_timestamp_ns_ = decoder.reference_thread_time_us() * 1000;
+ thread_instruction_count_ = decoder.reference_thread_instruction_count();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/track_event_sequence_state.h b/src/trace_processor/importers/proto/track_event_sequence_state.h
new file mode 100644
index 000000000..9291ef740
--- /dev/null
+++ b/src/trace_processor/importers/proto/track_event_sequence_state.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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_TRACK_EVENT_SEQUENCE_STATE_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
+
+#include <utility>
+
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TrackEventSequenceState {
+ public:
+ static TrackEventSequenceState CreateFirst() {
+ return TrackEventSequenceState(PersistentState());
+ }
+
+ TrackEventSequenceState OnIncrementalStateCleared() {
+ return TrackEventSequenceState(persistent_state_);
+ }
+
+ void OnPacketLoss() { timestamps_valid_ = false; }
+
+ bool pid_and_tid_valid() const { return persistent_state_.pid_and_tid_valid; }
+
+ int32_t pid() const { return persistent_state_.pid; }
+ int32_t tid() const { return persistent_state_.tid; }
+
+ bool timestamps_valid() const { return timestamps_valid_; }
+
+ int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
+ PERFETTO_DCHECK(timestamps_valid());
+ timestamp_ns_ += delta_ns;
+ return timestamp_ns_;
+ }
+
+ int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
+ PERFETTO_DCHECK(timestamps_valid());
+ thread_timestamp_ns_ += delta_ns;
+ return thread_timestamp_ns_;
+ }
+
+ int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
+ PERFETTO_DCHECK(timestamps_valid());
+ thread_instruction_count_ += delta;
+ return thread_instruction_count_;
+ }
+
+ void SetThreadDescriptor(const protos::pbzero::ThreadDescriptor::Decoder&);
+
+ private:
+ // State that is never cleared.
+ struct PersistentState {
+ // |pid_| and |tid_| are only valid after we parsed at least one
+ // ThreadDescriptor packet on the sequence.
+ bool pid_and_tid_valid = false;
+
+ // Process/thread ID of the packet sequence set by a ThreadDescriptor
+ // packet. Used as default values for TrackEvents that don't specify a
+ // pid/tid override. Only valid after |pid_and_tid_valid_| is set to true.
+ int32_t pid = 0;
+ int32_t tid = 0;
+ };
+
+ explicit TrackEventSequenceState(PersistentState persistent_state)
+ : persistent_state_(std::move(persistent_state)) {}
+
+ // We can only consider TrackEvent delta timestamps to be correct after we
+ // have observed a thread descriptor (since the last packet loss).
+ bool timestamps_valid_ = false;
+
+ // Current wall/thread timestamps/counters used as reference for the next
+ // TrackEvent delta timestamp.
+ int64_t timestamp_ns_ = 0;
+ int64_t thread_timestamp_ns_ = 0;
+ int64_t thread_instruction_count_ = 0;
+
+ PersistentState persistent_state_;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_TRACK_EVENT_SEQUENCE_STATE_H_
diff --git a/src/trace_processor/importers/proto/track_event_tokenizer.cc b/src/trace_processor/importers/proto/track_event_tokenizer.cc
index d9ed33607..238e2470a 100644
--- a/src/trace_processor/importers/proto/track_event_tokenizer.cc
+++ b/src/trace_processor/importers/proto/track_event_tokenizer.cc
@@ -92,6 +92,8 @@ ModuleResult TrackEventTokenizer::TokenizeTrackDescriptorPacket(
StringId name_id = kNullStringId;
if (track.has_name())
name_id = context_->storage->InternString(track.name());
+ else if (track.has_static_name())
+ name_id = context_->storage->InternString(track.static_name());
if (packet.has_trusted_pid()) {
context_->process_tracker->UpdateTrustedPid(
@@ -212,10 +214,7 @@ void TrackEventTokenizer::TokenizeThreadDescriptor(
const protos::pbzero::ThreadDescriptor::Decoder& thread) {
// TODO(eseckler): Remove support for legacy thread descriptor-based default
// tracks and delta timestamps.
- state.SetThreadDescriptor(thread.pid(), thread.tid(),
- thread.reference_timestamp_us() * 1000,
- thread.reference_thread_time_us() * 1000,
- thread.reference_thread_instruction_count());
+ state.SetThreadDescriptor(thread);
}
void TrackEventTokenizer::TokenizeTrackEventPacket(
diff --git a/src/trace_processor/importers/proto/v8_module.cc b/src/trace_processor/importers/proto/v8_module.cc
index 89360b6b4..88d8f53d2 100644
--- a/src/trace_processor/importers/proto/v8_module.cc
+++ b/src/trace_processor/importers/proto/v8_module.cc
@@ -142,7 +142,8 @@ std::optional<uint32_t> V8Module::GetDefaultTid(
void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8JsCode::Decoder code(bytes);
@@ -169,7 +170,8 @@ void V8Module::ParseV8JsCode(protozero::ConstBytes bytes,
void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8InternalCode::Decoder code(bytes);
@@ -190,7 +192,8 @@ void V8Module::ParseV8InternalCode(protozero::ConstBytes bytes,
void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8WasmCode::Decoder code(bytes);
@@ -217,7 +220,8 @@ void V8Module::ParseV8WasmCode(protozero::ConstBytes bytes,
void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
int64_t ts,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
V8RegExpCode::Decoder code(bytes);
@@ -238,7 +242,8 @@ void V8Module::ParseV8RegExpCode(protozero::ConstBytes bytes,
void V8Module::ParseV8CodeMove(protozero::ConstBytes bytes,
int64_t,
const TracePacketData& data) {
- V8SequenceState& state = *data.sequence_state->GetOrCreate<V8SequenceState>();
+ V8SequenceState& state =
+ *data.sequence_state->GetCustomState<V8SequenceState>();
protos::pbzero::V8CodeMove::Decoder v8_code_move(bytes);
std::optional<IsolateId> isolate_id =
diff --git a/src/trace_processor/importers/proto/v8_sequence_state.h b/src/trace_processor/importers/proto/v8_sequence_state.h
index d2e008a19..1b60ca0a2 100644
--- a/src/trace_processor/importers/proto/v8_sequence_state.h
+++ b/src/trace_processor/importers/proto/v8_sequence_state.h
@@ -24,7 +24,6 @@
#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"
namespace perfetto {
namespace trace_processor {
@@ -34,7 +33,7 @@ class V8Tracker;
// Helper class to deal with V8 related interned data.
class V8SequenceState final
- : public PacketSequenceStateGeneration::InternedDataTracker {
+ : public PacketSequenceStateGeneration::CustomState {
public:
explicit V8SequenceState(TraceProcessorContext* context);
diff --git a/src/trace_processor/importers/proto/vulkan_memory_tracker.h b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
index 9d1afc56b..dd44a8911 100644
--- a/src/trace_processor/importers/proto/vulkan_memory_tracker.h
+++ b/src/trace_processor/importers/proto/vulkan_memory_tracker.h
@@ -17,19 +17,18 @@
#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/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
#include "protos/perfetto/trace/gpu/vulkan_memory_event.pbzero.h"
+#include "protos/perfetto/trace/profiling/profile_common.pbzero.h"
namespace perfetto {
namespace trace_processor {
using protos::pbzero::VulkanMemoryEvent;
-class TraceProcessorContext;
-
class VulkanMemoryTracker {
public:
enum class DeviceCounterType {
diff --git a/src/trace_processor/metrics/sql/android/android_startup.sql b/src/trace_processor/metrics/sql/android/android_startup.sql
index 4564f647f..95d050bbe 100644
--- a/src/trace_processor/metrics/sql/android/android_startup.sql
+++ b/src/trace_processor/metrics/sql/android/android_startup.sql
@@ -18,6 +18,10 @@ SELECT RUN_METRIC('android/cpu_info.sql');
-- Create the base tables and views containing the launch spans.
INCLUDE PERFETTO MODULE android.startup.startups;
+
+-- TTID and TTFD
+INCLUDE PERFETTO MODULE android.startup.time_to_display;
+
SELECT RUN_METRIC('android/process_metadata.sql');
-- Define the helper functions which will be used throught the remainder
@@ -161,6 +165,16 @@ SELECT
SELECT COUNT(1) FROM android_startup_processes p
WHERE p.startup_id =launches.startup_id
),
+ 'time_to_initial_display', (
+ SELECT time_to_initial_display
+ FROM android_startup_time_to_display s
+ WHERE s.startup_id = launches.startup_id
+ ),
+ 'time_to_full_display', (
+ SELECT time_to_full_display
+ FROM android_startup_time_to_display s
+ WHERE s.startup_id = launches.startup_id
+ ),
'event_timestamps', AndroidStartupMetric_EventTimestamps(
'intent_received', launches.ts,
'first_frame', launches.ts_end
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/startup/time_to_display.sql b/src/trace_processor/perfetto_sql/stdlib/android/startup/time_to_display.sql
index 7264bb75e..1a93fc745 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/startup/time_to_display.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/startup/time_to_display.sql
@@ -142,7 +142,7 @@ CREATE PERFETTO TABLE android_startup_time_to_display(
-- Startup id.
startup_id INT,
-- Time to initial display (TTID)
- time_to_inital_display INT,
+ time_to_initial_display INT,
-- Time to full display (TTFD)
time_to_full_display INT,
-- `android_frames.frame_id` of frame for initial display
@@ -154,7 +154,7 @@ CREATE PERFETTO TABLE android_startup_time_to_display(
) AS
SELECT
startup_id,
- ttid AS time_to_inital_display,
+ ttid AS time_to_initial_display,
ttfd AS time_to_full_display,
_ttid.frame_id AS ttid_frame_id,
_ttfd.frame_id AS ttfd_frame_id,
diff --git a/src/trace_processor/sorter/BUILD.gn b/src/trace_processor/sorter/BUILD.gn
index 5d27204ef..8d4c9f97b 100644
--- a/src/trace_processor/sorter/BUILD.gn
+++ b/src/trace_processor/sorter/BUILD.gn
@@ -50,9 +50,11 @@ perfetto_unittest_source_set("unittests") {
"../../../gn:default_deps",
"../../../gn:gtest_and_gmock",
"../../../include/perfetto/trace_processor:storage",
+ "../../../include/perfetto/trace_processor:trace_processor",
"../../base",
"../importers/common:parser_types",
"../importers/proto:minimal",
+ "../importers/proto:packet_sequence_state_generation_hdr",
"../types",
]
}
diff --git a/src/trace_processor/sorter/trace_sorter.h b/src/trace_processor/sorter/trace_sorter.h
index dd3850429..5ea0e0daa 100644
--- a/src/trace_processor/sorter/trace_sorter.h
+++ b/src/trace_processor/sorter/trace_sorter.h
@@ -28,7 +28,6 @@
#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/common/parser_types.h"
#include "src/trace_processor/importers/common/trace_parser.h"
#include "src/trace_processor/importers/fuchsia/fuchsia_record.h"
#include "src/trace_processor/importers/systrace/systrace_line.h"
diff --git a/src/trace_processor/sorter/trace_sorter_unittest.cc b/src/trace_processor/sorter/trace_sorter_unittest.cc
index 3fc8f76f8..42421df43 100644
--- a/src/trace_processor/sorter/trace_sorter_unittest.cc
+++ b/src/trace_processor/sorter/trace_sorter_unittest.cc
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "perfetto/trace_processor/trace_blob_view.h"
-#include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
+#include "src/trace_processor/sorter/trace_sorter.h"
#include <map>
#include <random>
@@ -22,9 +21,10 @@
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/trace_blob.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/parser_types.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
-#include "src/trace_processor/sorter/trace_sorter.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
+#include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -105,26 +105,25 @@ class TraceSorterTest : public ::testing::Test {
};
TEST_F(TraceSorterTest, TestFtrace) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view = test_buffer_.slice_off(0, 1);
EXPECT_CALL(*parser_,
MOCK_ParseFtracePacket(0, 1000, view.data(), 1, kNullMachineId));
context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
- std::move(view), state.current_generation());
+ std::move(view), state);
context_.sorter->ExtractEventsForced();
}
TEST_F(TraceSorterTest, TestTracePacket) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view = test_buffer_.slice_off(0, 1);
EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
- context_.sorter->PushTracePacket(1000, state.current_generation(),
- std::move(view));
+ context_.sorter->PushTracePacket(1000, state, std::move(view));
context_.sorter->ExtractEventsForced();
}
TEST_F(TraceSorterTest, Ordering) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
TraceBlobView view_3 = test_buffer_.slice_off(0, 3);
@@ -140,22 +139,18 @@ TEST_F(TraceSorterTest, Ordering) {
kNullMachineId));
context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
- std::move(view_4),
- state.current_generation());
- context_.sorter->PushTracePacket(1001, state.current_generation(),
- std::move(view_2));
- context_.sorter->PushTracePacket(1100, state.current_generation(),
- std::move(view_3));
+ std::move(view_4), state);
+ context_.sorter->PushTracePacket(1001, state, std::move(view_2));
+ context_.sorter->PushTracePacket(1100, state, std::move(view_3));
context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
- std::move(view_1),
- state.current_generation());
+ std::move(view_1), state);
context_.sorter->ExtractEventsForced();
}
TEST_F(TraceSorterTest, IncrementalExtraction) {
CreateSorter(false);
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
@@ -166,10 +161,8 @@ TEST_F(TraceSorterTest, IncrementalExtraction) {
// Flush at the start of packet sequence to match behavior of the
// service.
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1200, state.current_generation(),
- std::move(view_2));
- context_.sorter->PushTracePacket(1100, state.current_generation(),
- std::move(view_1));
+ context_.sorter->PushTracePacket(1200, state, std::move(view_2));
+ context_.sorter->PushTracePacket(1100, state, std::move(view_1));
// No data should be exttracted at this point because we haven't
// seen two flushes yet.
@@ -182,10 +175,8 @@ TEST_F(TraceSorterTest, IncrementalExtraction) {
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1400, state.current_generation(),
- std::move(view_4));
- context_.sorter->PushTracePacket(1300, state.current_generation(),
- std::move(view_3));
+ context_.sorter->PushTracePacket(1400, state, std::move(view_4));
+ context_.sorter->PushTracePacket(1300, state, std::move(view_3));
// This ReadBuffer call should finally extract until the first OnReadBuffer
// call.
@@ -197,8 +188,7 @@ TEST_F(TraceSorterTest, IncrementalExtraction) {
context_.sorter->NotifyReadBufferEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1500, state.current_generation(),
- std::move(view_5));
+ context_.sorter->PushTracePacket(1500, state, std::move(view_5));
// Nothing should be extracted as we haven't seen the second flush.
context_.sorter->NotifyReadBufferEvent();
@@ -222,7 +212,7 @@ TEST_F(TraceSorterTest, IncrementalExtraction) {
TEST_F(TraceSorterTest, OutOfOrder) {
CreateSorter(false);
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
TraceBlobView view_1 = test_buffer_.slice_off(0, 1);
TraceBlobView view_2 = test_buffer_.slice_off(0, 2);
@@ -231,10 +221,8 @@ TEST_F(TraceSorterTest, OutOfOrder) {
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1200, state.current_generation(),
- std::move(view_2));
- context_.sorter->PushTracePacket(1100, state.current_generation(),
- std::move(view_1));
+ context_.sorter->PushTracePacket(1200, state, std::move(view_2));
+ context_.sorter->PushTracePacket(1100, state, std::move(view_1));
context_.sorter->NotifyReadBufferEvent();
// Both of the packets should have been pushed through.
@@ -250,8 +238,7 @@ TEST_F(TraceSorterTest, OutOfOrder) {
// Now, pass the third packet out of order.
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1150, state.current_generation(),
- std::move(view_3));
+ context_.sorter->PushTracePacket(1150, state, std::move(view_3));
context_.sorter->NotifyReadBufferEvent();
// The third packet should still be pushed through.
@@ -268,8 +255,7 @@ TEST_F(TraceSorterTest, OutOfOrder) {
// Push the fourth packet also out of order but after third.
context_.sorter->NotifyFlushEvent();
context_.sorter->NotifyFlushEvent();
- context_.sorter->PushTracePacket(1170, state.current_generation(),
- std::move(view_4));
+ context_.sorter->PushTracePacket(1170, state, std::move(view_4));
context_.sorter->NotifyReadBufferEvent();
// The fourt packet should still be pushed through.
@@ -286,7 +272,7 @@ TEST_F(TraceSorterTest, OutOfOrder) {
// Tests that the output of the TraceSorter matches the timestamp order
// (% events happening at the same time on different CPUs).
TEST_F(TraceSorterTest, MultiQueueSorting) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
std::minstd_rand0 rnd_engine(0);
std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;
@@ -320,8 +306,7 @@ TEST_F(TraceSorterTest, MultiQueueSorting) {
for (uint8_t j = 0; j < num_cpus; j++) {
uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
expectations[ts].push_back(cpu);
- context_.sorter->PushFtraceEvent(cpu, ts, tbv.slice_off(i, 1),
- state.current_generation());
+ context_.sorter->PushFtraceEvent(cpu, ts, tbv.slice_off(i, 1), state);
}
}
@@ -331,7 +316,7 @@ TEST_F(TraceSorterTest, MultiQueueSorting) {
// An generalized version of MultiQueueSorting with multiple machines.
TEST_F(TraceSorterTest, MultiMachineSorting) {
- PacketSequenceState state(&context_);
+ auto state = PacketSequenceStateGeneration::CreateFirst(&context_);
std::minstd_rand0 rnd_engine(0);
struct ExpectedMachineAndCpu {
@@ -426,9 +411,8 @@ TEST_F(TraceSorterTest, MultiMachineSorting) {
for (uint8_t j = 0; j < num_cpus; j++) {
uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
expectations[ts].push_back(ExpectedMachineAndCpu{machine, cpu});
- context_.sorter->PushFtraceEvent(cpu, ts,
- tbv.slice_off(m * alloc_size + i, 1),
- state.current_generation(), machine);
+ context_.sorter->PushFtraceEvent(
+ cpu, ts, tbv.slice_off(m * alloc_size + i, 1), state, machine);
}
}
}
diff --git a/src/trace_processor/sorter/trace_token_buffer_unittest.cc b/src/trace_processor/sorter/trace_token_buffer_unittest.cc
index a8657d28b..59f7e9356 100644
--- a/src/trace_processor/sorter/trace_token_buffer_unittest.cc
+++ b/src/trace_processor/sorter/trace_token_buffer_unittest.cc
@@ -19,10 +19,11 @@
#include <optional>
#include "perfetto/base/compiler.h"
+#include "perfetto/trace_processor/ref_counted.h"
#include "perfetto/trace_processor/trace_blob.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/parser_types.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/types/trace_processor_context.h"
#include "test/gtest_and_gmock.h"
@@ -34,17 +35,18 @@ class TraceTokenBufferUnittest : public testing::Test {
protected:
TraceTokenBuffer store;
TraceProcessorContext context;
- PacketSequenceState state{&context};
+ RefPtr<PacketSequenceStateGeneration> state =
+ PacketSequenceStateGeneration::CreateFirst(&context);
};
TEST_F(TraceTokenBufferUnittest, TracePacketDataInOut) {
TraceBlobView tbv(TraceBlob::Allocate(1024));
- TracePacketData tpd{tbv.copy(), state.current_generation()};
+ TracePacketData tpd{tbv.copy(), state};
TraceTokenBuffer::Id id = store.Append(std::move(tpd));
TracePacketData extracted = store.Extract<TracePacketData>(id);
ASSERT_EQ(extracted.packet, tbv);
- ASSERT_EQ(extracted.sequence_state, state.current_generation());
+ ASSERT_EQ(extracted.sequence_state, state);
}
TEST_F(TraceTokenBufferUnittest, PacketAppendMultipleBlobs) {
@@ -53,14 +55,14 @@ TEST_F(TraceTokenBufferUnittest, PacketAppendMultipleBlobs) {
TraceBlobView tbv_3(TraceBlob::Allocate(4096));
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_1.copy(), state});
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_2.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_1).packet, tbv_1);
ASSERT_EQ(store.Extract<TracePacketData>(id_2).packet, tbv_2);
TraceTokenBuffer::Id id_3 =
- store.Append(TracePacketData{tbv_3.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_3.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_3).packet, tbv_3);
}
@@ -71,14 +73,14 @@ TEST_F(TraceTokenBufferUnittest, BlobSharing) {
TraceBlobView tbv_3 = root.slice_off(1536, 512);
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_1.copy(), state});
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_2.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_1).packet, tbv_1);
ASSERT_EQ(store.Extract<TracePacketData>(id_2).packet, tbv_2);
TraceTokenBuffer::Id id_3 =
- store.Append(TracePacketData{tbv_3.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_3.copy(), state});
ASSERT_EQ(store.Extract<TracePacketData>(id_3).packet, tbv_3);
}
@@ -88,13 +90,11 @@ TEST_F(TraceTokenBufferUnittest, SequenceStateSharing) {
TraceBlobView tbv_2 = root.slice_off(1024, 512);
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{tbv_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{tbv_1.copy(), state});
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{tbv_2.copy(), state.current_generation()});
- ASSERT_EQ(store.Extract<TracePacketData>(id_1).sequence_state,
- state.current_generation());
- ASSERT_EQ(store.Extract<TracePacketData>(id_2).sequence_state,
- state.current_generation());
+ store.Append(TracePacketData{tbv_2.copy(), state});
+ ASSERT_EQ(store.Extract<TracePacketData>(id_1).sequence_state, state);
+ ASSERT_EQ(store.Extract<TracePacketData>(id_2).sequence_state, state);
}
TEST_F(TraceTokenBufferUnittest, ManySequenceState) {
@@ -103,10 +103,9 @@ TEST_F(TraceTokenBufferUnittest, ManySequenceState) {
std::array<TraceTokenBuffer::Id, 1024> ids;
std::array<PacketSequenceStateGeneration*, 1024> refs;
for (uint32_t i = 0; i < 1024; ++i) {
- refs[i] = state.current_generation().get();
- ids[i] = store.Append(
- TracePacketData{root.slice_off(i, 1), state.current_generation()});
- state.OnIncrementalStateCleared();
+ refs[i] = state.get();
+ ids[i] = store.Append(TracePacketData{root.slice_off(i, 1), state});
+ state = state->OnNewTracePacketDefaults(TraceBlobView());
}
for (uint32_t i = 0; i < 1024; ++i) {
@@ -120,22 +119,22 @@ TEST_F(TraceTokenBufferUnittest, PacketLargeOffset) {
TraceBlobView slice_1 = tbv.slice_off(0, 1024ul);
TraceTokenBuffer::Id id_1 =
- store.Append(TracePacketData{slice_1.copy(), state.current_generation()});
+ store.Append(TracePacketData{slice_1.copy(), state});
TracePacketData out_1 = store.Extract<TracePacketData>(id_1);
ASSERT_EQ(out_1.packet, slice_1);
- ASSERT_EQ(out_1.sequence_state, state.current_generation());
+ ASSERT_EQ(out_1.sequence_state, state);
TraceBlobView slice_2 = tbv.slice_off(128ul * 1024, 1024ul);
TraceTokenBuffer::Id id_2 =
- store.Append(TracePacketData{slice_2.copy(), state.current_generation()});
+ store.Append(TracePacketData{slice_2.copy(), state});
TracePacketData out_2 = store.Extract<TracePacketData>(id_2);
ASSERT_EQ(out_2.packet, slice_2);
- ASSERT_EQ(out_2.sequence_state, state.current_generation());
+ ASSERT_EQ(out_2.sequence_state, state);
}
TEST_F(TraceTokenBufferUnittest, TrackEventDataInOut) {
TraceBlobView tbv(TraceBlob::Allocate(1234));
- TrackEventData ted(tbv.copy(), state.current_generation());
+ TrackEventData ted(tbv.copy(), state);
ted.thread_instruction_count = 123;
ted.extra_counter_values = {10, 2, 0, 0, 0, 0, 0, 0};
auto counter_array = ted.extra_counter_values;
@@ -143,8 +142,7 @@ TEST_F(TraceTokenBufferUnittest, TrackEventDataInOut) {
TraceTokenBuffer::Id id = store.Append(std::move(ted));
TrackEventData extracted = store.Extract<TrackEventData>(id);
ASSERT_EQ(extracted.trace_packet_data.packet, tbv);
- ASSERT_EQ(extracted.trace_packet_data.sequence_state,
- state.current_generation());
+ ASSERT_EQ(extracted.trace_packet_data.sequence_state, state);
ASSERT_EQ(extracted.thread_instruction_count, 123);
ASSERT_EQ(extracted.thread_timestamp, std::nullopt);
ASSERT_DOUBLE_EQ(extracted.counter_value, 0.0);
diff --git a/src/trace_processor/util/BUILD.gn b/src/trace_processor/util/BUILD.gn
index 86ecf9cd0..5ca39a1d0 100644
--- a/src/trace_processor/util/BUILD.gn
+++ b/src/trace_processor/util/BUILD.gn
@@ -305,6 +305,7 @@ source_set("unittests") {
"../../protozero:testing_messages_zero",
"../importers/proto:gen_cc_track_event_descriptor",
"../importers/proto:minimal",
+ "../importers/proto:packet_sequence_state_generation_hdr",
"../storage",
"../types",
]
diff --git a/src/trace_processor/util/debug_annotation_parser_unittest.cc b/src/trace_processor/util/debug_annotation_parser_unittest.cc
index d9a416893..902e9da02 100644
--- a/src/trace_processor/util/debug_annotation_parser_unittest.cc
+++ b/src/trace_processor/util/debug_annotation_parser_unittest.cc
@@ -18,6 +18,7 @@
#include "perfetto/ext/base/string_view.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/trace_processor/ref_counted.h"
#include "perfetto/trace_processor/trace_blob.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "protos/perfetto/common/descriptor.pbzero.h"
@@ -27,7 +28,8 @@
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "src/protozero/test/example_proto/test_messages.pbzero.h"
-#include "src/trace_processor/importers/proto/packet_sequence_state.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_builder.h"
+#include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/test_messages.descriptor.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -54,13 +56,13 @@ base::Status ParseDebugAnnotation(
class DebugAnnotationParserTest : public ::testing::Test,
public ProtoToArgsParser::Delegate {
protected:
- DebugAnnotationParserTest() : sequence_state_(&context_) {
- context_.storage.reset(new TraceStorage());
- }
+ DebugAnnotationParserTest() { context_.storage.reset(new TraceStorage()); }
const std::vector<std::string>& args() const { return args_; }
- PacketSequenceState* mutable_seq_state() { return &sequence_state_; }
+ void InternMessage(uint32_t field_id, TraceBlobView message) {
+ state_builder_.InternMessage(field_id, std::move(message));
+ }
private:
using Key = ProtoToArgsParser::Key;
@@ -132,23 +134,19 @@ class DebugAnnotationParserTest : public ::testing::Test,
InternedMessageView* GetInternedMessageView(uint32_t field_id,
uint64_t iid) override {
- if (field_id !=
- protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber) {
- return nullptr;
- }
- return sequence_state_.current_generation()->GetInternedMessageView(
- field_id, iid);
+ return state_builder_.current_generation()->GetInternedMessageView(field_id,
+ iid);
}
PacketSequenceStateGeneration* seq_state() final {
- return sequence_state_.current_generation().get();
+ return state_builder_.current_generation().get();
}
std::vector<std::string> args_;
std::map<std::string, size_t> array_indices_;
TraceProcessorContext context_;
- PacketSequenceState sequence_state_;
+ PacketSequenceStateBuilder state_builder_{&context_};
};
// This test checks that in when an array is nested inside a dict which is
@@ -303,7 +301,7 @@ TEST_F(DebugAnnotationParserTest, InternedString) {
string->set_str("foo");
std::vector<uint8_t> data_serialized = string.SerializeAsArray();
- mutable_seq_state()->InternMessage(
+ InternMessage(
protos::pbzero::InternedData::kDebugAnnotationStringValuesFieldNumber,
TraceBlobView(
TraceBlob::CopyFrom(data_serialized.data(), data_serialized.size())));
diff --git a/src/trace_processor/util/interned_message_view.h b/src/trace_processor/util/interned_message_view.h
index f6a9a13da..7ee28c365 100644
--- a/src/trace_processor/util/interned_message_view.h
+++ b/src/trace_processor/util/interned_message_view.h
@@ -103,7 +103,7 @@ class InternedMessageView {
return submessage_view;
}
- const TraceBlobView& message() { return message_; }
+ const TraceBlobView& message() const { return message_; }
private:
using SubMessageViewMap =
diff --git a/src/traced/probes/packages_list/packages_list_parser.cc b/src/traced/probes/packages_list/packages_list_parser.cc
index 9b58e20fb..3bba17b8c 100644
--- a/src/traced/probes/packages_list/packages_list_parser.cc
+++ b/src/traced/probes/packages_list/packages_list_parser.cc
@@ -16,6 +16,8 @@
#include "src/traced/probes/packages_list/packages_list_parser.h"
+#include <stdlib.h>
+
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/string_splitter.h"
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index b9efcf53d..8fd1d8a2b 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -1855,7 +1855,10 @@ void TracingMuxerImpl::UpdateDataSourceOnAllBackends(RegisteredDataSource& rds,
rds.descriptor.set_no_flush(rds.no_flush);
}
rds.descriptor.set_will_notify_on_start(true);
- rds.descriptor.set_will_notify_on_stop(true);
+ if (!rds.descriptor.has_will_notify_on_stop()) {
+ rds.descriptor.set_will_notify_on_stop(true);
+ }
+
rds.descriptor.set_handles_incremental_state_clear(true);
rds.descriptor.set_id(rds.static_state->id);
if (is_registered) {
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index 5e1e27758..5072c3d85 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -2485,7 +2485,7 @@ TEST_P(PerfettoApiTest, TrackEventThreadTime) {
EXPECT_FALSE(found_counter_track_descriptor);
found_counter_track_descriptor = true;
thread_time_counter_uuid = packet.track_descriptor().uuid();
- EXPECT_EQ("thread_time", packet.track_descriptor().name());
+ EXPECT_EQ("thread_time", packet.track_descriptor().static_name());
auto counter = packet.track_descriptor().counter();
EXPECT_EQ(
perfetto::protos::gen::
@@ -5795,8 +5795,10 @@ TEST_P(PerfettoApiTest, CountersDeltaEncoding) {
auto& desc = packet.track_descriptor();
if (!desc.has_counter())
continue;
- counter_names[desc.uuid()] = desc.name();
- EXPECT_EQ((desc.name() != "Framerate3"), desc.counter().is_incremental());
+ counter_names[desc.uuid()] =
+ desc.has_name() ? desc.name() : desc.static_name();
+ EXPECT_EQ((desc.static_name() != "Framerate3"),
+ desc.counter().is_incremental());
}
if (packet.has_track_event()) {
auto event = packet.track_event();
@@ -5869,7 +5871,8 @@ TEST_P(PerfettoApiTest, Counters) {
continue;
}
auto desc = packet.track_descriptor();
- counter_names[desc.uuid()] = desc.name();
+ counter_names[desc.uuid()] =
+ desc.has_name() ? desc.name() : desc.static_name();
if (desc.name() == "Framerate") {
EXPECT_EQ("fps", desc.counter().unit_name());
} else if (desc.name() == "Goats teleported") {
diff --git a/src/tracing/track.cc b/src/tracing/track.cc
index 02e6e035e..dc02609b3 100644
--- a/src/tracing/track.cc
+++ b/src/tracing/track.cc
@@ -118,8 +118,13 @@ void ThreadTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
protos::gen::TrackDescriptor CounterTrack::Serialize() const {
auto desc = Track::Serialize();
- desc.set_name(name_);
auto* counter = desc.mutable_counter();
+ if (static_name_) {
+ desc.set_static_name(static_name_.value);
+ } else {
+ desc.set_name(dynamic_name_.value);
+ }
+
if (category_)
counter->add_categories(category_);
if (unit_ != perfetto::protos::pbzero::CounterDescriptor::UNIT_UNSPECIFIED)
diff --git a/src/tracing/track_event_state_tracker.cc b/src/tracing/track_event_state_tracker.cc
index 157429235..e65d86fe9 100644
--- a/src/tracing/track_event_state_tracker.cc
+++ b/src/tracing/track_event_state_tracker.cc
@@ -246,7 +246,11 @@ void TrackEventStateTracker::UpdateIncrementalState(
track.index = static_cast<uint32_t>(session_state->tracks.size() + 1);
track.uuid = track_descriptor.uuid();
- track.name = track_descriptor.name().ToStdString();
+ if (track_descriptor.has_name()) {
+ track.name = track_descriptor.name().ToStdString();
+ } else if (track_descriptor.has_static_name()) {
+ track.name = track_descriptor.static_name().ToStdString();
+ }
track.pid = 0;
track.tid = 0;
if (track_descriptor.has_process()) {
diff --git a/test/trace_processor/diff_tests/metrics/startup/tests.py b/test/trace_processor/diff_tests/metrics/startup/tests.py
index b365fcf1d..9194f4195 100644
--- a/test/trace_processor/diff_tests/metrics/startup/tests.py
+++ b/test/trace_processor/diff_tests/metrics/startup/tests.py
@@ -40,3 +40,9 @@ class Startup(TestSuite):
trace=Path('android_startup_unlock.py'),
query=Metric('android_startup'),
out=Path('android_startup_unlock.out'))
+
+ def test_ttid_and_ttfd(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api31_startup_warm.perfetto-trace'),
+ query=Metric('android_startup'),
+ out=Path('ttid_and_ttfd.out'))
diff --git a/test/trace_processor/diff_tests/metrics/startup/ttid_and_ttfd.out b/test/trace_processor/diff_tests/metrics/startup/ttid_and_ttfd.out
new file mode 100644
index 000000000..f5dcfcf92
--- /dev/null
+++ b/test/trace_processor/diff_tests/metrics/startup/ttid_and_ttfd.out
@@ -0,0 +1,98 @@
+android_startup {
+ startup {
+ startup_id: 1
+ package_name: "androidx.benchmark.integration.macrobenchmark.target"
+ process_name: "androidx.benchmark.integration.macrobenchmark.target"
+ zygote_new_process: false
+ to_first_frame {
+ dur_ns: 64748027
+ main_thread_by_task_state {
+ running_dur_ns: 18635782
+ runnable_dur_ns: 4030310
+ uninterruptible_sleep_dur_ns: 0
+ interruptible_sleep_dur_ns: 42081935
+ uninterruptible_io_sleep_dur_ns: 0
+ uninterruptible_non_io_sleep_dur_ns: 0
+ }
+ other_processes_spawned_count: 3
+ time_activity_manager {
+ dur_ns: 9369168
+ dur_ms: 9.369168
+ }
+ time_activity_start {
+ dur_ns: 10707813
+ dur_ms: 10.707813
+ }
+ time_activity_resume {
+ dur_ns: 11126928
+ dur_ms: 11.126928
+ }
+ time_choreographer {
+ dur_ns: 21174429
+ dur_ms: 21.174429
+ }
+ dur_ms: 64.748027
+ time_inflate {
+ dur_ns: 2598178
+ dur_ms: 2.598178
+ }
+ time_get_resources {
+ dur_ns: 285520
+ dur_ms: 0.28552
+ }
+ mcycles_by_core_type {
+ little: 238
+ big: 293
+ bigger: 83
+ }
+ time_jit_thread_pool_on_cpu {
+ dur_ns: 15833
+ dur_ms: 0.015833
+ }
+ time_to_running_state {
+ dur_ns: 2552657
+ dur_ms: 2.552657
+ }
+ }
+ activity_hosting_process_count: 1
+ process {
+ name: "androidx.benchmark.integration.macrobenchmark.target"
+ uid: 10246
+ pid: 22871
+ }
+ report_fully_drawn {
+ dur_ns: 543742658
+ dur_ms: 543.742658
+ }
+ activities {
+ name: "androidx.benchmark.integration.macrobenchmark.target.TrivialStartupFullyDrawnActivity"
+ method: "performCreate"
+ ts_method_start: 186982074137030
+ }
+ activities {
+ name: "androidx.benchmark.integration.macrobenchmark.target.TrivialStartupFullyDrawnActivity"
+ method: "performResume"
+ ts_method_start: 186982080918073
+ }
+ event_timestamps {
+ intent_received: 186982050780778
+ first_frame: 186982115528805
+ }
+ system_state {
+ dex2oat_running: false
+ installd_running: false
+ broadcast_dispatched_count: 0
+ broadcast_received_count: 0
+ most_active_non_launch_processes: "system_server"
+ most_active_non_launch_processes: "/system/bin/surfaceflinger"
+ most_active_non_launch_processes: "com.android.systemui"
+ most_active_non_launch_processes: "/vendor/bin/hw/vendor.qti.hardware.display.allocator-service"
+ most_active_non_launch_processes: "/vendor/bin/hw/android.hardware.graphics.composer@2.4-service-sm8150"
+ installd_dur_ns: 0
+ dex2oat_dur_ns: 0
+ }
+ startup_type: "warm"
+ time_to_initial_display: 62373965
+ time_to_full_display: 555968701
+ }
+}
diff --git a/test/trace_processor/diff_tests/parser/profiling/tests.py b/test/trace_processor/diff_tests/parser/profiling/tests.py
index 9420112ee..aa71d729c 100644
--- a/test/trace_processor/diff_tests/parser/profiling/tests.py
+++ b/test/trace_processor/diff_tests/parser/profiling/tests.py
@@ -310,6 +310,7 @@ class Profiling(TestSuite):
from stack_profile_callsite spc
join stack_profile_frame spf on (spc.frame_id = spf.id)
where spf.name = "_ZN3art28ResolveFieldWithAccessChecksEPNS_6ThreadEPNS_11ClassLinkerEtPNS_9ArtMethodEbbm")
+ and depth != 10 -- Skipped because cause symbolization issues on clang vs gcc due to llvm-demangle
order by depth asc;
""",
out=Csv("""
@@ -324,7 +325,6 @@ class Profiling(TestSuite):
7,"aot","/system/framework/arm64/boot-framework.oat","com.android.internal.os.ZygoteInit.main"
8,"aot","/system/framework/arm64/boot-framework.oat","com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run"
9,"common-frame","/system/framework/arm64/boot.oat","art_jni_trampoline"
- 10,"[NULL]","/apex/com.android.art/lib64/libart.so","art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*) (.__uniq.165753521025965369065708152063621506277)"
11,"common-frame","/apex/com.android.art/lib64/libart.so","_jobject* art::InvokeMethod<(art::PointerSize)8>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long)"
12,"common-frame","/apex/com.android.art/lib64/libart.so","art_quick_invoke_static_stub"
13,"aot","/system/framework/arm64/boot-framework.oat","android.app.ActivityThread.main"
diff --git a/test/trace_processor/diff_tests/stdlib/android/startups_tests.py b/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
index 197ac2a58..95ff515ac 100644
--- a/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
@@ -103,7 +103,7 @@ class Startups(TestSuite):
SELECT * FROM android_startup_time_to_display;
""",
out=Csv("""
- "startup_id","time_to_inital_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
+ "startup_id","time_to_initial_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
1,33198906,"[NULL]",1,"[NULL]",355
2,35039927,537343160,4,5,383
"""))
@@ -116,7 +116,7 @@ class Startups(TestSuite):
SELECT * FROM android_startup_time_to_display;
""",
out=Csv("""
- "startup_id","time_to_inital_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
+ "startup_id","time_to_initial_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
1,34629656,"[NULL]",1,"[NULL]",355
2,108563770,581026583,4,5,388
"""))
@@ -129,7 +129,7 @@ class Startups(TestSuite):
SELECT * FROM android_startup_time_to_display;
""",
out=Csv("""
- "startup_id","time_to_inital_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
+ "startup_id","time_to_initial_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
1,264869885,715406822,65,66,396
"""))
@@ -141,7 +141,7 @@ class Startups(TestSuite):
SELECT * FROM android_startup_time_to_display;
""",
out=Csv("""
- "startup_id","time_to_inital_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
+ "startup_id","time_to_initial_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
1,40534066,542222554,5872867,5872953,184
"""))
@@ -153,7 +153,7 @@ class Startups(TestSuite):
SELECT * FROM android_startup_time_to_display;
""",
out=Csv("""
- "startup_id","time_to_inital_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
+ "startup_id","time_to_initial_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
1,62373965,555968701,5873800,5873889,185
"""))
@@ -165,6 +165,6 @@ class Startups(TestSuite):
SELECT * FROM android_startup_time_to_display;
""",
out=Csv("""
- "startup_id","time_to_inital_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
+ "startup_id","time_to_initial_display","time_to_full_display","ttid_frame_id","ttfd_frame_id","upid"
1,143980066,620815843,5873276,5873353,229
"""))
diff --git a/test/trace_processor/diff_tests/stdlib/prelude/pprof_functions_tests.py b/test/trace_processor/diff_tests/stdlib/prelude/pprof_functions_tests.py
index d810c089f..c706c07db 100644
--- a/test/trace_processor/diff_tests/stdlib/prelude/pprof_functions_tests.py
+++ b/test/trace_processor/diff_tests/stdlib/prelude/pprof_functions_tests.py
@@ -225,7 +225,7 @@ class PreludePprofFunctions(TestSuite):
android.app.ActivityThread.main [aot] (0x717454cc)
art_quick_invoke_static_stub [common-frame] (0x724db2de00)
_jobject* art::InvokeMethod<(art::PointerSize)8>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned long) [common-frame] (0x724db545ec)
- art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*) (.__uniq.165753521025965369065708152063621506277) (0x724db53ad0)
+ art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobjectArray*) (0x724db53ad0)
art_jni_trampoline [common-frame] (0x6ff5c578)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run [aot] (0x71c4ab6c)
com.android.internal.os.ZygoteInit.main [aot] (0x71c54c7c)
diff --git a/tools/install-build-deps b/tools/install-build-deps
index a3befb086..8e1d88f1a 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -195,15 +195,15 @@ BUILD_DEPS_HOST = [
Dependency(
'buildtools/libcxx',
'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxx.git',
- 'f8571eaba606bde2eb8cd34b30104ca33e7c207e', 'all', 'all'),
+ '852bc6746f45add53fec19f3a29280e69e358d44', 'all', 'all'),
Dependency(
'buildtools/libcxxabi',
'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libcxxabi.git',
- '8dd405113a4f3694e910b79785dd7fb7535a888a', 'all', 'all'),
+ 'a37a3aa431f132b02a58656f13984d51098330a2', 'all', 'all'),
Dependency(
'buildtools/libunwind',
'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git',
- 'aabcd8753678f1536e15eb6385a948470debdae4', 'all', 'all'),
+ '419b03c0b8f20d6da9ddcb0d661a94a97cdd7dad', 'all', 'all'),
# Keep in sync with chromium DEPS.
Dependency(
@@ -259,8 +259,8 @@ BUILD_DEPS_HOST = [
# If updating the version, also update bazel/deps.bzl.
Dependency(
'buildtools/llvm-project.tgz',
- 'https://storage.googleapis.com/perfetto/llvm-project-3b4c59c156919902c785ce3cbae0eee2ee53064d.tgz',
- 'f4a52e7f36edd7cacc844d5ae0e5f60b6f57c5afc40683e99f295886c9ce8ff4',
+ 'https://storage.googleapis.com/perfetto/llvm-project-617a15a9eac96088ae5e9134248d8236e34b91b1.tgz',
+ '7e2541446a27f2a09a84520da7bc93cd71749ba0f17318f2d5291fbf45b97956',
'all', 'all'),
# These dependencies are for libunwindstack, which is used by src/profiling.
diff --git a/ui/release/channels.json b/ui/release/channels.json
index c80cab971..7e403f22a 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,7 +2,7 @@
"channels": [
{
"name": "stable",
- "rev": "c7da51a07f6bee116c7e1c3b91fa7abfc2a084bb"
+ "rev": "444bb44f0712aeb12d6ab546035811d4541a8f93"
},
{
"name": "canary",
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 7ca7a7417..fc3018e83 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -635,11 +635,13 @@ export function getDefaultRecordingTargets(): RecordingTarget[] {
}
export function getBuiltinChromeCategoryList(): string[] {
- // List of static Chrome categories, last updated at 2023-05-30 from HEAD of
+ // List of static Chrome categories, last updated at 2024-05-15 from HEAD of
// Chromium's //base/trace_event/builtin_categories.h.
return [
'accessibility',
'AccountFetcherService',
+ 'android.adpf',
+ 'android.ui.jank',
'android_webview',
'android_webview.timeline',
'aogh',
@@ -676,6 +678,7 @@ export function getBuiltinChromeCategoryList(): string[] {
'compositor',
'content',
'content_capture',
+ 'interactions',
'delegated_ink_trails',
'device',
'devtools',
@@ -703,6 +706,7 @@ export function getBuiltinChromeCategoryList(): string[] {
'gpu.angle',
'gpu.angle.texture_metrics',
'gpu.capture',
+ 'graphics.pipeline',
'headless',
'history',
'hwoverlays',
@@ -710,6 +714,7 @@ export function getBuiltinChromeCategoryList(): string[] {
'ime',
'IndexedDB',
'input',
+ 'input.scrolling',
'io',
'ipc',
'Java',
@@ -729,7 +734,9 @@ export function getBuiltinChromeCategoryList(): string[] {
'mus',
'native',
'navigation',
+ 'navigation.debug',
'net',
+ 'network.scheduler',
'netlog',
'offline_pages',
'omnibox',
@@ -792,19 +799,19 @@ export function getBuiltinChromeCategoryList(): string[] {
'webengine.fidl',
'weblayer',
'WebCore',
+ 'webnn',
'webrtc',
'webrtc_stats',
'xr',
'disabled-by-default-android_view_hierarchy',
'disabled-by-default-animation-worklet',
'disabled-by-default-audio',
- 'disabled-by-default-audio-worklet',
'disabled-by-default-audio.latency',
+ 'disabled-by-default-audio-worklet',
'disabled-by-default-base',
'disabled-by-default-blink.debug',
'disabled-by-default-blink.debug.display_lock',
'disabled-by-default-blink.debug.layout',
- 'disabled-by-default-blink.debug.layout.scrollbars',
'disabled-by-default-blink.debug.layout.trees',
'disabled-by-default-blink.feature_usage',
'disabled-by-default-blink.image_decoding',
@@ -832,6 +839,9 @@ export function getBuiltinChromeCategoryList(): string[] {
'disabled-by-default-devtools.timeline.layers',
'disabled-by-default-devtools.timeline.picture',
'disabled-by-default-devtools.timeline.stack',
+ 'disabled-by-default-devtools.target-rundown',
+ 'disabled-by-default-devtools.v8-source-rundown',
+ 'disabled-by-default-devtools.v8-source-rundown-sources',
'disabled-by-default-file',
'disabled-by-default-fonts',
'disabled-by-default-gpu_cmd_queue',
@@ -839,6 +849,7 @@ export function getBuiltinChromeCategoryList(): string[] {
'disabled-by-default-gpu.debug',
'disabled-by-default-gpu.decoder',
'disabled-by-default-gpu.device',
+ 'disabled-by-default-gpu.graphite.dawn',
'disabled-by-default-gpu.service',
'disabled-by-default-gpu.vulkan.vma',
'disabled-by-default-histogram_samples',
@@ -864,7 +875,9 @@ export function getBuiltinChromeCategoryList(): string[] {
'disabled-by-default-skia.gpu',
'disabled-by-default-skia.gpu.cache',
'disabled-by-default-skia.shaders',
+ 'disabled-by-default-skottie',
'disabled-by-default-SyncFileSystem',
+ 'disabled-by-default-system_power',
'disabled-by-default-system_stats',
'disabled-by-default-thread_pool_diagnostics',
'disabled-by-default-toplevel.ipc',
@@ -883,6 +896,7 @@ export function getBuiltinChromeCategoryList(): string[] {
'disabled-by-default-v8.wasm.detailed',
'disabled-by-default-v8.wasm.turbofan',
'disabled-by-default-video_and_image_capture',
+ 'disabled-by-default-display.framedisplayed',
'disabled-by-default-viz.gpu_composite_time',
'disabled-by-default-viz.debug.overlay_planes',
'disabled-by-default-viz.hit_testing_flow',
@@ -891,8 +905,10 @@ export function getBuiltinChromeCategoryList(): string[] {
'disabled-by-default-viz.surface_id_flow',
'disabled-by-default-viz.surface_lifetime',
'disabled-by-default-viz.triangles',
+ 'disabled-by-default-viz.visual_debugger',
'disabled-by-default-webaudio.audionode',
'disabled-by-default-webgpu',
+ 'disabled-by-default-webnn',
'disabled-by-default-webrtc',
'disabled-by-default-worker.scheduler',
'disabled-by-default-xr.debug',
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index 7c9766ca2..445bd4a8c 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -1145,7 +1145,7 @@ async function computeVisibleTime(
return HighPrecisionTimeSpan.fromTime(visibleStart, visibleEnd);
}
-async function getTraceTimeDetails(engine: Engine): Promise<TraceTime> {
+async function getTraceTimeDetails(engine: EngineBase): Promise<TraceTime> {
const traceTime = await engine.getTraceTimeBounds();
// Find the first REALTIME or REALTIME_COARSE clock snapshot.