Merge "Use pid_t = unsigned int only for non gnuc compilers"
diff --git a/.gn b/.gn
index 692a951..d7ecabe 100644
--- a/.gn
+++ b/.gn
@@ -13,3 +13,4 @@
# limitations under the License.
buildconfig = "//gn/standalone/BUILDCONFIG.gn"
+script_executable = "python3"
diff --git a/BUILD b/BUILD
index 83099f4..37ac3de 100644
--- a/BUILD
+++ b/BUILD
@@ -1819,6 +1819,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_config_android_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_config_android_protos",
],
)
@@ -1994,6 +1995,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_config_interceptors_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_config_interceptors_protos",
],
)
@@ -2152,6 +2154,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_config_profiling_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_config_profiling_protos",
],
)
@@ -2218,6 +2221,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_config_sys_stats_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_config_sys_stats_protos",
],
)
@@ -2261,7 +2265,18 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_config_zero",
deps = [
+ ":protos_perfetto_common_zero",
+ ":protos_perfetto_config_android_zero",
+ ":protos_perfetto_config_ftrace_zero",
+ ":protos_perfetto_config_gpu_zero",
+ ":protos_perfetto_config_inode_file_zero",
+ ":protos_perfetto_config_interceptors_zero",
+ ":protos_perfetto_config_power_zero",
+ ":protos_perfetto_config_process_stats_zero",
+ ":protos_perfetto_config_profiling_zero",
":protos_perfetto_config_protos",
+ ":protos_perfetto_config_sys_stats_zero",
+ ":protos_perfetto_config_track_event_zero",
],
)
@@ -2502,6 +2517,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_android_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_trace_android_protos",
],
)
@@ -2662,6 +2678,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_gpu_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_trace_gpu_protos",
],
)
@@ -2695,7 +2712,11 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_interned_data_zero",
deps = [
+ ":protos_perfetto_common_zero",
+ ":protos_perfetto_trace_gpu_zero",
":protos_perfetto_trace_interned_data_protos",
+ ":protos_perfetto_trace_profiling_zero",
+ ":protos_perfetto_trace_track_event_zero",
],
)
@@ -2755,6 +2776,18 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_minimal_zero",
deps = [
+ ":protos_perfetto_common_zero",
+ ":protos_perfetto_config_android_zero",
+ ":protos_perfetto_config_ftrace_zero",
+ ":protos_perfetto_config_gpu_zero",
+ ":protos_perfetto_config_inode_file_zero",
+ ":protos_perfetto_config_interceptors_zero",
+ ":protos_perfetto_config_power_zero",
+ ":protos_perfetto_config_process_stats_zero",
+ ":protos_perfetto_config_profiling_zero",
+ ":protos_perfetto_config_sys_stats_zero",
+ ":protos_perfetto_config_track_event_zero",
+ ":protos_perfetto_config_zero",
":protos_perfetto_trace_minimal_protos",
],
)
@@ -2815,7 +2848,33 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_non_minimal_zero",
deps = [
+ ":protos_perfetto_common_zero",
+ ":protos_perfetto_config_android_zero",
+ ":protos_perfetto_config_ftrace_zero",
+ ":protos_perfetto_config_gpu_zero",
+ ":protos_perfetto_config_inode_file_zero",
+ ":protos_perfetto_config_interceptors_zero",
+ ":protos_perfetto_config_power_zero",
+ ":protos_perfetto_config_process_stats_zero",
+ ":protos_perfetto_config_profiling_zero",
+ ":protos_perfetto_config_sys_stats_zero",
+ ":protos_perfetto_config_track_event_zero",
+ ":protos_perfetto_config_zero",
+ ":protos_perfetto_trace_android_zero",
+ ":protos_perfetto_trace_chrome_zero",
+ ":protos_perfetto_trace_filesystem_zero",
+ ":protos_perfetto_trace_ftrace_zero",
+ ":protos_perfetto_trace_gpu_zero",
+ ":protos_perfetto_trace_interned_data_zero",
+ ":protos_perfetto_trace_minimal_zero",
":protos_perfetto_trace_non_minimal_protos",
+ ":protos_perfetto_trace_perfetto_zero",
+ ":protos_perfetto_trace_power_zero",
+ ":protos_perfetto_trace_profiling_zero",
+ ":protos_perfetto_trace_ps_zero",
+ ":protos_perfetto_trace_sys_stats_zero",
+ ":protos_perfetto_trace_system_info_zero",
+ ":protos_perfetto_trace_track_event_zero",
],
)
@@ -2875,6 +2934,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_power_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_trace_power_protos",
],
)
@@ -2916,6 +2976,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_processor_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_trace_processor_protos",
],
)
@@ -2950,6 +3011,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_profiling_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_trace_profiling_protos",
],
)
@@ -3008,6 +3070,7 @@
perfetto_cc_protozero_library(
name = "protos_perfetto_trace_sys_stats_zero",
deps = [
+ ":protos_perfetto_common_zero",
":protos_perfetto_trace_sys_stats_protos",
],
)
@@ -3564,7 +3627,6 @@
":src_profiling_deobfuscator",
":src_profiling_symbolizer_symbolize_database",
":src_profiling_symbolizer_symbolizer",
- ":src_trace_processor_containers_containers",
":tools_trace_to_text_pprofbuilder",
":tools_trace_to_text_utils",
],
diff --git a/bazel/rules.bzl b/bazel/rules.bzl
index 1767aa4..4503867 100644
--- a/bazel/rules.bzl
+++ b/bazel/rules.bzl
@@ -93,9 +93,20 @@
):
return
+ # A perfetto_cc_protozero_library has two types of dependencies:
+ # 1. Exactly one dependency on a proto_library target. This defines the
+ # .proto sources for the target
+ # 2. Zero or more deps on other perfetto_cc_protozero_library targets. This
+ # to deal with the case of foo.proto including common.proto from another
+ # target.
+ _proto_deps = [d for d in deps if d.endswith("_protos")]
+ _cc_deps = [d for d in deps if d not in _proto_deps]
+ if len(_proto_deps) != 1:
+ fail("Too many proto deps for target %s" % name)
+
proto_gen(
name = name + "_src",
- deps = deps,
+ deps = _proto_deps,
suffix = "pbzero",
plugin = PERFETTO_CONFIG.root + ":protozero_plugin",
wrapper_namespace = "pbzero",
@@ -113,7 +124,7 @@
name = name,
srcs = [":" + name + "_src"],
hdrs = [":" + name + "_h"],
- deps = [PERFETTO_CONFIG.root + ":protozero"],
+ deps = [PERFETTO_CONFIG.root + ":protozero"] + _cc_deps,
**kwargs
)
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index a59c492..98022c9 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -1058,6 +1058,7 @@
visibility = _buildtools_visibility
cflags = [
"-DJSON_USE_EXCEPTION=0",
+ "-Wno-deprecated-declarations",
# Using -isystem instead of include_dirs (-I), so we don't need to suppress
# warnings coming from third-party headers. Doing so would mask warnings in
diff --git a/debian/control b/debian/control
index be52af4..5467a93 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,15 @@
Section: kernel
Priority: optional
Maintainer: Sami Kyostila <skyostil@google.com>
-Build-Depends: debhelper (>= 10)
+Build-Depends: debhelper (>= 10),
+ ca-certificates,
+ curl,
+ generate-ninja,
+ git,
+ libprotoc-dev,
+ ninja-build,
+ protobuf-compiler,
+ python3
Standards-Version: 3.9.8
Homepage: https://perfetto.dev
Vcs-Git: https://android.googlesource.com/platform/external/perfetto/
diff --git a/debian/perfetto.install b/debian/perfetto.install
index 1ae73aa..ded0fdc 100644
--- a/debian/perfetto.install
+++ b/debian/perfetto.install
@@ -1,8 +1,6 @@
out/release/libperfetto.so usr/lib
out/release/traced usr/sbin
-out/release/traced_perf usr/sbin
out/release/traced_probes usr/sbin
out/release/perfetto usr/bin
debian/traced.service lib/systemd/system
-debian/traced-perf.service lib/systemd/system
debian/traced-probes.service lib/systemd/system
diff --git a/debian/rules b/debian/rules
index 594466f..e6f1de4 100755
--- a/debian/rules
+++ b/debian/rules
@@ -3,11 +3,14 @@
dh $@
override_dh_auto_configure:
- tools/install-build-deps
- tools/gn gen out/release --args="is_debug=false"
+ tools/install-build-deps --no-toolchain
+ gn gen out/release --args="is_debug=false use_custom_libcxx=false\
+ is_hermetic_clang=false is_system_compiler=true is_clang=false\
+ skip_buildtools_check=true enable_perfetto_integration_tests=false\
+ enable_perfetto_unittests=false perfetto_use_system_protobuf=true"
override_dh_auto_build:
- tools/ninja -C out/release
+ ninja -C out/release perfetto traced traced_probes
override_dh_auto_clean:
- tools/gn clean out/release
+ rm -rf out/release
diff --git a/debian/triggers b/debian/triggers
new file mode 100644
index 0000000..dd86603
--- /dev/null
+++ b/debian/triggers
@@ -0,0 +1 @@
+activate-noawait ldconfig
diff --git a/gn/write_buildflag_header.py b/gn/write_buildflag_header.py
index 8045cce..617ab7d 100644
--- a/gn/write_buildflag_header.py
+++ b/gn/write_buildflag_header.py
@@ -67,7 +67,7 @@
guard = '%s_' % args.out.upper()
guard = guard.replace('/', '_').replace('\\', '_').replace('.', '_')
lines = []
- lines.append('// Generated by %s' % __file__)
+ lines.append('// Generated by %s' % os.path.basename(__file__))
lines.append('')
lines.append('// fix_include_guards: off')
lines.append('#ifndef %s' % guard)
diff --git a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
index 7a34606..f0179c6 100644
--- a/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/android_tree/perfetto_build_flags.h
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// Generated by ../../gn/write_buildflag_header.py
+// Generated by write_buildflag_header.py
// fix_include_guards: off
#ifndef GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
index ada8006..6745b3f 100644
--- a/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
+++ b/include/perfetto/base/build_configs/bazel/perfetto_build_flags.h
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-// Generated by ../../gn/write_buildflag_header.py
+// Generated by write_buildflag_header.py
// fix_include_guards: off
#ifndef GEN_BUILD_CONFIG_PERFETTO_BUILD_FLAGS_H_
diff --git a/include/perfetto/ext/base/string_utils.h b/include/perfetto/ext/base/string_utils.h
index 7310b01..e8fa418 100644
--- a/include/perfetto/ext/base/string_utils.h
+++ b/include/perfetto/ext/base/string_utils.h
@@ -98,6 +98,7 @@
bool StartsWith(const std::string& str, const std::string& prefix);
bool EndsWith(const std::string& str, const std::string& suffix);
bool Contains(const std::string& haystack, const std::string& needle);
+bool Contains(const std::string& haystack, char needle);
size_t Find(const StringView& needle, const StringView& haystack);
bool CaseInsensitiveEqual(const std::string& first, const std::string& second);
std::string Join(const std::vector<std::string>& parts,
diff --git a/include/perfetto/profiling/pprof_builder.h b/include/perfetto/profiling/pprof_builder.h
index df18c5a..20b9d2e 100644
--- a/include/perfetto/profiling/pprof_builder.h
+++ b/include/perfetto/profiling/pprof_builder.h
@@ -17,6 +17,7 @@
#ifndef INCLUDE_PERFETTO_PROFILING_PPROF_BUILDER_H_
#define INCLUDE_PERFETTO_PROFILING_PPROF_BUILDER_H_
+#include <iostream>
#include <string>
#include <vector>
@@ -47,19 +48,9 @@
enum class ConversionMode { kHeapProfile, kPerfProfile };
-enum class ConversionFlags : uint64_t {
- kNone = 0,
- // Suffix frame names with additional information. Current annotations are
- // specific to apps running within the Android runtime, and include
- // information such as whether the given frame was interpreted / executed
- // under JIT / etc.
- kAnnotateFrames = 1
-};
-
bool TraceToPprof(trace_processor::TraceProcessor* tp,
std::vector<SerializedProfile>* output,
ConversionMode mode = ConversionMode::kHeapProfile,
- uint64_t flags = 0,
uint64_t pid = 0,
const std::vector<uint64_t>& timestamps = {});
diff --git a/include/perfetto/protozero/proto_utils.h b/include/perfetto/protozero/proto_utils.h
index bb2e5ce..841042b 100644
--- a/include/perfetto/protozero/proto_utils.h
+++ b/include/perfetto/protozero/proto_utils.h
@@ -276,6 +276,21 @@
using message_type = MessageType;
};
+namespace internal {
+
+// Ideally we would create variables of FieldMetadata<...> type directly,
+// but before C++17's support for constexpr inline variables arrive, we have to
+// actually use pointers to inline functions instead to avoid having to define
+// symbols in *.pbzero.cc files.
+//
+// Note: protozero bindings will generate Message::kFieldName variable and which
+// can then be passed to TRACE_EVENT macro for inline writing of typed messages.
+// The fact that the former can be passed to the latter is a part of the stable
+// API, while the particular type is not and users should not rely on it.
+template <typename T>
+using FieldMetadataHelper = T (*)(void);
+
+} // namespace internal
} // namespace proto_utils
} // namespace protozero
diff --git a/include/perfetto/tracing/internal/write_track_event_args.h b/include/perfetto/tracing/internal/write_track_event_args.h
index 8263110..9a68ab5 100644
--- a/include/perfetto/tracing/internal/write_track_event_args.h
+++ b/include/perfetto/tracing/internal/write_track_event_args.h
@@ -100,7 +100,8 @@
FieldMetadataType>::value>>
PERFETTO_ALWAYS_INLINE void WriteTrackEventArgs(
EventContext event_ctx,
- const FieldMetadataType& field_name,
+ protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadataType>
+ field_name,
ArgValue&& arg_value,
Args&&... args) {
static_assert(
diff --git a/include/perfetto/tracing/traced_proto.h b/include/perfetto/tracing/traced_proto.h
index d88dbc1..88ee99e 100644
--- a/include/perfetto/tracing/traced_proto.h
+++ b/include/perfetto/tracing/traced_proto.h
@@ -166,9 +166,10 @@
} // namespace internal
template <typename MessageType, typename FieldMetadataType, typename ValueType>
-void WriteIntoTracedProto(TracedProto<MessageType> message,
- const FieldMetadataType&,
- ValueType&& value) {
+void WriteIntoTracedProto(
+ TracedProto<MessageType> message,
+ protozero::proto_utils::internal::FieldMetadataHelper<FieldMetadataType>,
+ ValueType&& value) {
static_assert(
std::is_base_of<protozero::proto_utils::FieldMetadataBase,
FieldMetadataType>::value,
diff --git a/include/perfetto/tracing/traced_value.h b/include/perfetto/tracing/traced_value.h
index 838dd47..ee36fb5 100644
--- a/include/perfetto/tracing/traced_value.h
+++ b/include/perfetto/tracing/traced_value.h
@@ -49,9 +49,9 @@
//
// To define how a custom class should be written into the trace, users should
// define one of the two following functions:
-// - Foo::WriteIntoTracedValue(TracedValue) const
+// - Foo::WriteIntoTrace(TracedValue) const
// (preferred for code which depends on perfetto directly)
-// - perfetto::TraceFormatTraits<T>::WriteIntoTracedValue(
+// - perfetto::TraceFormatTraits<T>::WriteIntoTrace(
// TracedValue, const T&);
// (should be used if T is defined in a library which doesn't know anything
// about tracing).
@@ -81,17 +81,17 @@
// });
//
// template <typename T>
-// TraceFormatTraits<std::optional<T>>::WriteIntoTracedValue(
+// TraceFormatTraits<std::optional<T>>::WriteIntoTrace(
// TracedValue context, const std::optional<T>& value) {
// if (!value) {
// std::move(context).WritePointer(nullptr);
// return;
// }
-// perfetto::WriteIntoTracedValue(std::move(context), *value);
+// perfetto::WriteIntoTrace(std::move(context), *value);
// }
//
// template <typename T>
-// TraceFormatTraits<std::vector<T>>::WriteIntoTracedValue(
+// TraceFormatTraits<std::vector<T>>::WriteIntoTrace(
// TracedValue context, const std::array<T>& value) {
// auto array = std::move(context).WriteArray();
// for (const auto& item: value) {
@@ -100,7 +100,7 @@
// }
//
// class Foo {
-// void WriteIntoTracedValue(TracedValue context) const {
+// void WriteIntoTrace(TracedValue context) const {
// auto dict = std::move(context).WriteDictionary();
// dict->Set("key", 42);
// dict->Set("foo", "bar");
@@ -265,6 +265,13 @@
value.WriteIntoTracedValue(std::move(context));
}
+// If T has WriteIntoTrace member function, call it.
+template <typename T>
+decltype(std::declval<T>().WriteIntoTrace(std::declval<TracedValue>()), void())
+WriteImpl(base::priority_tag<4>, TracedValue context, T&& value) {
+ value.WriteIntoTrace(std::move(context));
+}
+
// If perfetto::TraceFormatTraits<T>::WriteIntoTracedValue(TracedValue, const
// T&) is available, use it.
template <typename T>
@@ -277,6 +284,18 @@
std::move(context), std::forward<T>(value));
}
+// If perfetto::TraceFormatTraits<T>::WriteIntoTrace(TracedValue, const T&)
+// is available, use it.
+template <typename T>
+decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace(
+ std::declval<TracedValue>(),
+ std::declval<T>()),
+ void())
+WriteImpl(base::priority_tag<3>, TracedValue context, T&& value) {
+ TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace(
+ std::move(context), std::forward<T>(value));
+}
+
// If T has operator(), which takes TracedValue, use it.
// Very useful for lambda resolutions.
template <typename T>
@@ -429,7 +448,7 @@
typename std::enable_if<std::is_integral<T>::value &&
!std::is_same<T, bool>::value &&
std::is_signed<T>::value>::type> {
- inline static void WriteIntoTracedValue(TracedValue context, T value) {
+ inline static void WriteIntoTrace(TracedValue context, T value) {
std::move(context).WriteInt64(value);
}
};
@@ -442,7 +461,7 @@
typename std::enable_if<std::is_integral<T>::value &&
!std::is_same<T, bool>::value &&
std::is_unsigned<T>::value>::type> {
- inline static void WriteIntoTracedValue(TracedValue context, T value) {
+ inline static void WriteIntoTrace(TracedValue context, T value) {
std::move(context).WriteUInt64(value);
}
};
@@ -450,7 +469,7 @@
// Specialisation for bools.
template <>
struct TraceFormatTraits<bool> {
- inline static void WriteIntoTracedValue(TracedValue context, bool value) {
+ inline static void WriteIntoTrace(TracedValue context, bool value) {
std::move(context).WriteBoolean(value);
}
};
@@ -460,7 +479,7 @@
struct TraceFormatTraits<
T,
typename std::enable_if<std::is_floating_point<T>::value>::type> {
- inline static void WriteIntoTracedValue(TracedValue context, T value) {
+ inline static void WriteIntoTrace(TracedValue context, T value) {
std::move(context).WriteDouble(static_cast<double>(value));
}
};
@@ -473,7 +492,7 @@
std::is_enum<T>::value &&
std::is_signed<
typename internal::safe_underlying_type<T>::type>::value>::type> {
- inline static void WriteIntoTracedValue(TracedValue context, T value) {
+ inline static void WriteIntoTrace(TracedValue context, T value) {
std::move(context).WriteInt64(static_cast<int64_t>(value));
}
};
@@ -486,7 +505,7 @@
std::is_enum<T>::value &&
std::is_unsigned<
typename internal::safe_underlying_type<T>::type>::value>::type> {
- inline static void WriteIntoTracedValue(TracedValue context, T value) {
+ inline static void WriteIntoTrace(TracedValue context, T value) {
std::move(context).WriteUInt64(static_cast<uint64_t>(value));
}
};
@@ -494,24 +513,21 @@
// Specialisations for C-style strings.
template <>
struct TraceFormatTraits<const char*> {
- inline static void WriteIntoTracedValue(TracedValue context,
- const char* value) {
+ inline static void WriteIntoTrace(TracedValue context, const char* value) {
std::move(context).WriteString(value);
}
};
template <>
struct TraceFormatTraits<char[]> {
- inline static void WriteIntoTracedValue(TracedValue context,
- const char value[]) {
+ inline static void WriteIntoTrace(TracedValue context, const char value[]) {
std::move(context).WriteString(value);
}
};
template <size_t N>
struct TraceFormatTraits<char[N]> {
- inline static void WriteIntoTracedValue(TracedValue context,
- const char value[N]) {
+ inline static void WriteIntoTrace(TracedValue context, const char value[N]) {
std::move(context).WriteString(value);
}
};
@@ -519,8 +535,8 @@
// Specialisation for C++ strings.
template <>
struct TraceFormatTraits<std::string> {
- inline static void WriteIntoTracedValue(TracedValue context,
- const std::string& value) {
+ inline static void WriteIntoTrace(TracedValue context,
+ const std::string& value) {
std::move(context).WriteString(value);
}
};
@@ -528,15 +544,14 @@
// Specialisation for (const) void*, which writes the pointer value.
template <>
struct TraceFormatTraits<void*> {
- inline static void WriteIntoTracedValue(TracedValue context, void* value) {
+ inline static void WriteIntoTrace(TracedValue context, void* value) {
std::move(context).WritePointer(value);
}
};
template <>
struct TraceFormatTraits<const void*> {
- inline static void WriteIntoTracedValue(TracedValue context,
- const void* value) {
+ inline static void WriteIntoTrace(TracedValue context, const void* value) {
std::move(context).WritePointer(value);
}
};
@@ -545,8 +560,8 @@
// object it points to.
template <typename T>
struct TraceFormatTraits<std::unique_ptr<T>, check_traced_value_support_t<T>> {
- inline static void WriteIntoTracedValue(TracedValue context,
- const std::unique_ptr<T>& value) {
+ inline static void WriteIntoTrace(TracedValue context,
+ const std::unique_ptr<T>& value) {
::perfetto::WriteIntoTracedValue(std::move(context), value.get());
}
};
@@ -555,7 +570,7 @@
// points to.
template <typename T>
struct TraceFormatTraits<T*, check_traced_value_support_t<T>> {
- inline static void WriteIntoTracedValue(TracedValue context, T* value) {
+ inline static void WriteIntoTrace(TracedValue context, T* value) {
if (!value) {
std::move(context).WritePointer(nullptr);
return;
@@ -567,7 +582,7 @@
// Specialisation for nullptr.
template <>
struct TraceFormatTraits<std::nullptr_t> {
- inline static void WriteIntoTracedValue(TracedValue context, std::nullptr_t) {
+ inline static void WriteIntoTrace(TracedValue context, std::nullptr_t) {
std::move(context).WritePointer(nullptr);
}
};
diff --git a/infra/ci/config.py b/infra/ci/config.py
index f35178e..be325ab 100755
--- a/infra/ci/config.py
+++ b/infra/ci/config.py
@@ -145,6 +145,7 @@
if len(sys.argv) > 1 and sys.argv[1] == 'js':
jsn = json.dumps(vars, indent=2)
- print('// Auto-generated by %s, do not edit.\n' % __file__)
+ print('// Auto-generated by %s, do not edit.\n' %
+ os.path.basename(__file__))
print('\'use strict\';\n')
print('const cfg = JSON.parse(`%s`);\n' % jsn.replace(r'\"', r'\\\"'))
diff --git a/infra/perfetto.dev/build.js b/infra/perfetto.dev/build.js
index 086234d..1fc657c 100644
--- a/infra/perfetto.dev/build.js
+++ b/infra/perfetto.dev/build.js
@@ -73,7 +73,11 @@
// Check that deps are current before starting.
const installBuildDeps = pjoin(ROOT_DIR, 'tools/install-build-deps');
- const depsArgs = ['--check-only', '/dev/null', '--ui'];
+
+ // --filter=nodejs is to match what cloud_build_entrypoint.sh passes to
+ // install-build-deps. It doesn't bother installing the full toolchains
+ // because, unlike the Perfetto UI, it doesn't need Wasm.
+ const depsArgs = ['--check-only=/dev/null', '--ui', '--filter=nodejs'];
exec(installBuildDeps, depsArgs);
console.log('Entering', cfg.outDir);
diff --git a/protos/perfetto/trace/ftrace/cpuhp.proto b/protos/perfetto/trace/ftrace/cpuhp.proto
index 3214b51..dc45682 100644
--- a/protos/perfetto/trace/ftrace/cpuhp.proto
+++ b/protos/perfetto/trace/ftrace/cpuhp.proto
@@ -29,3 +29,9 @@
optional uint32 state = 3;
optional uint64 time = 4;
}
+message CpuhpPauseFtraceEvent {
+ optional uint32 active_cpus = 1;
+ optional uint32 cpus = 2;
+ optional uint32 pause = 3;
+ optional uint32 time = 4;
+}
diff --git a/protos/perfetto/trace/ftrace/ftrace_event.proto b/protos/perfetto/trace/ftrace/ftrace_event.proto
index e8ac22a..24ebae0 100644
--- a/protos/perfetto/trace/ftrace/ftrace_event.proto
+++ b/protos/perfetto/trace/ftrace/ftrace_event.proto
@@ -440,5 +440,6 @@
G2dTracingMarkWriteFtraceEvent g2d_tracing_mark_write = 349;
MaliTracingMarkWriteFtraceEvent mali_tracing_mark_write = 350;
DmaHeapStatFtraceEvent dma_heap_stat = 351;
+ CpuhpPauseFtraceEvent cpuhp_pause = 352;
}
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index fd4bcb0..78c593a 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -3121,6 +3121,12 @@
optional uint32 state = 3;
optional uint64 time = 4;
}
+message CpuhpPauseFtraceEvent {
+ optional uint32 active_cpus = 1;
+ optional uint32 cpus = 2;
+ optional uint32 pause = 3;
+ optional uint32 time = 4;
+}
// End of protos/perfetto/trace/ftrace/cpuhp.proto
@@ -5394,6 +5400,7 @@
G2dTracingMarkWriteFtraceEvent g2d_tracing_mark_write = 349;
MaliTracingMarkWriteFtraceEvent mali_tracing_mark_write = 350;
DmaHeapStatFtraceEvent dma_heap_stat = 351;
+ CpuhpPauseFtraceEvent cpuhp_pause = 352;
}
}
diff --git a/src/base/string_utils.cc b/src/base/string_utils.cc
index ac3b16b..c0b0780 100644
--- a/src/base/string_utils.cc
+++ b/src/base/string_utils.cc
@@ -98,6 +98,10 @@
return haystack.find(needle) != std::string::npos;
}
+bool Contains(const std::string& haystack, const char needle) {
+ return haystack.find(needle) != std::string::npos;
+}
+
size_t Find(const StringView& needle, const StringView& haystack) {
if (needle.empty())
return 0;
diff --git a/src/base/subprocess_posix.cc b/src/base/subprocess_posix.cc
index c5321f6..85df339 100644
--- a/src/base/subprocess_posix.cc
+++ b/src/base/subprocess_posix.cc
@@ -381,7 +381,7 @@
return;
PERFETTO_DCHECK(args.input.empty() || s_->input_written < args.input.size());
- if (args.input.size()) {
+ if (!args.input.empty()) {
int64_t wsize =
PERFETTO_EINTR(write(*s_->stdin_pipe.wr, &args.input[s_->input_written],
args.input.size() - s_->input_written));
diff --git a/src/perfetto_cmd/config.cc b/src/perfetto_cmd/config.cc
index 1dbba97..0e1dccf 100644
--- a/src/perfetto_cmd/config.cc
+++ b/src/perfetto_cmd/config.cc
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_utils.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/trace_config.h"
@@ -116,10 +117,10 @@
std::vector<std::string> atrace_apps = options.atrace_apps;
for (const auto& category : options.categories) {
- if (category.find('/') == std::string::npos) {
- atrace_categories.push_back(category);
- } else {
+ if (base::Contains(category, '/')) {
ftrace_events.push_back(category);
+ } else {
+ atrace_categories.push_back(category);
}
}
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 84d9af3..c76e064 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -926,6 +926,9 @@
}
if (save_to_incidentd_) {
+ if (!uuid_.empty()) {
+ PERFETTO_LOG("go/trace-uuid/%s", uuid_.c_str());
+ }
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
SaveTraceIntoDropboxAndIncidentOrCrash();
#endif
diff --git a/src/profiling/common/producer_support.cc b/src/profiling/common/producer_support.cc
index d6a58ec..fc92714 100644
--- a/src/profiling/common/producer_support.cc
+++ b/src/profiling/common/producer_support.cc
@@ -61,10 +61,6 @@
return true;
}
- if (ds_config.enable_extra_guardrails()) {
- return false; // no extra guardrails on user builds.
- }
-
uint64_t uid_without_profile = uid % kAidUserOffset;
if (uid_without_profile < kAidAppStart || kAidAppEnd < uid_without_profile) {
// TODO(fmayer): relax this.
@@ -82,9 +78,14 @@
PERFETTO_ELOG("Failed to parse packages.list.");
return false;
}
- if (pkg.uid == uid_without_profile &&
- (pkg.profileable_from_shell || pkg.debuggable)) {
- return true;
+ if (pkg.uid == uid_without_profile) {
+ if (pkg.profileable) {
+ return true;
+ }
+ if (!ds_config.enable_extra_guardrails() &&
+ (pkg.profileable_from_shell || pkg.debuggable)) {
+ return true;
+ }
}
}
return false;
diff --git a/src/profiling/common/producer_support_unittest.cc b/src/profiling/common/producer_support_unittest.cc
index df2129a..4b94e89 100644
--- a/src/profiling/common/producer_support_unittest.cc
+++ b/src/profiling/common/producer_support_unittest.cc
@@ -32,7 +32,7 @@
EXPECT_TRUE(CanProfileAndroid(ds_config, 1, "userdebug", "/dev/null"));
}
-TEST(CanProfileAndroidTest, NonUserNonProfileableApp) {
+TEST(CanProfileAndroidTest, NonUserNonProfileableByShellApp) {
DataSourceConfig ds_config;
ds_config.set_enable_extra_guardrails(false);
auto tmp = base::TempFile::Create();
@@ -44,7 +44,7 @@
EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "userdebug", tmp.path()));
}
-TEST(CanProfileAndroidTest, NonUserNonProfileableAppExtraGuardrails) {
+TEST(CanProfileAndroidTest, NonUserNonProfileableByShellAppExtraGuardrails) {
DataSourceConfig ds_config;
ds_config.set_enable_extra_guardrails(true);
auto tmp = base::TempFile::Create();
@@ -56,7 +56,7 @@
EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "userdebug", tmp.path()));
}
-TEST(CanProfileAndroidTest, UserProfileableApp) {
+TEST(CanProfileAndroidTest, UserProfileableByShellApp) {
DataSourceConfig ds_config;
ds_config.set_enable_extra_guardrails(false);
auto tmp = base::TempFile::Create();
@@ -68,7 +68,7 @@
EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "user", tmp.path()));
}
-TEST(CanProfileAndroidTest, UserProfileableAppExtraGuardrails) {
+TEST(CanProfileAndroidTest, UserProfileableByShellAppExtraGuardrails) {
DataSourceConfig ds_config;
ds_config.set_enable_extra_guardrails(true);
auto tmp = base::TempFile::Create();
@@ -80,7 +80,19 @@
EXPECT_FALSE(CanProfileAndroid(ds_config, 10001, "user", tmp.path()));
}
-TEST(CanProfileAndroidTest, UserProfileableAppMultiuser) {
+TEST(CanProfileAndroidTest, UserProfileableAppExtraGuardrails) {
+ DataSourceConfig ds_config;
+ ds_config.set_enable_extra_guardrails(true);
+ auto tmp = base::TempFile::Create();
+ constexpr char content[] =
+ "invalid.example.profileable 10001 0 "
+ "/data/user/0/invalid.example.profileable default:targetSdkVersion=10000 "
+ "none 2 1\n";
+ base::WriteAll(tmp.fd(), content, sizeof(content));
+ EXPECT_TRUE(CanProfileAndroid(ds_config, 10001, "user", tmp.path()));
+}
+
+TEST(CanProfileAndroidTest, UserProfileableByShellAppMultiuser) {
DataSourceConfig ds_config;
ds_config.set_enable_extra_guardrails(false);
auto tmp = base::TempFile::Create();
@@ -92,7 +104,7 @@
EXPECT_TRUE(CanProfileAndroid(ds_config, 210001, "user", tmp.path()));
}
-TEST(CanProfileAndroidTest, UserNonProfileableApp) {
+TEST(CanProfileAndroidTest, UserNonProfileableByShellApp) {
DataSourceConfig ds_config;
ds_config.set_enable_extra_guardrails(false);
auto tmp = base::TempFile::Create();
diff --git a/src/profiling/perf/unwinding.h b/src/profiling/perf/unwinding.h
index 2eb296f..398747a 100644
--- a/src/profiling/perf/unwinding.h
+++ b/src/profiling/perf/unwinding.h
@@ -17,6 +17,7 @@
#ifndef SRC_PROFILING_PERF_UNWINDING_H_
#define SRC_PROFILING_PERF_UNWINDING_H_
+#include <condition_variable>
#include <map>
#include <thread>
diff --git a/src/protozero/protoc_plugin/protozero_plugin.cc b/src/protozero/protoc_plugin/protozero_plugin.cc
index e2d3192..c3dc58b 100644
--- a/src/protozero/protoc_plugin/protozero_plugin.cc
+++ b/src/protozero/protoc_plugin/protozero_plugin.cc
@@ -831,16 +831,25 @@
void GenerateFieldMetadata(const std::string& message_cpp_type,
const FieldDescriptor* field) {
- const char* code_stub =
- "using $field_metadata_type$ =\n"
- " ::protozero::proto_utils::FieldMetadata<\n"
- " $field_id$,\n"
- " ::protozero::proto_utils::RepetitionType::$repetition_type$,\n"
- " ::protozero::proto_utils::ProtoSchemaType::$proto_field_type$,\n"
- " $cpp_type$,\n"
- " $message_cpp_type$>;\n"
- "static constexpr const $field_metadata_type$& $field_metadata_var$ = "
- "{};\n";
+ const char* code_stub = R"(
+using $field_metadata_type$ =
+ ::protozero::proto_utils::FieldMetadata<
+ $field_id$,
+ ::protozero::proto_utils::RepetitionType::$repetition_type$,
+ ::protozero::proto_utils::ProtoSchemaType::$proto_field_type$,
+ $cpp_type$,
+ $message_cpp_type$>;
+
+// Ceci n'est pas une pipe.
+// This is actually a variable of FieldMetadataHelper<FieldMetadata<...>>
+// type (and users are expected to use it as such, hence kCamelCase name).
+// It is declared as a function to keep protozero bindings header-only as
+// inline constexpr variables are not available until C++17 (while inline
+// functions are).
+// TODO(altimin): Use inline variable instead after adopting C++17.
+static constexpr $field_metadata_type$ $field_metadata_var$() { return {}; }
+)";
+
stub_h_->Print(code_stub, "field_id", std::to_string(field->number()),
"repetition_type", FieldToRepetitionType(field),
"proto_field_type", FieldToProtoSchemaType(field),
diff --git a/src/trace_processor/forwarding_trace_parser.cc b/src/trace_processor/forwarding_trace_parser.cc
index 6583ead..4ba663e 100644
--- a/src/trace_processor/forwarding_trace_parser.cc
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -161,7 +161,7 @@
return kJsonTraceType;
// Systrace with header but no leading HTML.
- if (start.find("# tracer") != std::string::npos)
+ if (base::Contains(start, "# tracer"))
return kSystraceTraceType;
// Systrace with leading HTML.
@@ -170,7 +170,7 @@
return kSystraceTraceType;
// Ctrace is deflate'ed systrace.
- if (start.find("TRACE:") != std::string::npos)
+ if (base::Contains(start, "TRACE:"))
return kCtraceTraceType;
// Ninja's buils log (.ninja_log).
diff --git a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
index d493173..1bf293a 100644
--- a/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_descriptors.cc
@@ -24,7 +24,7 @@
namespace trace_processor {
namespace {
-std::array<MessageDescriptor, 351> descriptors{{
+std::array<MessageDescriptor, 353> descriptors{{
{nullptr, 0, {}},
{nullptr, 0, {}},
{nullptr, 0, {}},
@@ -3741,6 +3741,27 @@
{"value", ProtoSchemaType::kInt32},
},
},
+ {
+ "dma_heap_stat",
+ 3,
+ {
+ {},
+ {"inode", ProtoSchemaType::kUint64},
+ {"len", ProtoSchemaType::kInt64},
+ {"total_allocated", ProtoSchemaType::kUint64},
+ },
+ },
+ {
+ "cpuhp_pause",
+ 4,
+ {
+ {},
+ {"active_cpus", ProtoSchemaType::kUint32},
+ {"cpus", ProtoSchemaType::kUint32},
+ {"pause", ProtoSchemaType::kUint32},
+ {"time", ProtoSchemaType::kUint32},
+ },
+ },
}};
} // namespace
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 69929a8..c226575 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -30,6 +30,7 @@
#include "protos/perfetto/common/gpu_counter_descriptor.pbzero.h"
#include "protos/perfetto/trace/ftrace/binder.pbzero.h"
+#include "protos/perfetto/trace/ftrace/cpuhp.pbzero.h"
#include "protos/perfetto/trace/ftrace/dmabuf_heap.pbzero.h"
#include "protos/perfetto/trace/ftrace/dpu.pbzero.h"
#include "protos/perfetto/trace/ftrace/fastrpc.pbzero.h"
@@ -553,6 +554,10 @@
ParseMaliTracingMarkWrite(ts, pid, data);
break;
}
+ case FtraceEvent::kCpuhpPauseFieldNumber: {
+ ParseCpuhpPause(ts, pid, data);
+ break;
+ }
default:
break;
}
@@ -1459,5 +1464,12 @@
timestamp, static_cast<double>(evt.len()), delta_track);
}
+void FtraceParser::ParseCpuhpPause(int64_t,
+ uint32_t,
+ protozero::ConstBytes blob) {
+ protos::pbzero::CpuhpPauseFtraceEvent::Decoder evt(blob.data, blob.size);
+ // TODO(b/183110813): Parse and visualize this event.
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index b1ba46e..68ee8e5 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -142,6 +142,7 @@
void ParseFastRpcDmaStat(int64_t timestamp,
uint32_t pid,
protozero::ConstBytes);
+ void ParseCpuhpPause(int64_t, uint32_t, protozero::ConstBytes);
TraceProcessorContext* context_;
RssStatTracker rss_stat_tracker_;
diff --git a/src/trace_processor/importers/json/json_utils.cc b/src/trace_processor/importers/json/json_utils.cc
index 2265eab..5d0b2d1 100644
--- a/src/trace_processor/importers/json/json_utils.cc
+++ b/src/trace_processor/importers/json/json_utils.cc
@@ -22,7 +22,7 @@
#if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
#include <json/reader.h>
-#include "include/perfetto/ext/base/string_utils.h"
+#include "perfetto/ext/base/string_utils.h"
#endif
namespace perfetto {
diff --git a/src/trace_processor/importers/proto/profiler_util.cc b/src/trace_processor/importers/proto/profiler_util.cc
index f7fe9af..175942f 100644
--- a/src/trace_processor/importers/proto/profiler_util.cc
+++ b/src/trace_processor/importers/proto/profiler_util.cc
@@ -17,6 +17,7 @@
#include "src/trace_processor/importers/proto/profiler_util.h"
#include "perfetto/ext/base/optional.h"
+#include "perfetto/ext/base/string_utils.h"
#include "src/trace_processor/storage/trace_storage.h"
namespace perfetto {
@@ -144,13 +145,13 @@
protos::pbzero::ObfuscatedMember::Decoder& member) {
std::string member_deobfuscated_name =
member.deobfuscated_name().ToStdString();
- if (member_deobfuscated_name.find('.') == std::string::npos) {
+ if (base::Contains(member_deobfuscated_name, '.')) {
+ // Fully qualified name.
+ return member_deobfuscated_name;
+ } else {
// Name relative to class.
return cls.deobfuscated_name().ToStdString() + "." +
member_deobfuscated_name;
- } else {
- // Fully qualified name.
- return member_deobfuscated_name;
}
}
diff --git a/src/trace_processor/importers/proto/proto_trace_reader.cc b/src/trace_processor/importers/proto/proto_trace_reader.cc
index 16e7908..6c80e87 100644
--- a/src/trace_processor/importers/proto/proto_trace_reader.cc
+++ b/src/trace_processor/importers/proto/proto_trace_reader.cc
@@ -195,16 +195,10 @@
context_->clock_tracker->ToTraceTime(converted_clock_id, timestamp);
if (!trace_ts.has_value()) {
// ToTraceTime() will increase the |clock_sync_failure| stat on failure.
- static const char seq_extra_err[] =
- " Because the clock id is sequence-scoped, the ClockSnapshot must "
- "be emitted on the same TraceWriter sequence of the packet that "
- "refers to that clock id.";
- return util::ErrStatus(
- "Failed to convert TracePacket's timestamp from clock_id=%" PRIu32
- " seq_id=%" PRIu32
- ". This is usually due to the lack of a prior ClockSnapshot "
- "proto.%s",
- timestamp_clock_id, seq_id, is_seq_scoped ? seq_extra_err : "");
+ // We don't return an error here as it will cause the trace to stop
+ // parsing. Instead, we rely on the stat increment in ToTraceTime() to
+ // inform the user about the error.
+ return util::OkStatus();
}
timestamp = trace_ts.value();
}
diff --git a/src/trace_processor/metrics/android/android_sysui_cuj.sql b/src/trace_processor/metrics/android/android_sysui_cuj.sql
index 67f8ccf..2a0bba1 100644
--- a/src/trace_processor/metrics/android/android_sysui_cuj.sql
+++ b/src/trace_processor/metrics/android/android_sysui_cuj.sql
@@ -277,7 +277,7 @@
WHERE remainder <> "")
SELECT frame_number, jank_cause
FROM split_jank_type
- WHERE jank_cause NOT IN ('', 'App Deadline Missed', 'None')
+ WHERE jank_cause NOT IN ('', 'App Deadline Missed', 'None', 'Buffer Stuffing')
ORDER BY frame_number ASC;
DROP TABLE IF EXISTS android_sysui_cuj_missed_frames_hwui_times;
diff --git a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
index 1b2395a..f54fa96 100644
--- a/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
+++ b/src/trace_processor/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index d793059..e93c0b4 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -203,7 +203,7 @@
PERFETTO_TP_TABLE(PERFETTO_TP_PERF_SAMPLE_DEF);
// Symbolization data for a frame. Rows with the same symbol_set_id describe
-// one callframe, with the most-inlined symbol having id == symbol_set_id.
+// one frame, with the bottom-most inlined frame having id == symbol_set_id.
//
// For instance, if the function foo has an inlined call to the function bar,
// which has an inlined call to baz, the stack_profile_symbol table would look
@@ -212,9 +212,9 @@
// ```
// |id|symbol_set_id|name |source_file|line_number|
// |--|-------------|-------------|-----------|-----------|
-// |1 | 1 |baz |foo.cc | 36 |
+// |1 | 1 |foo |foo.cc | 60 |
// |2 | 1 |bar |foo.cc | 30 |
-// |3 | 1 |foo |foo.cc | 60 |
+// |3 | 1 |baz |foo.cc | 36 |
// ```
// @param name name of the function.
// @param source_file name of the source file containing the function.
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index f7c656c..073c5f5 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -265,7 +265,7 @@
"SELECT name FROM sqlite_master WHERE type='table'");
for (uint32_t rows = 0; tables_it.Next(); rows++) {
std::string table_name = tables_it.Get(0).string_value;
- PERFETTO_CHECK(table_name.find('\'') == std::string::npos);
+ PERFETTO_CHECK(base::Contains(table_name, '\''));
std::string export_sql = "CREATE TABLE perfetto_export." + table_name +
" AS SELECT * FROM " + table_name;
diff --git a/src/traced/probes/ftrace/event_info.cc b/src/traced/probes/ftrace/event_info.cc
index 0bd85ba..e660f63 100644
--- a/src/traced/probes/ftrace/event_info.cc
+++ b/src/traced/probes/ftrace/event_info.cc
@@ -1085,6 +1085,25 @@
kUnsetFtraceId,
346,
kUnsetSize},
+ {"cpuhp_pause",
+ "cpuhp",
+ {
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "active_cpus", 1, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "cpus", 2, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "pause", 3, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
+ "time", 4, ProtoSchemaType::kUint32,
+ TranslationStrategy::kInvalidTranslationStrategy},
+ },
+ kUnsetFtraceId,
+ 352,
+ kUnsetSize},
{"dma_heap_stat",
"dmabuf_heap",
{
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index fa789ae..24b84b5 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -269,6 +269,7 @@
events.insert(GroupAndName("power", "suspend_resume"));
events.insert(GroupAndName("cpuhp", "cpuhp_enter"));
events.insert(GroupAndName("cpuhp", "cpuhp_exit"));
+ events.insert(GroupAndName("cpuhp", "cpuhp_pause"));
AddEventGroup(table, "msm_bus", &events);
events.insert(GroupAndName("msm_bus", "bus_update_request_end"));
events.insert(GroupAndName("msm_bus", "bus_update_request"));
diff --git a/src/traced/probes/ftrace/test/data/synthetic/available_events b/src/traced/probes/ftrace/test/data/synthetic/available_events
index b20b698..2ee225a 100644
--- a/src/traced/probes/ftrace/test/data/synthetic/available_events
+++ b/src/traced/probes/ftrace/test/data/synthetic/available_events
@@ -11,3 +11,4 @@
dpu:tracing_mark_write
g2d:tracing_mark_write
power:suspend_resume
+cpuhp:cpuhp_pause
diff --git a/src/traced/probes/ftrace/test/data/synthetic/events/cpuhp/cpuhp_pause/format b/src/traced/probes/ftrace/test/data/synthetic/events/cpuhp/cpuhp_pause/format
new file mode 100644
index 0000000..e0ff5e8
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/synthetic/events/cpuhp/cpuhp_pause/format
@@ -0,0 +1,14 @@
+name: cpuhp_pause
+ID: 68
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:unsigned int cpus; offset:8; size:4; signed:0;
+ field:unsigned int active_cpus; offset:12; size:4; signed:0;
+ field:unsigned int time; offset:16; size:4; signed:0;
+ field:unsigned char pause; offset:20; size:1; signed:0;
+
+print fmt: "req_cpus=0x%x act_cpus=0x%x time=%u us paused=%d", REC->cpus, REC->active_cpus, REC->time, REC->pause
diff --git a/src/traced/probes/packages_list/packages_list_parser.cc b/src/traced/probes/packages_list/packages_list_parser.cc
index bcbccaa..e00e296 100644
--- a/src/traced/probes/packages_list/packages_list_parser.cc
+++ b/src/traced/probes/packages_list/packages_list_parser.cc
@@ -50,12 +50,13 @@
}
case 6: {
char* end;
- long long profilable_from_shell = strtoll(ss.cur_token(), &end, 10);
+ long long profilable_level = strtoll(ss.cur_token(), &end, 10);
if ((*end != '\0' && *end != '\n') || *ss.cur_token() == '\0') {
PERFETTO_ELOG("Failed to parse packages.list profilable_from_shell.");
return false;
}
- package->profileable_from_shell = profilable_from_shell != 0;
+ package->profileable_from_shell = profilable_level != 0;
+ package->profileable = profilable_level == 2;
break;
}
case 7: {
diff --git a/src/traced/probes/packages_list/packages_list_parser.h b/src/traced/probes/packages_list/packages_list_parser.h
index 3deb3c5..ee35ddd 100644
--- a/src/traced/probes/packages_list/packages_list_parser.h
+++ b/src/traced/probes/packages_list/packages_list_parser.h
@@ -26,6 +26,7 @@
std::string name;
uint64_t uid = 0;
bool debuggable = false;
+ bool profileable = false;
bool profileable_from_shell = false;
int64_t version_code = 0;
};
diff --git a/src/tracing/traced_value_unittest.cc b/src/tracing/traced_value_unittest.cc
index 1aa050b..66c86db 100644
--- a/src/tracing/traced_value_unittest.cc
+++ b/src/tracing/traced_value_unittest.cc
@@ -91,7 +91,7 @@
ASSERT_TYPE_SUPPORTED(const int*);
ASSERT_TYPE_SUPPORTED(void*);
ASSERT_TYPE_SUPPORTED(const void*);
-ASSERT_TYPE_SUPPORTED(nullptr_t);
+ASSERT_TYPE_SUPPORTED(std::nullptr_t);
ASSERT_TYPE_NOT_SUPPORTED(NonSupportedType*);
ASSERT_TYPE_NOT_SUPPORTED(const NonSupportedType*);
@@ -250,7 +250,7 @@
namespace {
-class HasConvertorMember {
+class HasWriteIntoTracedValueConvertorMember {
public:
void WriteIntoTracedValue(TracedValue context) const {
auto dict = std::move(context).WriteDictionary();
@@ -259,7 +259,17 @@
}
};
-class HasExternalConvertor {};
+class HasWriteIntoTraceConvertorMember {
+ public:
+ void WriteIntoTrace(TracedValue context) const {
+ auto dict = std::move(context).WriteDictionary();
+ dict.Add("int", 42);
+ dict.Add("bool", false);
+ }
+};
+
+class HasExternalWriteIntoTraceConvertor {};
+class HasExternalWriteIntoTracedValueConvertor {};
class HasAllConversionMethods {
public:
@@ -302,9 +312,18 @@
} // namespace
template <>
-struct TraceFormatTraits<HasExternalConvertor> {
- static void WriteIntoTracedValue(TracedValue context,
- const HasExternalConvertor&) {
+struct TraceFormatTraits<HasExternalWriteIntoTraceConvertor> {
+ static void WriteIntoTrace(TracedValue context,
+ const HasExternalWriteIntoTraceConvertor&) {
+ std::move(context).WriteString("TraceFormatTraits::WriteIntoTrace");
+ }
+};
+
+template <>
+struct TraceFormatTraits<HasExternalWriteIntoTracedValueConvertor> {
+ static void WriteIntoTracedValue(
+ TracedValue context,
+ const HasExternalWriteIntoTracedValueConvertor&) {
std::move(context).WriteString("TraceFormatTraits::WriteIntoTracedValue");
}
};
@@ -326,8 +345,10 @@
return internal::DebugAnnotationToString(message.SerializeAsString());
}
-ASSERT_TYPE_SUPPORTED(HasConvertorMember);
-ASSERT_TYPE_SUPPORTED(HasExternalConvertor);
+ASSERT_TYPE_SUPPORTED(HasWriteIntoTraceConvertorMember);
+ASSERT_TYPE_SUPPORTED(HasWriteIntoTracedValueConvertorMember);
+ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTraceConvertor);
+ASSERT_TYPE_SUPPORTED(HasExternalWriteIntoTracedValueConvertor);
ASSERT_TYPE_SUPPORTED(HasAllConversionMethods);
ASSERT_TYPE_SUPPORTED(HasConstWriteMember);
@@ -364,19 +385,27 @@
ASSERT_TYPE_SUPPORTED(std::unique_ptr<const HasConstAndNonConstWriteMember*>);
TEST(TracedValueTest, UserDefinedConvertors) {
- HasConvertorMember value1;
+ HasWriteIntoTraceConvertorMember value1;
EXPECT_EQ(TracedValueToString(value1), "{int:42,bool:false}");
EXPECT_EQ(TracedValueToString(&value1), "{int:42,bool:false}");
- HasExternalConvertor value2;
- EXPECT_EQ(TracedValueToString(value2),
+ HasWriteIntoTracedValueConvertorMember value2;
+ EXPECT_EQ(TracedValueToString(value2), "{int:42,bool:false}");
+ EXPECT_EQ(TracedValueToString(&value2), "{int:42,bool:false}");
+
+ HasExternalWriteIntoTracedValueConvertor value3;
+ EXPECT_EQ(TracedValueToString(value3),
"TraceFormatTraits::WriteIntoTracedValue");
- EXPECT_EQ(TracedValueToString(&value2),
+ EXPECT_EQ(TracedValueToString(&value3),
"TraceFormatTraits::WriteIntoTracedValue");
- HasAllConversionMethods value3;
- EXPECT_EQ(TracedValueToString(value3), "T::WriteIntoTracedValue");
- EXPECT_EQ(TracedValueToString(&value3), "T::WriteIntoTracedValue");
+ HasExternalWriteIntoTraceConvertor value4;
+ EXPECT_EQ(TracedValueToString(value4), "TraceFormatTraits::WriteIntoTrace");
+ EXPECT_EQ(TracedValueToString(&value4), "TraceFormatTraits::WriteIntoTrace");
+
+ HasAllConversionMethods value5;
+ EXPECT_EQ(TracedValueToString(value5), "T::WriteIntoTracedValue");
+ EXPECT_EQ(TracedValueToString(&value5), "T::WriteIntoTracedValue");
}
TEST(TracedValueTest, WriteAsLambda) {
diff --git a/test/trace_processor/graphics/android_sysui_cuj.out b/test/trace_processor/graphics/android_sysui_cuj.out
index cf6c74e..1cdea90 100644
--- a/test/trace_processor/graphics/android_sysui_cuj.out
+++ b/test/trace_processor/graphics/android_sysui_cuj.out
@@ -63,7 +63,6 @@
number: 8
ts: 400000000
dur: 10000000
- jank_cause: "Buffer Stuffing"
vsync: 120
}
}
diff --git a/test/trace_processor/graphics/android_sysui_cuj_event.out b/test/trace_processor/graphics/android_sysui_cuj_event.out
index e36ea72..4519815 100644
--- a/test/trace_processor/graphics/android_sysui_cuj_event.out
+++ b/test/trace_processor/graphics/android_sysui_cuj_event.out
@@ -6,4 +6,3 @@
"slice","SHADE_ROW_EXPAND - jank cause",70000000,10000000,"RenderThread - scheduler"
"slice","SHADE_ROW_EXPAND - jank cause",100000000,15000000,"GPU completion - long completion time"
"slice","SHADE_ROW_EXPAND - jank cause",200000000,15000000,"SurfaceFlinger GPU Deadline Missed,SurfaceFlinger Scheduling"
-"slice","SHADE_ROW_EXPAND - jank cause",400000000,15000000,"Buffer Stuffing"
diff --git a/tools/ftrace_proto_gen/event_list b/tools/ftrace_proto_gen/event_list
index 45727f0..1351543 100644
--- a/tools/ftrace_proto_gen/event_list
+++ b/tools/ftrace_proto_gen/event_list
@@ -346,3 +346,4 @@
g2d/tracing_mark_write
mali/tracing_mark_write
dmabuf_heap/dma_heap_stat
+cpuhp/cpuhp_pause
diff --git a/tools/gen_bazel b/tools/gen_bazel
index 11719bb..ca38248 100755
--- a/tools/gen_bazel
+++ b/tools/gen_bazel
@@ -318,13 +318,13 @@
plugin_label.comment = target.name
plugin_label.deps += [':' + sources_label_name]
- # When using the cppgen plugin we need to pass down also the transitive deps.
+ # When using the plugins we need to pass down also the transitive deps.
# For instance consider foo.proto including common.proto. The generated
# foo.cc will #include "common.gen.h". Hence the generated cc_protocpp_library
# rule need to pass down the dependency on the target that generates
- # common.gen.{cc,h}. This is not needed for protozero because protozero
- # headers are fully hermetic deps-wise and use only on forward declarations.
- if target.proto_deps and target.proto_plugin in ('cppgen', 'ipc'):
+ # common.gen.{cc,h}.
+ if target.proto_deps and target.proto_plugin in (
+ 'cppgen', 'ipc', 'protozero'):
plugin_label.deps += [
':' + get_bazel_label_name(x) for x in target.proto_deps
]
diff --git a/tools/heap_profile b/tools/heap_profile
index 41b386d..6e42672 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (C) 2017 The Android Open Source Project
#
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 560c1ba..40a1501 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -55,7 +55,7 @@
]
# Dependencies required to build code on the host or when targeting desktop OS.
-BUILD_DEPS_HOST = [
+BUILD_DEPS_TOOLCHAIN_HOST = [
# GN. From https://chrome-infra-packages.appspot.com/dl/gn/gn/.
# git_revision:83dad00afb232d7235dd70dff1ee90292d72a01e .
Dependency(
@@ -117,6 +117,21 @@
'6f8af488be74ed8787d04e107080d05330587a4198ba047bd5b7f5b0c3150d61',
'windows', 'x64'),
+ # Keep the revision in sync with Chrome's PACKAGE_VERSION in
+ # tools/clang/scripts/update.py.
+ Dependency(
+ 'buildtools/linux64/clang.tgz',
+ 'https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/clang-llvmorg-12-init-5035-gd0abc757-3.tgz',
+ 'b0c3015209b6d624844ad230064eb5c9b4429a2eafd4854981e73217c563d93d',
+ 'linux', 'x64'),
+ Dependency(
+ 'buildtools/win/clang.tgz',
+ 'https://commondatastorage.googleapis.com/chromium-browser-clang/Win/clang-llvmorg-12-init-5035-gd0abc757-3.tgz',
+ 'b2854d871a466e3a060469b5edb24ca355ef64576d38778f64acbd3c6d7cf530',
+ 'windows', 'x64'),
+]
+
+BUILD_DEPS_HOST = [
# Keep in sync with Android's //external/googletest/README.version.
Dependency(
'buildtools/googletest',
@@ -145,19 +160,6 @@
'https://chromium.googlesource.com/external/github.com/llvm/llvm-project/libunwind.git',
'd999d54f4bca789543a2eb6c995af2d9b5a1f3ed', 'all', 'all'),
- # Keep the revision in sync with Chrome's PACKAGE_VERSION in
- # tools/clang/scripts/update.py.
- Dependency(
- 'buildtools/linux64/clang.tgz',
- 'https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/clang-llvmorg-12-init-5035-gd0abc757-3.tgz',
- 'b0c3015209b6d624844ad230064eb5c9b4429a2eafd4854981e73217c563d93d',
- 'linux', 'x64'),
- Dependency(
- 'buildtools/win/clang.tgz',
- 'https://commondatastorage.googleapis.com/chromium-browser-clang/Win/clang-llvmorg-12-init-5035-gd0abc757-3.tgz',
- 'b2854d871a466e3a060469b5edb24ca355ef64576d38778f64acbd3c6d7cf530',
- 'windows', 'x64'),
-
# Keep in sync with chromium DEPS.
Dependency(
'buildtools/libfuzzer',
@@ -208,7 +210,7 @@
Dependency(
'buildtools/android-unwinding',
'https://android.googlesource.com/platform/system/unwinding.git',
- '5f15cdbdb71db0eb6512e9432a63b8c4075a6c00', 'all', 'all'),
+ 'b296bb6fcaa7f59e0ed57bb7a4238ee0f9bfb5bf', 'all', 'all'),
Dependency('buildtools/android-logging',
'https://android.googlesource.com/platform/system/logging.git',
'7b36b566c9113fc703d68f76e8f40c0c2432481c', 'all', 'all'),
@@ -476,11 +478,15 @@
parser.add_argument('--check-only')
parser.add_argument('--filter', default='')
parser.add_argument('--verify', help='Check all URLs', action='store_true')
+ parser.add_argument('--no-toolchain', help='Do not download toolchain',
+ action='store_true')
args = parser.parse_args()
if args.verify:
CheckHashes()
return 0
deps = BUILD_DEPS_HOST
+ if not args.no_toolchain:
+ deps += BUILD_DEPS_TOOLCHAIN_HOST
if args.android:
deps += BUILD_DEPS_ANDROID + TEST_DEPS_ANDROID
if args.ui:
diff --git a/tools/java_heap_dump b/tools/java_heap_dump
index ced597e..03abb01 100755
--- a/tools/java_heap_dump
+++ b/tools/java_heap_dump
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# Copyright (C) 2020 The Android Open Source Project
#
@@ -168,10 +168,11 @@
print(cfg)
return 0
- user = subprocess.check_output(['adb', 'shell', 'whoami']).strip()
+ user = subprocess.check_output(
+ ['adb', 'shell', 'whoami']).strip().decode('utf8')
perfetto_pid = subprocess.check_output(
['adb', 'exec-out',
- PERFETTO_CMD.format(cfg=cfg, user=user)]).strip()
+ PERFETTO_CMD.format(cfg=cfg, user=user)]).strip().decode('utf8')
try:
int(perfetto_pid.strip())
except ValueError:
diff --git a/tools/trace_processor b/tools/trace_processor
index 5b84f0c..d15dd62 100755
--- a/tools/trace_processor
+++ b/tools/trace_processor
@@ -21,7 +21,7 @@
# cat ./trace_processor | python -
BASH_FALLBACK = """ "
-exec python - "$@" <<'#'EOF
+exec python3 - "$@" <<'#'EOF
#"""
import hashlib
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 1ef6484..c1674d8 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -71,7 +71,6 @@
"../../protos/third_party/pprof:zero",
"../../src/profiling/symbolizer",
"../../src/profiling/symbolizer:symbolize_database",
- "../../src/trace_processor/containers:containers",
]
sources = [ "pprof_builder.cc" ]
}
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index e4a9f1d..8384b7a 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -32,6 +32,7 @@
#include "tools/trace_to_text/trace_to_systrace.h"
#include "tools/trace_to_text/trace_to_text.h"
+
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <unistd.h>
#endif
@@ -42,19 +43,17 @@
int Usage(const char* argv0) {
fprintf(stderr,
- "Usage: %s MODE [OPTIONS] [input file] [output file]\n"
- "modes:\n"
- " systrace|json|ctrace|text|profile|hprof|symbolize|deobfuscate\n"
- "options:\n"
- " [--truncate start|end]\n"
- " [--full-sort]\n"
- "\"profile\" mode options:\n"
- " [--perf] generate a perf profile instead of a heap profile\n"
- " [--no-annotations] do not suffix frame names with derived "
- "annotations\n"
- " [--timestamps TIMESTAMP1,TIMESTAMP2,...] generate profiles "
- "only for these *specific* timestamps\n"
- " [--pid PID] generate profiles only for this process id\n",
+ "Usage: %s systrace|json|ctrace|text|profile [--pid PID] "
+ "[--timestamps TIMESTAMP1,TIMESTAMP2,...] "
+ "[--truncate start|end] "
+ "[--full-sort] "
+ "[trace.pb] "
+ "[trace.txt]\n"
+ "\nProfile mode only:\n"
+ "\t--perf generate a perf profile\n"
+ "\t--timestamps TIMESTAMP1,TIMESTAMP2,... generate profiles "
+ "only for these timestamps\n"
+ "\t--pid PID generate profiles only for this process id\n",
argv0);
return 1;
}
@@ -76,7 +75,6 @@
std::vector<uint64_t> timestamps;
bool full_sort = false;
bool perf_profile = false;
- bool profile_no_annotations = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
printf("%s\n", base::GetVersionString());
@@ -105,8 +103,6 @@
}
} else if (strcmp(argv[i], "--perf") == 0) {
perf_profile = true;
- } else if (strcmp(argv[i], "--no-annotations") == 0) {
- profile_no_annotations = true;
} else if (strcmp(argv[i], "--full-sort") == 0) {
full_sort = true;
} else {
@@ -191,11 +187,10 @@
return TraceToText(input_stream, output_stream);
if (format == "profile") {
- return perf_profile
- ? TraceToPerfProfile(input_stream, output_stream, pid,
- timestamps, !profile_no_annotations)
- : TraceToHeapProfile(input_stream, output_stream, pid,
- timestamps, !profile_no_annotations);
+ return perf_profile ? TraceToPerfProfile(input_stream, output_stream, pid,
+ timestamps)
+ : TraceToHeapProfile(input_stream, output_stream, pid,
+ timestamps);
}
if (format == "hprof")
diff --git a/tools/trace_to_text/pprof_builder.cc b/tools/trace_to_text/pprof_builder.cc
index 588c438..fdb8717 100644
--- a/tools/trace_to_text/pprof_builder.cc
+++ b/tools/trace_to_text/pprof_builder.cc
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include "perfetto/base/build_config.h"
-
#include "perfetto/profiling/pprof_builder.h"
+#include "perfetto/base/build_config.h"
+
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <cxxabi.h>
#endif
@@ -27,120 +27,29 @@
#include <algorithm>
#include <map>
#include <set>
-#include <unordered_map>
#include <utility>
#include <vector>
#include "tools/trace_to_text/utils.h"
#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/hash.h"
+#include "perfetto/base/time.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/protozero/packed_repeated_fields.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "perfetto/trace_processor/trace_processor.h"
+
#include "src/profiling/symbolizer/symbolize_database.h"
#include "src/profiling/symbolizer/symbolizer.h"
-#include "src/trace_processor/containers/string_pool.h"
#include "protos/perfetto/trace/trace.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
#include "protos/third_party/pprof/profile.pbzero.h"
-// Quick hint on navigating the file:
-// Conversions for both perf and heap profiles start with |TraceToPprof|.
-// Non-shared logic is in the |heap_profile| and |perf_profile| namespaces.
-//
-// To build one or more profiles, first the callstack information is queried
-// from the SQL tables, and converted into an in-memory representation by
-// |PreprocessLocations|. Then an instance of |GProfileBuilder| is used to
-// accumulate samples for that profile, and emit all additional information as a
-// serialized proto. Only the entities referenced by that particular
-// |GProfileBuilder| instance are emitted.
-//
-// See protos/third_party/pprof/profile.proto for the meaning of terms like
-// function/location/line.
-
-namespace {
-using StringId = ::perfetto::trace_processor::StringPool::Id;
-
-// In-memory representation of a Profile.Function.
-struct Function {
- StringId name_id = StringId::Null();
- StringId system_name_id = StringId::Null();
- StringId filename_id = StringId::Null();
-
- Function(StringId n, StringId s, StringId f)
- : name_id(n), system_name_id(s), filename_id(f) {}
-
- bool operator==(const Function& other) const {
- return std::tie(name_id, system_name_id, filename_id) ==
- std::tie(other.name_id, other.system_name_id, other.filename_id);
- }
-};
-
-// In-memory representation of a Profile.Line.
-struct Line {
- int64_t function_id = 0; // LocationTracker's interned Function id
- int64_t line_no = 0;
-
- Line(int64_t func, int64_t line) : function_id(func), line_no(line) {}
-
- bool operator==(const Line& other) const {
- return function_id == other.function_id && line_no == other.line_no;
- }
-};
-
-// In-memory representation of a Profile.Location.
-struct Location {
- int64_t mapping_id = 0; // sqlite row id
- // Common case: location references a single function.
- int64_t single_function_id = 0; // interned Function id
- // Alternatively: multiple inlined functions, recovered via offline
- // symbolisation. Leaf-first ordering.
- std::vector<Line> inlined_functions;
-
- Location(int64_t map, int64_t func, std::vector<Line> inlines)
- : mapping_id(map),
- single_function_id(func),
- inlined_functions(std::move(inlines)) {}
-
- bool operator==(const Location& other) const {
- return std::tie(mapping_id, single_function_id, inlined_functions) ==
- std::tie(other.mapping_id, other.single_function_id,
- other.inlined_functions);
- }
-};
-} // namespace
-
-template <>
-struct std::hash<Function> {
- size_t operator()(const Function& loc) const {
- perfetto::base::Hash hasher;
- hasher.Update(loc.name_id.raw_id());
- hasher.Update(loc.system_name_id.raw_id());
- hasher.Update(loc.filename_id.raw_id());
- return static_cast<size_t>(hasher.digest());
- }
-};
-
-template <>
-struct std::hash<Location> {
- size_t operator()(const Location& loc) const {
- perfetto::base::Hash hasher;
- hasher.Update(loc.mapping_id);
- hasher.Update(loc.single_function_id);
- for (auto line : loc.inlined_functions) {
- hasher.Update(line.function_id);
- hasher.Update(line.line_no);
- }
- return static_cast<size_t>(hasher.digest());
- }
-};
-
namespace perfetto {
namespace trace_to_text {
+
namespace {
using ::perfetto::trace_processor::Iterator;
@@ -174,6 +83,84 @@
return ret;
}
+// Return map from callsite_id to list of frame_ids that make up the callstack.
+std::vector<std::vector<int64_t>> GetCallsiteToFrames(
+ trace_processor::TraceProcessor* tp) {
+ Iterator count_it =
+ tp->ExecuteQuery("select count(*) from stack_profile_callsite;");
+ if (!count_it.Next()) {
+ PERFETTO_DFATAL_OR_ELOG("Failed to get number of callsites: %s",
+ count_it.Status().message().c_str());
+ return {};
+ }
+ int64_t count = count_it.Get(0).AsLong();
+
+ Iterator it = tp->ExecuteQuery(
+ "select id, parent_id, frame_id from stack_profile_callsite order by "
+ "depth;");
+ std::vector<std::vector<int64_t>> result(static_cast<size_t>(count));
+ while (it.Next()) {
+ int64_t id = it.Get(0).AsLong();
+ int64_t frame_id = it.Get(2).AsLong();
+ std::vector<int64_t>& path = result[static_cast<size_t>(id)];
+ path.push_back(frame_id);
+
+ auto parent_id_value = it.Get(1);
+ if (!parent_id_value.is_null()) {
+ const std::vector<int64_t>& parent_path =
+ result[static_cast<size_t>(parent_id_value.AsLong())];
+ path.insert(path.end(), parent_path.begin(), parent_path.end());
+ }
+ }
+
+ if (!it.Status().ok()) {
+ PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+ it.Status().message().c_str());
+ return {};
+ }
+ return result;
+}
+
+base::Optional<int64_t> GetMaxSymbolId(trace_processor::TraceProcessor* tp) {
+ auto max_symbol_id_it =
+ tp->ExecuteQuery("select max(id) from stack_profile_symbol");
+ if (!max_symbol_id_it.Next()) {
+ PERFETTO_DFATAL_OR_ELOG("Failed to get max symbol set id: %s",
+ max_symbol_id_it.Status().message().c_str());
+ return base::nullopt;
+ }
+ auto value = max_symbol_id_it.Get(0);
+ if (value.is_null())
+ return base::nullopt;
+ return base::make_optional(value.AsLong());
+}
+
+struct Line {
+ int64_t symbol_id;
+ uint32_t line_number;
+};
+
+std::map<int64_t, std::vector<Line>> GetSymbolSetIdToLines(
+ trace_processor::TraceProcessor* tp) {
+ std::map<int64_t, std::vector<Line>> result;
+ Iterator it = tp->ExecuteQuery(
+ "SELECT symbol_set_id, id, line_number FROM stack_profile_symbol;");
+ while (it.Next()) {
+ int64_t symbol_set_id = it.Get(0).AsLong();
+ int64_t id = it.Get(1).AsLong();
+ int64_t line_number = it.Get(2).AsLong();
+ result[symbol_set_id].emplace_back(
+ Line{id, static_cast<uint32_t>(line_number)});
+ }
+
+ if (!it.Status().ok()) {
+ PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+ it.Status().message().c_str());
+ return {};
+ }
+ return result;
+}
+
base::Optional<int64_t> GetStatsEntry(
trace_processor::TraceProcessor* tp,
const std::string& name,
@@ -195,373 +182,73 @@
return base::make_optional(it.Get(0).AsLong());
}
-// Interns Locations, Lines, and Functions. Interning is done by the entity's
-// contents, and has no relation to the row ids in the SQL tables.
-// Contains all data for the trace, so can be reused when emitting multiple
-// profiles.
-//
-// TODO(rsavitski): consider moving mappings into here as well. For now, they're
-// still emitted in a single scan during profile building. Mappings should be
-// unique-enough already in the SQL tables, with only incremental state clearing
-// duplicating entries.
-class LocationTracker {
- public:
- int64_t InternLocation(Location loc) {
- auto it = locations_.find(loc);
- if (it == locations_.end()) {
- bool inserted = false;
- std::tie(it, inserted) = locations_.emplace(
- std::move(loc), static_cast<int64_t>(locations_.size()));
- PERFETTO_DCHECK(inserted);
- }
- return it->second;
- }
-
- int64_t InternFunction(Function func) {
- auto it = functions_.find(func);
- if (it == functions_.end()) {
- bool inserted = false;
- std::tie(it, inserted) =
- functions_.emplace(func, static_cast<int64_t>(functions_.size()));
- PERFETTO_DCHECK(inserted);
- }
- return it->second;
- }
-
- bool IsCallsiteProcessed(int64_t callstack_id) const {
- return callsite_to_locations_.find(callstack_id) !=
- callsite_to_locations_.end();
- }
-
- void MaybeSetCallsiteLocations(int64_t callstack_id,
- const std::vector<int64_t>& locs) {
- // nop if already set
- callsite_to_locations_.emplace(callstack_id, locs);
- }
-
- const std::vector<int64_t>& LocationsForCallstack(
- int64_t callstack_id) const {
- auto it = callsite_to_locations_.find(callstack_id);
- PERFETTO_CHECK(callstack_id >= 0 && it != callsite_to_locations_.end());
- return it->second;
- }
-
- const std::unordered_map<Location, int64_t>& AllLocations() const {
- return locations_;
- }
- const std::unordered_map<Function, int64_t>& AllFunctions() const {
- return functions_;
- }
-
- private:
- // Root-first location ids for a given callsite id.
- std::unordered_map<int64_t, std::vector<int64_t>> callsite_to_locations_;
- std::unordered_map<Location, int64_t> locations_;
- std::unordered_map<Function, int64_t> functions_;
-};
-
-struct PreprocessedInline {
- StringId system_name_id = StringId::Null();
- StringId filename_id = StringId::Null();
- int64_t line_no = 0;
-
- PreprocessedInline(StringId s, StringId f, int64_t line)
- : system_name_id(s), filename_id(f), line_no(line) {}
-};
-
-std::unordered_map<int64_t, std::vector<PreprocessedInline>>
-PreprocessInliningInfo(trace_processor::TraceProcessor* tp,
- trace_processor::StringPool* interner) {
- std::unordered_map<int64_t, std::vector<PreprocessedInline>> inlines;
-
- // Most-inlined function (leaf) has the lowest id within a symbol set. Query
- // such that the per-set line vectors are built up leaf-first.
- Iterator it = tp->ExecuteQuery(
- "select symbol_set_id, name, source_file, line_number from "
- "stack_profile_symbol order by symbol_set_id asc, id asc;");
- while (it.Next()) {
- int64_t symbol_set_id = it.Get(0).AsLong();
- auto func_sysname = it.Get(1).is_null() ? "" : it.Get(1).AsString();
- auto filename = it.Get(2).is_null() ? "" : it.Get(2).AsString();
- int64_t line_no = it.Get(3).AsLong();
-
- inlines[symbol_set_id].emplace_back(interner->InternString(func_sysname),
- interner->InternString(filename),
- line_no);
- }
-
- if (!it.Status().ok()) {
- PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
- it.Status().message().c_str());
- return {};
- }
- return inlines;
-}
-
-// Extracts and interns the unique frames and locations (as defined by the proto
-// format) from the callstack SQL tables.
-//
-// Approach:
-// * for each callstack (callsite ids of the leaves):
-// * use experimental_annotated_callstack to build the full list of
-// constituent frames
-// * for each frame (root to leaf):
-// * intern the location and function(s)
-// * remember the mapping from callsite_id to the callstack so far (from
-// the root and including the frame being considered)
-//
-// Optionally mixes in the annotations as a frame name suffix (since there's no
-// good way to attach extra info to locations in the proto format). This relies
-// on the annotations (produced by experimental_annotated_callstack) to be
-// stable for a given callsite (equivalently: dependent only on their parents).
-LocationTracker PreprocessLocations(trace_processor::TraceProcessor* tp,
- trace_processor::StringPool* interner,
- bool annotate_frames) {
- LocationTracker tracker;
-
- // Keyed by symbol_set_id, discarded once this function converts the inlines
- // into Line and Function entries.
- std::unordered_map<int64_t, std::vector<PreprocessedInline>> inlining_info =
- PreprocessInliningInfo(tp, interner);
-
- // Higher callsite ids most likely correspond to the deepest stacks, so we'll
- // fill more of the overall callsite->location map by visiting the callsited
- // in decreasing id order. Since processing a callstack also fills in the data
- // for all parent callsites.
- Iterator cid_it = tp->ExecuteQuery(
- "select id from stack_profile_callsite order by id desc;");
- while (cid_it.Next()) {
- int64_t query_cid = cid_it.Get(0).AsLong();
-
- // If the leaf has been processed, the rest of the stack is already known.
- if (tracker.IsCallsiteProcessed(query_cid))
- continue;
-
- std::string annotated_query =
- "select sp.id, sp.annotation, spf.mapping, "
- "ifnull(spf.deobfuscated_name, spf.name), spf.symbol_set_id from "
- "experimental_annotated_callstack(" +
- std::to_string(query_cid) +
- ") sp join stack_profile_frame spf on (sp.frame_id == spf.id) "
- "order by depth asc";
- Iterator c_it = tp->ExecuteQuery(annotated_query);
-
- std::vector<int64_t> callstack_loc_ids;
- while (c_it.Next()) {
- int64_t cid = c_it.Get(0).AsLong();
- int64_t mapping_id = c_it.Get(2).AsLong();
- auto annotation = c_it.Get(1).is_null() ? "" : c_it.Get(1).AsString();
- auto func_sysname = c_it.Get(3).is_null() ? "" : c_it.Get(3).AsString();
- base::Optional<int64_t> symbol_set_id =
- c_it.Get(4).is_null() ? base::nullopt
- : base::make_optional(c_it.Get(4).AsLong());
-
- Location loc(mapping_id, /*single_function_id=*/-1, {});
-
- auto intern_function = [interner, &tracker, annotate_frames](
- StringId func_sysname_id, StringId filename_id,
- const std::string& anno) {
- std::string func_name = interner->Get(func_sysname_id).ToStdString();
- MaybeDemangle(&func_name);
- if (annotate_frames && !anno.empty() && !func_name.empty())
- func_name = func_name + " [" + anno + "]";
- StringId func_name_id =
- interner->InternString(base::StringView(func_name));
- Function func(func_name_id, func_sysname_id, filename_id);
- return tracker.InternFunction(func);
- };
-
- // Inlining information available
- if (symbol_set_id.has_value()) {
- auto it = inlining_info.find(*symbol_set_id);
- if (it == inlining_info.end()) {
- PERFETTO_DFATAL_OR_ELOG(
- "Failed to find stack_profile_symbol entry for symbol_set_id "
- "%" PRIi64 "",
- *symbol_set_id);
- return {};
- }
-
- // N inlined functions
- for (const auto& line : it->second) {
- int64_t func_id = intern_function(line.system_name_id,
- line.filename_id, annotation);
-
- loc.inlined_functions.emplace_back(func_id, line.line_no);
- }
- } else {
- // Otherwise - single function
- int64_t func_id =
- intern_function(interner->InternString(func_sysname),
- /*filename_id=*/StringId::Null(), annotation);
- loc.single_function_id = func_id;
- }
-
- int64_t loc_id = tracker.InternLocation(std::move(loc));
-
- // Update the tracker with the locations so far (for example, at depth 2,
- // we'll have 3 root-most locations in |callstack_loc_ids|).
- callstack_loc_ids.push_back(loc_id);
- tracker.MaybeSetCallsiteLocations(cid, callstack_loc_ids);
- }
-
- if (!c_it.Status().ok()) {
- PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
- c_it.Status().message().c_str());
- return {};
- }
- }
-
- if (!cid_it.Status().ok()) {
- PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
- cid_it.Status().message().c_str());
- return {};
- }
-
- return tracker;
-}
-
-// Builds the |perftools.profiles.Profile| proto.
+// Helper for constructing |perftools.profiles.Profile| protos.
class GProfileBuilder {
public:
- GProfileBuilder(const LocationTracker& locations,
- trace_processor::StringPool* interner)
- : locations_(locations), interner_(interner) {
- // The pprof format requires the first entry in the string table to be the
+ GProfileBuilder(
+ const std::vector<std::vector<int64_t>>& callsite_to_frames,
+ const std::map<int64_t, std::vector<Line>>& symbol_set_id_to_lines,
+ int64_t max_symbol_id)
+ : callsite_to_frames_(callsite_to_frames),
+ symbol_set_id_to_lines_(symbol_set_id_to_lines),
+ max_symbol_id_(max_symbol_id) {
+ // The pprof format expects the first entry in the string table to be the
// empty string.
- int64_t empty_id = ToStringTableId(StringId::Null());
+ int64_t empty_id = Intern("");
PERFETTO_CHECK(empty_id == 0);
}
void WriteSampleTypes(
const std::vector<std::pair<std::string, std::string>>& sample_types) {
+ // The interner might eagerly append to the profile proto, prevent it from
+ // breaking up other messages by making a separate pass.
+ for (const auto& st : sample_types) {
+ Intern(st.first);
+ Intern(st.second);
+ }
for (const auto& st : sample_types) {
auto* sample_type = result_->add_sample_type();
- sample_type->set_type(
- ToStringTableId(interner_->InternString(base::StringView(st.first))));
- sample_type->set_unit(ToStringTableId(
- interner_->InternString(base::StringView(st.second))));
+ sample_type->set_type(Intern(st.first));
+ sample_type->set_unit(Intern(st.second));
}
}
bool AddSample(const protozero::PackedVarInt& values, int64_t callstack_id) {
- const auto& location_ids = locations_.LocationsForCallstack(callstack_id);
- if (location_ids.empty()) {
+ const auto& frames = FramesForCallstack(callstack_id);
+ if (frames.empty()) {
PERFETTO_DFATAL_OR_ELOG(
"Failed to find frames for callstack id %" PRIi64 "", callstack_id);
return false;
}
-
- // LocationTracker stores location lists root-first, but the pprof format
- // requires leaf-first.
- protozero::PackedVarInt packed_locs;
- for (auto it = location_ids.rbegin(); it != location_ids.rend(); ++it)
- packed_locs.Append(ToPprofId(*it));
+ protozero::PackedVarInt location_ids;
+ for (int64_t frame : frames)
+ location_ids.Append(ToPprofId(frame));
auto* gsample = result_->add_sample();
gsample->set_value(values);
- gsample->set_location_id(packed_locs);
+ gsample->set_location_id(location_ids);
- // Remember the locations s.t. we only serialize the referenced ones.
- seen_locations_.insert(location_ids.cbegin(), location_ids.cend());
+ // remember frames to be emitted
+ seen_frames_.insert(frames.cbegin(), frames.cend());
+
return true;
}
std::string CompleteProfile(trace_processor::TraceProcessor* tp) {
std::set<int64_t> seen_mappings;
- std::set<int64_t> seen_functions;
+ std::set<int64_t> seen_symbol_ids;
- if (!WriteLocations(&seen_mappings, &seen_functions))
- return {};
- if (!WriteFunctions(seen_functions))
+ // Write the location info for frames referenced by the added samples.
+ if (!WriteFrames(tp, &seen_mappings, &seen_symbol_ids))
return {};
if (!WriteMappings(tp, seen_mappings))
return {};
-
- WriteStringTable();
+ if (!WriteSymbols(tp, seen_symbol_ids))
+ return {};
return result_.SerializeAsString();
}
private:
- // Serializes the Profile.Location entries referenced by this profile.
- bool WriteLocations(std::set<int64_t>* seen_mappings,
- std::set<int64_t>* seen_functions) {
- const std::unordered_map<Location, int64_t>& locations =
- locations_.AllLocations();
-
- size_t written_locations = 0;
- for (const auto& loc_and_id : locations) {
- const auto& loc = loc_and_id.first;
- int64_t id = loc_and_id.second;
-
- if (seen_locations_.find(id) == seen_locations_.end())
- continue;
-
- written_locations += 1;
- seen_mappings->emplace(loc.mapping_id);
-
- auto* glocation = result_->add_location();
- glocation->set_id(ToPprofId(id));
- glocation->set_mapping_id(ToPprofId(loc.mapping_id));
-
- if (!loc.inlined_functions.empty()) {
- for (const auto& line : loc.inlined_functions) {
- seen_functions->insert(line.function_id);
-
- auto* gline = glocation->add_line();
- gline->set_function_id(ToPprofId(line.function_id));
- gline->set_line(line.line_no);
- }
- } else {
- seen_functions->insert(loc.single_function_id);
-
- glocation->add_line()->set_function_id(
- ToPprofId(loc.single_function_id));
- }
- }
-
- if (written_locations != seen_locations_.size()) {
- PERFETTO_DFATAL_OR_ELOG(
- "Found only %zu/%zu locations during serialization.",
- written_locations, seen_locations_.size());
- return false;
- }
- return true;
- }
-
- // Serializes the Profile.Function entries referenced by this profile.
- bool WriteFunctions(const std::set<int64_t>& seen_functions) {
- const std::unordered_map<Function, int64_t>& functions =
- locations_.AllFunctions();
-
- size_t written_functions = 0;
- for (const auto& func_and_id : functions) {
- const auto& func = func_and_id.first;
- int64_t id = func_and_id.second;
-
- if (seen_functions.find(id) == seen_functions.end())
- continue;
-
- written_functions += 1;
-
- auto* gfunction = result_->add_function();
- gfunction->set_id(ToPprofId(id));
- gfunction->set_name(ToStringTableId(func.name_id));
- gfunction->set_system_name(ToStringTableId(func.system_name_id));
- if (!func.filename_id.is_null())
- gfunction->set_filename(ToStringTableId(func.filename_id));
- }
-
- if (written_functions != seen_functions.size()) {
- PERFETTO_DFATAL_OR_ELOG(
- "Found only %zu/%zu functions during serialization.",
- written_functions, seen_functions.size());
- return false;
- }
- return true;
- }
-
- // Serializes the Profile.Mapping entries referenced by this profile.
bool WriteMappings(trace_processor::TraceProcessor* tp,
const std::set<int64_t>& seen_mappings) {
Iterator mapping_it = tp->ExecuteQuery(
@@ -573,8 +260,7 @@
if (seen_mappings.find(id) == seen_mappings.end())
continue;
++mappings_no;
- auto interned_filename = ToStringTableId(
- interner_->InternString(mapping_it.Get(4).AsString()));
+ auto interned_filename = Intern(mapping_it.Get(4).AsString());
auto* gmapping = result_->add_mapping();
gmapping->set_id(ToPprofId(id));
// Do not set the build_id here to avoid downstream services
@@ -599,48 +285,145 @@
return true;
}
- void WriteStringTable() {
- for (StringId id : string_table_) {
- trace_processor::NullTermStringView s = interner_->Get(id);
- result_->add_string_table(s.data(), s.size());
+ bool WriteSymbols(trace_processor::TraceProcessor* tp,
+ const std::set<int64_t>& seen_symbol_ids) {
+ Iterator symbol_it = tp->ExecuteQuery(
+ "SELECT id, name, source_file FROM stack_profile_symbol");
+ size_t symbols_no = 0;
+ while (symbol_it.Next()) {
+ int64_t id = symbol_it.Get(0).AsLong();
+ if (seen_symbol_ids.find(id) == seen_symbol_ids.end())
+ continue;
+ ++symbols_no;
+ const std::string& name = symbol_it.Get(1).AsString();
+ std::string demangled_name = name;
+ MaybeDemangle(&demangled_name);
+
+ auto interned_demangled_name = Intern(demangled_name);
+ auto interned_system_name = Intern(name);
+ auto interned_filename = Intern(symbol_it.Get(2).AsString());
+ auto* gfunction = result_->add_function();
+ gfunction->set_id(ToPprofId(id));
+ gfunction->set_name(interned_demangled_name);
+ gfunction->set_system_name(interned_system_name);
+ gfunction->set_filename(interned_filename);
}
+
+ if (!symbol_it.Status().ok()) {
+ PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+ symbol_it.Status().message().c_str());
+ return false;
+ }
+
+ if (symbols_no != seen_symbol_ids.size()) {
+ PERFETTO_DFATAL_OR_ELOG("Missing symbols.");
+ return false;
+ }
+ return true;
}
- int64_t ToStringTableId(StringId interned_id) {
- auto it = interning_remapper_.find(interned_id);
- if (it == interning_remapper_.end()) {
- int64_t table_id = static_cast<int64_t>(string_table_.size());
- string_table_.push_back(interned_id);
- bool inserted = false;
- std::tie(it, inserted) =
- interning_remapper_.emplace(interned_id, table_id);
- PERFETTO_DCHECK(inserted);
+ bool WriteFrames(trace_processor::TraceProcessor* tp,
+ std::set<int64_t>* seen_mappings,
+ std::set<int64_t>* seen_symbol_ids) {
+ Iterator frame_it = tp->ExecuteQuery(
+ "SELECT spf.id, IFNULL(spf.deobfuscated_name, spf.name), spf.mapping, "
+ "spf.rel_pc, spf.symbol_set_id "
+ "FROM stack_profile_frame spf;");
+ size_t frames_no = 0;
+ while (frame_it.Next()) {
+ int64_t frame_id = frame_it.Get(0).AsLong();
+ if (seen_frames_.find(frame_id) == seen_frames_.end())
+ continue;
+ frames_no++;
+ std::string frame_name = frame_it.Get(1).AsString();
+ int64_t mapping_id = frame_it.Get(2).AsLong();
+ int64_t rel_pc = frame_it.Get(3).AsLong();
+ base::Optional<int64_t> symbol_set_id;
+ if (!frame_it.Get(4).is_null())
+ symbol_set_id = frame_it.Get(4).AsLong();
+
+ seen_mappings->emplace(mapping_id);
+ auto* glocation = result_->add_location();
+ glocation->set_id(ToPprofId(frame_id));
+ glocation->set_mapping_id(ToPprofId(mapping_id));
+ // TODO(fmayer): Convert to abspc.
+ // relpc + (mapping.start - (mapping.exact_offset -
+ // mapping.start_offset)).
+ glocation->set_address(static_cast<uint64_t>(rel_pc));
+ if (symbol_set_id) {
+ for (const Line& line : LineForSymbolSetId(*symbol_set_id)) {
+ seen_symbol_ids->emplace(line.symbol_id);
+ auto* gline = glocation->add_line();
+ gline->set_line(line.line_number);
+ gline->set_function_id(ToPprofId(line.symbol_id));
+ }
+ } else {
+ int64_t synthesized_symbol_id = ++max_symbol_id_;
+ std::string demangled_name = frame_name;
+ MaybeDemangle(&demangled_name);
+
+ auto* gline = glocation->add_line();
+ gline->set_line(0);
+ gline->set_function_id(ToPprofId(synthesized_symbol_id));
+
+ auto interned_demangled_name = Intern(demangled_name);
+ auto interned_system_name = Intern(frame_name);
+ auto* gfunction = result_->add_function();
+ gfunction->set_id(ToPprofId(synthesized_symbol_id));
+ gfunction->set_name(interned_demangled_name);
+ gfunction->set_system_name(interned_system_name);
+ }
+ }
+
+ if (!frame_it.Status().ok()) {
+ PERFETTO_DFATAL_OR_ELOG("Invalid iterator: %s",
+ frame_it.Status().message().c_str());
+ return false;
+ }
+ if (frames_no != seen_frames_.size()) {
+ PERFETTO_DFATAL_OR_ELOG("Missing frames.");
+ return false;
+ }
+ return true;
+ }
+
+ const std::vector<int64_t>& FramesForCallstack(int64_t callstack_id) {
+ size_t callsite_idx = static_cast<size_t>(callstack_id);
+ PERFETTO_CHECK(callstack_id >= 0 &&
+ callsite_idx < callsite_to_frames_.size());
+ return callsite_to_frames_[callsite_idx];
+ }
+
+ const std::vector<Line>& LineForSymbolSetId(int64_t symbol_set_id) {
+ auto it = symbol_set_id_to_lines_.find(symbol_set_id);
+ if (it == symbol_set_id_to_lines_.end())
+ return empty_line_vector_;
+ return it->second;
+ }
+
+ int64_t Intern(const std::string& s) {
+ auto it = string_table_.find(s);
+ if (it == string_table_.end()) {
+ std::tie(it, std::ignore) =
+ string_table_.emplace(s, string_table_.size());
+ result_->add_string_table(s);
}
return it->second;
}
- // Contains all locations, lines, functions (in memory):
- const LocationTracker& locations_;
-
- // String interner, strings referenced by LocationTracker are already
- // interned. The new internings will come from mappings, and sample types.
- trace_processor::StringPool* interner_;
-
- // The profile format uses the repeated string_table field's index as an
- // implicit id, so these structures remap the interned strings into sequential
- // ids. Only the strings referenced by this GProfileBuilder instance will be
- // added to the table.
- std::unordered_map<StringId, int64_t> interning_remapper_;
- std::vector<StringId> string_table_;
-
- // Profile proto being serialized.
protozero::HeapBuffered<third_party::perftools::profiles::pbzero::Profile>
result_;
+ std::map<std::string, int64_t> string_table_;
+ const std::vector<std::vector<int64_t>>& callsite_to_frames_;
+ const std::map<int64_t, std::vector<Line>>& symbol_set_id_to_lines_;
+ const std::vector<Line> empty_line_vector_;
+ int64_t max_symbol_id_;
- // Set of locations referenced by the added samples.
- std::set<int64_t> seen_locations_;
+ std::set<int64_t> seen_frames_;
};
+} // namespace
+
namespace heap_profile {
struct View {
const char* type;
@@ -760,12 +543,13 @@
static bool TraceToHeapPprof(trace_processor::TraceProcessor* tp,
std::vector<SerializedProfile>* output,
- bool annotate_frames,
uint64_t target_pid,
const std::vector<uint64_t>& target_timestamps) {
- trace_processor::StringPool interner;
- LocationTracker locations =
- PreprocessLocations(tp, &interner, annotate_frames);
+ const auto callsite_to_frames = GetCallsiteToFrames(tp);
+ const auto symbol_set_id_to_lines = GetSymbolSetIdToLines(tp);
+ base::Optional<int64_t> max_symbol_id = GetMaxSymbolId(tp);
+ if (!max_symbol_id.has_value())
+ return false;
bool any_fail = false;
Iterator it = tp->ExecuteQuery(
@@ -773,7 +557,8 @@
"from heap_profile_allocation hpa, "
"process p where p.upid = hpa.upid;");
while (it.Next()) {
- GProfileBuilder builder(locations, &interner);
+ GProfileBuilder builder(callsite_to_frames, symbol_set_id_to_lines,
+ max_symbol_id.value());
uint64_t upid = static_cast<uint64_t>(it.Get(0).AsLong());
uint64_t ts = static_cast<uint64_t>(it.Get(1).AsLong());
uint64_t profile_pid = static_cast<uint64_t>(it.Get(2).AsLong());
@@ -901,11 +686,12 @@
// perf and heap profiles.
static bool TraceToPerfPprof(trace_processor::TraceProcessor* tp,
std::vector<SerializedProfile>* output,
- bool annotate_frames,
uint64_t target_pid) {
- trace_processor::StringPool interner;
- LocationTracker locations =
- PreprocessLocations(tp, &interner, annotate_frames);
+ const auto callsite_to_frames = GetCallsiteToFrames(tp);
+ const auto symbol_set_id_to_lines = GetSymbolSetIdToLines(tp);
+ base::Optional<int64_t> max_symbol_id = GetMaxSymbolId(tp);
+ if (!max_symbol_id.has_value())
+ return false;
LogTracePerfEventIssues(tp);
@@ -917,7 +703,9 @@
if (target_pid != 0 && process.pid != target_pid)
continue;
- GProfileBuilder builder(locations, &interner);
+ GProfileBuilder builder(callsite_to_frames, symbol_set_id_to_lines,
+ max_symbol_id.value());
+
builder.WriteSampleTypes({{"samples", "count"}});
std::string query = "select callsite_id from perf_sample where utid in (" +
@@ -945,22 +733,17 @@
return true;
}
} // namespace perf_profile
-} // namespace
bool TraceToPprof(trace_processor::TraceProcessor* tp,
std::vector<SerializedProfile>* output,
ConversionMode mode,
- uint64_t flags,
uint64_t pid,
const std::vector<uint64_t>& timestamps) {
- bool annotate_frames =
- flags & static_cast<uint64_t>(ConversionFlags::kAnnotateFrames);
switch (mode) {
case (ConversionMode::kHeapProfile):
- return heap_profile::TraceToHeapPprof(tp, output, annotate_frames, pid,
- timestamps);
+ return heap_profile::TraceToHeapPprof(tp, output, pid, timestamps);
case (ConversionMode::kPerfProfile):
- return perf_profile::TraceToPerfPprof(tp, output, annotate_frames, pid);
+ return perf_profile::TraceToPerfPprof(tp, output, pid);
}
PERFETTO_FATAL("unknown conversion option"); // for gcc
}
diff --git a/tools/trace_to_text/trace_to_profile.cc b/tools/trace_to_text/trace_to_profile.cc
index c71a827..a394e2b 100644
--- a/tools/trace_to_text/trace_to_profile.cc
+++ b/tools/trace_to_text/trace_to_profile.cc
@@ -50,12 +50,6 @@
namespace trace_to_text {
namespace {
-uint64_t ToConversionFlags(bool annotate_frames) {
- return static_cast<uint64_t>(annotate_frames
- ? ConversionFlags::kAnnotateFrames
- : ConversionFlags::kNone);
-}
-
std::string GetRandomString(size_t n) {
std::random_device r;
auto rng = std::default_random_engine(r());
@@ -98,7 +92,6 @@
uint64_t pid,
std::vector<uint64_t> timestamps,
ConversionMode conversion_mode,
- uint64_t conversion_flags,
std::string dirname_prefix,
std::function<std::string(const SerializedProfile&)> filename_fn) {
std::vector<SerializedProfile> profiles;
@@ -113,8 +106,7 @@
MaybeSymbolize(tp.get());
MaybeDeobfuscate(tp.get());
- TraceToPprof(tp.get(), &profiles, conversion_mode, conversion_flags, pid,
- timestamps);
+ TraceToPprof(tp.get(), &profiles, conversion_mode, pid, timestamps);
if (profiles.empty()) {
return 0;
}
@@ -140,33 +132,31 @@
int TraceToHeapProfile(std::istream* input,
std::ostream* output,
uint64_t pid,
- std::vector<uint64_t> timestamps,
- bool annotate_frames) {
+ std::vector<uint64_t> timestamps) {
int file_idx = 0;
auto filename_fn = [&file_idx](const SerializedProfile& profile) {
return "heap_dump." + std::to_string(++file_idx) + "." +
std::to_string(profile.pid) + "." + profile.heap_name + ".pb";
};
- return TraceToProfile(
- input, output, pid, timestamps, ConversionMode::kHeapProfile,
- ToConversionFlags(annotate_frames), "heap_profile-", filename_fn);
+ return TraceToProfile(input, output, pid, timestamps,
+ ConversionMode::kHeapProfile, "heap_profile-",
+ filename_fn);
}
int TraceToPerfProfile(std::istream* input,
std::ostream* output,
uint64_t pid,
- std::vector<uint64_t> timestamps,
- bool annotate_frames) {
+ std::vector<uint64_t> timestamps) {
int file_idx = 0;
auto filename_fn = [&file_idx](const SerializedProfile& profile) {
return "profile." + std::to_string(++file_idx) + ".pid." +
std::to_string(profile.pid) + ".pb";
};
- return TraceToProfile(
- input, output, pid, timestamps, ConversionMode::kPerfProfile,
- ToConversionFlags(annotate_frames), "perf_profile-", filename_fn);
+ return TraceToProfile(input, output, pid, timestamps,
+ ConversionMode::kPerfProfile, "perf_profile-",
+ filename_fn);
}
} // namespace trace_to_text
diff --git a/tools/trace_to_text/trace_to_profile.h b/tools/trace_to_text/trace_to_profile.h
index 313b32b..1c41aad 100644
--- a/tools/trace_to_text/trace_to_profile.h
+++ b/tools/trace_to_text/trace_to_profile.h
@@ -27,15 +27,13 @@
int TraceToHeapProfile(std::istream* input,
std::ostream* output,
uint64_t pid,
- std::vector<uint64_t> timestamps,
- bool annotate_frames);
+ std::vector<uint64_t> timestamps);
// 0: success
int TraceToPerfProfile(std::istream* input,
std::ostream* output,
uint64_t pid,
- std::vector<uint64_t> timestamps,
- bool annotate_frames);
+ std::vector<uint64_t> timestamps);
} // namespace trace_to_text
} // namespace perfetto
diff --git a/tools/traceconv b/tools/traceconv
index c0cff60..bb90486 100755
--- a/tools/traceconv
+++ b/tools/traceconv
@@ -21,7 +21,7 @@
# cat ./traceconv | python -
BASH_FALLBACK = """ "
-exec python - "$@" <<'#'EOF
+exec python3 - "$@" <<'#'EOF
#"""
import hashlib
diff --git a/tools/write_version_header.py b/tools/write_version_header.py
index 0325f6f..dd02a69 100755
--- a/tools/write_version_header.py
+++ b/tools/write_version_header.py
@@ -123,7 +123,7 @@
guard = '%s_' % args.cpp_out.upper()
guard = re.sub(r'[^\w]', '_', guard)
lines = []
- lines.append('// Generated by %s' % __file__)
+ lines.append('// Generated by %s' % os.path.basename(__file__))
lines.append('')
lines.append('#ifndef %s' % guard)
lines.append('#define %s' % guard)
diff --git a/ui/release/channels.json b/ui/release/channels.json
index 6d53d32..160b544 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,11 +2,11 @@
"channels": [
{
"name": "stable",
- "rev": "b7ab2469bd84ac0a4883c7f6a8a67e73903459b0"
+ "rev": "06350fe212f5051d9e890411ca24ab4a84b33ae1"
},
{
"name": "canary",
- "rev": "06350fe212f5051d9e890411ca24ab4a84b33ae1"
+ "rev": "aaab326dc5b38858d516171ba68f4542e9e92d65"
},
{
"name": "autopush",
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 65c78d0..8d47424 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -519,11 +519,13 @@
'accessibility',
'AccountFetcherService',
'android_webview',
+ 'aogh',
'audio',
'base',
'benchmark',
'blink',
'blink.animations',
+ 'blink.bindings',
'blink.console',
'blink_gc',
'blink.net',
@@ -534,8 +536,13 @@
'browser',
'browsing_data',
'CacheStorage',
+ 'Calculators',
+ 'CameraStream',
'camera',
+ 'cast_app',
'cast_perf_test',
+ 'cast.mdns',
+ 'cast.mdns.socket',
'cast.stream',
'cc',
'cc.debug',
@@ -545,14 +552,17 @@
'compositor',
'content',
'content_capture',
+ 'device',
'devtools',
+ 'devtools.contrast',
'devtools.timeline',
+ 'disk_cache',
'download',
'download_service',
'drm',
'drmcursor',
'dwrite',
- 'DXVA Decoding',
+ 'DXVA_Decoding',
'EarlyJava',
'evdev',
'event',
@@ -563,10 +573,12 @@
'fonts',
'GAMEPAD',
'gpu',
+ 'gpu.angle',
'gpu.capture',
'headless',
'hwoverlays',
'identity',
+ 'ime',
'IndexedDB',
'input',
'io',
@@ -594,12 +606,17 @@
'omnibox',
'oobe',
'ozone',
+ 'partition_alloc',
'passwords',
'p2p',
'page-serialization',
+ 'paint_preview',
'pepper',
+ 'PlatformMalloc',
+ 'power',
'ppapi',
- 'ppapi proxy',
+ 'ppapi_proxy',
+ 'print',
'rail',
'renderer',
'renderer_host',
@@ -610,21 +627,26 @@
'sequence_manager',
'service_manager',
'ServiceWorker',
+ 'sharing',
'shell',
'shortcut_viewer',
'shutdown',
'SiteEngagement',
'skia',
+ 'sql',
+ 'stadia_media',
+ 'stadia_rtc',
'startup',
'sync',
'sync_lock_contention',
- 'thread_pool',
'test_gpu',
- 'test_tracing',
+ 'thread_pool',
'toplevel',
+ 'toplevel.flow',
'ui',
'v8',
'v8.execute',
+ 'v8.wasm',
'ValueStoreFrontend::Backend',
'views',
'views.frame',
@@ -637,6 +659,7 @@
'webrtc',
'xr',
'disabled-by-default-animation-worklet',
+ 'disabled-by-default-audio',
'disabled-by-default-audio-worklet',
'disabled-by-default-blink.debug',
'disabled-by-default-blink.debug.display_lock',
@@ -654,6 +677,7 @@
'disabled-by-default-cc.debug.scheduler',
'disabled-by-default-cc.debug.scheduler.frames',
'disabled-by-default-cc.debug.scheduler.now',
+ 'disabled-by-default-content.verbose',
'disabled-by-default-cpu_profiler',
'disabled-by-default-cpu_profiler.debug',
'disabled-by-default-devtools.screenshot',
@@ -668,34 +692,41 @@
'disabled-by-default-gpu_cmd_queue',
'disabled-by-default-gpu.dawn',
'disabled-by-default-gpu.debug',
- 'disabled-by-default-gpu_decoder',
+ 'disabled-by-default-gpu.decoder',
'disabled-by-default-gpu.device',
'disabled-by-default-gpu.service',
+ 'disabled-by-default-gpu.vulkan.vma',
'disabled-by-default-histogram_samples',
'disabled-by-default-ipc.flow',
'disabled-by-default-java-heap-profiler',
'disabled-by-default-layer-element',
+ 'disabled-by-default-layout_shift.debug',
'disabled-by-default-lifecycles',
'disabled-by-default-loading',
+ 'disabled-by-default-mediastream',
'disabled-by-default-memory-infra',
'disabled-by-default-memory-infra.v8.code_stats',
+ 'disabled-by-default-mojom',
'disabled-by-default-net',
'disabled-by-default-network',
'disabled-by-default-paint-worklet',
'disabled-by-default-power',
'disabled-by-default-renderer.scheduler',
'disabled-by-default-renderer.scheduler.debug',
+ 'disabled-by-default-sandbox',
'disabled-by-default-sequence_manager',
'disabled-by-default-sequence_manager.debug',
'disabled-by-default-sequence_manager.verbose_snapshots',
'disabled-by-default-skia',
'disabled-by-default-skia.gpu',
'disabled-by-default-skia.gpu.cache',
+ 'disabled-by-default-skia.shaders',
'disabled-by-default-SyncFileSystem',
'disabled-by-default-system_stats',
'disabled-by-default-thread_pool_diagnostics',
'disabled-by-default-toplevel.flow',
'disabled-by-default-toplevel.ipc',
+ 'disabled-by-default-user_action_samples',
'disabled-by-default-v8.compile',
'disabled-by-default-v8.cpu_profiler',
'disabled-by-default-v8.cpu_profiler.hires',
@@ -705,17 +736,24 @@
'disabled-by-default-v8.runtime',
'disabled-by-default-v8.runtime_stats',
'disabled-by-default-v8.runtime_stats_sampling',
+ 'disabled-by-default-v8.stack_trace',
'disabled-by-default-v8.turbofan',
'disabled-by-default-v8.wasm',
+ 'disabled-by-default-v8.wasm.detailed',
+ 'disabled-by-default-v8.wasm.turbofan',
'disabled-by-default-video_and_image_capture',
'disabled-by-default-viz.debug.overlay_planes',
+ 'disabled-by-default-viz.gpu_composite_time',
'disabled-by-default-viz.hit_testing_flow',
'disabled-by-default-viz.overdraw',
'disabled-by-default-viz.quads',
'disabled-by-default-viz.surface_id_flow',
'disabled-by-default-viz.surface_lifetime',
'disabled-by-default-viz.triangles',
+ 'disabled-by-default-webaudio.audionode',
+ 'disabled-by-default-webrtc',
'disabled-by-default-worker.scheduler',
+ 'disabled-by-default-xr.debug',
];
}