diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-05-16 01:07:35 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-05-16 01:07:35 +0000 |
commit | 3bd36db1d857a4e73a264abd2c0f51b171ea3fc4 (patch) | |
tree | 50cf23766bec31a01e2087f02b34856c56272e06 | |
parent | 491f58e520146ad9deb6e8aa5c7a4707bbe70628 (diff) | |
parent | 92c019c4e0a5e0a3c3ee9078992050cf95a0bf2a (diff) | |
download | perfetto-sdk-release.tar.gz |
Snap for 11847757 from 92c019c4e0a5e0a3c3ee9078992050cf95a0bf2a to sdk-releasesdk-release
Change-Id: Iad1aa7b5b9ef2a5127db8d35c184ea60307c1ee3
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", ], @@ -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", ], ) @@ -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 (RendTimestamp 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.ToFirstFrameRtoFirstFrameA 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. |