Merge "Project import generated by Copybara."
diff --git a/Android.bp b/Android.bp
index 4ebd425..de0d6e9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4030,6 +4030,165 @@
],
}
+// GN: //protos/perfetto/trace:descriptor
+genrule {
+ name: "perfetto_protos_perfetto_trace_descriptor",
+ srcs: [
+ "protos/perfetto/common/android_energy_consumer_descriptor.proto",
+ "protos/perfetto/common/android_log_constants.proto",
+ "protos/perfetto/common/builtin_clock.proto",
+ "protos/perfetto/common/commit_data_request.proto",
+ "protos/perfetto/common/data_source_descriptor.proto",
+ "protos/perfetto/common/descriptor.proto",
+ "protos/perfetto/common/gpu_counter_descriptor.proto",
+ "protos/perfetto/common/interceptor_descriptor.proto",
+ "protos/perfetto/common/observable_events.proto",
+ "protos/perfetto/common/perf_events.proto",
+ "protos/perfetto/common/sys_stats_counters.proto",
+ "protos/perfetto/common/trace_stats.proto",
+ "protos/perfetto/common/tracing_service_capabilities.proto",
+ "protos/perfetto/common/tracing_service_state.proto",
+ "protos/perfetto/common/track_event_descriptor.proto",
+ "protos/perfetto/config/android/android_log_config.proto",
+ "protos/perfetto/config/android/android_polled_state_config.proto",
+ "protos/perfetto/config/android/packages_list_config.proto",
+ "protos/perfetto/config/chrome/chrome_config.proto",
+ "protos/perfetto/config/data_source_config.proto",
+ "protos/perfetto/config/ftrace/ftrace_config.proto",
+ "protos/perfetto/config/gpu/gpu_counter_config.proto",
+ "protos/perfetto/config/gpu/vulkan_memory_config.proto",
+ "protos/perfetto/config/inode_file/inode_file_config.proto",
+ "protos/perfetto/config/interceptor_config.proto",
+ "protos/perfetto/config/interceptors/console_config.proto",
+ "protos/perfetto/config/power/android_power_config.proto",
+ "protos/perfetto/config/process_stats/process_stats_config.proto",
+ "protos/perfetto/config/profiling/heapprofd_config.proto",
+ "protos/perfetto/config/profiling/java_hprof_config.proto",
+ "protos/perfetto/config/profiling/perf_event_config.proto",
+ "protos/perfetto/config/stress_test_config.proto",
+ "protos/perfetto/config/sys_stats/sys_stats_config.proto",
+ "protos/perfetto/config/test_config.proto",
+ "protos/perfetto/config/trace_config.proto",
+ "protos/perfetto/config/track_event/track_event_config.proto",
+ "protos/perfetto/trace/android/android_log.proto",
+ "protos/perfetto/trace/android/frame_timeline_event.proto",
+ "protos/perfetto/trace/android/gpu_mem_event.proto",
+ "protos/perfetto/trace/android/graphics_frame_event.proto",
+ "protos/perfetto/trace/android/initial_display_state.proto",
+ "protos/perfetto/trace/android/packages_list.proto",
+ "protos/perfetto/trace/chrome/chrome_benchmark_metadata.proto",
+ "protos/perfetto/trace/chrome/chrome_metadata.proto",
+ "protos/perfetto/trace/chrome/chrome_trace_event.proto",
+ "protos/perfetto/trace/clock_snapshot.proto",
+ "protos/perfetto/trace/extension_descriptor.proto",
+ "protos/perfetto/trace/filesystem/inode_file_map.proto",
+ "protos/perfetto/trace/ftrace/binder.proto",
+ "protos/perfetto/trace/ftrace/block.proto",
+ "protos/perfetto/trace/ftrace/cgroup.proto",
+ "protos/perfetto/trace/ftrace/clk.proto",
+ "protos/perfetto/trace/ftrace/compaction.proto",
+ "protos/perfetto/trace/ftrace/cpuhp.proto",
+ "protos/perfetto/trace/ftrace/dmabuf_heap.proto",
+ "protos/perfetto/trace/ftrace/dpu.proto",
+ "protos/perfetto/trace/ftrace/ext4.proto",
+ "protos/perfetto/trace/ftrace/f2fs.proto",
+ "protos/perfetto/trace/ftrace/fastrpc.proto",
+ "protos/perfetto/trace/ftrace/fence.proto",
+ "protos/perfetto/trace/ftrace/filemap.proto",
+ "protos/perfetto/trace/ftrace/ftrace.proto",
+ "protos/perfetto/trace/ftrace/ftrace_event.proto",
+ "protos/perfetto/trace/ftrace/ftrace_event_bundle.proto",
+ "protos/perfetto/trace/ftrace/ftrace_stats.proto",
+ "protos/perfetto/trace/ftrace/g2d.proto",
+ "protos/perfetto/trace/ftrace/generic.proto",
+ "protos/perfetto/trace/ftrace/gpu_mem.proto",
+ "protos/perfetto/trace/ftrace/i2c.proto",
+ "protos/perfetto/trace/ftrace/ion.proto",
+ "protos/perfetto/trace/ftrace/ipi.proto",
+ "protos/perfetto/trace/ftrace/irq.proto",
+ "protos/perfetto/trace/ftrace/kmem.proto",
+ "protos/perfetto/trace/ftrace/lowmemorykiller.proto",
+ "protos/perfetto/trace/ftrace/mali.proto",
+ "protos/perfetto/trace/ftrace/mdss.proto",
+ "protos/perfetto/trace/ftrace/mm_event.proto",
+ "protos/perfetto/trace/ftrace/oom.proto",
+ "protos/perfetto/trace/ftrace/power.proto",
+ "protos/perfetto/trace/ftrace/raw_syscalls.proto",
+ "protos/perfetto/trace/ftrace/regulator.proto",
+ "protos/perfetto/trace/ftrace/sched.proto",
+ "protos/perfetto/trace/ftrace/scm.proto",
+ "protos/perfetto/trace/ftrace/sde.proto",
+ "protos/perfetto/trace/ftrace/signal.proto",
+ "protos/perfetto/trace/ftrace/sync.proto",
+ "protos/perfetto/trace/ftrace/systrace.proto",
+ "protos/perfetto/trace/ftrace/task.proto",
+ "protos/perfetto/trace/ftrace/test_bundle_wrapper.proto",
+ "protos/perfetto/trace/ftrace/thermal.proto",
+ "protos/perfetto/trace/ftrace/vmscan.proto",
+ "protos/perfetto/trace/ftrace/workqueue.proto",
+ "protos/perfetto/trace/gpu/gpu_counter_event.proto",
+ "protos/perfetto/trace/gpu/gpu_log.proto",
+ "protos/perfetto/trace/gpu/gpu_render_stage_event.proto",
+ "protos/perfetto/trace/gpu/vulkan_api_event.proto",
+ "protos/perfetto/trace/gpu/vulkan_memory_event.proto",
+ "protos/perfetto/trace/interned_data/interned_data.proto",
+ "protos/perfetto/trace/memory_graph.proto",
+ "protos/perfetto/trace/perfetto/perfetto_metatrace.proto",
+ "protos/perfetto/trace/perfetto/tracing_service_event.proto",
+ "protos/perfetto/trace/power/android_energy_estimation_breakdown.proto",
+ "protos/perfetto/trace/power/battery_counters.proto",
+ "protos/perfetto/trace/power/power_rails.proto",
+ "protos/perfetto/trace/profiling/deobfuscation.proto",
+ "protos/perfetto/trace/profiling/heap_graph.proto",
+ "protos/perfetto/trace/profiling/profile_common.proto",
+ "protos/perfetto/trace/profiling/profile_packet.proto",
+ "protos/perfetto/trace/profiling/smaps.proto",
+ "protos/perfetto/trace/ps/process_stats.proto",
+ "protos/perfetto/trace/ps/process_tree.proto",
+ "protos/perfetto/trace/sys_stats/sys_stats.proto",
+ "protos/perfetto/trace/system_info.proto",
+ "protos/perfetto/trace/system_info/cpu_info.proto",
+ "protos/perfetto/trace/test_event.proto",
+ "protos/perfetto/trace/test_extensions.proto",
+ "protos/perfetto/trace/trace.proto",
+ "protos/perfetto/trace/trace_packet.proto",
+ "protos/perfetto/trace/trace_packet_defaults.proto",
+ "protos/perfetto/trace/track_event/chrome_application_state_info.proto",
+ "protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.proto",
+ "protos/perfetto/trace/track_event/chrome_content_settings_event_info.proto",
+ "protos/perfetto/trace/track_event/chrome_frame_reporter.proto",
+ "protos/perfetto/trace/track_event/chrome_histogram_sample.proto",
+ "protos/perfetto/trace/track_event/chrome_keyed_service.proto",
+ "protos/perfetto/trace/track_event/chrome_latency_info.proto",
+ "protos/perfetto/trace/track_event/chrome_legacy_ipc.proto",
+ "protos/perfetto/trace/track_event/chrome_message_pump.proto",
+ "protos/perfetto/trace/track_event/chrome_mojo_event_info.proto",
+ "protos/perfetto/trace/track_event/chrome_process_descriptor.proto",
+ "protos/perfetto/trace/track_event/chrome_renderer_scheduler_state.proto",
+ "protos/perfetto/trace/track_event/chrome_thread_descriptor.proto",
+ "protos/perfetto/trace/track_event/chrome_user_event.proto",
+ "protos/perfetto/trace/track_event/chrome_window_handle_event_info.proto",
+ "protos/perfetto/trace/track_event/counter_descriptor.proto",
+ "protos/perfetto/trace/track_event/debug_annotation.proto",
+ "protos/perfetto/trace/track_event/log_message.proto",
+ "protos/perfetto/trace/track_event/process_descriptor.proto",
+ "protos/perfetto/trace/track_event/source_location.proto",
+ "protos/perfetto/trace/track_event/task_execution.proto",
+ "protos/perfetto/trace/track_event/thread_descriptor.proto",
+ "protos/perfetto/trace/track_event/track_descriptor.proto",
+ "protos/perfetto/trace/track_event/track_event.proto",
+ "protos/perfetto/trace/trigger.proto",
+ "protos/perfetto/trace/ui_state.proto",
+ ],
+ tools: [
+ "aprotoc",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --descriptor_set_out=$(out) $(in)",
+ out: [
+ "perfetto_protos_perfetto_trace_descriptor.bin",
+ ],
+}
+
// GN: //protos/perfetto/trace/filesystem:cpp
genrule {
name: "perfetto_protos_perfetto_trace_filesystem_cpp_gen",
@@ -7335,6 +7494,14 @@
],
}
+// GN: //src/protozero:proto_ring_buffer
+filegroup {
+ name: "perfetto_src_protozero_proto_ring_buffer",
+ srcs: [
+ "src/protozero/proto_ring_buffer.cc",
+ ],
+}
+
// GN: //src/protozero/protoc_plugin:cppgen_plugin
cc_binary_host {
name: "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
@@ -7558,6 +7725,7 @@
"src/protozero/message_handle_unittest.cc",
"src/protozero/message_unittest.cc",
"src/protozero/proto_decoder_unittest.cc",
+ "src/protozero/proto_ring_buffer_unittest.cc",
"src/protozero/proto_utils_unittest.cc",
"src/protozero/scattered_stream_writer_unittest.cc",
"src/protozero/test/cppgen_conformance_unittest.cc",
@@ -7897,7 +8065,6 @@
filegroup {
name: "perfetto_src_trace_processor_rpc_rpc",
srcs: [
- "src/trace_processor/rpc/proto_ring_buffer.cc",
"src/trace_processor/rpc/query_result_serializer.cc",
"src/trace_processor/rpc/rpc.cc",
],
@@ -7907,7 +8074,6 @@
filegroup {
name: "perfetto_src_trace_processor_rpc_unittests",
srcs: [
- "src/trace_processor/rpc/proto_ring_buffer_unittest.cc",
"src/trace_processor/rpc/query_result_serializer_unittest.cc",
],
}
@@ -8648,6 +8814,7 @@
"src/tracing/ipc/default_socket.cc",
"src/tracing/ipc/memfd.cc",
"src/tracing/ipc/posix_shared_memory.cc",
+ "src/tracing/ipc/shared_memory_windows.cc",
],
}
@@ -8690,6 +8857,7 @@
name: "perfetto_src_tracing_platform_impl",
srcs: [
"src/tracing/platform_posix.cc",
+ "src/tracing/platform_windows.cc",
],
}
@@ -8799,6 +8967,21 @@
],
}
+// GN: //tools/trace_to_text:gen_cc_trace_descriptor
+genrule {
+ name: "perfetto_tools_trace_to_text_gen_cc_trace_descriptor",
+ srcs: [
+ ":perfetto_protos_perfetto_trace_descriptor",
+ ],
+ cmd: "$(location tools/gen_cc_proto_descriptor.py) --gen_dir=$(genDir) --cpp_out=$(out) $(in)",
+ out: [
+ "tools/trace_to_text/trace.descriptor.h",
+ ],
+ tool_files: [
+ "tools/gen_cc_proto_descriptor.py",
+ ],
+}
+
// GN: //tools/trace_to_text:pprofbuilder
filegroup {
name: "perfetto_tools_trace_to_text_pprofbuilder",
@@ -9083,6 +9266,7 @@
":perfetto_src_protozero_filtering_filter_util",
":perfetto_src_protozero_filtering_message_filter",
":perfetto_src_protozero_filtering_unittests",
+ ":perfetto_src_protozero_proto_ring_buffer",
":perfetto_src_protozero_protozero",
":perfetto_src_protozero_testing_messages_cpp_gen",
":perfetto_src_protozero_testing_messages_lite_gen",
@@ -9609,6 +9793,7 @@
"perfetto_src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_cc_metrics_descriptor",
"perfetto_src_trace_processor_metrics_gen_merged_sql_metrics",
+ "perfetto_tools_trace_to_text_gen_cc_trace_descriptor",
],
defaults: [
"perfetto_defaults",
diff --git a/BUILD b/BUILD
index 3440cca..45b742f 100644
--- a/BUILD
+++ b/BUILD
@@ -803,6 +803,15 @@
],
)
+# GN target: //src/protozero:proto_ring_buffer
+filegroup(
+ name = "src_protozero_proto_ring_buffer",
+ srcs = [
+ "src/protozero/proto_ring_buffer.cc",
+ "src/protozero/proto_ring_buffer.h",
+ ],
+)
+
# GN target: //src/trace_processor/analysis:analysis
filegroup(
name = "src_trace_processor_analysis_analysis",
@@ -1048,8 +1057,6 @@
filegroup(
name = "src_trace_processor_rpc_rpc",
srcs = [
- "src/trace_processor/rpc/proto_ring_buffer.cc",
- "src/trace_processor/rpc/proto_ring_buffer.h",
"src/trace_processor/rpc/query_result_serializer.cc",
"src/trace_processor/rpc/query_result_serializer.h",
"src/trace_processor/rpc/rpc.cc",
@@ -1681,6 +1688,8 @@
"src/tracing/ipc/memfd.h",
"src/tracing/ipc/posix_shared_memory.cc",
"src/tracing/ipc/posix_shared_memory.h",
+ "src/tracing/ipc/shared_memory_windows.cc",
+ "src/tracing/ipc/shared_memory_windows.h",
],
)
@@ -1735,6 +1744,7 @@
name = "src_tracing_platform_impl",
srcs = [
"src/tracing/platform_posix.cc",
+ "src/tracing/platform_windows.cc",
],
)
@@ -1777,6 +1787,16 @@
],
)
+perfetto_cc_proto_descriptor(
+ name = "tools_trace_to_text_gen_cc_trace_descriptor",
+ deps = [
+ ":protos_perfetto_trace_descriptor",
+ ],
+ outs = [
+ "tools/trace_to_text/trace.descriptor.h",
+ ],
+)
+
# GN target: //tools/trace_to_text:pprofbuilder
filegroup(
name = "tools_trace_to_text_pprofbuilder",
@@ -2615,6 +2635,17 @@
],
)
+# GN target: //protos/perfetto/trace:descriptor
+perfetto_proto_descriptor(
+ name = "protos_perfetto_trace_descriptor",
+ deps = [
+ ":protos_perfetto_trace_protos",
+ ],
+ outs = [
+ "protos_perfetto_trace_descriptor.bin",
+ ],
+)
+
# GN target: //protos/perfetto/trace/filesystem:lite
perfetto_cc_proto_library(
name = "protos_perfetto_trace_filesystem_lite",
@@ -3080,6 +3111,46 @@
],
)
+# GN target: //protos/perfetto/trace:descriptor
+perfetto_proto_library(
+ name = "protos_perfetto_trace_protos",
+ srcs = [
+ "protos/perfetto/trace/trace.proto",
+ ],
+ visibility = [
+ PERFETTO_CONFIG.proto_library_visibility,
+ ],
+ deps = [
+ ":protos_perfetto_common_protos",
+ ":protos_perfetto_config_android_protos",
+ ":protos_perfetto_config_ftrace_protos",
+ ":protos_perfetto_config_gpu_protos",
+ ":protos_perfetto_config_inode_file_protos",
+ ":protos_perfetto_config_interceptors_protos",
+ ":protos_perfetto_config_power_protos",
+ ":protos_perfetto_config_process_stats_protos",
+ ":protos_perfetto_config_profiling_protos",
+ ":protos_perfetto_config_protos",
+ ":protos_perfetto_config_sys_stats_protos",
+ ":protos_perfetto_config_track_event_protos",
+ ":protos_perfetto_trace_android_protos",
+ ":protos_perfetto_trace_chrome_protos",
+ ":protos_perfetto_trace_filesystem_protos",
+ ":protos_perfetto_trace_ftrace_protos",
+ ":protos_perfetto_trace_gpu_protos",
+ ":protos_perfetto_trace_interned_data_protos",
+ ":protos_perfetto_trace_minimal_protos",
+ ":protos_perfetto_trace_non_minimal_protos",
+ ":protos_perfetto_trace_perfetto_protos",
+ ":protos_perfetto_trace_power_protos",
+ ":protos_perfetto_trace_profiling_protos",
+ ":protos_perfetto_trace_ps_protos",
+ ":protos_perfetto_trace_sys_stats_protos",
+ ":protos_perfetto_trace_system_info_protos",
+ ":protos_perfetto_trace_track_event_protos",
+ ],
+)
+
# GN target: //protos/perfetto/trace/ps:lite
perfetto_cc_proto_library(
name = "protos_perfetto_trace_ps_lite",
@@ -3583,6 +3654,7 @@
":src_profiling_deobfuscator",
":src_profiling_symbolizer_symbolize_database",
":src_profiling_symbolizer_symbolizer",
+ ":src_protozero_proto_ring_buffer",
":src_trace_processor_analysis_analysis",
":src_trace_processor_db_db",
":src_trace_processor_export_json",
@@ -3834,6 +3906,7 @@
":src_trace_processor_importers_gen_cc_track_event_descriptor",
":src_trace_processor_metrics_gen_cc_all_chrome_metrics_descriptor",
":src_trace_processor_metrics_gen_cc_metrics_descriptor",
+ ":tools_trace_to_text_gen_cc_trace_descriptor",
] + PERFETTO_CONFIG.deps.jsoncpp +
PERFETTO_CONFIG.deps.protobuf_full +
PERFETTO_CONFIG.deps.sqlite +
diff --git a/buildtools/BUILD.gn b/buildtools/BUILD.gn
index 98022c9..97ab40a 100644
--- a/buildtools/BUILD.gn
+++ b/buildtools/BUILD.gn
@@ -788,7 +788,9 @@
defines = [ "HAVE_POSIX_REGEX" ]
public_configs = [ ":benchmark_config" ]
all_dependent_configs = [ ":benchmark_config" ]
- cflags = [ "-Wno-deprecated-declarations" ]
+ if (!is_win) {
+ cflags = [ "-Wno-deprecated-declarations" ]
+ }
configs -= [ "//gn/standalone:extra_warnings" ]
deps = [ "//gn:default_deps" ]
}
@@ -1056,10 +1058,11 @@
config("jsoncpp_config") {
visibility = _buildtools_visibility
- cflags = [
- "-DJSON_USE_EXCEPTION=0",
- "-Wno-deprecated-declarations",
-
+ cflags = [ "-DJSON_USE_EXCEPTION=0" ]
+ if (!is_win) {
+ cflags += [ "-Wno-deprecated-declarations" ]
+ }
+ cflags += [
# 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
# our own code.
diff --git a/docs/data-sources/cpu-scheduling.md b/docs/data-sources/cpu-scheduling.md
index 8b771e8..29a2144 100644
--- a/docs/data-sources/cpu-scheduling.md
+++ b/docs/data-sources/cpu-scheduling.md
@@ -147,3 +147,45 @@
![](/docs/images/latency.png "Scheduling wake-up events in the UI")
+### Decoding `end_state`
+
+The [sched_slice](/docs/analysis/sql-tables.autogen#sched_slice) table contains
+information on scheduling activity of the system:
+
+```
+> select * from sched_slice limit 1
+id type ts dur cpu utid end_state priority
+0 sched_slice 70730062200 125364 0 1 S 130
+```
+
+Each row of the table shows when a given thread (`utid`) began running
+(`ts`), on which core it ran (`cpu`), for how long it ran (`dur`),
+and why it stopped running: `end_state`.
+
+`end_state` is encoded as one or more ascii characters. The UI uses
+the following translations to convert `end_state` into human readable
+text:
+
+| end_state | Translation |
+|------------|------------------------|
+| R | Runnable |
+| S | Sleeping |
+| D | Uninterruptible Sleep |
+| T | Stopped |
+| t | Traced |
+| X | Exit (Dead) |
+| Z | Exit (Zombie) |
+| x | Task Dead |
+| I | Task Dead |
+| K | Wake Kill |
+| W | Waking |
+| P | Parked |
+| N | No Load |
+| + | (Preempted) |
+
+Not all combinations of characters are meaningful.
+
+If we do not know when the scheduling ended (for example because the
+trace ended while the thread was still running) `end_state` will be
+`NULL` and `dur` will be -1.
+
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index c1ff723..d7263e7 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -144,9 +144,12 @@
# system backend in the client library.
# This includes building things that rely on POSIX sockets, this places
# limitations on the supported operating systems.
- enable_perfetto_ipc = !is_win && !is_fuchsia && !is_nacl &&
- (perfetto_build_standalone ||
- perfetto_build_with_android || build_with_chromium)
+ # For now the IPC layer is conservatively not enabled on Chromium+Windows
+ # builds.
+ enable_perfetto_ipc =
+ !is_fuchsia && !is_nacl &&
+ (perfetto_build_standalone || perfetto_build_with_android ||
+ (build_with_chromium && !is_win))
# Makes the heap profiling daemon target reachable. It works only on Android,
# but is built on Linux as well for test/compiler coverage.
@@ -186,7 +189,7 @@
build_with_chromium || perfetto_build_with_android
enable_perfetto_integration_tests =
- (perfetto_build_standalone && !is_win) || perfetto_build_with_android
+ perfetto_build_standalone || perfetto_build_with_android
enable_perfetto_benchmarks = perfetto_build_standalone && !is_win
@@ -314,9 +317,6 @@
# |is_perfetto_build_generator| must be true.
assert(!perfetto_build_with_android || is_perfetto_build_generator)
-# The IPC layer based on UNIX sockets can't be built on Win.
-assert(!enable_perfetto_ipc || !is_win)
-
# We should never end up in a state where is_perfetto_embedder=true but
# perfetto_build_with_embedder=false.
assert(!is_perfetto_embedder || perfetto_build_with_embedder)
diff --git a/gn/proto_library.gni b/gn/proto_library.gni
index 03d6455..5b87753 100644
--- a/gn/proto_library.gni
+++ b/gn/proto_library.gni
@@ -173,6 +173,17 @@
} else {
deps += [ "$perfetto_root_path/src/ipc:common" ]
}
+ if (is_win) {
+ # TODO(primiano): investigate this. In Windows standalone builds, some
+ # executable targets end up in a state where no code pulls a dep on the
+ # ipc:client (in turn that seems a subtle consequence of not having
+ # traced_probes on Windows). This dep here is effectively needed because
+ # the client-side code in the generated .ipc.cc effectively depends on the
+ # client-side IPC library. Perhaps we just should do this unconditionally
+ # on all platforms?
+ deps += [ "$perfetto_root_path/src/ipc:client" ]
+ }
+
if (defined(invoker.deps)) {
deps += invoker.deps
}
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index af70070..31941ed 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -161,6 +161,8 @@
cflags += [
"/bigobj", # Some of our files are bigger than the regular limits.
"/Gy", # Enable function-level linking.
+ "/FS", # Preserve previous PDB behavior.
+ "/utf-8", # Assume UTF-8 by default to avoid code page dependencies.
]
defines += [
"_CRT_NONSTDC_NO_WARNINGS",
diff --git a/include/perfetto/ext/base/getopt.h b/include/perfetto/ext/base/getopt.h
index 77c1490..bf993fc 100644
--- a/include/perfetto/ext/base/getopt.h
+++ b/include/perfetto/ext/base/getopt.h
@@ -34,8 +34,10 @@
// replacement to the various main.cc, which can't know about the nested
// namespace.
using ::perfetto::base::getopt_compat::optarg;
+using ::perfetto::base::getopt_compat::opterr;
using ::perfetto::base::getopt_compat::optind;
using ::perfetto::base::getopt_compat::option;
+using ::perfetto::base::getopt_compat::optopt;
constexpr auto getopt = ::perfetto::base::getopt_compat::getopt;
constexpr auto getopt_long = ::perfetto::base::getopt_compat::getopt_long;
constexpr auto no_argument = ::perfetto::base::getopt_compat::no_argument;
diff --git a/include/perfetto/ext/base/getopt_compat.h b/include/perfetto/ext/base/getopt_compat.h
index d1f5436..d854ff0 100644
--- a/include/perfetto/ext/base/getopt_compat.h
+++ b/include/perfetto/ext/base/getopt_compat.h
@@ -53,6 +53,8 @@
extern char* optarg;
extern int optind;
+extern int optopt;
+extern int opterr;
int getopt_long(int argc,
char** argv,
diff --git a/include/perfetto/ext/tracing/core/tracing_service.h b/include/perfetto/ext/tracing/core/tracing_service.h
index 20382a1..c26d949 100644
--- a/include/perfetto/ext/tracing/core/tracing_service.h
+++ b/include/perfetto/ext/tracing/core/tracing_service.h
@@ -326,7 +326,8 @@
ProducerSMBScrapingMode smb_scraping_mode =
ProducerSMBScrapingMode::kDefault,
size_t shared_memory_page_size_hint_bytes = 0,
- std::unique_ptr<SharedMemory> shm = nullptr) = 0;
+ std::unique_ptr<SharedMemory> shm = nullptr,
+ const std::string& sdk_version = {}) = 0;
// Connects a Consumer instance and obtains a ConsumerEndpoint, which is
// essentially a 1:1 channel between one Consumer and the Service.
diff --git a/protos/perfetto/common/tracing_service_state.proto b/protos/perfetto/common/tracing_service_state.proto
index 119cea8..1ef4c56 100644
--- a/protos/perfetto/common/tracing_service_state.proto
+++ b/protos/perfetto/common/tracing_service_state.proto
@@ -34,6 +34,12 @@
// Unix uid of the remote process.
optional int32 uid = 3;
+
+ // The version of the client library used by the producer.
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string sdk_version = 4;
}
// Describes a data source registered by a producer. Data sources are listed
@@ -57,4 +63,10 @@
// Number of tracing sessions in the started state. Always <= num_sessions.
optional int32 num_sessions_started = 4;
+
+ // The version of traced (the same returned by `traced --version`).
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string tracing_service_version = 5;
}
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 4c6e882..c8b55e3 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -197,6 +197,12 @@
// Unix uid of the remote process.
optional int32 uid = 3;
+
+ // The version of the client library used by the producer.
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string sdk_version = 4;
}
// Describes a data source registered by a producer. Data sources are listed
@@ -220,6 +226,12 @@
// Number of tracing sessions in the started state. Always <= num_sessions.
optional int32 num_sessions_started = 4;
+
+ // The version of traced (the same returned by `traced --version`).
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string tracing_service_version = 5;
}
// End of protos/perfetto/common/tracing_service_state.proto
diff --git a/protos/perfetto/ipc/producer_port.proto b/protos/perfetto/ipc/producer_port.proto
index 1b193eb..9be72ea 100644
--- a/protos/perfetto/ipc/producer_port.proto
+++ b/protos/perfetto/ipc/producer_port.proto
@@ -152,6 +152,21 @@
// SetupTracing response. See TracingService::ConnectProducer() and
// |using_shmem_provided_by_producer| in InitializeConnectionResponse.
optional bool producer_provided_shmem = 6;
+
+ // ---------------------------------------------------
+ // All fields below have been introduced in Android S.
+ // ---------------------------------------------------
+
+ // The version of the client library used by the producer.
+ // This is a human readable string with and its format varies depending on
+ // the build system that is used to build the code and the repo (standalone
+ // vs AOSP). This is intended for human debugging only.
+ optional string sdk_version = 8;
+
+ // On Windows, when producer_provided_shmem = true, the client creates a named
+ // SHM region and passes the name (an unguessable token) back to the service.
+ // Introduced in v13.
+ optional string shm_key_windows = 7;
}
message InitializeConnectionResponse {
@@ -262,9 +277,16 @@
message StopDataSource { optional uint64 instance_id = 1; }
- // This message also transports the file descriptor for the shared memory
- // buffer (not a proto field).
- message SetupTracing { optional uint32 shared_buffer_page_size_kb = 1; }
+ // On Android/Linux/Mac this message also transports the file descriptor for
+ // the shared memory buffer (not a proto field).
+ message SetupTracing {
+ optional uint32 shared_buffer_page_size_kb = 1;
+
+ // On Windows, instead, we pass the name (an unguessable token) of a shared
+ // memory region that can be attached by the other process by name.
+ // Introduced in v13.
+ optional string shm_key_windows = 2;
+ }
message Flush {
// The instance id (i.e. StartDataSource.new_instance_id) of the data
diff --git a/protos/perfetto/trace/BUILD.gn b/protos/perfetto/trace/BUILD.gn
index ed7b6ae..a807061 100644
--- a/protos/perfetto/trace/BUILD.gn
+++ b/protos/perfetto/trace/BUILD.gn
@@ -76,6 +76,7 @@
"cpp",
"lite",
"zero",
+ "source_set",
]
deps = [
":minimal_@TYPE@",
@@ -109,12 +110,11 @@
sources = [ "perfetto_trace.proto" ]
}
-if (perfetto_build_standalone) {
- perfetto_proto_library("descriptor") {
- proto_generators = [ "descriptor" ]
- generate_descriptor = "trace.descriptor"
- sources = [ "trace.proto" ]
- }
+perfetto_proto_library("descriptor") {
+ proto_generators = [ "descriptor" ]
+ generate_descriptor = "trace.descriptor"
+ sources = [ "trace.proto" ]
+ deps = [ ":non_minimal_source_set" ]
}
# This target exports perfetto trace protos allowing both host and device
diff --git a/protos/perfetto/trace/ftrace/BUILD.gn b/protos/perfetto/trace/ftrace/BUILD.gn
index 5684450..7edf7fe 100644
--- a/protos/perfetto/trace/ftrace/BUILD.gn
+++ b/protos/perfetto/trace/ftrace/BUILD.gn
@@ -21,6 +21,7 @@
"cpp",
"zero",
"lite",
+ "source_set",
]
sources = ftrace_proto_names
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 57f945c..7fe24f3 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -197,6 +197,12 @@
// Unix uid of the remote process.
optional int32 uid = 3;
+
+ // The version of the client library used by the producer.
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string sdk_version = 4;
}
// Describes a data source registered by a producer. Data sources are listed
@@ -220,6 +226,12 @@
// Number of tracing sessions in the started state. Always <= num_sessions.
optional int32 num_sessions_started = 4;
+
+ // The version of traced (the same returned by `traced --version`).
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string tracing_service_version = 5;
}
// End of protos/perfetto/common/tracing_service_state.proto
@@ -8326,6 +8338,12 @@
// Ticks per second - sysconf(_SC_CLK_TCK).
optional int64 hz = 3;
+
+ // The version of traced (the same returned by `traced --version`).
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string tracing_service_version = 4;
}
// End of protos/perfetto/trace/system_info.proto
diff --git a/protos/perfetto/trace/system_info.proto b/protos/perfetto/trace/system_info.proto
index 90a7a57..ddce4ca 100644
--- a/protos/perfetto/trace/system_info.proto
+++ b/protos/perfetto/trace/system_info.proto
@@ -31,4 +31,10 @@
// Ticks per second - sysconf(_SC_CLK_TCK).
optional int64 hz = 3;
+
+ // The version of traced (the same returned by `traced --version`).
+ // This is a human readable string with and its format varies depending on
+ // the build system and the repo (standalone vs AOSP).
+ // This is intended for human debugging only.
+ optional string tracing_service_version = 4;
}
diff --git a/src/base/getopt_compat.cc b/src/base/getopt_compat.cc
index 19c8adc..0c80dc6 100644
--- a/src/base/getopt_compat.cc
+++ b/src/base/getopt_compat.cc
@@ -30,6 +30,8 @@
char* optarg = nullptr;
int optind = 0;
+int optopt = 0;
+int opterr = 1;
namespace {
@@ -47,7 +49,7 @@
const option* LookupShortOpt(const std::vector<option>& opts, char c) {
for (const option& opt : opts) {
- if (opt.name == nullptr && opt.val == c)
+ if (!*opt.name && opt.val == c)
return &opt;
}
return nullptr;
@@ -78,6 +80,7 @@
}
res->emplace_back();
option& opt = res->back();
+ opt.name = "";
opt.val = c;
opt.has_arg = no_argument;
if (*sopt == ':') {
@@ -108,6 +111,7 @@
return '?';
char* arg = argv[optind];
+ optopt = 0;
if (!nextchar) {
// If |nextchar| is null we are NOT in the middle of a short option and we
@@ -120,11 +124,14 @@
size_t len = sep ? static_cast<size_t>(sep - arg) : strlen(arg);
const option* opt = LookupLongOpt(opts, arg, len);
+
if (!opt) {
- fprintf(stderr, "unrecognized option '--%s'\n", arg);
+ if (opterr)
+ fprintf(stderr, "unrecognized option '--%s'\n", arg);
return '?';
}
+ optopt = opt->val;
if (opt->has_arg == no_argument) {
if (sep) {
fprintf(stderr, "option '--%s' doesn't allow an argument\n", arg);
@@ -137,7 +144,8 @@
optarg = sep + 1;
return opt->val;
} else if (optind >= argc) {
- fprintf(stderr, "option '--%s' requires an argument\n", arg);
+ if (opterr)
+ fprintf(stderr, "option '--%s' requires an argument\n", arg);
return '?';
} else {
optarg = argv[optind++];
@@ -173,8 +181,10 @@
}
const option* opt = LookupShortOpt(opts, cur_char);
+ optopt = cur_char;
if (!opt) {
- fprintf(stderr, "invalid option -- '%c'\n", cur_char);
+ if (opterr)
+ fprintf(stderr, "invalid option -- '%c'\n", cur_char);
return '?';
}
if (opt->has_arg == no_argument) {
@@ -189,7 +199,8 @@
if (!nextchar) {
// Case 1.
if (optind >= argc) {
- fprintf(stderr, "option requires an argument -- '%c'\n", cur_char);
+ if (opterr)
+ fprintf(stderr, "option requires an argument -- '%c'\n", cur_char);
return '?';
} else {
optarg = argv[optind++];
diff --git a/src/base/getopt_compat_unittest.cc b/src/base/getopt_compat_unittest.cc
index a7d4db3..aeeb2ed 100644
--- a/src/base/getopt_compat_unittest.cc
+++ b/src/base/getopt_compat_unittest.cc
@@ -47,6 +47,8 @@
GetoptFn getopt = &getopt_compat::getopt;
GetoptLongFn getopt_long = &getopt_compat::getopt_long;
int& optind = getopt_compat::optind;
+ int& optopt = getopt_compat::optopt;
+ int& opterr = getopt_compat::opterr;
char*& optarg = getopt_compat::optarg;
};
@@ -58,6 +60,8 @@
GetoptFn getopt = &::getopt;
GetoptLongFn getopt_long = &::getopt_long;
int& optind = ::optind;
+ int& optopt = ::optopt;
+ int& opterr = ::opterr;
char*& optarg = ::optarg;
};
#endif
@@ -382,6 +386,33 @@
}
}
+TYPED_TEST(GetoptCompatTest, OpterrHandling) {
+ auto& t = this->impl;
+ t.opterr = 0; // Make errors silent.
+
+ const char* sops = "ab:";
+ this->SetCmdline({"argv0", "-a", "-c", "-b"});
+ EXPECT_EQ(t.getopt(this->argc, this->argv, sops), 'a');
+ EXPECT_EQ(t.optarg, nullptr);
+ EXPECT_EQ(t.getopt(this->argc, this->argv, sops), '?');
+ EXPECT_EQ(t.optopt, 'c');
+ EXPECT_EQ(t.getopt(this->argc, this->argv, sops), '?');
+ EXPECT_EQ(t.optopt, 'b');
+ EXPECT_EQ(t.getopt(this->argc, this->argv, sops), -1);
+
+ using LongOptionType = typename decltype(this->impl)::LongOptionType;
+ LongOptionType lopts[]{
+ {"requires_arg", 1 /*required_argument*/, nullptr, 42},
+ {nullptr, 0, nullptr, 0},
+ };
+ this->SetCmdline({"argv0", "-a", "--unkonwn", "--requires_arg"});
+ EXPECT_EQ(t.getopt_long(this->argc, this->argv, sops, lopts, nullptr), 'a');
+ EXPECT_EQ(t.getopt_long(this->argc, this->argv, sops, lopts, nullptr), '?');
+ EXPECT_EQ(t.getopt_long(this->argc, this->argv, sops, lopts, nullptr), '?');
+ EXPECT_EQ(t.optopt, 42);
+ EXPECT_EQ(t.getopt_long(this->argc, this->argv, sops, lopts, nullptr), -1);
+}
+
} // namespace
} // namespace base
} // namespace perfetto
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index c8f6abc..13cf84a 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -1037,6 +1037,7 @@
printf(" id: %d\n", producer.id());
printf(" name: \"%s\" \n", producer.name().c_str());
printf(" uid: %d \n", producer.uid());
+ printf(" sdk_version: \"%s\" \n", producer.sdk_version().c_str());
printf("}\n");
}
@@ -1048,6 +1049,8 @@
printf(" }\n");
printf("}\n");
}
+ printf("tracing_service_version: \"%s\"\n",
+ svc_state.tracing_service_version().c_str());
printf("num_sessions: %d\n", svc_state.num_sessions());
printf("num_sessions_started: %d\n", svc_state.num_sessions_started());
}
diff --git a/src/profiling/memory/client_api_factory_standalone.cc b/src/profiling/memory/client_api_factory_standalone.cc
index f21ce0d..b49da1f 100644
--- a/src/profiling/memory/client_api_factory_standalone.cc
+++ b/src/profiling/memory/client_api_factory_standalone.cc
@@ -149,6 +149,9 @@
}
});
task_runner.Run();
+ // We currently do not Quit the task_runner, but if we ever do it will be
+ // very hard to debug if we don't exit here.
+ exit(0);
}
// This is called by AHeapProfile_initSession (client_api.cc) to construct a
diff --git a/src/profiling/memory/heapprofd_producer.cc b/src/profiling/memory/heapprofd_producer.cc
index c460426..6a47344 100644
--- a/src/profiling/memory/heapprofd_producer.cc
+++ b/src/profiling/memory/heapprofd_producer.cc
@@ -573,7 +573,7 @@
return;
}
- PERFETTO_DLOG("Stopping data source %" PRIu64, id);
+ PERFETTO_LOG("Stopping data source %" PRIu64, id);
DataSource& data_source = it->second;
data_source.was_stopped = true;
@@ -1211,6 +1211,8 @@
DataSource& ds = p.second;
if (gr.IsOverCpuThreshold(ds.guardrail_config)) {
ds.hit_guardrail = true;
+ PERFETTO_LOG("Data source %" PRIu64 " hit CPU guardrail. Shutting down.",
+ ds.id);
ShutdownDataSource(&ds);
}
}
@@ -1230,6 +1232,9 @@
DataSource& ds = p.second;
if (gr.IsOverMemoryThreshold(ds.guardrail_config)) {
ds.hit_guardrail = true;
+ PERFETTO_LOG("Data source %" PRIu64
+ " hit memory guardrail. Shutting down.",
+ ds.id);
ShutdownDataSource(&ds);
}
}
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index 69d911a..b11a569 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -44,9 +44,22 @@
]
}
+source_set("proto_ring_buffer") {
+ deps = [
+ ":protozero",
+ "../../gn:default_deps",
+ "../base",
+ ]
+ sources = [
+ "proto_ring_buffer.cc",
+ "proto_ring_buffer.h",
+ ]
+}
+
perfetto_unittest_source_set("unittests") {
testonly = true
deps = [
+ ":proto_ring_buffer",
":protozero",
":testing_messages_cpp",
":testing_messages_lite",
@@ -62,6 +75,7 @@
"message_handle_unittest.cc",
"message_unittest.cc",
"proto_decoder_unittest.cc",
+ "proto_ring_buffer_unittest.cc",
"proto_utils_unittest.cc",
"scattered_stream_writer_unittest.cc",
"test/cppgen_conformance_unittest.cc",
diff --git a/src/trace_processor/rpc/proto_ring_buffer.cc b/src/protozero/proto_ring_buffer.cc
similarity index 95%
rename from src/trace_processor/rpc/proto_ring_buffer.cc
rename to src/protozero/proto_ring_buffer.cc
index 3354efe..92fe153 100644
--- a/src/trace_processor/rpc/proto_ring_buffer.cc
+++ b/src/protozero/proto_ring_buffer.cc
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "src/trace_processor/rpc/proto_ring_buffer.h"
+#include "src/protozero/proto_ring_buffer.h"
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/paged_memory.h"
#include "perfetto/protozero/proto_utils.h"
-namespace perfetto {
-namespace trace_processor {
+namespace protozero {
namespace {
constexpr size_t kGrowBytes = 128 * 1024;
@@ -74,7 +73,7 @@
} // namespace
ProtoRingBuffer::ProtoRingBuffer()
- : buf_(base::PagedMemory::Allocate(kGrowBytes)) {}
+ : buf_(perfetto::base::PagedMemory::Allocate(kGrowBytes)) {}
ProtoRingBuffer::~ProtoRingBuffer() = default;
void ProtoRingBuffer::Append(const void* data_void, size_t data_len) {
@@ -137,7 +136,7 @@
failed_ = true;
return;
}
- auto new_buf = base::PagedMemory::Allocate(new_size);
+ auto new_buf = perfetto::base::PagedMemory::Allocate(new_size);
memcpy(new_buf.Get(), buf_.Get(), buf_.size());
buf_ = std::move(new_buf);
avail = new_size - wr_;
@@ -184,5 +183,4 @@
return msg;
}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace protozero
diff --git a/src/trace_processor/rpc/proto_ring_buffer.h b/src/protozero/proto_ring_buffer.h
similarity index 85%
rename from src/trace_processor/rpc/proto_ring_buffer.h
rename to src/protozero/proto_ring_buffer.h
index 62934ca..06ef539 100644
--- a/src/trace_processor/rpc/proto_ring_buffer.h
+++ b/src/protozero/proto_ring_buffer.h
@@ -14,28 +14,28 @@
* limitations under the License.
*/
-#ifndef SRC_TRACE_PROCESSOR_RPC_PROTO_RING_BUFFER_H_
-#define SRC_TRACE_PROCESSOR_RPC_PROTO_RING_BUFFER_H_
+#ifndef SRC_PROTOZERO_PROTO_RING_BUFFER_H_
+#define SRC_PROTOZERO_PROTO_RING_BUFFER_H_
#include <stdint.h>
#include "perfetto/ext/base/paged_memory.h"
-namespace perfetto {
-namespace trace_processor {
+namespace protozero {
-// This class buffers and tokenizes proto messages used for the TraceProcessor
-// RPC interface (See comments in trace_processor.proto).
-// From a logical level, the RPC is a sequence of protos like this.
+// This class buffers and tokenizes proto messages.
+//
+// From a logical level, it works with a sequence of protos like this.
// [ header 1 ] [ payload 1 ]
// [ header 2 ] [ payload 2 ]
// [ header 3 ] [ payload 3 ]
// Where [ header ] is a variable-length sequence of:
// [ Field ID = 1, type = length-delimited] [ length (varint) ].
-// The RPC pipe is byte-oriented, not message-oriented (like a TCP stream).
-// The pipe is not required to respect the boundaries of each message, it only
-// guarantees that data is not lost or duplicated. The following sequence of
-// inbound events is possible:
+//
+// The input to this class is byte-oriented, not message-oriented (like a TCP
+// stream or a pipe). The caller is not required to respect the boundaries of
+// each message; only guarantee that data is not lost or duplicated. The
+// following sequence of inbound events is possible:
// 1. [ hdr 1 (incomplete) ... ]
// 2. [ ... hdr 1 ] [ payload 1 ] [ hdr 2 ] [ payoad 2 ] [ hdr 3 ] [ pay... ]
// 3. [ ...load 3 ]
@@ -126,14 +126,13 @@
size_t avail() const { return buf_.size() - (wr_ - rd_); }
private:
- base::PagedMemory buf_;
+ perfetto::base::PagedMemory buf_;
Message fastpath_{};
bool failed_ = false; // Set in case of an unrecoverable framing faiulre.
size_t rd_ = 0; // Offset of the read cursor in |buf_|.
size_t wr_ = 0; // Offset of the write cursor in |buf_|.
};
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace protozero
-#endif // SRC_TRACE_PROCESSOR_RPC_PROTO_RING_BUFFER_H_
+#endif // SRC_PROTOZERO_PROTO_RING_BUFFER_H_
diff --git a/src/trace_processor/rpc/proto_ring_buffer_unittest.cc b/src/protozero/proto_ring_buffer_unittest.cc
similarity index 95%
rename from src/trace_processor/rpc/proto_ring_buffer_unittest.cc
rename to src/protozero/proto_ring_buffer_unittest.cc
index 0e3944c..263baf3 100644
--- a/src/trace_processor/rpc/proto_ring_buffer_unittest.cc
+++ b/src/protozero/proto_ring_buffer_unittest.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/rpc/proto_ring_buffer.h"
+#include "src/protozero/proto_ring_buffer.h"
#include <stdint.h>
#include <sys/types.h>
@@ -30,8 +30,7 @@
using testing::ElementsAre;
-namespace perfetto {
-namespace trace_processor {
+namespace protozero {
// For ASSERT_EQ()
inline bool operator==(const ProtoRingBuffer::Message& a,
@@ -58,6 +57,8 @@
namespace {
+using ::perfetto::base::ArraySize;
+
constexpr uint32_t kMaxMsgSize = ProtoRingBuffer::kMaxMsgSize;
class ProtoRingBufferTest : public ::testing::Test {
@@ -137,14 +138,14 @@
uint32_t frag_lens[] = {120, 20, 471, 1};
uint32_t frag_sum = 0;
- for (uint32_t i = 0; i < base::ArraySize(frag_lens); i++)
+ for (uint32_t i = 0; i < ArraySize(frag_lens); i++)
frag_sum += frag_lens[i];
ASSERT_EQ(frag_sum, last_msg_.size());
// Append the messages in such a way that each appen either passes a portion
// of a message (the 20 ones) or more than a message.
uint32_t written = 0;
- for (uint32_t i = 0; i < base::ArraySize(frag_lens); i++) {
+ for (uint32_t i = 0; i < ArraySize(frag_lens); i++) {
buf.Append(&last_msg_[written], frag_lens[i]);
written += frag_lens[i];
for (;;) {
@@ -228,5 +229,4 @@
}
} // namespace
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace protozero
diff --git a/src/trace_processor/importers/json/json_trace_parser.cc b/src/trace_processor/importers/json/json_trace_parser.cc
index eabd57d..85de296 100644
--- a/src/trace_processor/importers/json/json_trace_parser.cc
+++ b/src/trace_processor/importers/json/json_trace_parser.cc
@@ -25,6 +25,7 @@
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
#include "perfetto/ext/base/utils.h"
+#include "src/trace_processor/importers/common/event_tracker.h"
#include "src/trace_processor/importers/common/flow_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
#include "src/trace_processor/importers/common/slice_tracker.h"
@@ -148,6 +149,61 @@
MaybeAddFlow(track_id, value);
break;
}
+ case 'C': { // TRACE_EVENT_COUNTER
+ auto args = value["args"];
+ if (!args.isObject()) {
+ context_->storage->IncrementStats(stats::json_parser_failure);
+ break;
+ }
+
+ std::string counter_name_prefix = name.ToStdString();
+ if (value.isMember("id")) {
+ counter_name_prefix += " id: " + value["id"].asString();
+ }
+
+ for (auto it = args.begin(); it != args.end(); ++it) {
+ std::string counter_name = counter_name_prefix + " " + it.name();
+ StringId counter_name_id =
+ context_->storage->InternString(base::StringView(counter_name));
+ TrackId track_id = context_->track_tracker->InternProcessCounterTrack(
+ counter_name_id, utid);
+ context_->event_tracker->PushCounter(timestamp, it->asDouble(),
+ track_id);
+ }
+ break;
+ }
+ case 'i': { // TRACE_EVENT_INSTANT
+ base::StringView scope;
+ if (value.isMember("s")) {
+ scope = value["s"].asCString();
+ }
+
+ TrackId track_id;
+ if (scope == "g") {
+ track_id = context_->track_tracker
+ ->GetOrCreateLegacyChromeGlobalInstantTrack();
+ } else if (scope == "p") {
+ if (!opt_pid) {
+ context_->storage->IncrementStats(stats::json_parser_failure);
+ break;
+ }
+ UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
+ track_id =
+ context_->track_tracker->InternLegacyChromeProcessInstantTrack(
+ upid);
+ } else if (scope == "t" || scope.data() == nullptr) {
+ if (!opt_tid) {
+ context_->storage->IncrementStats(stats::json_parser_failure);
+ break;
+ }
+ track_id = context_->track_tracker->InternThreadTrack(utid);
+ } else {
+ context_->storage->IncrementStats(stats::json_parser_failure);
+ break;
+ }
+ context_->slice_tracker->Scoped(timestamp, track_id, cat_id, name_id, 0);
+ break;
+ }
case 's': { // TRACE_EVENT_FLOW_START
TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
auto opt_source_id =
diff --git a/src/trace_processor/metrics/metrics.cc b/src/trace_processor/metrics/metrics.cc
index fe2492c..4f34d3c 100644
--- a/src/trace_processor/metrics/metrics.cc
+++ b/src/trace_processor/metrics/metrics.cc
@@ -71,8 +71,9 @@
} // namespace
-ProtoBuilder::ProtoBuilder(const ProtoDescriptor* descriptor)
- : descriptor_(descriptor) {}
+ProtoBuilder::ProtoBuilder(const DescriptorPool* pool,
+ const ProtoDescriptor* descriptor)
+ : pool_(pool), descriptor_(descriptor) {}
util::Status ProtoBuilder::AppendSqlValue(const std::string& field_name,
const SqlValue& value) {
@@ -117,9 +118,32 @@
case FieldDescriptorProto::TYPE_INT64:
case FieldDescriptorProto::TYPE_UINT32:
case FieldDescriptorProto::TYPE_BOOL:
- case FieldDescriptorProto::TYPE_ENUM:
message_->AppendVarInt(field->number(), value);
break;
+ case FieldDescriptorProto::TYPE_ENUM: {
+ auto opt_enum_descriptor_idx =
+ pool_->FindDescriptorIdx(field->resolved_type_name());
+ if (!opt_enum_descriptor_idx) {
+ return util::ErrStatus(
+ "Unable to find enum type %s to fill field %s (in proto message "
+ "%s)",
+ field->resolved_type_name().c_str(), field->name().c_str(),
+ descriptor_->full_name().c_str());
+ }
+ const auto& enum_desc = pool_->descriptors()[*opt_enum_descriptor_idx];
+ auto opt_enum_str = enum_desc.FindEnumString(static_cast<int32_t>(value));
+ if (!opt_enum_str) {
+ return util::ErrStatus("Invalid enum value %" PRId64
+ " "
+ "in enum type %s; encountered while filling "
+ "field %s (in proto message %s)",
+ value, field->resolved_type_name().c_str(),
+ field->name().c_str(),
+ descriptor_->full_name().c_str());
+ }
+ message_->AppendVarInt(field->number(), value);
+ break;
+ }
case FieldDescriptorProto::TYPE_SINT32:
case FieldDescriptorProto::TYPE_SINT64:
message_->AppendSignedVarInt(field->number(), value);
@@ -207,6 +231,30 @@
message_->AppendBytes(field->number(), data.data(), data.size());
break;
}
+ case FieldDescriptorProto::TYPE_ENUM: {
+ auto opt_enum_descriptor_idx =
+ pool_->FindDescriptorIdx(field->resolved_type_name());
+ if (!opt_enum_descriptor_idx) {
+ return util::ErrStatus(
+ "Unable to find enum type %s to fill field %s (in proto message "
+ "%s)",
+ field->resolved_type_name().c_str(), field->name().c_str(),
+ descriptor_->full_name().c_str());
+ }
+ const auto& enum_desc = pool_->descriptors()[*opt_enum_descriptor_idx];
+ std::string enum_str = data.ToStdString();
+ auto opt_enum_value = enum_desc.FindEnumValue(enum_str);
+ if (!opt_enum_value) {
+ return util::ErrStatus(
+ "Invalid enum string %s "
+ "in enum type %s; encountered while filling "
+ "field %s (in proto message %s)",
+ enum_str.c_str(), field->resolved_type_name().c_str(),
+ field->name().c_str(), descriptor_->full_name().c_str());
+ }
+ message_->AppendVarInt(field->number(), *opt_enum_value);
+ break;
+ }
default: {
return util::ErrStatus(
"Tried to write value of type string into field %s (in proto type "
@@ -546,7 +594,7 @@
return;
}
- ProtoBuilder builder(fn_ctx->desc);
+ ProtoBuilder builder(fn_ctx->pool, fn_ctx->desc);
for (int i = 0; i < argc; i += 2) {
if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) {
sqlite3_result_error(ctx, "BuildProto: Invalid args", -1);
@@ -637,9 +685,10 @@
util::Status ComputeMetrics(TraceProcessor* tp,
const std::vector<std::string> metrics_to_compute,
const std::vector<SqlMetricFile>& sql_metrics,
+ const DescriptorPool& pool,
const ProtoDescriptor& root_descriptor,
std::vector<uint8_t>* metrics_proto) {
- ProtoBuilder metric_builder(&root_descriptor);
+ ProtoBuilder metric_builder(&pool, &root_descriptor);
for (const auto& name : metrics_to_compute) {
auto metric_it =
std::find_if(sql_metrics.begin(), sql_metrics.end(),
diff --git a/src/trace_processor/metrics/metrics.h b/src/trace_processor/metrics/metrics.h
index dea62f7..b999225 100644
--- a/src/trace_processor/metrics/metrics.h
+++ b/src/trace_processor/metrics/metrics.h
@@ -61,7 +61,7 @@
// Visible for testing.
class ProtoBuilder {
public:
- ProtoBuilder(const ProtoDescriptor*);
+ ProtoBuilder(const DescriptorPool*, const ProtoDescriptor*);
util::Status AppendSqlValue(const std::string& field_name,
const SqlValue& value);
@@ -106,6 +106,7 @@
const uint8_t* ptr,
size_t size);
+ const DescriptorPool* pool_ = nullptr;
const ProtoDescriptor* descriptor_ = nullptr;
protozero::HeapBuffered<protozero::Message> message_;
};
@@ -176,6 +177,7 @@
util::Status ComputeMetrics(TraceProcessor* impl,
const std::vector<std::string> metrics_to_compute,
const std::vector<SqlMetricFile>& metrics,
+ const DescriptorPool& pool,
const ProtoDescriptor& root_descriptor,
std::vector<uint8_t>* metrics_proto);
diff --git a/src/trace_processor/metrics/metrics_unittest.cc b/src/trace_processor/metrics/metrics_unittest.cc
index 661df33..29f8f6d 100644
--- a/src/trace_processor/metrics/metrics_unittest.cc
+++ b/src/trace_processor/metrics/metrics_unittest.cc
@@ -74,13 +74,14 @@
// message TestProto {
// optional int64 int_value = 1;
// }
+ DescriptorPool pool;
ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
".perfetto.protos.TestProto",
ProtoDescriptor::Type::kMessage, base::nullopt);
descriptor.AddField(FieldDescriptor(
"int_value", 1, FieldDescriptorProto::TYPE_INT64, "", false));
- ProtoBuilder builder(&descriptor);
+ ProtoBuilder builder(&pool, &descriptor);
ASSERT_TRUE(builder.AppendLong("int_value", 12345).ok());
auto result_ser = builder.SerializeToProtoBuilderResult();
@@ -96,13 +97,14 @@
// message TestProto {
// optional double double_value = 1;
// }
+ DescriptorPool pool;
ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
".perfetto.protos.TestProto",
ProtoDescriptor::Type::kMessage, base::nullopt);
descriptor.AddField(FieldDescriptor(
"double_value", 1, FieldDescriptorProto::TYPE_DOUBLE, "", false));
- ProtoBuilder builder(&descriptor);
+ ProtoBuilder builder(&pool, &descriptor);
ASSERT_TRUE(builder.AppendDouble("double_value", 1.2345).ok());
auto result_ser = builder.SerializeToProtoBuilderResult();
@@ -118,13 +120,14 @@
// message TestProto {
// optional string string_value = 1;
// }
+ DescriptorPool pool;
ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
".perfetto.protos.TestProto",
ProtoDescriptor::Type::kMessage, base::nullopt);
descriptor.AddField(FieldDescriptor(
"string_value", 1, FieldDescriptorProto::TYPE_STRING, "", false));
- ProtoBuilder builder(&descriptor);
+ ProtoBuilder builder(&pool, &descriptor);
ASSERT_TRUE(builder.AppendString("string_value", "hello world!").ok());
auto result_ser = builder.SerializeToProtoBuilderResult();
@@ -143,6 +146,7 @@
// }
// optional NestedProto nested_value = 1;
// }
+ DescriptorPool pool;
ProtoDescriptor nested("file.proto", ".perfetto.protos",
".perfetto.protos.TestProto.NestedProto",
ProtoDescriptor::Type::kMessage, base::nullopt);
@@ -158,12 +162,12 @@
field.set_resolved_type_name(".perfetto.protos.TestProto.NestedProto");
descriptor.AddField(field);
- ProtoBuilder nest_builder(&nested);
+ ProtoBuilder nest_builder(&pool, &nested);
ASSERT_TRUE(nest_builder.AppendLong("nested_int_value", 789).ok());
auto nest_ser = nest_builder.SerializeToProtoBuilderResult();
- ProtoBuilder builder(&descriptor);
+ ProtoBuilder builder(&pool, &descriptor);
ASSERT_TRUE(
builder.AppendBytes("nested_value", nest_ser.data(), nest_ser.size())
.ok());
@@ -190,6 +194,7 @@
// message TestProto {
// repeated int64 int_value = 1;
// }
+ DescriptorPool pool;
ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
".perfetto.protos.TestProto",
ProtoDescriptor::Type::kMessage, base::nullopt);
@@ -202,7 +207,7 @@
std::vector<uint8_t> rep_ser = rep_builder.SerializeToProtoBuilderResult();
- ProtoBuilder builder(&descriptor);
+ ProtoBuilder builder(&pool, &descriptor);
ASSERT_TRUE(
builder.AppendBytes("rep_int_value", rep_ser.data(), rep_ser.size())
.ok());
@@ -215,6 +220,55 @@
ASSERT_FALSE(++it);
}
+TEST_F(ProtoBuilderTest, AppendEnums) {
+ using FieldDescriptorProto = protos::pbzero::FieldDescriptorProto;
+
+ // Create the descriptor version of the following enum and message:
+ // enum TestEnum {
+ // FIRST = 1,
+ // SECOND = 2,
+ // THIRD = 3
+ // }
+ // message TestMessage {
+ // optional TestEnum enum_value = 1;
+ // }
+ DescriptorPool pool;
+ ProtoDescriptor enum_descriptor("file.proto", ".perfetto.protos",
+ ".perfetto.protos.TestEnum",
+ ProtoDescriptor::Type::kEnum, base::nullopt);
+ enum_descriptor.AddEnumValue(1, "FIRST");
+ enum_descriptor.AddEnumValue(2, "SECOND");
+ enum_descriptor.AddEnumValue(3, "THIRD");
+ pool.AddProtoDescriptorForTesting(enum_descriptor);
+
+ ProtoDescriptor descriptor("file.proto", ".perfetto.protos",
+ ".perfetto.protos.TestMessage",
+ ProtoDescriptor::Type::kMessage, base::nullopt);
+ FieldDescriptor enum_field("enum_value", 1, FieldDescriptorProto::TYPE_ENUM,
+ ".perfetto.protos.TestEnum", false);
+ enum_field.set_resolved_type_name(".perfetto.protos.TestEnum");
+ descriptor.AddField(enum_field);
+ pool.AddProtoDescriptorForTesting(descriptor);
+
+ ProtoBuilder value_builder(&pool, &descriptor);
+ ASSERT_FALSE(value_builder.AppendLong("enum_value", 4).ok());
+ ASSERT_TRUE(value_builder.AppendLong("enum_value", 3).ok());
+ ASSERT_FALSE(value_builder.AppendLong("enum_value", 6).ok());
+
+ auto value_proto = DecodeSingleFieldProto<false>(
+ value_builder.SerializeToProtoBuilderResult());
+ ASSERT_EQ(value_proto.Get(1).as_int32(), 3);
+
+ ProtoBuilder str_builder(&pool, &descriptor);
+ ASSERT_FALSE(str_builder.AppendString("enum_value", "FOURTH").ok());
+ ASSERT_TRUE(str_builder.AppendString("enum_value", "SECOND").ok());
+ ASSERT_FALSE(str_builder.AppendString("enum_value", "OTHER").ok());
+
+ auto str_proto = DecodeSingleFieldProto<false>(
+ str_builder.SerializeToProtoBuilderResult());
+ ASSERT_EQ(str_proto.Get(1).as_int32(), 2);
+}
+
} // namespace
} // namespace metrics
diff --git a/src/trace_processor/metrics/trace_stats.sql b/src/trace_processor/metrics/trace_stats.sql
index f647442..702fc91 100644
--- a/src/trace_processor/metrics/trace_stats.sql
+++ b/src/trace_processor/metrics/trace_stats.sql
@@ -22,16 +22,16 @@
'name', name,
'idx', idx,
'count', value,
- -- TraceAnalysisStats.Source enum:
'source', CASE source
- WHEN 'trace' THEN 1
- WHEN 'analysis' THEN 2
+ WHEN 'trace' THEN 'SOURCE_TRACE'
+ WHEN 'analysis' THEN 'SOURCE_ANALYSIS'
+ ELSE 'SOURCE_UNKNOWN'
END,
- -- TraceAnalysisStats.Severity enum:
'severity', CASE severity
- WHEN 'info' THEN 1
- WHEN 'data_loss' THEN 2
- WHEN 'error' THEN 3
+ WHEN 'info' THEN 'SEVERITY_INFO'
+ WHEN 'data_loss' THEN 'SEVERITY_DATA_LOSS'
+ WHEN 'error' THEN 'SEVERITY_ERROR'
+ ELSE 'SEVERITY_UNKNOWN'
END
))
FROM stats ORDER BY name ASC
diff --git a/src/trace_processor/rpc/BUILD.gn b/src/trace_processor/rpc/BUILD.gn
index 63cc752..09b9061 100644
--- a/src/trace_processor/rpc/BUILD.gn
+++ b/src/trace_processor/rpc/BUILD.gn
@@ -23,8 +23,6 @@
# interface) and by the :httpd module for the HTTP interface.
source_set("rpc") {
sources = [
- "proto_ring_buffer.cc",
- "proto_ring_buffer.h",
"query_result_serializer.cc",
"query_result_serializer.h",
"rpc.cc",
@@ -38,15 +36,13 @@
"../../../protos/perfetto/trace_processor:zero",
"../../base",
"../../protozero",
+ "../../protozero:proto_ring_buffer",
]
}
perfetto_unittest_source_set("unittests") {
testonly = true
- sources = [
- "proto_ring_buffer_unittest.cc",
- "query_result_serializer_unittest.cc",
- ]
+ sources = [ "query_result_serializer_unittest.cc" ]
deps = [
":rpc",
"..:lib",
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 68def35..5418f55 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -1033,7 +1033,7 @@
return util::Status("Root metrics proto descriptor not found");
const auto& root_descriptor = pool_.descriptors()[opt_idx.value()];
- return metrics::ComputeMetrics(this, metric_names, sql_metrics_,
+ return metrics::ComputeMetrics(this, metric_names, sql_metrics_, pool_,
root_descriptor, metrics_proto);
}
diff --git a/src/trace_processor/trace_sorter.cc b/src/trace_processor/trace_sorter.cc
index 760bf75..c1bc9e5 100644
--- a/src/trace_processor/trace_sorter.cc
+++ b/src/trace_processor/trace_sorter.cc
@@ -185,13 +185,14 @@
if (PERFETTO_UNLIKELY(bypass_next_stage_for_testing_))
return;
+ int64_t timestamp = ttp.timestamp;
if (queue_idx == 0) {
// queues_[0] is for non-ftrace packets.
- parser_->ParseTracePacket(ttp.timestamp, std::move(ttp));
+ parser_->ParseTracePacket(timestamp, std::move(ttp));
} else {
// Ftrace queues start at offset 1. So queues_[1] = cpu[0] and so on.
uint32_t cpu = static_cast<uint32_t>(queue_idx - 1);
- parser_->ParseFtracePacket(cpu, ttp.timestamp, std::move(ttp));
+ parser_->ParseFtracePacket(cpu, timestamp, std::move(ttp));
}
}
diff --git a/src/trace_processor/trace_sorter.h b/src/trace_processor/trace_sorter.h
index abcf01a..a93cd26 100644
--- a/src/trace_processor/trace_sorter.h
+++ b/src/trace_processor/trace_sorter.h
@@ -91,8 +91,10 @@
inline void PushSystraceLine(std::unique_ptr<SystraceLine> systrace_line) {
DCHECK_ftrace_batch_cpu(kNoBatch);
+
+ int64_t timestamp = systrace_line->ts;
AppendNonFtraceAndMaybeExtractEvents(TimestampedTracePiece(
- systrace_line->ts, packet_idx_++, std::move(systrace_line)));
+ timestamp, packet_idx_++, std::move(systrace_line)));
}
inline void PushTrackEventPacket(int64_t timestamp,
@@ -115,20 +117,20 @@
// global ordering and doing that in batches only after all ftrace events
// for a bundle are pushed.
}
-
- // As with |PushFtraceEvent|, doesn't immediately sort the affected queues.
- // TODO(rsavitski): if a trace has a mix of normal & "compact" events (being
- // pushed through this function), the ftrace batches will no longer be fully
- // sorted by timestamp. In such situations, we will have to sort at the end of
- // the batch. We can do better as both sub-sequences are sorted however.
- // Consider adding extra queues, or pushing them in a merge-sort fashion
- // instead.
inline void PushInlineFtraceEvent(uint32_t cpu,
int64_t timestamp,
InlineSchedSwitch inline_sched_switch) {
set_ftrace_batch_cpu_for_DCHECK(cpu);
GetQueue(cpu + 1)->Append(
TimestampedTracePiece(timestamp, packet_idx_++, inline_sched_switch));
+
+ // As with |PushFtraceEvent|, doesn't immediately sort the affected queues.
+ // TODO(rsavitski): if a trace has a mix of normal & "compact" events (being
+ // pushed through this function), the ftrace batches will no longer be fully
+ // sorted by timestamp. In such situations, we will have to sort at the end
+ // of the batch. We can do better as both sub-sequences are sorted however.
+ // Consider adding extra queues, or pushing them in a merge-sort fashion
+ // instead.
}
inline void PushInlineFtraceEvent(uint32_t cpu,
int64_t timestamp,
diff --git a/src/trace_processor/util/descriptors.cc b/src/trace_processor/util/descriptors.cc
index b5b00e1..068da6f 100644
--- a/src/trace_processor/util/descriptors.cc
+++ b/src/trace_processor/util/descriptors.cc
@@ -148,8 +148,8 @@
auto idx = static_cast<uint32_t>(descriptors_.size()) - 1;
for (auto it = decoder.enum_type(); it; ++it) {
- AddEnumProtoDescriptors(file_name, package_name, idx, *it,
- merge_existing_messages);
+ RETURN_IF_ERROR(AddEnumProtoDescriptors(file_name, package_name, idx, *it,
+ merge_existing_messages));
}
for (auto it = decoder.nested_type(); it; ++it) {
RETURN_IF_ERROR(AddNestedProtoDescriptors(file_name, package_name, idx, *it,
@@ -229,8 +229,9 @@
merge_existing_messages));
}
for (auto enum_it = file.enum_type(); enum_it; ++enum_it) {
- AddEnumProtoDescriptors(file_name, package, base::nullopt, *enum_it,
- merge_existing_messages);
+ RETURN_IF_ERROR(AddEnumProtoDescriptors(file_name, package, base::nullopt,
+ *enum_it,
+ merge_existing_messages));
}
for (auto ext_it = file.extension(); ext_it; ++ext_it) {
extensions.emplace_back(package, *ext_it);
diff --git a/src/trace_processor/util/descriptors.h b/src/trace_processor/util/descriptors.h
index 7108781..a5c7cde 100644
--- a/src/trace_processor/util/descriptors.h
+++ b/src/trace_processor/util/descriptors.h
@@ -87,7 +87,9 @@
void AddEnumValue(int32_t integer_representation,
std::string string_representation) {
PERFETTO_DCHECK(type_ == Type::kEnum);
- enum_values_[integer_representation] = std::move(string_representation);
+ enum_values_by_name_[string_representation] = integer_representation;
+ enum_names_by_value_[integer_representation] =
+ std::move(string_representation);
}
const FieldDescriptor* FindFieldByName(const std::string& name) const {
@@ -114,9 +116,16 @@
base::Optional<std::string> FindEnumString(const int32_t value) const {
PERFETTO_DCHECK(type_ == Type::kEnum);
- auto it = enum_values_.find(value);
- return it == enum_values_.end() ? base::nullopt
- : base::Optional<std::string>(it->second);
+ auto it = enum_names_by_value_.find(value);
+ return it == enum_names_by_value_.end() ? base::nullopt
+ : base::make_optional(it->second);
+ }
+
+ base::Optional<int32_t> FindEnumValue(const std::string& value) const {
+ PERFETTO_DCHECK(type_ == Type::kEnum);
+ auto it = enum_values_by_name_.find(value);
+ return it == enum_values_by_name_.end() ? base::nullopt
+ : base::make_optional(it->second);
}
const std::string& file_name() const { return file_name_; }
@@ -141,7 +150,8 @@
const Type type_;
base::Optional<uint32_t> parent_id_;
std::unordered_map<uint32_t, FieldDescriptor> fields_;
- std::unordered_map<int32_t, std::string> enum_values_;
+ std::unordered_map<int32_t, std::string> enum_names_by_value_;
+ std::unordered_map<std::string, int32_t> enum_values_by_name_;
};
using ExtensionInfo = std::pair<std::string, protozero::ConstBytes>;
@@ -156,12 +166,16 @@
base::Optional<uint32_t> FindDescriptorIdx(
const std::string& full_name) const;
+ std::vector<uint8_t> SerializeAsDescriptorSet();
+
+ void AddProtoDescriptorForTesting(ProtoDescriptor descriptor) {
+ descriptors_.emplace_back(std::move(descriptor));
+ }
+
const std::vector<ProtoDescriptor>& descriptors() const {
return descriptors_;
}
- std::vector<uint8_t> SerializeAsDescriptorSet();
-
private:
base::Status AddNestedProtoDescriptors(const std::string& file_name,
const std::string& package_name,
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index 2440d39..848751e 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -50,14 +50,17 @@
}
}
-# Separate target because the embedder might not want this (e.g. on Windows).
+# Separate target because the embedder might not want this.
source_set("platform_impl") {
deps = [
"../../gn:default_deps",
"../../include/perfetto/tracing",
"../base",
]
- sources = [ "platform_posix.cc" ]
+ sources = [
+ "platform_posix.cc",
+ "platform_windows.cc",
+ ]
}
# Fake platform that allows buiding the client lib on all OSes. You can only use
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index 7084dec..63839b0 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -57,6 +57,7 @@
#include "perfetto/ext/base/metatrace.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/utils.h"
+#include "perfetto/ext/base/version.h"
#include "perfetto/ext/base/watchdog.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/consumer.h"
@@ -332,7 +333,8 @@
bool in_process,
ProducerSMBScrapingMode smb_scraping_mode,
size_t shared_memory_page_size_hint_bytes,
- std::unique_ptr<SharedMemory> shm) {
+ std::unique_ptr<SharedMemory> shm,
+ const std::string& sdk_version) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (lockdown_mode_ && uid != base::GetCurrentUserId()) {
@@ -361,8 +363,8 @@
}
std::unique_ptr<ProducerEndpointImpl> endpoint(new ProducerEndpointImpl(
- id, uid, this, task_runner_, producer, producer_name, in_process,
- smb_scraping_enabled));
+ id, uid, this, task_runner_, producer, producer_name, sdk_version,
+ in_process, smb_scraping_enabled));
auto it_and_inserted = producers_.emplace(id, endpoint.get());
PERFETTO_DCHECK(it_and_inserted.second);
endpoint->shmem_size_hint_bytes_ = shared_memory_size_hint_bytes;
@@ -3039,7 +3041,7 @@
tracing_session->did_emit_system_info = true;
protozero::HeapBuffered<protos::pbzero::TracePacket> packet;
auto* info = packet->set_system_info();
- base::ignore_result(info); // For PERFETTO_OS_WIN.
+ info->set_tracing_service_version(base::GetVersionString());
#if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) && \
!PERFETTO_BUILDFLAG(PERFETTO_OS_NACL)
struct utsname uname_info;
@@ -3479,6 +3481,7 @@
TracingServiceState svc_state;
const auto& sessions = service_->tracing_sessions_;
+ svc_state.set_tracing_service_version(base::GetVersionString());
svc_state.set_num_sessions(static_cast<int>(sessions.size()));
int num_started = 0;
@@ -3490,6 +3493,7 @@
auto* producer = svc_state.add_producers();
producer->set_id(static_cast<int>(kv.first));
producer->set_name(kv.second->name_);
+ producer->set_sdk_version(kv.second->sdk_version_);
producer->set_uid(static_cast<int32_t>(producer->uid()));
}
@@ -3547,6 +3551,7 @@
base::TaskRunner* task_runner,
Producer* producer,
const std::string& producer_name,
+ const std::string& sdk_version,
bool in_process,
bool smb_scraping_enabled)
: id_(id),
@@ -3555,6 +3560,7 @@
task_runner_(task_runner),
producer_(producer),
name_(producer_name),
+ sdk_version_(sdk_version),
in_process_(in_process),
smb_scraping_enabled_(smb_scraping_enabled),
weak_ptr_factory_(this) {}
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index 27b172c..401aaa1 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -87,6 +87,7 @@
base::TaskRunner*,
Producer*,
const std::string& producer_name,
+ const std::string& sdk_version,
bool in_process,
bool smb_scraping_enabled);
~ProducerEndpointImpl() override;
@@ -154,6 +155,7 @@
size_t shmem_page_size_hint_bytes_ = 0;
bool is_shmem_provided_by_producer_ = false;
const std::string name_;
+ std::string sdk_version_;
bool in_process_;
bool smb_scraping_enabled_;
@@ -291,7 +293,8 @@
ProducerSMBScrapingMode smb_scraping_mode =
ProducerSMBScrapingMode::kDefault,
size_t shared_memory_page_size_hint_bytes = 0,
- std::unique_ptr<SharedMemory> shm = nullptr) override;
+ std::unique_ptr<SharedMemory> shm = nullptr,
+ const std::string& sdk_version = {}) override;
std::unique_ptr<TracingService::ConsumerEndpoint> ConnectConsumer(
Consumer*,
diff --git a/src/tracing/ipc/BUILD.gn b/src/tracing/ipc/BUILD.gn
index 93c97a6..f86aeb5 100644
--- a/src/tracing/ipc/BUILD.gn
+++ b/src/tracing/ipc/BUILD.gn
@@ -32,6 +32,8 @@
"memfd.h",
"posix_shared_memory.cc",
"posix_shared_memory.h",
+ "shared_memory_windows.cc",
+ "shared_memory_windows.h",
]
deps = [
"../../../gn:default_deps",
diff --git a/src/tracing/ipc/default_socket.cc b/src/tracing/ipc/default_socket.cc
index 3ad5cee..42b47e7 100644
--- a/src/tracing/ipc/default_socket.cc
+++ b/src/tracing/ipc/default_socket.cc
@@ -23,19 +23,22 @@
#include "perfetto/ext/tracing/core/basic_types.h"
#include <stdlib.h>
-#include <unistd.h>
-namespace perfetto {
-#if !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-// On non-Android platforms, check /run/perfetto/ before using /tmp/ as the
-// socket base directory.
-namespace {
-const char* kRunPerfettoBaseDir = "/run/perfetto/";
-
-bool UseRunPerfettoBaseDir() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <unistd.h>
+#endif
+
+namespace perfetto {
+namespace {
+
+const char* kRunPerfettoBaseDir = "/run/perfetto/";
+
+// On Linux and CrOS, check /run/perfetto/ before using /tmp/ as the socket
+// base directory.
+bool UseRunPerfettoBaseDir() {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX)
// Note that the trailing / in |kRunPerfettoBaseDir| ensures we are checking
// against a directory, not a file.
int res = PERFETTO_EINTR(access(kRunPerfettoBaseDir, X_OK));
@@ -50,12 +53,12 @@
}
return false;
#else
+ base::ignore_result(kRunPerfettoBaseDir);
return false;
#endif
}
} // anonymous namespace
-#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
static_assert(kInvalidUid == ipc::kInvalidUid, "kInvalidUid mismatching");
@@ -74,6 +77,7 @@
name = producer_socket;
#endif
}
+ base::ignore_result(UseRunPerfettoBaseDir); // Silence unused func warnings.
return name;
}
diff --git a/src/tracing/ipc/producer/producer_ipc_client_impl.cc b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
index 64b1023..97b622c 100644
--- a/src/tracing/ipc/producer/producer_ipc_client_impl.cc
+++ b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
@@ -21,6 +21,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/base/task_runner.h"
+#include "perfetto/ext/base/version.h"
#include "perfetto/ext/ipc/client.h"
#include "perfetto/ext/tracing/core/commit_data_request.h"
#include "perfetto/ext/tracing/core/producer.h"
@@ -29,7 +30,12 @@
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
#include "perfetto/tracing/core/trace_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include "src/tracing/ipc/shared_memory_windows.h"
+#else
#include "src/tracing/ipc/posix_shared_memory.h"
+#endif
// TODO(fmayer): think to what happens when ProducerIPCClientImpl gets destroyed
// w.r.t. the Producer pointer. Also think to lifetime of the Producer* during
@@ -158,8 +164,13 @@
int shm_fd = -1;
if (shared_memory_) {
- shm_fd = static_cast<PosixSharedMemory*>(shared_memory_.get())->fd();
req.set_producer_provided_shmem(true);
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ auto key = static_cast<SharedMemoryWindows*>(shared_memory_.get())->key();
+ req.set_shm_key_windows(key);
+#else
+ shm_fd = static_cast<PosixSharedMemory*>(shared_memory_.get())->fd();
+#endif
}
#if PERFETTO_DCHECK_IS_ON()
@@ -169,6 +180,7 @@
req.set_build_flags(
protos::gen::InitializeConnectionRequest::BUILD_FLAGS_DCHECKS_OFF);
#endif
+ req.set_sdk_version(base::GetVersionString());
producer_port_.InitializeConnection(req, std::move(on_init), shm_fd);
// Create the back channel to receive commands from the Service.
@@ -253,15 +265,25 @@
}
if (cmd.has_setup_tracing()) {
+ std::unique_ptr<SharedMemory> ipc_shared_memory;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ const std::string& shm_key = cmd.setup_tracing().shm_key_windows();
+ if (!shm_key.empty())
+ ipc_shared_memory = SharedMemoryWindows::Attach(shm_key);
+#else
base::ScopedFile shmem_fd = ipc_channel_->TakeReceivedFD();
if (shmem_fd) {
+ // TODO(primiano): handle mmap failure in case of OOM.
+ ipc_shared_memory =
+ PosixSharedMemory::AttachToFd(std::move(shmem_fd),
+ /*require_seals_if_supported=*/false);
+ }
+#endif
+ if (ipc_shared_memory) {
// This is the nominal case used in most configurations, where the service
// provides the SMB.
PERFETTO_CHECK(!is_shmem_provided_by_producer_ && !shared_memory_);
- // TODO(primiano): handle mmap failure in case of OOM.
- shared_memory_ =
- PosixSharedMemory::AttachToFd(std::move(shmem_fd),
- /*require_seals_if_supported=*/false);
+ shared_memory_ = std::move(ipc_shared_memory);
shared_buffer_page_size_kb_ =
cmd.setup_tracing().shared_buffer_page_size_kb();
shared_memory_arbiter_ = SharedMemoryArbiter::CreateInstance(
diff --git a/src/tracing/ipc/service/producer_ipc_service.cc b/src/tracing/ipc/service/producer_ipc_service.cc
index cfa79b1..71abd8c 100644
--- a/src/tracing/ipc/service/producer_ipc_service.cc
+++ b/src/tracing/ipc/service/producer_ipc_service.cc
@@ -26,7 +26,12 @@
#include "perfetto/ext/tracing/core/tracing_service.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include "src/tracing/ipc/shared_memory_windows.h"
+#else
#include "src/tracing/ipc/posix_shared_memory.h"
+#endif
// The remote Producer(s) are not trusted. All the methods from the ProducerPort
// IPC layer (e.g. RegisterDataSource()) must assume that the remote Producer is
@@ -93,7 +98,18 @@
// If the producer provided an SMB, tell the service to attempt to adopt it.
std::unique_ptr<SharedMemory> shmem;
if (req.producer_provided_shmem()) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ if (!req.has_shm_key_windows() || req.shm_key_windows().empty()) {
+ PERFETTO_ELOG(
+ "shm_key_windows must be non-empty when "
+ "producer_provided_shmem = true");
+ } else {
+ shmem = SharedMemoryWindows::Attach(req.shm_key_windows());
+ // Attach() does error logging if something fails, no need to extra ELOGs.
+ }
+#else
base::ScopedFile shmem_fd = ipc::Service::TakeReceivedFD();
+
if (shmem_fd) {
shmem = PosixSharedMemory::AttachToFd(
std::move(shmem_fd), /*require_seals_if_supported=*/true);
@@ -107,6 +123,7 @@
"InitializeConnectionRequest's producer_provided_shmem flag is set "
"but the producer didn't provide an FD");
}
+#endif
}
// ConnectProducer will call OnConnect() on the next task.
@@ -114,7 +131,8 @@
producer.get(), client_info.uid(), req.producer_name(),
req.shared_memory_size_hint_bytes(),
/*in_process=*/false, smb_scraping_mode,
- req.shared_memory_page_size_hint_bytes(), std::move(shmem));
+ req.shared_memory_page_size_hint_bytes(), std::move(shmem),
+ req.sdk_version());
// Could happen if the service has too many producers connected.
if (!producer->service_endpoint) {
@@ -455,10 +473,17 @@
// Nominal case (% Chrome): service provides SMB.
setup_tracing->set_shared_buffer_page_size_kb(
static_cast<uint32_t>(service_endpoint->shared_buffer_page_size_kb()));
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ const std::string& shm_key =
+ static_cast<SharedMemoryWindows*>(service_endpoint->shared_memory())
+ ->key();
+ setup_tracing->set_shm_key_windows(shm_key);
+#else
const int shm_fd =
static_cast<PosixSharedMemory*>(service_endpoint->shared_memory())
->fd();
cmd.set_fd(shm_fd);
+#endif
}
async_producer_commands.Resolve(std::move(cmd));
}
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.cc b/src/tracing/ipc/service/service_ipc_host_impl.cc
index d19fef6..5618b3c 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.cc
+++ b/src/tracing/ipc/service/service_ipc_host_impl.cc
@@ -20,10 +20,15 @@
#include "perfetto/base/task_runner.h"
#include "perfetto/ext/ipc/host.h"
#include "perfetto/ext/tracing/core/tracing_service.h"
-#include "src/tracing/ipc/posix_shared_memory.h"
#include "src/tracing/ipc/service/consumer_ipc_service.h"
#include "src/tracing/ipc/service/producer_ipc_service.h"
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include "src/tracing/ipc/shared_memory_windows.h"
+#else
+#include "src/tracing/ipc/posix_shared_memory.h"
+#endif
+
namespace perfetto {
// TODO(fmayer): implement per-uid connection limit (b/69093705).
@@ -66,8 +71,13 @@
bool ServiceIPCHostImpl::DoStart() {
// Create and initialize the platform-independent tracing business logic.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ std::unique_ptr<SharedMemory::Factory> shm_factory(
+ new SharedMemoryWindows::Factory());
+#else
std::unique_ptr<SharedMemory::Factory> shm_factory(
new PosixSharedMemory::Factory());
+#endif
svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_);
if (!producer_ipc_port_ || !consumer_ipc_port_) {
diff --git a/src/tracing/ipc/shared_memory_windows.cc b/src/tracing/ipc/shared_memory_windows.cc
new file mode 100644
index 0000000..579d810
--- /dev/null
+++ b/src/tracing/ipc/shared_memory_windows.cc
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/tracing/ipc/shared_memory_windows.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include <memory>
+#include <random>
+
+#include <Windows.h>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_utils.h"
+
+namespace perfetto {
+
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Create(size_t size) {
+ base::ScopedPlatformHandle shmem_handle;
+ std::random_device rnd_dev;
+ uint64_t rnd_key = (static_cast<uint64_t>(rnd_dev()) << 32) | rnd_dev();
+ std::string key = "perfetto_shm_" + base::Uint64ToHexStringNoPrefix(rnd_key);
+ shmem_handle.reset(CreateFileMappingA(
+ INVALID_HANDLE_VALUE, // Use paging file.
+ nullptr, // Default security.
+ PAGE_READWRITE,
+ static_cast<DWORD>(size >> 32), // maximum object size (high-order DWORD)
+ static_cast<DWORD>(size), // maximum object size (low-order DWORD)
+ key.c_str()));
+
+ if (!shmem_handle) {
+ PERFETTO_PLOG("CreateFileMapping() call failed");
+ return nullptr;
+ }
+ void* start =
+ MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+ /*offsetLow=*/0, size);
+ if (!start) {
+ PERFETTO_PLOG("MapViewOfFile() failed");
+ return nullptr;
+ }
+
+ return std::unique_ptr<SharedMemoryWindows>(new SharedMemoryWindows(
+ start, size, std::move(key), std::move(shmem_handle)));
+}
+
+// static
+std::unique_ptr<SharedMemoryWindows> SharedMemoryWindows::Attach(
+ const std::string& key) {
+ base::ScopedPlatformHandle shmem_handle;
+ shmem_handle.reset(
+ OpenFileMappingA(FILE_MAP_ALL_ACCESS, /*inherit=*/false, key.c_str()));
+ if (!shmem_handle) {
+ PERFETTO_PLOG("Failed to OpenFileMapping()");
+ return nullptr;
+ }
+
+ void* start =
+ MapViewOfFile(*shmem_handle, FILE_MAP_ALL_ACCESS, /*offsetHigh=*/0,
+ /*offsetLow=*/0, /*dwNumberOfBytesToMap=*/0);
+ if (!start) {
+ PERFETTO_PLOG("MapViewOfFile() failed");
+ return nullptr;
+ }
+
+ MEMORY_BASIC_INFORMATION info{};
+ if (!VirtualQuery(start, &info, sizeof(info))) {
+ PERFETTO_PLOG("VirtualQuery() failed");
+ return nullptr;
+ }
+ size_t size = info.RegionSize;
+ return std::unique_ptr<SharedMemoryWindows>(
+ new SharedMemoryWindows(start, size, key, std::move(shmem_handle)));
+}
+
+SharedMemoryWindows::SharedMemoryWindows(void* start,
+ size_t size,
+ std::string key,
+ base::ScopedPlatformHandle handle)
+ : start_(start),
+ size_(size),
+ key_(std::move(key)),
+ handle_(std::move(handle)) {}
+
+SharedMemoryWindows::~SharedMemoryWindows() {
+ if (start_)
+ UnmapViewOfFile(start_);
+}
+
+SharedMemoryWindows::Factory::~Factory() = default;
+
+std::unique_ptr<SharedMemory> SharedMemoryWindows::Factory::CreateSharedMemory(
+ size_t size) {
+ return SharedMemoryWindows::Create(size);
+}
+
+} // namespace perfetto
+
+#endif // !OS_WIN
diff --git a/src/tracing/ipc/shared_memory_windows.h b/src/tracing/ipc/shared_memory_windows.h
new file mode 100644
index 0000000..803c8a8
--- /dev/null
+++ b/src/tracing/ipc/shared_memory_windows.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+#define SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/tracing/core/shared_memory.h"
+
+namespace perfetto {
+
+// Implements the SharedMemory and its factory for the Windows IPC transport.
+// This used only for standalone builds and NOT in chromium, which instead uses
+// a custom Mojo wrapper (MojoSharedMemory in chromium's //services/tracing/).
+class SharedMemoryWindows : public SharedMemory {
+ public:
+ class Factory : public SharedMemory::Factory {
+ public:
+ ~Factory() override;
+ std::unique_ptr<SharedMemory> CreateSharedMemory(size_t) override;
+ };
+
+ // Create a brand new SHM region.
+ static std::unique_ptr<SharedMemoryWindows> Create(size_t size);
+ static std::unique_ptr<SharedMemoryWindows> Attach(const std::string& key);
+ ~SharedMemoryWindows() override;
+ const std::string& key() const { return key_; }
+
+ // SharedMemory implementation.
+ void* start() const override { return start_; }
+ size_t size() const override { return size_; }
+
+ private:
+ SharedMemoryWindows(void* start,
+ size_t size,
+ std::string,
+ base::ScopedPlatformHandle);
+ SharedMemoryWindows(const SharedMemoryWindows&) = delete;
+ SharedMemoryWindows& operator=(const SharedMemoryWindows&) = delete;
+
+ void* const start_;
+ const size_t size_;
+ std::string key_;
+ base::ScopedPlatformHandle handle_;
+};
+
+} // namespace perfetto
+
+#endif // OS_WIN
+
+#endif // SRC_TRACING_IPC_SHARED_MEMORY_WINDOWS_H_
diff --git a/src/tracing/platform_windows.cc b/src/tracing/platform_windows.cc
new file mode 100644
index 0000000..651812a
--- /dev/null
+++ b/src/tracing/platform_windows.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+
+#include <Windows.h>
+
+#include "perfetto/ext/base/thread_task_runner.h"
+#include "perfetto/tracing/internal/tracing_tls.h"
+#include "perfetto/tracing/platform.h"
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives. So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from chromium's base/threading/thread_local_storage_win.cc
+// which in turn is from http://www.codeproject.com/threads/tls.asp.
+
+#ifdef _WIN64
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:perfetto_thread_callback_base")
+#else
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_perfetto_thread_callback_base")
+#endif
+
+namespace perfetto {
+
+namespace {
+
+class PlatformWindows : public Platform {
+ public:
+ static PlatformWindows* instance;
+ PlatformWindows();
+ ~PlatformWindows() override;
+
+ ThreadLocalObject* GetOrCreateThreadLocalObject() override;
+ std::unique_ptr<base::TaskRunner> CreateTaskRunner(
+ const CreateTaskRunnerArgs&) override;
+ std::string GetCurrentProcessName() override;
+ void OnThreadExit();
+
+ private:
+ DWORD tls_key_{};
+};
+
+using ThreadLocalObject = Platform::ThreadLocalObject;
+
+// static
+PlatformWindows* PlatformWindows::instance = nullptr;
+
+PlatformWindows::PlatformWindows() {
+ instance = this;
+ tls_key_ = ::TlsAlloc();
+ PERFETTO_CHECK(tls_key_ != TLS_OUT_OF_INDEXES);
+}
+
+PlatformWindows::~PlatformWindows() {
+ ::TlsFree(tls_key_);
+ instance = nullptr;
+}
+
+void PlatformWindows::OnThreadExit() {
+ auto tls = static_cast<ThreadLocalObject*>(::TlsGetValue(tls_key_));
+ if (tls) {
+ // At this point we rely on the TLS object to be still set to the TracingTLS
+ // we are deleting. See comments in TracingTLS::~TracingTLS().
+ delete tls;
+ }
+}
+
+ThreadLocalObject* PlatformWindows::GetOrCreateThreadLocalObject() {
+ void* tls_ptr = ::TlsGetValue(tls_key_);
+
+ auto* tls = static_cast<ThreadLocalObject*>(tls_ptr);
+ if (!tls) {
+ tls = ThreadLocalObject::CreateInstance().release();
+ ::TlsSetValue(tls_key_, tls);
+ }
+ return tls;
+}
+
+std::unique_ptr<base::TaskRunner> PlatformWindows::CreateTaskRunner(
+ const CreateTaskRunnerArgs&) {
+ return std::unique_ptr<base::TaskRunner>(
+ new base::ThreadTaskRunner(base::ThreadTaskRunner::CreateAndStart()));
+}
+
+std::string PlatformWindows::GetCurrentProcessName() {
+ char buf[MAX_PATH];
+ auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
+ std::string name(buf, static_cast<size_t>(len));
+ size_t sep = name.find_last_of('\\');
+ if (sep != std::string::npos)
+ name = name.substr(sep + 1);
+ return name;
+}
+
+} // namespace
+
+// static
+Platform* Platform::GetDefaultPlatform() {
+ static PlatformWindows* thread_safe_init_instance = new PlatformWindows();
+ return thread_safe_init_instance;
+}
+
+} // namespace perfetto
+
+// -----------------------
+// Thread-local destructor
+// -----------------------
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// See VC\crt\src\tlssup.c for reference.
+
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard perfetto_thread_callback_base. (We force a
+// reference to this variable with a linker /INCLUDE:symbol pragma to ensure
+// that.) If this variable is discarded, the OnThreadExit function will never be
+// called.
+
+void NTAPI PerfettoOnThreadExit(PVOID, DWORD, PVOID);
+void NTAPI PerfettoOnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+ if (reason == DLL_THREAD_DETACH || reason == DLL_PROCESS_DETACH) {
+ if (perfetto::PlatformWindows::instance)
+ perfetto::PlatformWindows::instance->OnThreadExit();
+ }
+}
+
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLP")
+
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base;
+const PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = PerfettoOnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else // _WIN64
+
+#pragma data_seg(".CRT$XLP")
+PIMAGE_TLS_CALLBACK perfetto_thread_callback_base = OnThreadExit;
+// Reset the default section.
+#pragma data_seg()
+
+#endif // _WIN64
+
+} // extern "C"
+
+#endif // OS_WIN
diff --git a/test/cts/heapprofd_java_test_cts.cc b/test/cts/heapprofd_java_test_cts.cc
index f7cfc1a..a0205f1 100644
--- a/test/cts/heapprofd_java_test_cts.cc
+++ b/test/cts/heapprofd_java_test_cts.cc
@@ -134,5 +134,55 @@
AssertNoProfileContents(packets);
}
+TEST(HeapprofdJavaCtsTest, DebuggableAppRuntimeByPid) {
+ std::string app_name = "android.perfetto.cts.app.debuggable";
+
+ base::TestTaskRunner task_runner;
+
+ // (re)start the target app's main activity
+ if (IsAppRunning(app_name)) {
+ StopApp(app_name, "old.app.stopped", &task_runner);
+ task_runner.RunUntilCheckpoint("old.app.stopped", 1000 /*ms*/);
+ }
+ StartAppActivity(app_name, "MainActivity", "target.app.running", &task_runner,
+ /*delay_ms=*/100);
+ task_runner.RunUntilCheckpoint("target.app.running", 1000 /*ms*/);
+ // If we try to dump too early in app initialization, we sometimes deadlock.
+ sleep(1);
+
+ int target_pid = PidForProcessName(app_name);
+ ASSERT_NE(target_pid, -1);
+
+ // set up tracing
+ TestHelper helper(&task_runner);
+ helper.ConnectConsumer();
+ helper.WaitForConsumerConnect();
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(40 * 1024);
+ trace_config.set_duration_ms(6000);
+ trace_config.set_unique_session_name(RandomSessionName().c_str());
+
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("android.java_hprof");
+ ds_config->set_target_buffer(0);
+
+ protos::gen::JavaHprofConfig java_hprof_config;
+ java_hprof_config.add_pid(static_cast<uint64_t>(target_pid));
+ ds_config->set_java_hprof_config_raw(java_hprof_config.SerializeAsString());
+
+ // start tracing
+ helper.StartTracing(trace_config);
+ helper.WaitForTracingDisabled();
+ helper.ReadData();
+ helper.WaitForReadData();
+ PERFETTO_CHECK(IsAppRunning(app_name));
+ StopApp(app_name, "new.app.stopped", &task_runner);
+ task_runner.RunUntilCheckpoint("new.app.stopped", 1000 /*ms*/);
+
+ const auto& packets = helper.trace();
+ AssertGraphPresent(packets);
+}
+
} // namespace
} // namespace perfetto
diff --git a/test/test_helper.h b/test/test_helper.h
index 4ac4c46..d9a99b9 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -34,8 +34,7 @@
#include "test/fake_producer.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-// TODO(primiano): uncomment in next CL.
-// #include "src/tracing/ipc/shared_memory_windows.h"
+#include "src/tracing/ipc/shared_memory_windows.h"
#else
#include "src/traced/probes/probes_producer.h"
#include "src/tracing/ipc/posix_shared_memory.h"
@@ -168,12 +167,12 @@
void CreateProducerProvidedSmb() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
- // TODO(primiano): in next CLs introduce SharedMemoryWindows.
+ SharedMemoryWindows::Factory factory;
#else
PosixSharedMemory::Factory factory;
+#endif
shm_ = factory.CreateSharedMemory(1024 * 1024);
shm_arbiter_ = SharedMemoryArbiter::CreateUnboundInstance(shm_.get(), 4096);
-#endif
}
void ProduceStartupEventBatch(const protos::gen::TestConfig& config,
diff --git a/test/trace_processor/parsing/counters_json_counters.out b/test/trace_processor/parsing/counters_json_counters.out
new file mode 100644
index 0000000..dfe4747
--- /dev/null
+++ b/test/trace_processor/parsing/counters_json_counters.out
@@ -0,0 +1,4 @@
+"name","ts","value"
+"ctr cats",0,0.000000
+"ctr cats",10000,10.000000
+"ctr cats",20000,0.000000
diff --git a/test/trace_processor/parsing/index b/test/trace_processor/parsing/index
index 4b2ca9a..65ef807 100644
--- a/test/trace_processor/parsing/index
+++ b/test/trace_processor/parsing/index
@@ -142,3 +142,7 @@
# Floating point numbers
../../data/decimal_timestamp.json slices.sql decimal_timestamp_slices.out
+
+# JSON instants and counters
+../../data/counters.json json_counters.sql counters_json_counters.out
+../../data/instants.json json_instants.sql instants_json_instants.out
diff --git a/test/trace_processor/parsing/instants_json_instants.out b/test/trace_processor/parsing/instants_json_instants.out
new file mode 100644
index 0000000..2fb9fb4
--- /dev/null
+++ b/test/trace_processor/parsing/instants_json_instants.out
@@ -0,0 +1,5 @@
+"ts","slice_name","tid","pid"
+1234523300,"Thread",2347,"[NULL]"
+1235523300,"Global","[NULL]","[NULL]"
+1236523300,"Process","[NULL]",2320
+1237523300,"None",6790,"[NULL]"
diff --git a/test/trace_processor/parsing/json_counters.sql b/test/trace_processor/parsing/json_counters.sql
new file mode 100644
index 0000000..604c2c1
--- /dev/null
+++ b/test/trace_processor/parsing/json_counters.sql
@@ -0,0 +1,6 @@
+select
+ process_counter_track.name,
+ counter.ts,
+ counter.value
+from counter
+join process_counter_track on (counter.track_id = process_counter_track.id);
\ No newline at end of file
diff --git a/test/trace_processor/parsing/json_instants.sql b/test/trace_processor/parsing/json_instants.sql
new file mode 100644
index 0000000..d76ef89
--- /dev/null
+++ b/test/trace_processor/parsing/json_instants.sql
@@ -0,0 +1,12 @@
+select
+ slice.ts,
+ slice.name as slice_name,
+ thread.tid,
+ process.pid
+from slice
+join track on (slice.track_id = track.id)
+left join thread_track on (slice.track_id = thread_track.id)
+left join thread on (thread_track.utid = thread.utid)
+left join process_track on (slice.track_id = process_track.id)
+left join process on (process_track.upid = process.upid)
+where dur = 0;
\ No newline at end of file
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 5ae4b85..cc8094b 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -163,9 +163,9 @@
for line in (line.strip() for line in lines if not line.startswith('#')):
assert os.path.exists(line), 'file %s should exist' % line
if line.startswith('test/data/'):
- # Skip test data files that require GCS. They are only for benchmarks.
- # We don't run benchmarks in the android tree.
- continue
+ # Skip test data files that require GCS. They are only for benchmarks.
+ # We don't run benchmarks in the android tree.
+ continue
if line.endswith('/.'):
yield line[:-1] + '**/*'
else:
@@ -182,16 +182,16 @@
('cflags', {'-Wglobal-constructors', '-Werror=global-constructors'}),
('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
('stubs', {
- 'versions': ['S'],
- 'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
+ 'versions': ['S'],
+ 'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
}),
('export_include_dirs', {'src/profiling/memory/include'}),
],
'heapprofd_api_noop': [
('version_script', 'src/profiling/memory/heapprofd_client_api.map.txt'),
('stubs', {
- 'versions': ['S'],
- 'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
+ 'versions': ['S'],
+ 'symbol_file': 'src/profiling/memory/heapprofd_client_api.map.txt',
}),
('export_include_dirs', {'src/profiling/memory/include'}),
],
@@ -210,42 +210,42 @@
('include_dirs', {'bionic/libc/kernel'}),
],
'perfetto_integrationtests': [
- ('test_suites', {'general-tests'}),
- ('test_config', 'PerfettoIntegrationTests.xml'),
+ ('test_suites', {'general-tests'}),
+ ('test_config', 'PerfettoIntegrationTests.xml'),
],
- 'traced_probes': [
- ('required', {'libperfetto_android_internal',
- 'trigger_perfetto',
- 'traced_perf',
- 'mm_events'}),
- ],
+ 'traced_probes': [('required', {
+ 'libperfetto_android_internal', 'trigger_perfetto', 'traced_perf',
+ 'mm_events'
+ }),],
'libperfetto_android_internal': [('static_libs', {'libhealthhalutils'}),],
'trace_processor_shell': [
- ('strip', {'all': True}),
- ('host', {
- 'stl': 'libc++_static',
- 'dist': {'targets': ['sdk_repo']},
- }),
+ ('strip', {
+ 'all': True
+ }),
+ ('host', {
+ 'stl': 'libc++_static',
+ 'dist': {
+ 'targets': ['sdk_repo']
+ },
+ }),
],
'libperfetto_client_experimental': [
- ('apex_available', {
- '//apex_available:platform',
- 'com.android.art',
- 'com.android.art.debug'}),
- ('min_sdk_version', 'S'),
- ('shared_libs', {'liblog'}),
- ('export_include_dirs', {'include', buildflags_dir}),
+ ('apex_available', {
+ '//apex_available:platform', 'com.android.art',
+ 'com.android.art.debug'
+ }),
+ ('min_sdk_version', 'S'),
+ ('shared_libs', {'liblog'}),
+ ('export_include_dirs', {'include', buildflags_dir}),
],
'perfetto_trace_protos': [
- ('apex_available', {
- '//apex_available:platform',
- 'com.android.art',
- 'com.android.art.debug'}),
- ('min_sdk_version', 'S'),
+ ('apex_available', {
+ '//apex_available:platform', 'com.android.art',
+ 'com.android.art.debug'
+ }),
+ ('min_sdk_version', 'S'),
],
- 'libperfetto': [
- ('export_include_dirs', {'include', buildflags_dir}),
- ],
+ 'libperfetto': [('export_include_dirs', {'include', buildflags_dir}),],
}
@@ -325,6 +325,7 @@
def enable_uapi_headers(module):
module.include_dirs.add('bionic/libc/kernel')
+
def enable_bionic_libc_platform_headers_on_android(module):
module.header_libs.add('bionic_libc_platform_headers')
@@ -332,20 +333,32 @@
# Android equivalents for third-party libraries that the upstream project
# depends on.
builtin_deps = {
- '//gn:default_deps': lambda x: None,
- '//gn:gtest_main': lambda x: None,
- '//gn:protoc': lambda x: None,
- '//gn:gtest_and_gmock': enable_gtest_and_gmock,
- '//gn:libunwind': enable_libunwind,
- '//gn:protobuf_full': enable_protobuf_full,
- '//gn:protobuf_lite': enable_protobuf_lite,
- '//gn:protoc_lib': enable_protoc_lib,
- '//gn:libunwindstack': enable_libunwindstack,
- '//gn:sqlite': enable_sqlite,
- '//gn:zlib': enable_zlib,
- '//gn:bionic_kernel_uapi_headers' : enable_uapi_headers,
+ '//gn:default_deps':
+ lambda x: None,
+ '//gn:gtest_main':
+ lambda x: None,
+ '//gn:protoc':
+ lambda x: None,
+ '//gn:gtest_and_gmock':
+ enable_gtest_and_gmock,
+ '//gn:libunwind':
+ enable_libunwind,
+ '//gn:protobuf_full':
+ enable_protobuf_full,
+ '//gn:protobuf_lite':
+ enable_protobuf_lite,
+ '//gn:protoc_lib':
+ enable_protoc_lib,
+ '//gn:libunwindstack':
+ enable_libunwindstack,
+ '//gn:sqlite':
+ enable_sqlite,
+ '//gn:zlib':
+ enable_zlib,
+ '//gn:bionic_kernel_uapi_headers':
+ enable_uapi_headers,
'//src/profiling/memory:bionic_libc_platform_headers_on_android':
- enable_bionic_libc_platform_headers_on_android,
+ enable_bionic_libc_platform_headers_on_android,
}
# ----------------------------------------------------------------------------
@@ -546,7 +559,6 @@
output.append('}')
output.append('')
-
def add_android_static_lib(self, lib):
if self.type == 'cc_binary_host':
raise Exception('Adding Android static lib for host tool is unsupported')
@@ -555,7 +567,6 @@
else:
self.static_libs.add(lib)
-
def add_android_shared_lib(self, lib):
if self.type == 'cc_binary_host':
raise Exception('Adding Android shared lib for host tool is unsupported')
@@ -564,7 +575,6 @@
else:
self.shared_libs.add(lib)
-
def _output_field(self, output, name, sort=True):
value = getattr(self, name)
return write_blueprint_key_value(output, name, value, sort)
@@ -767,10 +777,8 @@
'tools/gen_cc_proto_descriptor.py',
]
module.cmd = ' '.join([
- '$(location tools/gen_cc_proto_descriptor.py)',
- '--gen_dir=$(genDir)',
- '--cpp_out=$(out)',
- '$(in)'
+ '$(location tools/gen_cc_proto_descriptor.py)', '--gen_dir=$(genDir)',
+ '--cpp_out=$(out)', '$(in)'
])
module.genrule_headers.add(module.name)
module.srcs.update(
@@ -784,14 +792,12 @@
module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
script_path = gn_utils.label_to_path(target.script)
module.genrule_headers.add(bp_module_name)
- module.tool_files = [ script_path ]
+ module.tool_files = [script_path]
module.out.update(target.outputs)
module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
module.cmd = ' '.join([
- 'python3 $(location %s)' % script_path,
- '--no_git',
- '--changelog=$(location CHANGELOG)',
- '--cpp_out=$(out)'
+ 'python3 $(location %s)' % script_path, '--no_git',
+ '--changelog=$(location CHANGELOG)', '--cpp_out=$(out)'
])
blueprint.add_module(module)
return module
@@ -821,6 +827,7 @@
return blueprint.modules[bp_module_name]
target = gn.get_target(gn_target_name)
+ name_without_toolchain = gn_utils.label_without_toolchain(target.name)
if target.type == 'executable':
if target.toolchain == gn_utils.HOST_TOOLCHAIN:
module_type = 'cc_binary_host'
@@ -846,10 +853,10 @@
elif target.type == 'action':
if 'gen_merged_sql_metrics' in target.name:
module = create_merged_sql_metrics_module(blueprint, target)
- elif re.match('.*gen_cc_.*_descriptor$', target.name):
+ elif re.match('.*gen_cc_.*_descriptor$', name_without_toolchain):
module = create_cc_proto_descriptor_module(blueprint, target)
- elif target.type == 'action' and gn_utils.label_without_toolchain(
- target.name) == gn_utils.GEN_VERSION_TARGET:
+ elif target.type == 'action' and \
+ name_without_toolchain == gn_utils.GEN_VERSION_TARGET:
module = create_gen_version_module(blueprint, target, bp_module_name)
else:
raise Error('Unhandled action: {}'.format(target.name))
@@ -857,8 +864,7 @@
raise Error('Unknown target %s (%s)' % (target.name, target.type))
blueprint.add_module(module)
- module.host_supported = (gn_utils.label_without_toolchain(target.name) in
- target_host_supported)
+ module.host_supported = (name_without_toolchain in target_host_supported)
module.init_rc = target_initrc.get(target.name, [])
module.srcs.update(
gn_utils.label_to_path(src)
@@ -1033,7 +1039,7 @@
# perfetto_component.gni is fixed.
# Check for ODR violations
# for target_name in default_targets:
- # checker = gn_utils.ODRChecker(gn, target_name)
+ # checker = gn_utils.ODRChecker(gn, target_name)
output = [
"""// Copyright (C) 2017 The Android Open Source Project
diff --git a/tools/install-build-deps b/tools/install-build-deps
index 878f1f6..6575bea 100755
--- a/tools/install-build-deps
+++ b/tools/install-build-deps
@@ -234,8 +234,8 @@
# Example traces for regression tests.
Dependency(
'test/data.zip',
- 'https://storage.googleapis.com/perfetto/test-data-20210513-224349.zip',
- '3dcc146f4ce38d17fd1f8c4c65af07e7cf7c5c4cb8aa4c7bf73ec3a095d997d1',
+ 'https://storage.googleapis.com/perfetto/test-data-20210518-223638.zip',
+ 'a9119ae4828fae92c9ec8449e3fd91d753e60b60fa59611fb8e6c0dd6ed69b13',
'all', 'all',
),
diff --git a/tools/java_heap_dump b/tools/java_heap_dump
index 8e0f31f..5f301b6 100755
--- a/tools/java_heap_dump
+++ b/tools/java_heap_dump
@@ -24,6 +24,7 @@
import sys
import tempfile
import time
+import uuid
NULL = open(os.devnull)
@@ -61,9 +62,11 @@
}}
"""
+UUID = str(uuid.uuid4())[-6:]
+PROFILE_PATH = '/data/misc/perfetto-traces/java-profile-' + UUID
+
PERFETTO_CMD = ('CFG=\'{cfg}\'; echo ${{CFG}} | '
- 'perfetto --txt -c - -o '
- '/data/misc/perfetto-traces/java-profile-{user} -d')
+ 'perfetto --txt -c - -o ' + PROFILE_PATH + ' -d')
SDK = {
'S': 31,
@@ -212,8 +215,10 @@
time.sleep(1)
subprocess.check_call(
- ['adb', 'pull', '/data/misc/perfetto-traces/java-profile-{}'.format(user),
- output_file], stdout=NULL)
+ ['adb', 'pull', PROFILE_PATH, output_file], stdout=NULL)
+
+ subprocess.check_call(
+ ['adb', 'shell', 'rm', PROFILE_PATH], stdout=NULL)
print("Wrote profile to {}".format(output_file))
print("This can be viewed using https://ui.perfetto.dev.")
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 7c409a3..503e688 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -13,6 +13,7 @@
# limitations under the License.
import("../../gn/perfetto.gni")
+import("../../gn/perfetto_cc_proto_descriptor.gni")
import("../../gn/perfetto_host_executable.gni")
import("../../gn/wasm.gni")
@@ -131,6 +132,7 @@
testonly = true
deps = [
":common",
+ ":gen_cc_trace_descriptor",
":utils",
"../../gn:default_deps",
"../../gn:protobuf_full",
@@ -155,3 +157,8 @@
]
}
}
+
+perfetto_cc_proto_descriptor("gen_cc_trace_descriptor") {
+ descriptor_name = "trace.descriptor"
+ descriptor_target = "../../protos/perfetto/trace:descriptor"
+}
diff --git a/tools/trace_to_text/trace_to_profile.cc b/tools/trace_to_text/trace_to_profile.cc
index c71a827..5b3fc4f 100644
--- a/tools/trace_to_text/trace_to_profile.cc
+++ b/tools/trace_to_text/trace_to_profile.cc
@@ -59,10 +59,9 @@
std::string GetRandomString(size_t n) {
std::random_device r;
auto rng = std::default_random_engine(r());
- std::uniform_int_distribution<char> dist('a', 'z');
std::string result(n, ' ');
for (size_t i = 0; i < n; ++i) {
- result[i] = dist(rng);
+ result[i] = 'a' + (rng() % ('z' - 'a'));
}
return result;
}
diff --git a/tools/trace_to_text/trace_to_text.cc b/tools/trace_to_text/trace_to_text.cc
index 2fef5a5..070bb14 100644
--- a/tools/trace_to_text/trace_to_text.cc
+++ b/tools/trace_to_text/trace_to_text.cc
@@ -16,7 +16,6 @@
#include "tools/trace_to_text/trace_to_text.h"
-#include <google/protobuf/compiler/importer.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
@@ -25,6 +24,7 @@
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/scoped_file.h"
#include "tools/trace_to_text/proto_full_utils.h"
+#include "tools/trace_to_text/trace.descriptor.h"
#include "tools/trace_to_text/utils.h"
#include "protos/perfetto/trace/trace.pbzero.h"
@@ -36,17 +36,17 @@
namespace perfetto {
namespace trace_to_text {
-
namespace {
+
using google::protobuf::Descriptor;
+using google::protobuf::DescriptorPool;
using google::protobuf::DynamicMessageFactory;
using google::protobuf::FieldDescriptor;
using google::protobuf::FileDescriptor;
+using google::protobuf::FileDescriptorSet;
using google::protobuf::Message;
using google::protobuf::Reflection;
using google::protobuf::TextFormat;
-using google::protobuf::compiler::DiskSourceTree;
-using google::protobuf::compiler::Importer;
using google::protobuf::io::OstreamOutputStream;
using google::protobuf::io::ZeroCopyOutputStream;
@@ -147,42 +147,34 @@
} // namespace
int TraceToText(std::istream* input, std::ostream* output) {
- const std::string proto_path = "protos/perfetto/trace/trace_packet.proto";
-
- if (!base::OpenFile(proto_path, O_RDONLY)) {
- PERFETTO_ELOG("Cannot open %s.", proto_path.c_str());
- PERFETTO_ELOG(
- "Text mode only works from the perfetto directory. Googlers, see "
- "b/131425913");
- return 1;
+ DescriptorPool pool;
+ FileDescriptorSet desc_set;
+ desc_set.ParseFromArray(kTraceDescriptor.data(), kTraceDescriptor.size());
+ for (const auto& desc : desc_set.file()) {
+ pool.BuildFile(desc);
}
- DiskSourceTree dst;
- dst.MapPath("", "");
- MultiFileErrorCollectorImpl mfe;
- Importer importer(&dst, &mfe);
- const FileDescriptor* parsed_file =
- importer.Import("protos/perfetto/trace/trace_packet.proto");
+ DynamicMessageFactory factory(&pool);
+ const Descriptor* trace_descriptor =
+ pool.FindMessageTypeByName("perfetto.protos.TracePacket");
+ const Message* prototype = factory.GetPrototype(trace_descriptor);
+ std::unique_ptr<Message> msg(prototype->New());
- DynamicMessageFactory dmf;
- const Descriptor* trace_descriptor = parsed_file->message_type(0);
- const Message* root = dmf.GetPrototype(trace_descriptor);
OstreamOutputStream zero_copy_output(output);
OstreamOutputStream* zero_copy_output_ptr = &zero_copy_output;
- Message* msg = root->New();
constexpr uint32_t kCompressedPacketFieldDescriptor = 50;
const Reflection* reflect = msg->GetReflection();
const FieldDescriptor* compressed_desc =
trace_descriptor->FindFieldByNumber(kCompressedPacketFieldDescriptor);
- Message* compressed_msg_scratch = root->New();
+ std::unique_ptr<Message> compressed_msg_scratch(prototype->New());
std::string compressed_packet_scratch;
TextFormat::Printer printer;
printer.SetInitialIndentLevel(1);
ForEachPacketBlobInTrace(
- input, [msg, reflect, compressed_desc, zero_copy_output_ptr,
- &compressed_packet_scratch, compressed_msg_scratch,
+ input, [&msg, reflect, compressed_desc, zero_copy_output_ptr,
+ &compressed_packet_scratch, &compressed_msg_scratch,
&printer](std::unique_ptr<char[]> buf, size_t size) {
if (!msg->ParseFromArray(buf.get(), static_cast<int>(size))) {
PERFETTO_ELOG("Skipping invalid packet");
@@ -191,7 +183,8 @@
if (reflect->HasField(*msg, compressed_desc)) {
const auto& compressed_packets = reflect->GetStringReference(
*msg, compressed_desc, &compressed_packet_scratch);
- PrintCompressedPackets(compressed_packets, compressed_msg_scratch,
+ PrintCompressedPackets(compressed_packets,
+ compressed_msg_scratch.get(),
zero_copy_output_ptr);
} else {
WriteToZeroCopyOutput(zero_copy_output_ptr, kPacketPrefix,
diff --git a/ui/release/channels.json b/ui/release/channels.json
index ffb232f..b6827d6 100644
--- a/ui/release/channels.json
+++ b/ui/release/channels.json
@@ -2,11 +2,11 @@
"channels": [
{
"name": "stable",
- "rev": "465b9a4473353091c7048b53ad90607295f86a4a"
+ "rev": "85ad7248ca898e29e71a6e76ea85f070c4c3e3a9"
},
{
"name": "canary",
- "rev": "a284e65f883e7c543c2619115be1ee0fbe5644a3"
+ "rev": "dac610dd857535ee840a1cdcc2a5103e59a99388"
},
{
"name": "autopush",
diff --git a/ui/src/controller/track_decider.ts b/ui/src/controller/track_decider.ts
index 26f343b..9db1325 100644
--- a/ui/src/controller/track_decider.ts
+++ b/ui/src/controller/track_decider.ts
@@ -569,7 +569,9 @@
process.pid as pid
from process_track
left join process using(upid)
- where process_track.name not like "% Timeline"
+ where
+ process_track.name is null or
+ process_track.name not like "% Timeline"
group by
process_track.upid,
process_track.name
diff --git a/ui/src/tracks/actual_frames/controller.ts b/ui/src/tracks/actual_frames/controller.ts
index b436fbe..58140f7 100644
--- a/ui/src/tracks/actual_frames/controller.ts
+++ b/ui/src/tracks/actual_frames/controller.ts
@@ -12,8 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {assertTrue} from '../../base/logging';
-import {slowlyCountRows} from '../../common/query_iterator';
+import {assertExists, assertTrue} from '../../base/logging';
+import {
+ iter,
+ NUM,
+ singleRow,
+ slowlyCountRows,
+ STR
+} from '../../common/query_iterator';
import {fromNs, toNs} from '../../common/time';
import {
TrackController,
@@ -46,26 +52,27 @@
if (this.maxDurNs === 0) {
const maxDurResult = await this.query(`
- select max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur))
+ select
+ max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur))
+ as maxDur
from experimental_slice_layout
where filter_track_ids = '${this.config.trackIds.join(',')}'
`);
- if (slowlyCountRows(maxDurResult) === 1) {
- this.maxDurNs = maxDurResult.columns[0].longValues![0];
- }
+ const row = singleRow({maxDur: NUM}, maxDurResult);
+ this.maxDurNs = assertExists(row).maxDur;
}
const rawResult = await this.query(`
SELECT
(s.ts + ${bucketNs / 2}) / ${bucketNs} * ${bucketNs} as tsq,
- s.ts,
+ s.ts as ts,
max(iif(s.dur = -1, (SELECT end_ts FROM trace_bounds) - s.ts, s.dur))
as dur,
- s.layout_depth,
- s.name,
- s.id,
- s.dur = 0 as is_instant,
- s.dur = -1 as is_incomplete,
+ s.layout_depth as layoutDepth,
+ s.name as name,
+ s.id as id,
+ s.dur = 0 as isInstant,
+ s.dur = -1 as isIncomplete,
CASE afs.jank_tag
WHEN 'Self Jank' THEN '${RED_COLOR}'
WHEN 'Other Jank' THEN '${YELLOW_COLOR}'
@@ -112,11 +119,23 @@
return idx;
}
- const cols = rawResult.columns;
- for (let row = 0; row < numRows; row++) {
- const startNsQ = +cols[0].longValues![row];
- const startNs = +cols[1].longValues![row];
- const durNs = +cols[2].longValues![row];
+ const it = iter(
+ {
+ 'tsq': NUM,
+ 'ts': NUM,
+ 'dur': NUM,
+ 'layoutDepth': NUM,
+ 'id': NUM,
+ 'name': STR,
+ 'isInstant': NUM,
+ 'isIncomplete': NUM,
+ 'color': STR,
+ },
+ rawResult);
+ for (let i = 0; it.valid(); i++, it.next()) {
+ const startNsQ = it.row.tsq;
+ const startNs = it.row.ts;
+ const durNs = it.row.dur;
const endNs = startNs + durNs;
let endNsQ = Math.floor((endNs + bucketNs / 2 - 1) / bucketNs) * bucketNs;
@@ -124,14 +143,14 @@
assertTrue(startNsQ !== endNsQ);
- slices.starts[row] = fromNs(startNsQ);
- slices.ends[row] = fromNs(endNsQ);
- slices.depths[row] = +cols[3].longValues![row];
- slices.titles[row] = internString(cols[4].stringValues![row]);
- slices.colors![row] = internString(cols[8].stringValues![row]);
- slices.sliceIds[row] = +cols[5].longValues![row];
- slices.isInstant[row] = +cols[6].longValues![row];
- slices.isIncomplete[row] = +cols[7].longValues![row];
+ slices.starts[i] = fromNs(startNsQ);
+ slices.ends[i] = fromNs(endNsQ);
+ slices.depths[i] = it.row.layoutDepth;
+ slices.titles[i] = internString(it.row.name);
+ slices.colors![i] = internString(it.row.color);
+ slices.sliceIds[i] = it.row.id;
+ slices.isInstant[i] = it.row.isInstant;
+ slices.isIncomplete[i] = it.row.isIncomplete;
}
return slices;
}
diff --git a/ui/src/tracks/cpu_slices/controller.ts b/ui/src/tracks/cpu_slices/controller.ts
index 1389cb4..d6ac723 100644
--- a/ui/src/tracks/cpu_slices/controller.ts
+++ b/ui/src/tracks/cpu_slices/controller.ts
@@ -88,7 +88,7 @@
`(ts + ${bucketNs / 2}) / ${bucketNs} * ${bucketNs}`;
const queryTable =
isCached ? this.tableName('sched_cached') : this.tableName('sched');
- const constainColumn = isCached ? 'cached_tsq' : 'ts';
+ const constraintColumn = isCached ? 'cached_tsq' : 'ts';
const rawResult = await this.query(`
select
@@ -99,8 +99,8 @@
id
from ${queryTable}
where
- ${constainColumn} >= ${startNs - this.maxDurNs} and
- ${constainColumn} <= ${endNs}
+ ${constraintColumn} >= ${startNs - this.maxDurNs} and
+ ${constraintColumn} <= ${endNs}
group by tsq
order by tsq
`);
diff --git a/ui/src/tracks/expected_frames/controller.ts b/ui/src/tracks/expected_frames/controller.ts
index 532eaa0..9707059 100644
--- a/ui/src/tracks/expected_frames/controller.ts
+++ b/ui/src/tracks/expected_frames/controller.ts
@@ -12,7 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import {slowlyCountRows} from '../../common/query_iterator';
+import {assertExists} from '../../base/logging';
+import {
+ iter,
+ NUM,
+ singleRow,
+ slowlyCountRows,
+ STR
+} from '../../common/query_iterator';
import {fromNs, toNs} from '../../common/time';
import {
TrackController,
@@ -39,12 +46,12 @@
if (this.maxDurNs === 0) {
const maxDurResult = await this.query(`
select max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur))
+ as maxDur
from experimental_slice_layout
where filter_track_ids = '${this.config.trackIds.join(',')}'
`);
- if (slowlyCountRows(maxDurResult) === 1) {
- this.maxDurNs = maxDurResult.columns[0].longValues![0];
- }
+ const row = singleRow({maxDur: NUM}, maxDurResult);
+ this.maxDurNs = assertExists(row).maxDur;
}
const rawResult = await this.query(`
@@ -52,11 +59,11 @@
(ts + ${bucketNs / 2}) / ${bucketNs} * ${bucketNs} as tsq,
ts,
max(iif(dur = -1, (SELECT end_ts FROM trace_bounds) - ts, dur)) as dur,
- layout_depth,
+ layout_depth as layoutDepth,
name,
id,
- dur = 0 as is_instant,
- dur = -1 as is_incomplete
+ dur = 0 as isInstant,
+ dur = -1 as isIncomplete
from experimental_slice_layout
where
filter_track_ids = '${this.config.trackIds.join(',')}' and
@@ -94,11 +101,22 @@
}
const greenIndex = internString('#4CAF50');
- const cols = rawResult.columns;
- for (let row = 0; row < numRows; row++) {
- const startNsQ = +cols[0].longValues![row];
- const startNs = +cols[1].longValues![row];
- const durNs = +cols[2].longValues![row];
+ const it = iter(
+ {
+ tsq: NUM,
+ ts: NUM,
+ dur: NUM,
+ layoutDepth: NUM,
+ id: NUM,
+ name: STR,
+ isInstant: NUM,
+ isIncomplete: NUM,
+ },
+ rawResult);
+ for (let i = 0; it.valid(); it.next(), ++i) {
+ const startNsQ = it.row.tsq;
+ const startNs = it.row.ts;
+ const durNs = it.row.dur;
const endNs = startNs + durNs;
let endNsQ = Math.floor((endNs + bucketNs / 2 - 1) / bucketNs) * bucketNs;
@@ -108,14 +126,14 @@
throw new Error('Should never happen');
}
- slices.starts[row] = fromNs(startNsQ);
- slices.ends[row] = fromNs(endNsQ);
- slices.depths[row] = +cols[3].longValues![row];
- slices.titles[row] = internString(cols[4].stringValues![row]);
- slices.sliceIds[row] = +cols[5].longValues![row];
- slices.isInstant[row] = +cols[6].longValues![row];
- slices.isIncomplete[row] = +cols[7].longValues![row];
- slices.colors![row] = greenIndex;
+ slices.starts[i] = fromNs(startNsQ);
+ slices.ends[i] = fromNs(endNsQ);
+ slices.depths[i] = it.row.layoutDepth;
+ slices.titles[i] = internString(it.row.name);
+ slices.sliceIds[i] = it.row.id;
+ slices.isInstant[i] = it.row.isInstant;
+ slices.isIncomplete[i] = it.row.isIncomplete;
+ slices.colors![i] = greenIndex;
}
return slices;
}
diff --git a/ui/src/tracks/process_scheduling/controller.ts b/ui/src/tracks/process_scheduling/controller.ts
index c7676ed..687d16d 100644
--- a/ui/src/tracks/process_scheduling/controller.ts
+++ b/ui/src/tracks/process_scheduling/controller.ts
@@ -134,7 +134,7 @@
`(ts + ${bucketNs / 2}) / ${bucketNs} * ${bucketNs}`;
const queryTable = isCached ? this.tableName('process_sched_cached') :
this.tableName('process_sched');
- const constainColumn = isCached ? 'cached_tsq' : 'ts';
+ const constraintColumn = isCached ? 'cached_tsq' : 'ts';
return this.query(`
select
${tsq} as tsq,
@@ -144,8 +144,8 @@
utid
from ${queryTable}
where
- ${constainColumn} >= ${startNs - this.maxDurNs} and
- ${constainColumn} <= ${endNs}
+ ${constraintColumn} >= ${startNs - this.maxDurNs} and
+ ${constraintColumn} <= ${endNs}
group by tsq, cpu
order by tsq, cpu
`);