Merge "trace_processor: split gfp_flags and variadic into their own folder"
diff --git a/Android.bp b/Android.bp
index 8b04b25..f3f690c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -773,8 +773,6 @@
":perfetto_src_tracing_ipc",
":perfetto_src_tracing_tracing",
":perfetto_test_end_to_end_integrationtests",
- ":perfetto_test_task_runner_thread",
- ":perfetto_test_task_runner_thread_delegates",
":perfetto_test_test_helper",
"test/cts/device_feature_test_cts.cc",
"test/cts/end_to_end_integrationtest_cts.cc",
@@ -906,6 +904,215 @@
],
}
+// GN: //test/cts:perfetto_cts_jni_deps
+cc_library_static {
+ name: "perfetto_cts_jni_deps",
+ srcs: [
+ ":perfetto_include_perfetto_base_base",
+ ":perfetto_include_perfetto_ext_base_base",
+ ":perfetto_include_perfetto_ext_ipc_ipc",
+ ":perfetto_include_perfetto_ext_traced_sys_stats_counters",
+ ":perfetto_include_perfetto_ext_traced_traced",
+ ":perfetto_include_perfetto_ext_tracing_core_core",
+ ":perfetto_include_perfetto_ext_tracing_ipc_ipc",
+ ":perfetto_include_perfetto_protozero_protozero",
+ ":perfetto_include_perfetto_tracing_core_core",
+ ":perfetto_include_perfetto_tracing_core_forward_decls",
+ ":perfetto_include_perfetto_tracing_tracing",
+ ":perfetto_protos_perfetto_common_cpp_gen",
+ ":perfetto_protos_perfetto_common_zero_gen",
+ ":perfetto_protos_perfetto_config_android_cpp_gen",
+ ":perfetto_protos_perfetto_config_android_zero_gen",
+ ":perfetto_protos_perfetto_config_cpp_gen",
+ ":perfetto_protos_perfetto_config_ftrace_cpp_gen",
+ ":perfetto_protos_perfetto_config_ftrace_zero_gen",
+ ":perfetto_protos_perfetto_config_gpu_cpp_gen",
+ ":perfetto_protos_perfetto_config_gpu_zero_gen",
+ ":perfetto_protos_perfetto_config_inode_file_cpp_gen",
+ ":perfetto_protos_perfetto_config_inode_file_zero_gen",
+ ":perfetto_protos_perfetto_config_power_cpp_gen",
+ ":perfetto_protos_perfetto_config_power_zero_gen",
+ ":perfetto_protos_perfetto_config_process_stats_cpp_gen",
+ ":perfetto_protos_perfetto_config_process_stats_zero_gen",
+ ":perfetto_protos_perfetto_config_profiling_cpp_gen",
+ ":perfetto_protos_perfetto_config_profiling_zero_gen",
+ ":perfetto_protos_perfetto_config_sys_stats_cpp_gen",
+ ":perfetto_protos_perfetto_config_sys_stats_zero_gen",
+ ":perfetto_protos_perfetto_config_zero_gen",
+ ":perfetto_protos_perfetto_ipc_cpp_gen",
+ ":perfetto_protos_perfetto_ipc_ipc_gen",
+ ":perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen",
+ ":perfetto_protos_perfetto_trace_android_cpp_gen",
+ ":perfetto_protos_perfetto_trace_android_zero_gen",
+ ":perfetto_protos_perfetto_trace_chrome_cpp_gen",
+ ":perfetto_protos_perfetto_trace_chrome_zero_gen",
+ ":perfetto_protos_perfetto_trace_filesystem_cpp_gen",
+ ":perfetto_protos_perfetto_trace_filesystem_zero_gen",
+ ":perfetto_protos_perfetto_trace_ftrace_cpp_gen",
+ ":perfetto_protos_perfetto_trace_ftrace_zero_gen",
+ ":perfetto_protos_perfetto_trace_gpu_cpp_gen",
+ ":perfetto_protos_perfetto_trace_gpu_zero_gen",
+ ":perfetto_protos_perfetto_trace_interned_data_cpp_gen",
+ ":perfetto_protos_perfetto_trace_interned_data_zero_gen",
+ ":perfetto_protos_perfetto_trace_minimal_cpp_gen",
+ ":perfetto_protos_perfetto_trace_minimal_zero_gen",
+ ":perfetto_protos_perfetto_trace_non_minimal_cpp_gen",
+ ":perfetto_protos_perfetto_trace_non_minimal_zero_gen",
+ ":perfetto_protos_perfetto_trace_perfetto_cpp_gen",
+ ":perfetto_protos_perfetto_trace_perfetto_zero_gen",
+ ":perfetto_protos_perfetto_trace_power_cpp_gen",
+ ":perfetto_protos_perfetto_trace_power_zero_gen",
+ ":perfetto_protos_perfetto_trace_profiling_cpp_gen",
+ ":perfetto_protos_perfetto_trace_profiling_zero_gen",
+ ":perfetto_protos_perfetto_trace_ps_cpp_gen",
+ ":perfetto_protos_perfetto_trace_ps_zero_gen",
+ ":perfetto_protos_perfetto_trace_sys_stats_cpp_gen",
+ ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+ ":perfetto_protos_perfetto_trace_track_event_cpp_gen",
+ ":perfetto_protos_perfetto_trace_track_event_zero_gen",
+ ":perfetto_src_android_internal_headers",
+ ":perfetto_src_android_internal_lazy_library_loader",
+ ":perfetto_src_base_base",
+ ":perfetto_src_base_test_support",
+ ":perfetto_src_base_unix_socket",
+ ":perfetto_src_ipc_ipc",
+ ":perfetto_src_perfetto_cmd_perfetto_atoms",
+ ":perfetto_src_protozero_protozero",
+ ":perfetto_src_traced_probes_android_log_android_log",
+ ":perfetto_src_traced_probes_data_source",
+ ":perfetto_src_traced_probes_filesystem_filesystem",
+ ":perfetto_src_traced_probes_ftrace_format_parser",
+ ":perfetto_src_traced_probes_ftrace_ftrace",
+ ":perfetto_src_traced_probes_metatrace_metatrace",
+ ":perfetto_src_traced_probes_packages_list_packages_list",
+ ":perfetto_src_traced_probes_power_power",
+ ":perfetto_src_traced_probes_probes_src",
+ ":perfetto_src_traced_probes_ps_ps",
+ ":perfetto_src_traced_probes_sys_stats_sys_stats",
+ ":perfetto_src_tracing_common",
+ ":perfetto_src_tracing_ipc",
+ ":perfetto_src_tracing_tracing",
+ ":perfetto_test_test_helper",
+ ],
+ export_include_dirs: [
+ "include",
+ "include/perfetto/base/build_configs/android_tree",
+ ],
+ generated_headers: [
+ "perfetto_protos_perfetto_common_cpp_gen_headers",
+ "perfetto_protos_perfetto_common_zero_gen_headers",
+ "perfetto_protos_perfetto_config_android_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_android_zero_gen_headers",
+ "perfetto_protos_perfetto_config_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+ "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+ "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
+ "perfetto_protos_perfetto_config_power_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_power_zero_gen_headers",
+ "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+ "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+ "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
+ "perfetto_protos_perfetto_config_zero_gen_headers",
+ "perfetto_protos_perfetto_ipc_cpp_gen_headers",
+ "perfetto_protos_perfetto_ipc_ipc_gen_headers",
+ "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_android_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_android_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_chrome_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_filesystem_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_ftrace_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_gpu_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_interned_data_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_minimal_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_non_minimal_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_perfetto_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_power_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_power_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_profiling_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_ps_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+ ],
+ export_generated_headers: [
+ "perfetto_protos_perfetto_common_cpp_gen_headers",
+ "perfetto_protos_perfetto_common_zero_gen_headers",
+ "perfetto_protos_perfetto_config_android_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_android_zero_gen_headers",
+ "perfetto_protos_perfetto_config_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_ftrace_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_ftrace_zero_gen_headers",
+ "perfetto_protos_perfetto_config_gpu_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_gpu_zero_gen_headers",
+ "perfetto_protos_perfetto_config_inode_file_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_inode_file_zero_gen_headers",
+ "perfetto_protos_perfetto_config_power_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_power_zero_gen_headers",
+ "perfetto_protos_perfetto_config_process_stats_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_process_stats_zero_gen_headers",
+ "perfetto_protos_perfetto_config_profiling_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_profiling_zero_gen_headers",
+ "perfetto_protos_perfetto_config_sys_stats_cpp_gen_headers",
+ "perfetto_protos_perfetto_config_sys_stats_zero_gen_headers",
+ "perfetto_protos_perfetto_config_zero_gen_headers",
+ "perfetto_protos_perfetto_ipc_cpp_gen_headers",
+ "perfetto_protos_perfetto_ipc_ipc_gen_headers",
+ "perfetto_protos_perfetto_ipc_wire_protocol_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_android_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_android_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_chrome_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_chrome_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_filesystem_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_filesystem_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_ftrace_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_ftrace_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_gpu_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_gpu_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_interned_data_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_interned_data_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_minimal_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_minimal_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_non_minimal_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_non_minimal_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_perfetto_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_perfetto_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_power_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_power_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_profiling_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_ps_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+ "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
+ "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
+ ],
+ defaults: [
+ "perfetto_defaults",
+ ],
+ cflags: [
+ "-DGOOGLE_PROTOBUF_NO_RTTI",
+ "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+ ],
+}
+
// GN: //gn:default_deps
cc_defaults {
name: "perfetto_defaults",
@@ -1129,8 +1336,6 @@
":perfetto_src_tracing_test_api_test_support",
":perfetto_src_tracing_tracing",
":perfetto_test_end_to_end_integrationtests",
- ":perfetto_test_task_runner_thread",
- ":perfetto_test_task_runner_thread_delegates",
":perfetto_test_test_helper",
],
shared_libs: [
@@ -6236,6 +6441,7 @@
"src/tracing/internal/track_event_internal.cc",
"src/tracing/platform.cc",
"src/tracing/tracing.cc",
+ "src/tracing/track.cc",
"src/tracing/track_event_category_registry.cc",
"src/tracing/virtual_destructors.cc",
],
@@ -6358,27 +6564,11 @@
],
}
-// GN: //test:task_runner_thread
-filegroup {
- name: "perfetto_test_task_runner_thread",
- srcs: [
- "test/task_runner_thread.cc",
- ],
-}
-
-// GN: //test:task_runner_thread_delegates
-filegroup {
- name: "perfetto_test_task_runner_thread_delegates",
- srcs: [
- "test/fake_producer.cc",
- "test/task_runner_thread_delegates.cc",
- ],
-}
-
// GN: //test:test_helper
filegroup {
name: "perfetto_test_test_helper",
srcs: [
+ "test/fake_producer.cc",
"test/test_helper.cc",
],
}
@@ -7303,25 +7493,6 @@
// These targets are appended to the autogenerated Android.bp by tools/gen_android_bp.
-cc_library_static {
- name: "perfetto_cts_jni_deps",
- srcs: [
- "src/base/test/test_task_runner.cc",
- "test/fake_producer.cc",
- "test/task_runner_thread_delegates.cc",
- ],
- shared_libs: [
- "libprotobuf-cpp-lite",
- ],
- static_libs: [
- "libgtest",
- "libperfetto_client_experimental",
- ],
- defaults: [
- "perfetto_defaults",
- ],
-}
-
java_library_host {
name: "perfetto_config-full",
proto: {
diff --git a/Android.bp.extras b/Android.bp.extras
index 9586516..65a81f4 100644
--- a/Android.bp.extras
+++ b/Android.bp.extras
@@ -1,24 +1,5 @@
// These targets are appended to the autogenerated Android.bp by tools/gen_android_bp.
-cc_library_static {
- name: "perfetto_cts_jni_deps",
- srcs: [
- "src/base/test/test_task_runner.cc",
- "test/fake_producer.cc",
- "test/task_runner_thread_delegates.cc",
- ],
- shared_libs: [
- "libprotobuf-cpp-lite",
- ],
- static_libs: [
- "libgtest",
- "libperfetto_client_experimental",
- ],
- defaults: [
- "perfetto_defaults",
- ],
-}
-
java_library_host {
name: "perfetto_config-full",
proto: {
diff --git a/BUILD b/BUILD
index 0a41965..cf45542 100644
--- a/BUILD
+++ b/BUILD
@@ -245,8 +245,11 @@
"include/perfetto/base/build_config.h",
"include/perfetto/base/compiler.h",
"include/perfetto/base/export.h",
+ "include/perfetto/base/flat_set.h",
"include/perfetto/base/logging.h",
+ "include/perfetto/base/proc_utils.h",
"include/perfetto/base/task_runner.h",
+ "include/perfetto/base/thread_utils.h",
"include/perfetto/base/time.h",
],
)
@@ -259,7 +262,6 @@
"include/perfetto/ext/base/container_annotations.h",
"include/perfetto/ext/base/event_fd.h",
"include/perfetto/ext/base/file_utils.h",
- "include/perfetto/ext/base/flat_set.h",
"include/perfetto/ext/base/hash.h",
"include/perfetto/ext/base/lookup_set.h",
"include/perfetto/ext/base/metatrace.h",
@@ -268,7 +270,6 @@
"include/perfetto/ext/base/optional.h",
"include/perfetto/ext/base/paged_memory.h",
"include/perfetto/ext/base/pipe.h",
- "include/perfetto/ext/base/proc_utils.h",
"include/perfetto/ext/base/scoped_file.h",
"include/perfetto/ext/base/small_set.h",
"include/perfetto/ext/base/string_splitter.h",
@@ -279,7 +280,6 @@
"include/perfetto/ext/base/thread_annotations.h",
"include/perfetto/ext/base/thread_checker.h",
"include/perfetto/ext/base/thread_task_runner.h",
- "include/perfetto/ext/base/thread_utils.h",
"include/perfetto/ext/base/unix_socket.h",
"include/perfetto/ext/base/unix_task_runner.h",
"include/perfetto/ext/base/utils.h",
@@ -477,6 +477,7 @@
"include/perfetto/tracing/trace_writer_base.h",
"include/perfetto/tracing/tracing.h",
"include/perfetto/tracing/tracing_backend.h",
+ "include/perfetto/tracing/track.h",
"include/perfetto/tracing/track_event.h",
"include/perfetto/tracing/track_event_category_registry.h",
"include/perfetto/tracing/track_event_interned_data_index.h",
@@ -1133,6 +1134,7 @@
"src/tracing/internal/track_event_internal.cc",
"src/tracing/platform.cc",
"src/tracing/tracing.cc",
+ "src/tracing/track.cc",
"src/tracing/track_event_category_registry.cc",
"src/tracing/virtual_destructors.cc",
],
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index e490551..85819b7 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -19,8 +19,11 @@
"build_config.h",
"compiler.h",
"export.h",
+ "flat_set.h",
"logging.h",
+ "proc_utils.h",
"task_runner.h",
+ "thread_utils.h",
"time.h",
]
}
diff --git a/include/perfetto/ext/base/flat_set.h b/include/perfetto/base/flat_set.h
similarity index 91%
rename from include/perfetto/ext/base/flat_set.h
rename to include/perfetto/base/flat_set.h
index e33fcf7..068ad3c 100644
--- a/include/perfetto/ext/base/flat_set.h
+++ b/include/perfetto/base/flat_set.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_FLAT_SET_H_
-#define INCLUDE_PERFETTO_EXT_BASE_FLAT_SET_H_
+#ifndef INCLUDE_PERFETTO_BASE_FLAT_SET_H_
+#define INCLUDE_PERFETTO_BASE_FLAT_SET_H_
#include <algorithm>
#include <vector>
@@ -63,14 +63,15 @@
size_t count(T value) const { return find(value) == entries_.end() ? 0 : 1; }
- void insert(T value) {
+ std::pair<iterator, bool> insert(T value) {
auto entries_end = entries_.end();
auto it = std::lower_bound(entries_.begin(), entries_end, value);
if (it != entries_end && *it == value)
- return;
+ return std::make_pair(it, false);
// If the value is not found |it| is either end() or the next item strictly
// greater than |value|. In both cases we want to insert just before that.
- entries_.insert(it, std::move(value));
+ it = entries_.insert(it, std::move(value));
+ return std::make_pair(it, true);
}
size_t erase(T value) {
@@ -96,4 +97,4 @@
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_FLAT_SET_H_
+#endif // INCLUDE_PERFETTO_BASE_FLAT_SET_H_
diff --git a/include/perfetto/ext/base/proc_utils.h b/include/perfetto/base/proc_utils.h
similarity index 90%
rename from include/perfetto/ext/base/proc_utils.h
rename to include/perfetto/base/proc_utils.h
index d5bacb9..8818ec0 100644
--- a/include/perfetto/ext/base/proc_utils.h
+++ b/include/perfetto/base/proc_utils.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_PROC_UTILS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_PROC_UTILS_H_
+#ifndef INCLUDE_PERFETTO_BASE_PROC_UTILS_H_
+#define INCLUDE_PERFETTO_BASE_PROC_UTILS_H_
#include <stdint.h>
@@ -54,4 +54,4 @@
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_PROC_UTILS_H_
+#endif // INCLUDE_PERFETTO_BASE_PROC_UTILS_H_
diff --git a/include/perfetto/ext/base/thread_utils.h b/include/perfetto/base/thread_utils.h
similarity index 93%
rename from include/perfetto/ext/base/thread_utils.h
rename to include/perfetto/base/thread_utils.h
index 2e6495c..fa93c27 100644
--- a/include/perfetto/ext/base/thread_utils.h
+++ b/include/perfetto/base/thread_utils.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
-#define INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
+#ifndef INCLUDE_PERFETTO_BASE_THREAD_UTILS_H_
+#define INCLUDE_PERFETTO_BASE_THREAD_UTILS_H_
#include <stdint.h>
@@ -79,4 +79,4 @@
} // namespace base
} // namespace perfetto
-#endif // INCLUDE_PERFETTO_EXT_BASE_THREAD_UTILS_H_
+#endif // INCLUDE_PERFETTO_BASE_THREAD_UTILS_H_
diff --git a/include/perfetto/ext/base/BUILD.gn b/include/perfetto/ext/base/BUILD.gn
index 7d76c84..fd369cf 100644
--- a/include/perfetto/ext/base/BUILD.gn
+++ b/include/perfetto/ext/base/BUILD.gn
@@ -20,7 +20,6 @@
"container_annotations.h",
"event_fd.h",
"file_utils.h",
- "flat_set.h",
"hash.h",
"lookup_set.h",
"metatrace.h",
@@ -29,7 +28,6 @@
"optional.h",
"paged_memory.h",
"pipe.h",
- "proc_utils.h",
"scoped_file.h",
"small_set.h",
"string_splitter.h",
@@ -40,7 +38,6 @@
"thread_annotations.h",
"thread_checker.h",
"thread_task_runner.h",
- "thread_utils.h",
"unix_task_runner.h",
"utils.h",
"uuid.h",
diff --git a/include/perfetto/ext/base/metatrace.h b/include/perfetto/ext/base/metatrace.h
index 2c587c3..f5eb057 100644
--- a/include/perfetto/ext/base/metatrace.h
+++ b/include/perfetto/ext/base/metatrace.h
@@ -23,10 +23,10 @@
#include <string>
#include "perfetto/base/logging.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/metatrace_events.h"
#include "perfetto/ext/base/thread_annotations.h"
-#include "perfetto/ext/base/thread_utils.h"
#include "perfetto/ext/base/utils.h"
// A facility to trace execution of the perfetto codebase itself.
diff --git a/include/perfetto/ext/base/thread_task_runner.h b/include/perfetto/ext/base/thread_task_runner.h
index fac4553..6579fa5 100644
--- a/include/perfetto/ext/base/thread_task_runner.h
+++ b/include/perfetto/ext/base/thread_task_runner.h
@@ -34,7 +34,9 @@
//
class ThreadTaskRunner {
public:
- static ThreadTaskRunner CreateAndStart() { return ThreadTaskRunner(); }
+ static ThreadTaskRunner CreateAndStart(const std::string& name = "") {
+ return ThreadTaskRunner(name);
+ }
ThreadTaskRunner(const ThreadTaskRunner&) = delete;
ThreadTaskRunner& operator=(const ThreadTaskRunner&) = delete;
@@ -43,6 +45,14 @@
ThreadTaskRunner& operator=(ThreadTaskRunner&&);
~ThreadTaskRunner();
+ // Executes the given function on the task runner thread and blocks the caller
+ // thread until the function has run.
+ void PostTaskAndWaitForTesting(std::function<void()>);
+
+ // Can be called from another thread to get the CPU time of the thread the
+ // task-runner is executing on.
+ uint64_t GetThreadCPUTimeNsForTesting();
+
// Returns a pointer to the UnixTaskRunner, which is valid for the lifetime of
// this ThreadTaskRunner object (unless this object is moved-from, in which
// case the pointer remains valid for the lifetime of the new owning
@@ -53,10 +63,11 @@
UnixTaskRunner* get() const { return task_runner_; }
private:
- ThreadTaskRunner();
+ explicit ThreadTaskRunner(const std::string& name);
void RunTaskThread(std::function<void(UnixTaskRunner*)> initializer);
std::thread thread_;
+ std::string name_;
UnixTaskRunner* task_runner_ = nullptr;
};
diff --git a/include/perfetto/ext/base/unix_task_runner.h b/include/perfetto/ext/base/unix_task_runner.h
index 9ced3b9..9a743e3 100644
--- a/include/perfetto/ext/base/unix_task_runner.h
+++ b/include/perfetto/ext/base/unix_task_runner.h
@@ -19,11 +19,11 @@
#include "perfetto/base/build_config.h"
#include "perfetto/base/task_runner.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/event_fd.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/thread_checker.h"
-#include "perfetto/ext/base/thread_utils.h"
#include <poll.h>
#include <chrono>
diff --git a/include/perfetto/tracing/BUILD.gn b/include/perfetto/tracing/BUILD.gn
index 01294bd..60f4d4e 100644
--- a/include/perfetto/tracing/BUILD.gn
+++ b/include/perfetto/tracing/BUILD.gn
@@ -41,6 +41,7 @@
"trace_writer_base.h",
"tracing.h",
"tracing_backend.h",
+ "track.h",
"track_event.h",
"track_event_category_registry.h",
"track_event_interned_data_index.h",
diff --git a/include/perfetto/tracing/internal/track_event_data_source.h b/include/perfetto/tracing/internal/track_event_data_source.h
index 1debee3..e6c8af0 100644
--- a/include/perfetto/tracing/internal/track_event_data_source.h
+++ b/include/perfetto/tracing/internal/track_event_data_source.h
@@ -22,6 +22,7 @@
#include "perfetto/tracing/data_source.h"
#include "perfetto/tracing/event_context.h"
#include "perfetto/tracing/internal/track_event_internal.h"
+#include "perfetto/tracing/track.h"
#include "perfetto/tracing/track_event_category_registry.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
@@ -30,6 +31,34 @@
namespace perfetto {
namespace internal {
+namespace {
+
+// A template helper for determining whether a type can be used as a track event
+// lambda, i.e., it has the signature "void(EventContext)". This is achieved by
+// checking that we can pass an EventContext value (the inner declval) into a T
+// instance (the outer declval). If this is a valid expression, the result
+// evaluates to sizeof(0), i.e., true.
+// TODO(skyostil): Replace this with std::is_convertible<std::function<...>>
+// once we have C++14.
+template <typename T>
+static constexpr bool IsValidTraceLambdaImpl(
+ typename std::enable_if<static_cast<bool>(
+ sizeof(std::declval<T>()(std::declval<EventContext>()), 0))>::type* =
+ nullptr) {
+ return true;
+}
+
+template <typename T>
+static constexpr bool IsValidTraceLambdaImpl(...) {
+ return false;
+}
+
+template <typename T>
+static constexpr bool IsValidTraceLambda() {
+ return IsValidTraceLambdaImpl<T>(nullptr);
+}
+
+} // namespace
struct TrackEventDataSourceTraits : public perfetto::DefaultDataSourceTraits {
using IncrementalStateType = TrackEventIncrementalState;
@@ -87,8 +116,8 @@
}
// Once we've determined tracing to be enabled for this category, actually
- // write a trace event. Outlined to avoid bloating code at the actual trace
- // point.
+ // write a trace event onto this thread's default track. Outlined to avoid
+ // bloating code at the actual trace point.
// TODO(skyostil): Investigate whether this should be fully outlined to reduce
// binary size.
template <size_t CategoryIndex,
@@ -97,13 +126,51 @@
uint32_t instances,
const char* event_name,
perfetto::protos::pbzero::TrackEvent::Type type,
- ArgumentFunction arg_function = [](EventContext) {}) PERFETTO_NO_INLINE {
+ ArgumentFunction arg_function = [](EventContext) {},
+ typename std::enable_if<IsValidTraceLambda<ArgumentFunction>()>::type* =
+ nullptr) PERFETTO_NO_INLINE {
+ // We don't simply call TraceForCategory(..., Track(), ...) here, since that
+ // would add extra binary bloat to all trace points that target the default
+ // track.
Base::template TraceWithInstances<CategoryTracePointTraits<CategoryIndex>>(
instances, [&](typename Base::TraceContext ctx) {
// TODO(skyostil): Intern categories at compile time.
arg_function(TrackEventInternal::WriteEvent(
ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(),
Registry->GetCategory(CategoryIndex)->name, event_name, type));
+ // There's no need to emit a track descriptor for the default track
+ // here since that's done in ResetIncrementalState().
+ });
+ }
+
+ // This variant of the inner trace point takes a Track argument which can be
+ // used to emit events on a non-default track.
+ template <size_t CategoryIndex,
+ typename TrackType,
+ typename ArgumentFunction = void (*)(EventContext)>
+ static void TraceForCategory(
+ uint32_t instances,
+ const char* event_name,
+ perfetto::protos::pbzero::TrackEvent::Type type,
+ const TrackType& track,
+ ArgumentFunction arg_function = [](EventContext) {},
+ typename std::enable_if<IsValidTraceLambda<ArgumentFunction>()>::type* =
+ nullptr,
+ typename std::enable_if<
+ std::is_convertible<TrackType, Track>::value>::type* = nullptr)
+ PERFETTO_NO_INLINE {
+ PERFETTO_DCHECK(track);
+ Base::template TraceWithInstances<CategoryTracePointTraits<CategoryIndex>>(
+ instances, [&](typename Base::TraceContext ctx) {
+ // TODO(skyostil): Intern categories at compile time.
+ auto event_ctx = TrackEventInternal::WriteEvent(
+ ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(),
+ Registry->GetCategory(CategoryIndex)->name, event_name, type);
+ event_ctx.event()->set_track_uuid(track.uuid);
+ arg_function(std::move(event_ctx));
+ TrackEventInternal::WriteTrackDescriptorIfNeeded(
+ track, ctx.tls_inst_->trace_writer.get(),
+ ctx.GetIncrementalState());
});
}
@@ -124,27 +191,51 @@
perfetto::protos::pbzero::TrackEvent::Type type,
const char* arg_name,
ArgType&& arg_value) PERFETTO_ALWAYS_INLINE {
- TraceForCategoryWithDebugAnnotations<CategoryIndex, ArgType>(
- instances, event_name, type, arg_name,
+ TraceForCategoryWithDebugAnnotations<CategoryIndex, Track, ArgType>(
+ instances, event_name, type, Track(), arg_name,
std::forward<ArgType>(arg_value));
}
- template <size_t CategoryIndex, typename ArgType>
+ // A one argument trace point which takes an explicit track.
+ template <size_t CategoryIndex, typename TrackType, typename ArgType>
+ static void TraceForCategory(uint32_t instances,
+ const char* event_name,
+ perfetto::protos::pbzero::TrackEvent::Type type,
+ const TrackType& track,
+ const char* arg_name,
+ ArgType&& arg_value) PERFETTO_ALWAYS_INLINE {
+ PERFETTO_DCHECK(track);
+ TraceForCategoryWithDebugAnnotations<CategoryIndex, TrackType, ArgType>(
+ instances, event_name, type, track, arg_name,
+ std::forward<ArgType>(arg_value));
+ }
+
+ template <size_t CategoryIndex, typename TrackType, typename ArgType>
static void TraceForCategoryWithDebugAnnotations(
uint32_t instances,
const char* event_name,
perfetto::protos::pbzero::TrackEvent::Type type,
+ const TrackType& track,
const char* arg_name,
typename internal::DebugAnnotationArg<ArgType>::type arg_value)
PERFETTO_NO_INLINE {
Base::template TraceWithInstances<CategoryTracePointTraits<CategoryIndex>>(
instances, [&](typename Base::TraceContext ctx) {
- // TODO(skyostil): Intern categories at compile time.
- auto event_ctx = TrackEventInternal::WriteEvent(
- ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(),
- Registry->GetCategory(CategoryIndex)->name, event_name, type);
- TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name,
- arg_value);
+ {
+ // TODO(skyostil): Intern categories at compile time.
+ auto event_ctx = TrackEventInternal::WriteEvent(
+ ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(),
+ Registry->GetCategory(CategoryIndex)->name, event_name, type);
+ if (track)
+ event_ctx.event()->set_track_uuid(track.uuid);
+ TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name,
+ arg_value);
+ }
+ if (track) {
+ TrackEventInternal::WriteTrackDescriptorIfNeeded(
+ track, ctx.tls_inst_->trace_writer.get(),
+ ctx.GetIncrementalState());
+ }
});
}
@@ -160,16 +251,43 @@
ArgType&& arg_value,
const char* arg_name2,
ArgType2&& arg_value2) PERFETTO_ALWAYS_INLINE {
- TraceForCategoryWithDebugAnnotations<CategoryIndex, ArgType, ArgType2>(
- instances, event_name, type, arg_name, std::forward<ArgType>(arg_value),
- arg_name2, std::forward<ArgType2>(arg_value2));
+ TraceForCategoryWithDebugAnnotations<CategoryIndex, Track, ArgType,
+ ArgType2>(
+ instances, event_name, type, Track(), arg_name,
+ std::forward<ArgType>(arg_value), arg_name2,
+ std::forward<ArgType2>(arg_value2));
}
- template <size_t CategoryIndex, typename ArgType, typename ArgType2>
+ // A two argument trace point which takes an explicit track.
+ template <size_t CategoryIndex,
+ typename TrackType,
+ typename ArgType,
+ typename ArgType2>
+ static void TraceForCategory(uint32_t instances,
+ const char* event_name,
+ perfetto::protos::pbzero::TrackEvent::Type type,
+ const TrackType& track,
+ const char* arg_name,
+ ArgType&& arg_value,
+ const char* arg_name2,
+ ArgType2&& arg_value2) PERFETTO_ALWAYS_INLINE {
+ PERFETTO_DCHECK(track);
+ TraceForCategoryWithDebugAnnotations<CategoryIndex, TrackType, ArgType,
+ ArgType2>(
+ instances, event_name, type, track, arg_name,
+ std::forward<ArgType>(arg_value), arg_name2,
+ std::forward<ArgType2>(arg_value2));
+ }
+
+ template <size_t CategoryIndex,
+ typename TrackType,
+ typename ArgType,
+ typename ArgType2>
static void TraceForCategoryWithDebugAnnotations(
uint32_t instances,
const char* event_name,
perfetto::protos::pbzero::TrackEvent::Type type,
+ TrackType track,
const char* arg_name,
typename internal::DebugAnnotationArg<ArgType>::type arg_value,
const char* arg_name2,
@@ -178,16 +296,27 @@
Base::template TraceWithInstances<CategoryTracePointTraits<CategoryIndex>>(
instances, [&](typename Base::TraceContext ctx) {
// TODO(skyostil): Intern categories at compile time.
- auto event_ctx = TrackEventInternal::WriteEvent(
- ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(),
- Registry->GetCategory(CategoryIndex)->name, event_name, type);
- TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name,
- arg_value);
- TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name2,
- arg_value2);
+ {
+ auto event_ctx = TrackEventInternal::WriteEvent(
+ ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(),
+ Registry->GetCategory(CategoryIndex)->name, event_name, type);
+ if (track)
+ event_ctx.event()->set_track_uuid(track.uuid);
+ TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name,
+ arg_value);
+ TrackEventInternal::AddDebugAnnotation(&event_ctx, arg_name2,
+ arg_value2);
+ }
+ if (track) {
+ TrackEventInternal::WriteTrackDescriptorIfNeeded(
+ track, ctx.tls_inst_->trace_writer.get(),
+ ctx.GetIncrementalState());
+ }
});
}
+ // Initialize the track event library. Should be called before tracing is
+ // enabled.
static bool Register() {
// Registration is performed out-of-line so users don't need to depend on
// DataSourceDescriptor C++ bindings.
@@ -195,6 +324,29 @@
[](const DataSourceDescriptor& dsd) { return Base::Register(dsd); });
}
+ // Record metadata about different types of timeline tracks. See Track.
+ static void SetTrackDescriptor(
+ const Track& track,
+ std::function<void(protos::pbzero::TrackDescriptor*)> callback) {
+ SetTrackDescriptorImpl(track, std::move(callback));
+ }
+
+ static void SetProcessDescriptor(
+ std::function<void(protos::pbzero::TrackDescriptor*)> callback,
+ const ProcessTrack& track = ProcessTrack::Current()) {
+ SetTrackDescriptorImpl(std::move(track), std::move(callback));
+ }
+
+ static void SetThreadDescriptor(
+ std::function<void(protos::pbzero::TrackDescriptor*)> callback,
+ const ThreadTrack& track = ThreadTrack::Current()) {
+ SetTrackDescriptorImpl(std::move(track), std::move(callback));
+ }
+
+ static void EraseTrackDescriptor(const Track& track) {
+ TrackRegistry::Get()->EraseTrack(track);
+ }
+
private:
// Each category has its own enabled/disabled state, stored in the category
// registry.
@@ -204,6 +356,20 @@
return Registry->GetCategoryState(CategoryIndex);
}
};
+
+ // Records a track descriptor into the track descriptor registry and, if we
+ // are tracing, also mirrors the descriptor into the trace.
+ template <typename TrackType>
+ static void SetTrackDescriptorImpl(
+ const TrackType& track,
+ std::function<void(protos::pbzero::TrackDescriptor*)> callback) {
+ TrackRegistry::Get()->UpdateTrack(
+ track, [&](protos::pbzero::TrackDescriptor* desc) { callback(desc); });
+ Base::template Trace([&](typename Base::TraceContext ctx) {
+ TrackEventInternal::WriteTrackDescriptor(
+ track, ctx.tls_inst_->trace_writer.get());
+ });
+ }
};
} // namespace internal
diff --git a/include/perfetto/tracing/internal/track_event_internal.h b/include/perfetto/tracing/internal/track_event_internal.h
index e37a30b..a4ee050 100644
--- a/include/perfetto/tracing/internal/track_event_internal.h
+++ b/include/perfetto/tracing/internal/track_event_internal.h
@@ -17,15 +17,17 @@
#ifndef INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
#define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_INTERNAL_H_
-#include <unordered_map>
-
+#include "perfetto/base/flat_set.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
#include "perfetto/tracing/core/forward_decls.h"
#include "perfetto/tracing/debug_annotation.h"
#include "perfetto/tracing/trace_writer_base.h"
+#include "perfetto/tracing/track.h"
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
+#include <set>
+
namespace perfetto {
class EventContext;
namespace protos {
@@ -70,6 +72,11 @@
std::unique_ptr<BaseTrackEventInternedDataIndex>>;
std::array<InternedDataIndex, kMaxInternedDataFields> interned_data_indices =
{};
+
+ // Track uuids for which we have written descriptors into the trace. If a
+ // trace event uses a track which is not in this set, we'll write out a
+ // descriptor for it.
+ base::FlatSet<uint64_t> seen_tracks;
};
// The backend portion of the track event trace point implemention. Outlined to
@@ -101,7 +108,36 @@
WriteDebugAnnotation(annotation, value);
}
+ // If the given track hasn't been seen by the trace writer yet, write a
+ // descriptor for it into the trace. Doesn't take a lock unless the track
+ // descriptor is new.
+ template <typename TrackType>
+ static void WriteTrackDescriptorIfNeeded(
+ const TrackType& track,
+ TraceWriterBase* trace_writer,
+ TrackEventIncrementalState* incr_state) {
+ auto it_and_inserted = incr_state->seen_tracks.insert(track.uuid);
+ if (PERFETTO_LIKELY(!it_and_inserted.second))
+ return;
+ WriteTrackDescriptor(track, trace_writer);
+ }
+
+ // Unconditionally write a track descriptor into the trace.
+ template <typename TrackType>
+ static void WriteTrackDescriptor(const TrackType& track,
+ TraceWriterBase* trace_writer) {
+ TrackRegistry::Get()->SerializeTrack(
+ track, NewTracePacket(trace_writer, GetTimeNs()));
+ }
+
private:
+ static uint64_t GetTimeNs();
+ static void ResetIncrementalState(TraceWriterBase*, uint64_t timestamp);
+ static protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket(
+ TraceWriterBase*,
+ uint64_t timestamp,
+ uint32_t seq_flags =
+ protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
static protos::pbzero::DebugAnnotation* AddDebugAnnotation(
perfetto::EventContext*,
const char* name);
diff --git a/include/perfetto/tracing/track.h b/include/perfetto/tracing/track.h
new file mode 100644
index 0000000..a93b0f9
--- /dev/null
+++ b/include/perfetto/tracing/track.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_TRACK_H_
+#define INCLUDE_PERFETTO_TRACING_TRACK_H_
+
+#include "perfetto/base/proc_utils.h"
+#include "perfetto/base/thread_utils.h"
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+#include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
+
+#include <stdint.h>
+#include <map>
+#include <mutex>
+
+namespace perfetto {
+namespace internal {
+class TrackRegistry;
+}
+
+// Track events are recorded on a timeline track, which maintains the relative
+// time ordering of all events on that track. Each thread has its own default
+// track (ThreadTrack), which is by default where all track events are written.
+// Thread tracks are grouped under their hosting process (ProcessTrack).
+
+// Events which aren't strictly scoped to a thread or a process, or don't
+// correspond to synchronous code execution on a thread can use a custom
+// track (Track, ThreadTrack or ProcessTrack). A Track object can also
+// optionally be parented to a thread or a process.
+//
+// A track is represented by a uuid, which must be unique across the entire
+// recorded trace.
+//
+// For example, to record an event that begins and ends on different threads,
+// use a matching id to tie the begin and end events together:
+//
+// TRACE_EVENT_BEGIN("category", "AsyncEvent", perfetto::Track(8086));
+// ...
+// TRACE_EVENT_END("category", perfetto::Track(8086));
+//
+// Tracks can also be annotated with metadata:
+//
+// perfetto::TrackEvent::SetTrackDescriptor(
+// track, [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+// desc->set_name("MyTrack");
+// });
+//
+// The metadata remains valid between tracing sessions. To free up data for a
+// track, call EraseTrackDescriptor:
+//
+// perfetto::TrackEvent::EraseTrackDescriptor(track);
+//
+struct Track {
+ const uint64_t uuid;
+ const uint64_t parent_uuid;
+ constexpr Track() : uuid(0), parent_uuid(0) {}
+
+ // Construct a track with identifier |id|, optionally parented under |parent|.
+ // If no parent is specified, the track's parent is the current process's
+ // track.
+ //
+ // To minimize the chances for accidental id collisions across processes, the
+ // track's effective uuid is generated by xorring |id| with a random,
+ // per-process cookie.
+ explicit Track(uint64_t id, Track parent = MakeProcessTrack())
+ : uuid(id ^ parent.uuid), parent_uuid(parent.uuid) {}
+
+ explicit operator bool() const { return uuid; }
+ void Serialize(protos::pbzero::TrackDescriptor*) const;
+
+ protected:
+ static Track MakeThreadTrack(base::PlatformThreadID tid_) {
+ return Track(static_cast<uint64_t>(tid_), MakeProcessTrack());
+ }
+
+ static Track MakeProcessTrack() { return Track(process_uuid, Track()); }
+
+ private:
+ friend class internal::TrackRegistry;
+ static uint64_t process_uuid;
+};
+
+// A process track represents events that describe the state of the entire
+// application (e.g., counter events). Currently a ProcessTrack can only
+// represent the current process.
+struct ProcessTrack : public Track {
+ const base::PlatformProcessId pid;
+
+ static ProcessTrack Current() { return ProcessTrack(); }
+
+ void Serialize(protos::pbzero::TrackDescriptor*) const;
+
+ private:
+ ProcessTrack() : Track(MakeProcessTrack()), pid(base::GetProcessId()) {}
+};
+
+// A thread track is associated with a specific thread of execution. Currently
+// only threads in the current process can be referenced.
+struct ThreadTrack : public Track {
+ const base::PlatformProcessId pid;
+ const base::PlatformThreadID tid;
+
+ static ThreadTrack Current() { return ThreadTrack(base::GetThreadId()); }
+
+ // Represents a thread in the current process.
+ static ThreadTrack ForThread(base::PlatformThreadID tid_) {
+ return ThreadTrack(tid_);
+ }
+
+ void Serialize(protos::pbzero::TrackDescriptor*) const;
+
+ private:
+ explicit ThreadTrack(base::PlatformThreadID tid_)
+ : Track(MakeThreadTrack(tid_)),
+ pid(ProcessTrack::Current().pid),
+ tid(tid_) {}
+};
+
+namespace internal {
+
+// Keeps a map of uuids to serialized track descriptors and provides a
+// thread-safe way to read and write them. Each trace writer keeps a TLS set of
+// the tracks it has seen (see TrackEventIncrementalState). In the common case,
+// this registry is not consulted (and no locks are taken). However when a new
+// track is seen, this registry is used to write either 1) the default
+// descriptor for that track (see *Track::Serialize) or 2) a serialized
+// descriptor stored in the registry which may have additional metadata (e.g.,
+// track name).
+class TrackRegistry {
+ public:
+ using SerializedTrackDescriptor = std::string;
+
+ TrackRegistry();
+ ~TrackRegistry();
+
+ static void InitializeInstance();
+ static TrackRegistry* Get() { return instance_; }
+
+ void EraseTrack(Track);
+
+ // Store metadata for |track| in the registry. |fill_function| is called
+ // synchronously to record additional properties for the track.
+ template <typename TrackType>
+ void UpdateTrack(
+ const TrackType& track,
+ std::function<void(protos::pbzero::TrackDescriptor*)> fill_function) {
+ UpdateTrackImpl(track, [&](protos::pbzero::TrackDescriptor* desc) {
+ track.Serialize(desc);
+ fill_function(desc);
+ });
+ }
+
+ // If |track| exists in the registry, write out the serialized track
+ // descriptor for it into |packet|. Otherwise just the ephemeral track object
+ // is serialized without any additional metadata.
+ template <typename TrackType>
+ void SerializeTrack(
+ const TrackType& track,
+ protozero::MessageHandle<protos::pbzero::TracePacket> packet) {
+ // If the track has extra metadata (recorded with UpdateTrack), it will be
+ // found in the registry. To minimize the time the lock is held, make a copy
+ // of the data held in the registry and write it outside the lock.
+ std::string desc_copy;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ const auto& it = tracks_.find(track.uuid);
+ if (it != tracks_.end()) {
+ desc_copy = it->second;
+ PERFETTO_DCHECK(!desc_copy.empty());
+ }
+ }
+ if (!desc_copy.empty()) {
+ WriteTrackDescriptor(std::move(desc_copy), std::move(packet));
+ } else {
+ // Otherwise we just write the basic descriptor for this type of track
+ // (e.g., just uuid, no name).
+ track.Serialize(packet->set_track_descriptor());
+ }
+ }
+
+ static void WriteTrackDescriptor(
+ const SerializedTrackDescriptor& desc,
+ protozero::MessageHandle<protos::pbzero::TracePacket> packet);
+
+ private:
+ void UpdateTrackImpl(
+ Track,
+ std::function<void(protos::pbzero::TrackDescriptor*)> fill_function);
+
+ std::mutex mutex_;
+ std::map<uint64_t /* uuid */, SerializedTrackDescriptor> tracks_;
+
+ static TrackRegistry* instance_;
+};
+
+} // namespace internal
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_TRACING_TRACK_H_
diff --git a/include/perfetto/tracing/track_event.h b/include/perfetto/tracing/track_event.h
index fa4776b..95c2923 100644
--- a/include/perfetto/tracing/track_event.h
+++ b/include/perfetto/tracing/track_event.h
@@ -21,6 +21,7 @@
#include "perfetto/tracing/internal/track_event_data_source.h"
#include "perfetto/tracing/internal/track_event_internal.h"
#include "perfetto/tracing/internal/track_event_macros.h"
+#include "perfetto/tracing/track.h"
#include "perfetto/tracing/track_event_category_registry.h"
#include "protos/perfetto/trace/track_event/track_event.pbzero.h"
@@ -68,6 +69,14 @@
// });
// }
//
+// Note that track events must be nested consistently, i.e., the following is
+// not allowed:
+//
+// TRACE_EVENT_BEGIN("a", "bar", ...);
+// TRACE_EVENT_BEGIN("b", "foo", ...);
+// TRACE_EVENT_END("a"); // "foo" must be closed before "bar".
+// TRACE_EVENT_END("b");
+//
// ====================
// Implementation notes
// ====================
@@ -138,14 +147,17 @@
PERFETTO_INTERNAL_CATEGORY_STORAGE() \
} // namespace PERFETTO_TRACK_EVENT_NAMESPACE
-// Begin a thread-scoped slice under |category| with the title |name|. Both
-// strings must be static constants. The track event is only recorded if
-// |category| is enabled for a tracing session.
+// Begin a slice under |category| with the title |name|. Both strings must be
+// static constants. The track event is only recorded if |category| is enabled
+// for a tracing session.
//
// |name| must be a string with static lifetime (i.e., the same
// address must not be used for a different event name in the future). If you
// want to use a dynamically allocated name, do this:
//
+// The slice is thread-scoped (i.e., written to the default track of the current
+// thread) unless overridden with a custom track object (see Track).
+//
// TRACE_EVENT("category", nullptr, [&](perfetto::EventContext ctx) {
// ctx.event()->set_name(dynamic_name);
// });
@@ -155,18 +167,17 @@
category, name, \
::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN, ##__VA_ARGS__)
-// End a thread-scoped slice under |category|.
+// End a slice under |category|.
#define TRACE_EVENT_END(category, ...) \
PERFETTO_INTERNAL_TRACK_EVENT( \
category, nullptr, \
::perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END, ##__VA_ARGS__)
-// Begin a thread-scoped slice which gets automatically closed when going out of
-// scope.
+// Begin a slice which gets automatically closed when going out of scope.
#define TRACE_EVENT(category, name, ...) \
PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(category, name, ##__VA_ARGS__)
-// Emit a thread-scoped slice which has zero duration.
+// Emit a slice which has zero duration.
// TODO(skyostil): Add support for process-wide and global instant events.
#define TRACE_EVENT_INSTANT(category, name, ...) \
PERFETTO_INTERNAL_TRACK_EVENT( \
diff --git a/src/base/flat_set_benchmark.cc b/src/base/flat_set_benchmark.cc
index 12e5565..0773fbe 100644
--- a/src/base/flat_set_benchmark.cc
+++ b/src/base/flat_set_benchmark.cc
@@ -18,7 +18,7 @@
#include <benchmark/benchmark.h>
-#include "perfetto/ext/base/flat_set.h"
+#include "perfetto/base/flat_set.h"
namespace {
diff --git a/src/base/flat_set_unittest.cc b/src/base/flat_set_unittest.cc
index c853e13..406e05c 100644
--- a/src/base/flat_set_unittest.cc
+++ b/src/base/flat_set_unittest.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "perfetto/ext/base/flat_set.h"
+#include "perfetto/base/flat_set.h"
#include <random>
#include <set>
@@ -38,7 +38,9 @@
EXPECT_EQ(flat_set.find(42), flat_set.end());
EXPECT_EQ(flat_set.find(42), flat_set.begin());
- flat_set.insert(1);
+ auto it_and_inserted = flat_set.insert(1);
+ EXPECT_EQ(it_and_inserted.first, flat_set.find(1));
+ EXPECT_TRUE(it_and_inserted.second);
EXPECT_FALSE(flat_set.empty());
EXPECT_EQ(flat_set.size(), 1u);
{
@@ -52,7 +54,9 @@
EXPECT_NE(flat_set.begin(), flat_set.end());
EXPECT_EQ(std::distance(flat_set.begin(), flat_set.end()), 1);
- flat_set.insert(1);
+ it_and_inserted = flat_set.insert(1);
+ EXPECT_EQ(it_and_inserted.first, flat_set.find(1));
+ EXPECT_FALSE(it_and_inserted.second);
EXPECT_EQ(flat_set.size(), 1u);
EXPECT_TRUE(flat_set.count(1));
EXPECT_FALSE(flat_set.count(0));
@@ -62,10 +66,10 @@
EXPECT_FALSE(flat_set.count(1));
EXPECT_EQ(flat_set.size(), 0u);
- flat_set.insert(7);
- flat_set.insert(-4);
- flat_set.insert(11);
- flat_set.insert(-13);
+ EXPECT_TRUE(flat_set.insert(7).second);
+ EXPECT_TRUE(flat_set.insert(-4).second);
+ EXPECT_TRUE(flat_set.insert(11).second);
+ EXPECT_TRUE(flat_set.insert(-13).second);
EXPECT_TRUE(flat_set.count(7));
EXPECT_TRUE(flat_set.count(-4));
EXPECT_TRUE(flat_set.count(11));
@@ -94,8 +98,11 @@
for (int i = 0; i < 10000; i++) {
const int val = int_dist(rng);
if (i % 3) {
- flat_set.insert(val);
- gold_set.insert(val);
+ auto flat_result = flat_set.insert(val);
+ auto gold_result = gold_set.insert(val);
+ EXPECT_EQ(flat_result.first, flat_set.find(val));
+ EXPECT_EQ(gold_result.first, gold_set.find(val));
+ EXPECT_EQ(flat_result.second, gold_result.second);
} else {
flat_set.erase(val);
gold_set.erase(val);
diff --git a/src/base/thread_task_runner.cc b/src/base/thread_task_runner.cc
index 0576ee9..af89e8c 100644
--- a/src/base/thread_task_runner.cc
+++ b/src/base/thread_task_runner.cc
@@ -19,6 +19,7 @@
#include "perfetto/ext/base/thread_task_runner.h"
+#include <sys/prctl.h>
#include <condition_variable>
#include <functional>
#include <mutex>
@@ -52,7 +53,7 @@
thread_.join();
}
-ThreadTaskRunner::ThreadTaskRunner() {
+ThreadTaskRunner::ThreadTaskRunner(const std::string& name) : name_(name) {
std::mutex init_lock;
std::condition_variable init_cv;
@@ -66,6 +67,7 @@
// notifying).
init_cv.notify_one();
};
+
thread_ = std::thread(&ThreadTaskRunner::RunTaskThread, this,
std::move(initializer));
@@ -75,11 +77,43 @@
void ThreadTaskRunner::RunTaskThread(
std::function<void(UnixTaskRunner*)> initializer) {
+ if (!name_.empty()) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+ pthread_setname_np(name_.c_str());
+#else
+ prctl(PR_SET_NAME, name_.c_str());
+#endif
+ }
+
UnixTaskRunner task_runner;
task_runner.PostTask(std::bind(std::move(initializer), &task_runner));
task_runner.Run();
}
+void ThreadTaskRunner::PostTaskAndWaitForTesting(std::function<void()> fn) {
+ std::mutex mutex;
+ std::condition_variable cv;
+
+ std::unique_lock<std::mutex> lock(mutex);
+ bool done = false;
+ task_runner_->PostTask([&mutex, &cv, &done, &fn] {
+ fn();
+
+ std::lock_guard<std::mutex> inner_lock(mutex);
+ done = true;
+ cv.notify_one();
+ });
+ cv.wait(lock, [&done] { return done; });
+}
+
+uint64_t ThreadTaskRunner::GetThreadCPUTimeNsForTesting() {
+ uint64_t thread_time_ns = 0;
+ PostTaskAndWaitForTesting([&thread_time_ns] {
+ thread_time_ns = static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
+ });
+ return thread_time_ns;
+}
+
} // namespace base
} // namespace perfetto
diff --git a/src/base/watchdog_posix.cc b/src/base/watchdog_posix.cc
index 401ecdb..3517afd 100644
--- a/src/base/watchdog_posix.cc
+++ b/src/base/watchdog_posix.cc
@@ -28,8 +28,8 @@
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/ext/base/scoped_file.h"
-#include "perfetto/ext/base/thread_utils.h"
namespace perfetto {
namespace base {
diff --git a/src/base/watchdog_unittest.cc b/src/base/watchdog_unittest.cc
index f3bc850..2841a79 100644
--- a/src/base/watchdog_unittest.cc
+++ b/src/base/watchdog_unittest.cc
@@ -17,9 +17,9 @@
#include "perfetto/ext/base/watchdog.h"
#include "perfetto/base/logging.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/ext/base/paged_memory.h"
#include "perfetto/ext/base/scoped_file.h"
-#include "perfetto/ext/base/thread_utils.h"
#include "test/gtest_and_gmock.h"
#include <signal.h>
diff --git a/src/profiling/memory/client.cc b/src/profiling/memory/client.cc
index 8bcb2a0..ed65372 100644
--- a/src/profiling/memory/client.cc
+++ b/src/profiling/memory/client.cc
@@ -35,9 +35,9 @@
#include <new>
#include "perfetto/base/logging.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/scoped_file.h"
-#include "perfetto/ext/base/thread_utils.h"
#include "perfetto/ext/base/unix_socket.h"
#include "perfetto/ext/base/utils.h"
#include "src/profiling/memory/sampler.h"
diff --git a/src/profiling/memory/client_unittest.cc b/src/profiling/memory/client_unittest.cc
index e2f0500..68b2ee7 100644
--- a/src/profiling/memory/client_unittest.cc
+++ b/src/profiling/memory/client_unittest.cc
@@ -18,7 +18,7 @@
#include <thread>
-#include "perfetto/ext/base/thread_utils.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/ext/base/unix_socket.h"
#include "test/gtest_and_gmock.h"
diff --git a/src/profiling/memory/heapprofd_end_to_end_test.cc b/src/profiling/memory/heapprofd_end_to_end_test.cc
index d698650..96d4f50 100644
--- a/src/profiling/memory/heapprofd_end_to_end_test.cc
+++ b/src/profiling/memory/heapprofd_end_to_end_test.cc
@@ -47,23 +47,6 @@
using ::testing::Bool;
using ::testing::Eq;
-class HeapprofdDelegate : public ThreadDelegate {
- public:
- HeapprofdDelegate(const std::string& producer_socket)
- : producer_socket_(producer_socket) {}
- ~HeapprofdDelegate() override = default;
-
- void Initialize(base::TaskRunner* task_runner) override {
- producer_.reset(
- new HeapprofdProducer(HeapprofdMode::kCentral, task_runner));
- producer_->ConnectWithRetries(producer_socket_.c_str());
- }
-
- private:
- std::string producer_socket_;
- std::unique_ptr<HeapprofdProducer> producer_;
-};
-
constexpr const char* kHeapprofdModeProperty = "heapprofd.userdebug.mode";
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index 3fc8d82..c2908a0 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -242,7 +242,7 @@
int32_t row_id = static_cast<int32_t>(callsite_id.value);
node_to_row_id[i] = row_id;
- tables::HeapGraphAllocationTable::Row alloc_row{
+ tables::ExperimentalHeapGraphAllocationTable::Row alloc_row{
sequence_state.current_ts,
sequence_state.current_upid,
row_id,
@@ -250,7 +250,8 @@
static_cast<int64_t>(node_to_cumulative_count[i]),
static_cast<int64_t>(node.size),
static_cast<int64_t>(node_to_cumulative_size[i])};
- context_->storage->mutable_heap_graph_allocation_table()->Insert(alloc_row);
+ context_->storage->mutable_experimental_heap_graph_allocation_table()
+ ->Insert(alloc_row);
}
}
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index 2f93698..65c5304 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -85,8 +85,11 @@
PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_PROFILE_ALLOCATION_DEF);
+// This will eventually go away, when we also pre-compute the cumulative
+// sizes for native heap profiles.
#define PERFETTO_TP_HEAP_GRAPH_ALLOCATION_DEF(NAME, PARENT, C) \
- NAME(HeapGraphAllocationTable, "heap_graph_allocation") \
+ NAME(ExperimentalHeapGraphAllocationTable, \
+ "experimental_heap_graph_allocation") \
PERFETTO_TP_ROOT_TABLE(PARENT, C) \
C(int64_t, ts, Column::Flag::kSorted) \
C(uint32_t, upid) \
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index b523190..7e21a0a 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -446,8 +446,8 @@
*db_, &storage->heap_profile_allocation_table(),
storage->heap_profile_allocation_table().table_name());
DbSqliteTable::RegisterTable(
- *db_, &storage->heap_graph_allocation_table(),
- storage->heap_graph_allocation_table().table_name());
+ *db_, &storage->experimental_heap_graph_allocation_table(),
+ storage->experimental_heap_graph_allocation_table().table_name());
DbSqliteTable::RegisterTable(
*db_, &storage->cpu_profile_stack_sample_table(),
storage->cpu_profile_stack_sample_table().table_name());
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 5299168..26e1e00 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -603,11 +603,13 @@
return &heap_profile_allocation_table_;
}
- const tables::HeapGraphAllocationTable& heap_graph_allocation_table() const {
- return heap_graph_allocation_table_;
+ const tables::ExperimentalHeapGraphAllocationTable&
+ experimental_heap_graph_allocation_table() const {
+ return experimental_heap_graph_allocation_table_;
}
- tables::HeapGraphAllocationTable* mutable_heap_graph_allocation_table() {
- return &heap_graph_allocation_table_;
+ tables::ExperimentalHeapGraphAllocationTable*
+ mutable_experimental_heap_graph_allocation_table() {
+ return &experimental_heap_graph_allocation_table_;
}
const tables::CpuProfileStackSampleTable& cpu_profile_stack_sample_table()
@@ -837,8 +839,8 @@
nullptr};
tables::HeapProfileAllocationTable heap_profile_allocation_table_{
&string_pool_, nullptr};
- tables::HeapGraphAllocationTable heap_graph_allocation_table_{&string_pool_,
- nullptr};
+ tables::ExperimentalHeapGraphAllocationTable
+ experimental_heap_graph_allocation_table_{&string_pool_, nullptr};
tables::CpuProfileStackSampleTable cpu_profile_stack_sample_table_{
&string_pool_, nullptr};
diff --git a/src/traced/probes/filesystem/inode_file_data_source.h b/src/traced/probes/filesystem/inode_file_data_source.h
index ac5275c..8ccab1a 100644
--- a/src/traced/probes/filesystem/inode_file_data_source.h
+++ b/src/traced/probes/filesystem/inode_file_data_source.h
@@ -25,8 +25,8 @@
#include <string>
#include <unordered_map>
+#include "perfetto/base/flat_set.h"
#include "perfetto/base/task_runner.h"
-#include "perfetto/ext/base/flat_set.h"
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/traced/data_source_types.h"
#include "perfetto/ext/tracing/core/basic_types.h"
diff --git a/src/traced/probes/ftrace/ftrace_metadata.h b/src/traced/probes/ftrace/ftrace_metadata.h
index de9d89a..8294f25 100644
--- a/src/traced/probes/ftrace/ftrace_metadata.h
+++ b/src/traced/probes/ftrace/ftrace_metadata.h
@@ -23,8 +23,8 @@
#include <bitset>
+#include "perfetto/base/flat_set.h"
#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/flat_set.h"
#include "perfetto/ext/traced/data_source_types.h"
namespace perfetto {
diff --git a/src/traced/probes/ps/process_stats_data_source.h b/src/traced/probes/ps/process_stats_data_source.h
index 04c683e..100ef62 100644
--- a/src/traced/probes/ps/process_stats_data_source.h
+++ b/src/traced/probes/ps/process_stats_data_source.h
@@ -23,7 +23,7 @@
#include <unordered_map>
#include <vector>
-#include "perfetto/ext/base/flat_set.h"
+#include "perfetto/base/flat_set.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/basic_types.h"
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index aa7c6f6..6fd71dc 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -250,6 +250,7 @@
"internal/track_event_internal.cc",
"platform.cc",
"tracing.cc",
+ "track.cc",
"track_event_category_registry.cc",
"virtual_destructors.cc",
]
diff --git a/src/tracing/api_integrationtest.cc b/src/tracing/api_integrationtest.cc
index a9f3fbb..2fea0d0 100644
--- a/src/tracing/api_integrationtest.cc
+++ b/src/tracing/api_integrationtest.cc
@@ -21,6 +21,7 @@
#include <functional>
#include <list>
#include <mutex>
+#include <thread>
#include <vector>
#include "perfetto/tracing.h"
@@ -50,14 +51,19 @@
#include "protos/perfetto/trace/trace.gen.h"
#include "protos/perfetto/trace/trace_packet.gen.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
+#include "protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
+#include "protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "protos/perfetto/trace/track_event/log_message.gen.h"
#include "protos/perfetto/trace/track_event/log_message.pbzero.h"
#include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
+#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
#include "protos/perfetto/trace/track_event/source_location.gen.h"
#include "protos/perfetto/trace/track_event/source_location.pbzero.h"
#include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/track_descriptor.gen.h"
#include "protos/perfetto/trace/track_event/track_event.gen.h"
// Trace categories used in the tests.
@@ -345,7 +351,8 @@
bool incremental_state_was_cleared = false;
uint32_t sequence_id = 0;
for (const auto& packet : parsed_trace.packet()) {
- if (packet.incremental_state_cleared()) {
+ if (packet.sequence_flags() & perfetto::protos::pbzero::TracePacket::
+ SEQ_INCREMENTAL_STATE_CLEARED) {
incremental_state_was_cleared = true;
categories.clear();
event_names.clear();
@@ -558,25 +565,21 @@
bool begin_found = false;
bool end_found = false;
bool process_descriptor_found = false;
- bool thread_descriptor_found = false;
auto now = perfetto::test::GetTraceTimeNs();
uint32_t sequence_id = 0;
int32_t cur_pid = perfetto::test::GetCurrentProcessId();
for (const auto& packet : trace.packet()) {
- if (packet.has_process_descriptor()) {
- EXPECT_FALSE(process_descriptor_found);
- const auto& pd = packet.process_descriptor();
- EXPECT_EQ(cur_pid, pd.pid());
- process_descriptor_found = true;
+ if (packet.has_track_descriptor()) {
+ const auto& desc = packet.track_descriptor();
+ if (desc.has_process()) {
+ EXPECT_FALSE(process_descriptor_found);
+ const auto& pd = desc.process();
+ EXPECT_EQ(cur_pid, pd.pid());
+ process_descriptor_found = true;
+ }
}
- if (packet.has_thread_descriptor()) {
- EXPECT_FALSE(thread_descriptor_found);
- const auto& td = packet.thread_descriptor();
- EXPECT_EQ(cur_pid, td.pid());
- EXPECT_NE(0, td.tid());
- thread_descriptor_found = true;
- }
- if (packet.incremental_state_cleared()) {
+ if (packet.sequence_flags() &
+ perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
EXPECT_TRUE(packet.has_trace_packet_defaults());
incremental_state_was_cleared = true;
categories.clear();
@@ -585,6 +588,10 @@
if (!packet.has_track_event())
continue;
+ EXPECT_TRUE(
+ packet.sequence_flags() &
+ (perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED |
+ perfetto::protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE));
const auto& track_event = packet.track_event();
// Make sure we only see track events on one sequence.
@@ -636,7 +643,6 @@
}
EXPECT_TRUE(incremental_state_was_cleared);
EXPECT_TRUE(process_descriptor_found);
- EXPECT_TRUE(thread_descriptor_found);
EXPECT_TRUE(begin_found);
EXPECT_TRUE(end_found);
}
@@ -828,6 +834,230 @@
EXPECT_THAT(trace2, Not(HasSubstr("Session2_Third")));
}
+TEST_F(PerfettoApiTest, TrackEventProcessAndThreadDescriptors) {
+ // Thread and process descriptors can be set before tracing is enabled.
+ perfetto::TrackEvent::SetProcessDescriptor(
+ [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+ desc->set_name("hello.exe");
+ desc->set_chrome_process()->set_process_priority(1);
+ });
+
+ // Erased tracks shouldn't show up anywhere.
+ perfetto::Track erased(1234u);
+ perfetto::TrackEvent::SetTrackDescriptor(
+ erased, [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+ desc->set_name("ErasedTrack");
+ });
+ perfetto::TrackEvent::EraseTrackDescriptor(erased);
+
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+ TRACE_EVENT_INSTANT("test", "MainThreadEvent");
+
+ std::thread thread([&] {
+ perfetto::TrackEvent::SetThreadDescriptor(
+ [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+ desc->set_name("TestThread");
+ });
+ TRACE_EVENT_INSTANT("test", "ThreadEvent");
+ });
+ thread.join();
+
+ // Update the process descriptor while tracing is enabled. It should be
+ // immediately reflected in the trace.
+ perfetto::TrackEvent::SetProcessDescriptor(
+ [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+ desc->set_name("goodbye.exe");
+ });
+ perfetto::TrackEvent::Flush();
+
+ tracing_session->get()->StopBlocking();
+
+ // After tracing ends, setting the descriptor has no immediate effect.
+ perfetto::TrackEvent::SetProcessDescriptor(
+ [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+ desc->set_name("noop.exe");
+ });
+
+ std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
+ perfetto::protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
+
+ std::vector<perfetto::protos::gen::TrackDescriptor> descs;
+ std::vector<perfetto::protos::gen::TrackDescriptor> thread_descs;
+ constexpr uint32_t kMainThreadSequence = 2;
+ for (const auto& packet : trace.packet()) {
+ if (packet.has_track_descriptor()) {
+ if (packet.trusted_packet_sequence_id() == kMainThreadSequence) {
+ descs.push_back(packet.track_descriptor());
+ } else {
+ thread_descs.push_back(packet.track_descriptor());
+ }
+ }
+ }
+
+ // The main thread records the initial process name as well as the one that's
+ // set during tracing. Additionally it records a thread descriptor for the
+ // main thread.
+
+ EXPECT_EQ(3u, descs.size());
+
+ // Default track for the main thread.
+ EXPECT_EQ(0, descs[0].process().pid());
+ EXPECT_NE(0, descs[0].thread().pid());
+
+ // First process descriptor.
+ EXPECT_NE(0, descs[1].process().pid());
+ EXPECT_EQ("hello.exe", descs[1].name());
+
+ // Second process descriptor.
+ EXPECT_NE(0, descs[2].process().pid());
+ EXPECT_EQ("goodbye.exe", descs[2].name());
+
+ // The child thread records only its own thread descriptor (twice, since it
+ // was mutated).
+ EXPECT_EQ(2u, thread_descs.size());
+ EXPECT_EQ("TestThread", thread_descs[0].name());
+ EXPECT_NE(0, thread_descs[0].thread().pid());
+ EXPECT_NE(0, thread_descs[0].thread().tid());
+ EXPECT_EQ("TestThread", thread_descs[1].name());
+ EXPECT_NE(0, thread_descs[1].thread().pid());
+ EXPECT_NE(0, thread_descs[1].thread().tid());
+}
+
+TEST_F(PerfettoApiTest, TrackEventCustomTrack) {
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+ ds_cfg->set_legacy_config("bar");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ // Declare a custom track and give it a name.
+ uint64_t async_id = 123;
+ perfetto::TrackEvent::SetTrackDescriptor(
+ perfetto::Track(async_id),
+ [](perfetto::protos::pbzero::TrackDescriptor* desc) {
+ desc->set_name("MyCustomTrack");
+ });
+
+ // Start events on one thread and end them on another.
+ TRACE_EVENT_BEGIN("bar", "AsyncEvent", perfetto::Track(async_id), "debug_arg",
+ 123);
+
+ TRACE_EVENT_BEGIN("bar", "SubEvent", perfetto::Track(async_id),
+ [](perfetto::EventContext) {});
+ const auto main_thread_track =
+ perfetto::Track(async_id, perfetto::ThreadTrack::Current());
+ std::thread thread([&] {
+ TRACE_EVENT_END("bar", perfetto::Track(async_id));
+ TRACE_EVENT_END("bar", perfetto::Track(async_id), "arg1", false, "arg2",
+ true);
+ const auto thread_track =
+ perfetto::Track(async_id, perfetto::ThreadTrack::Current());
+ // Thread-scoped tracks will have different uuids on different thread even
+ // if the id matches.
+ ASSERT_NE(main_thread_track.uuid, thread_track.uuid);
+ });
+ thread.join();
+
+ perfetto::TrackEvent::Flush();
+ tracing_session->get()->StopBlocking();
+
+ std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
+ perfetto::protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
+
+ // Check that the track uuids match on the begin and end events.
+ const auto track = perfetto::Track(async_id);
+ constexpr uint32_t kMainThreadSequence = 2;
+ int event_count = 0;
+ bool found_descriptor = false;
+ for (const auto& packet : trace.packet()) {
+ if (packet.has_track_descriptor() &&
+ !packet.track_descriptor().has_process() &&
+ !packet.track_descriptor().has_thread()) {
+ auto td = packet.track_descriptor();
+ EXPECT_EQ("MyCustomTrack", td.name());
+ EXPECT_EQ(track.uuid, td.uuid());
+ EXPECT_EQ(perfetto::ProcessTrack::Current().uuid, td.parent_uuid());
+ found_descriptor = true;
+ continue;
+ }
+
+ if (!packet.has_track_event())
+ continue;
+ auto track_event = packet.track_event();
+ if (track_event.type() ==
+ perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN) {
+ EXPECT_EQ(kMainThreadSequence, packet.trusted_packet_sequence_id());
+ EXPECT_EQ(track.uuid, track_event.track_uuid());
+ } else {
+ EXPECT_NE(kMainThreadSequence, packet.trusted_packet_sequence_id());
+ EXPECT_EQ(track.uuid, track_event.track_uuid());
+ }
+ event_count++;
+ }
+ EXPECT_TRUE(found_descriptor);
+ EXPECT_EQ(4, event_count);
+ perfetto::TrackEvent::EraseTrackDescriptor(track);
+}
+
+TEST_F(PerfettoApiTest, TrackEventAnonymousCustomTrack) {
+ // Setup the trace config.
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name("track_event");
+ ds_cfg->set_legacy_config("bar");
+
+ // Create a new trace session.
+ auto* tracing_session = NewTrace(cfg);
+ tracing_session->get()->StartBlocking();
+
+ // Emit an async event without giving it an explicit descriptor.
+ uint64_t async_id = 4004;
+ auto track = perfetto::Track(async_id, perfetto::ThreadTrack::Current());
+ TRACE_EVENT_BEGIN("bar", "AsyncEvent", track);
+ std::thread thread([&] { TRACE_EVENT_END("bar", track); });
+ thread.join();
+
+ perfetto::TrackEvent::Flush();
+ tracing_session->get()->StopBlocking();
+
+ std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
+ perfetto::protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
+
+ // Check that a descriptor for the track was emitted.
+ bool found_descriptor = false;
+ for (const auto& packet : trace.packet()) {
+ if (packet.has_track_descriptor() &&
+ !packet.track_descriptor().has_process() &&
+ !packet.track_descriptor().has_thread()) {
+ auto td = packet.track_descriptor();
+ EXPECT_EQ(track.uuid, td.uuid());
+ EXPECT_EQ(perfetto::ThreadTrack::Current().uuid, td.parent_uuid());
+ found_descriptor = true;
+ }
+ }
+ EXPECT_TRUE(found_descriptor);
+}
+
TEST_F(PerfettoApiTest, TrackEventTypedArgs) {
// Setup the trace config.
perfetto::TraceConfig cfg;
diff --git a/src/tracing/internal/track_event_internal.cc b/src/tracing/internal/track_event_internal.cc
index 71afc7b..7bd766c 100644
--- a/src/tracing/internal/track_event_internal.cc
+++ b/src/tracing/internal/track_event_internal.cc
@@ -16,9 +16,9 @@
#include "perfetto/tracing/internal/track_event_internal.h"
+#include "perfetto/base/proc_utils.h"
+#include "perfetto/base/thread_utils.h"
#include "perfetto/base/time.h"
-#include "perfetto/ext/base/proc_utils.h"
-#include "perfetto/ext/base/thread_utils.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/track_event.h"
#include "perfetto/tracing/track_event_category_registry.h"
@@ -28,8 +28,7 @@
#include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
-#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
-#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
namespace perfetto {
namespace internal {
@@ -95,49 +94,6 @@
#endif
}
-uint64_t GetTimeNs() {
- if (GetClockType() == protos::pbzero::ClockSnapshot::Clock::BOOTTIME)
- return static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count());
- PERFETTO_DCHECK(GetClockType() ==
- protos::pbzero::ClockSnapshot::Clock::MONOTONIC);
- return static_cast<uint64_t>(perfetto::base::GetWallTimeNs().count());
-}
-
-protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket(
- TraceWriterBase* trace_writer,
- uint64_t timestamp) {
- auto packet = trace_writer->NewTracePacket();
- packet->set_timestamp(timestamp);
- // TODO(skyostil): Stop emitting this for every event once the trace processor
- // understands trace packet defaults.
- if (GetClockType() != protos::pbzero::ClockSnapshot::Clock::BOOTTIME)
- packet->set_timestamp_clock_id(GetClockType());
- return packet;
-}
-
-// static
-void WriteSequenceDescriptors(TraceWriterBase* trace_writer,
- uint64_t timestamp) {
- if (perfetto::base::GetThreadId() == g_main_thread) {
- auto packet = NewTracePacket(trace_writer, timestamp);
- packet->set_incremental_state_cleared(true);
- auto defaults = packet->set_trace_packet_defaults();
- defaults->set_timestamp_clock_id(GetClockType());
- auto pd = packet->set_process_descriptor();
- pd->set_pid(static_cast<int32_t>(base::GetProcessId()));
- // TODO(skyostil): Record command line.
- }
- {
- auto packet = NewTracePacket(trace_writer, timestamp);
- packet->set_incremental_state_cleared(true);
- auto defaults = packet->set_trace_packet_defaults();
- defaults->set_timestamp_clock_id(GetClockType());
- auto td = packet->set_thread_descriptor();
- td->set_pid(static_cast<int32_t>(base::GetProcessId()));
- td->set_tid(static_cast<int32_t>(perfetto::base::GetThreadId()));
- }
-}
-
} // namespace
// static
@@ -177,6 +133,57 @@
}
// static
+uint64_t TrackEventInternal::GetTimeNs() {
+ if (GetClockType() == protos::pbzero::ClockSnapshot::Clock::BOOTTIME)
+ return static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count());
+ PERFETTO_DCHECK(GetClockType() ==
+ protos::pbzero::ClockSnapshot::Clock::MONOTONIC);
+ return static_cast<uint64_t>(perfetto::base::GetWallTimeNs().count());
+}
+
+// static
+void TrackEventInternal::ResetIncrementalState(TraceWriterBase* trace_writer,
+ uint64_t timestamp) {
+ auto default_track = ThreadTrack::Current();
+ {
+ // Mark any incremental state before this point invalid. Also set up
+ // defaults so that we don't need to repeat constant data for each packet.
+ auto packet = NewTracePacket(
+ trace_writer, timestamp,
+ protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
+ auto defaults = packet->set_trace_packet_defaults();
+ defaults->set_timestamp_clock_id(GetClockType());
+
+ // Establish the default track for this event sequence.
+ auto track_defaults = defaults->set_track_event_defaults();
+ track_defaults->set_track_uuid(default_track.uuid);
+ }
+
+ // Every thread should write a descriptor for its default track, because most
+ // trace points won't explicitly reference it.
+ WriteTrackDescriptor(default_track, trace_writer);
+
+ // Additionally the main thread should dump the process descriptor.
+ if (perfetto::base::GetThreadId() == g_main_thread)
+ WriteTrackDescriptor(ProcessTrack::Current(), trace_writer);
+}
+
+// static
+protozero::MessageHandle<protos::pbzero::TracePacket>
+TrackEventInternal::NewTracePacket(TraceWriterBase* trace_writer,
+ uint64_t timestamp,
+ uint32_t seq_flags) {
+ auto packet = trace_writer->NewTracePacket();
+ packet->set_timestamp(timestamp);
+ // TODO(skyostil): Stop emitting this for every event once the trace processor
+ // understands trace packet defaults.
+ if (GetClockType() != protos::pbzero::ClockSnapshot::Clock::BOOTTIME)
+ packet->set_timestamp_clock_id(GetClockType());
+ packet->set_sequence_flags(seq_flags);
+ return packet;
+}
+
+// static
EventContext TrackEventInternal::WriteEvent(
TraceWriterBase* trace_writer,
TrackEventIncrementalState* incr_state,
@@ -189,7 +196,7 @@
if (incr_state->was_cleared) {
incr_state->was_cleared = false;
- WriteSequenceDescriptors(trace_writer, timestamp);
+ ResetIncrementalState(trace_writer, timestamp);
}
auto packet = NewTracePacket(trace_writer, timestamp);
diff --git a/src/tracing/test/api_test_support.cc b/src/tracing/test/api_test_support.cc
index 24d8d67..1667ffc 100644
--- a/src/tracing/test/api_test_support.cc
+++ b/src/tracing/test/api_test_support.cc
@@ -16,8 +16,8 @@
#include "src/tracing/test/api_test_support.h"
+#include "perfetto/base/proc_utils.h"
#include "perfetto/base/time.h"
-#include "perfetto/ext/base/proc_utils.h"
namespace perfetto {
namespace test {
diff --git a/src/tracing/test/tracing_module.cc b/src/tracing/test/tracing_module.cc
index 09b6e5f..7c10d4e 100644
--- a/src/tracing/test/tracing_module.cc
+++ b/src/tracing/test/tracing_module.cc
@@ -82,4 +82,11 @@
puts("Hello");
}
+void FunctionWithOneTrackEventWithCustomTrack() {
+ TRACE_EVENT_BEGIN("cat1", "EventWithTrack", perfetto::Track(8086));
+ // Simulates the non-tracing work of this function, which should take priority
+ // over the above trace event in terms of instruction scheduling.
+ puts("Hello");
+}
+
} // namespace tracing_module
diff --git a/src/tracing/test/tracing_module.h b/src/tracing/test/tracing_module.h
index e0fd1b3..c005a6f 100644
--- a/src/tracing/test/tracing_module.h
+++ b/src/tracing/test/tracing_module.h
@@ -37,6 +37,7 @@
void FunctionWithOneTrackEventWithTypedArgument();
void FunctionWithOneScopedTrackEvent();
void FunctionWithOneTrackEventWithDebugAnnotations();
+void FunctionWithOneTrackEventWithCustomTrack();
} // namespace tracing_module
diff --git a/src/tracing/tracing.cc b/src/tracing/tracing.cc
index fc6a696..54d5722 100644
--- a/src/tracing/tracing.cc
+++ b/src/tracing/tracing.cc
@@ -15,6 +15,7 @@
*/
#include "perfetto/tracing/tracing.h"
+#include "perfetto/tracing/internal/track_event_internal.h"
#include "src/tracing/internal/tracing_muxer_impl.h"
#include <condition_variable>
@@ -27,6 +28,7 @@
// Make sure the headers and implementation files agree on the build config.
PERFETTO_CHECK(args.dcheck_is_on_ == PERFETTO_DCHECK_IS_ON());
internal::TracingMuxerImpl::InitializeInstance(args);
+ internal::TrackRegistry::InitializeInstance();
}
// static
diff --git a/src/tracing/track.cc b/src/tracing/track.cc
new file mode 100644
index 0000000..91045c4
--- /dev/null
+++ b/src/tracing/track.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfetto/tracing/track.h"
+
+#include "perfetto/ext/base/uuid.h"
+#include "perfetto/tracing/internal/track_event_data_source.h"
+#include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
+#include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
+
+namespace perfetto {
+
+// static
+uint64_t Track::process_uuid;
+
+void Track::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ desc->set_uuid(uuid);
+ if (parent_uuid)
+ desc->set_parent_uuid(parent_uuid);
+}
+
+void ProcessTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ Track::Serialize(desc);
+ auto pd = desc->set_process();
+ pd->set_pid(pid);
+ // TODO(skyostil): Record command line.
+}
+
+void ThreadTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
+ Track::Serialize(desc);
+ auto td = desc->set_thread();
+ td->set_pid(pid);
+ td->set_tid(tid);
+ // TODO(skyostil): Record thread name.
+}
+
+namespace internal {
+
+// static
+TrackRegistry* TrackRegistry::instance_;
+
+TrackRegistry::TrackRegistry() = default;
+TrackRegistry::~TrackRegistry() = default;
+
+// static
+void TrackRegistry::InitializeInstance() {
+ PERFETTO_DCHECK(!instance_);
+ instance_ = new TrackRegistry();
+ Track::process_uuid = static_cast<uint64_t>(base::Uuidv4().lsb());
+}
+
+void TrackRegistry::UpdateTrackImpl(
+ Track track,
+ std::function<void(protos::pbzero::TrackDescriptor*)> fill_function) {
+ constexpr size_t kInitialSliceSize = 32;
+ constexpr size_t kMaximumSliceSize = 4096;
+ protozero::HeapBuffered<protos::pbzero::TrackDescriptor> new_descriptor(
+ kInitialSliceSize, kMaximumSliceSize);
+ fill_function(new_descriptor.get());
+ auto serialized_desc = new_descriptor.SerializeAsString();
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ tracks_[track.uuid] = std::move(serialized_desc);
+ }
+}
+
+void TrackRegistry::EraseTrack(Track track) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ tracks_.erase(track.uuid);
+}
+
+// static
+void TrackRegistry::WriteTrackDescriptor(
+ const SerializedTrackDescriptor& desc,
+ protozero::MessageHandle<protos::pbzero::TracePacket> packet) {
+ packet->AppendString(
+ perfetto::protos::pbzero::TracePacket::kTrackDescriptorFieldNumber, desc);
+}
+
+} // namespace internal
+} // namespace perfetto
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 3388f02..0fe00be 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -19,8 +19,6 @@
source_set("end_to_end_integrationtests") {
testonly = true
deps = [
- ":task_runner_thread",
- ":task_runner_thread_delegates",
":test_helper",
"../gn:default_deps",
"../gn:gtest_and_gmock",
@@ -73,8 +71,6 @@
]
testonly = true
deps = [
- ":task_runner_thread",
- ":task_runner_thread_delegates",
":test_helper",
"../gn:default_deps",
"../protos/perfetto/trace:zero",
@@ -98,38 +94,6 @@
]
}
-source_set("task_runner_thread") {
- testonly = true
- deps = [
- "../gn:default_deps",
- "../src/base",
- "../src/base:test_support",
- ]
- sources = [
- "task_runner_thread.cc",
- "task_runner_thread.h",
- ]
-}
-
-source_set("task_runner_thread_delegates") {
- testonly = true
- deps = [
- ":task_runner_thread",
- "../gn:default_deps",
- "../include/perfetto/ext/traced",
- "../protos/perfetto/config:cpp",
- "../src/base:test_support",
- "../src/traced/probes:probes_src",
- "../src/tracing:ipc",
- ]
- sources = [
- "fake_producer.cc",
- "fake_producer.h",
- "task_runner_thread_delegates.cc",
- "task_runner_thread_delegates.h",
- ]
-}
-
source_set("test_helper") {
testonly = true
public_deps = [
@@ -137,14 +101,17 @@
"../src/tracing:ipc",
]
deps = [
- ":task_runner_thread",
- ":task_runner_thread_delegates",
"../gn:default_deps",
"../include/perfetto/ext/traced",
+ "../protos/perfetto/config:cpp",
"../protos/perfetto/trace:zero",
"../src/base:test_support",
+ "../src/traced/probes:probes_src",
+ "../src/tracing:ipc",
]
sources = [
+ "fake_producer.cc",
+ "fake_producer.h",
"test_helper.cc",
"test_helper.h",
]
@@ -157,8 +124,6 @@
source_set("end_to_end_benchmarks") {
testonly = true
deps = [
- ":task_runner_thread",
- ":task_runner_thread_delegates",
":test_helper",
"../gn:benchmark",
"../gn:default_deps",
diff --git a/test/cts/BUILD.gn b/test/cts/BUILD.gn
index f7868d8..84aba0c 100644
--- a/test/cts/BUILD.gn
+++ b/test/cts/BUILD.gn
@@ -40,3 +40,13 @@
"utils.cc",
]
}
+
+static_library("perfetto_cts_jni_deps") {
+ complete_static_lib = true
+ testonly = true
+ deps = [
+ "..:test_helper",
+ "../../gn:default_deps",
+ "../../src/base:test_support",
+ ]
+}
diff --git a/test/end_to_end_benchmark.cc b/test/end_to_end_benchmark.cc
index 0668487..ff1fe74 100644
--- a/test/end_to_end_benchmark.cc
+++ b/test/end_to_end_benchmark.cc
@@ -22,8 +22,6 @@
#include "perfetto/tracing/core/trace_config.h"
#include "src/base/test/test_task_runner.h"
#include "test/gtest_and_gmock.h"
-#include "test/task_runner_thread.h"
-#include "test/task_runner_thread_delegates.h"
#include "test/test_helper.h"
#include "protos/perfetto/config/test_config.gen.h"
@@ -73,8 +71,10 @@
helper.WaitForProducerEnabled();
uint64_t wall_start_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
- uint64_t service_start_ns = helper.service_thread()->GetThreadCPUTimeNs();
- uint64_t producer_start_ns = helper.producer_thread()->GetThreadCPUTimeNs();
+ uint64_t service_start_ns =
+ helper.service_thread()->GetThreadCPUTimeNsForTesting();
+ uint64_t producer_start_ns =
+ helper.producer_thread()->GetThreadCPUTimeNsForTesting();
uint32_t iterations = 0;
for (auto _ : state) {
auto cname = "produced.and.committed." + std::to_string(iterations++);
@@ -83,9 +83,11 @@
task_runner.RunUntilCheckpoint(cname, time_for_messages_ms);
}
uint64_t service_ns =
- helper.service_thread()->GetThreadCPUTimeNs() - service_start_ns;
+ helper.service_thread()->GetThreadCPUTimeNsForTesting() -
+ service_start_ns;
uint64_t producer_ns =
- helper.producer_thread()->GetThreadCPUTimeNs() - producer_start_ns;
+ helper.producer_thread()->GetThreadCPUTimeNsForTesting() -
+ producer_start_ns;
uint64_t wall_ns =
static_cast<uint64_t>(base::GetWallTimeNs().count()) - wall_start_ns;
@@ -150,8 +152,8 @@
helper.WaitForProducerEnabled();
uint64_t wall_start_ns = static_cast<uint64_t>(base::GetWallTimeNs().count());
- uint64_t service_start_ns =
- static_cast<uint64_t>(helper.service_thread()->GetThreadCPUTimeNs());
+ uint64_t service_start_ns = static_cast<uint64_t>(
+ helper.service_thread()->GetThreadCPUTimeNsForTesting());
uint64_t consumer_start_ns =
static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
uint64_t read_time_taken_ns = 0;
@@ -193,7 +195,8 @@
}
}
uint64_t service_ns =
- helper.service_thread()->GetThreadCPUTimeNs() - service_start_ns;
+ helper.service_thread()->GetThreadCPUTimeNsForTesting() -
+ service_start_ns;
uint64_t consumer_ns =
static_cast<uint64_t>(base::GetThreadCPUTimeNs().count()) -
consumer_start_ns;
diff --git a/test/end_to_end_integrationtest.cc b/test/end_to_end_integrationtest.cc
index 209693d..52947df 100644
--- a/test/end_to_end_integrationtest.cc
+++ b/test/end_to_end_integrationtest.cc
@@ -35,8 +35,6 @@
#include "src/traced/probes/ftrace/ftrace_controller.h"
#include "src/traced/probes/ftrace/ftrace_procfs.h"
#include "test/gtest_and_gmock.h"
-#include "test/task_runner_thread.h"
-#include "test/task_runner_thread_delegates.h"
#include "test/test_helper.h"
#include "protos/perfetto/config/power/android_power_config.pbzero.h"
@@ -362,9 +360,8 @@
helper.StartServiceIfRequired();
#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- TaskRunnerThread producer_thread("perfetto.prd");
- producer_thread.Start(std::unique_ptr<ProbesProducerDelegate>(
- new ProbesProducerDelegate(TEST_PRODUCER_SOCK_NAME)));
+ ProbesProducerThread probes(TEST_PRODUCER_SOCK_NAME);
+ probes.Connect();
#endif
helper.ConnectConsumer();
@@ -408,9 +405,8 @@
helper.StartServiceIfRequired();
#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- TaskRunnerThread producer_thread("perfetto.prd");
- producer_thread.Start(std::unique_ptr<ProbesProducerDelegate>(
- new ProbesProducerDelegate(TEST_PRODUCER_SOCK_NAME)));
+ ProbesProducerThread probes(TEST_PRODUCER_SOCK_NAME);
+ probes.Connect();
#endif
helper.ConnectConsumer();
@@ -467,9 +463,8 @@
helper.StartServiceIfRequired();
#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- TaskRunnerThread producer_thread("perfetto.prd");
- producer_thread.Start(std::unique_ptr<ProbesProducerDelegate>(
- new ProbesProducerDelegate(TEST_PRODUCER_SOCK_NAME)));
+ ProbesProducerThread probes(TEST_PRODUCER_SOCK_NAME);
+ probes.Connect();
#else
base::ignore_result(TEST_PRODUCER_SOCK_NAME);
#endif
diff --git a/test/end_to_end_shared_memory_fuzzer.cc b/test/end_to_end_shared_memory_fuzzer.cc
index 052f888..ce53acf 100644
--- a/test/end_to_end_shared_memory_fuzzer.cc
+++ b/test/end_to_end_shared_memory_fuzzer.cc
@@ -30,8 +30,6 @@
#include "perfetto/tracing/core/data_source_descriptor.h"
#include "protos/perfetto/trace/test_event.pbzero.h"
#include "src/base/test/test_task_runner.h"
-#include "test/task_runner_thread.h"
-#include "test/task_runner_thread_delegates.h"
#include "test/test_helper.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
@@ -109,23 +107,33 @@
std::function<void()> on_produced_and_committed_;
};
-class FakeProducerDelegate : public ThreadDelegate {
+class FuzzerFakeProducerThread {
public:
- FakeProducerDelegate(const uint8_t* data,
- size_t size,
- std::function<void()> on_produced_and_committed)
+ FuzzerFakeProducerThread(const uint8_t* data,
+ size_t size,
+ std::function<void()> on_produced_and_committed)
: data_(data),
size_(size),
on_produced_and_committed_(on_produced_and_committed) {}
- ~FakeProducerDelegate() override = default;
- void Initialize(base::TaskRunner* task_runner) override {
- producer_.reset(new FakeProducer("android.perfetto.FakeProducer", data_,
- size_, on_produced_and_committed_));
- producer_->Connect(TEST_PRODUCER_SOCK_NAME, task_runner);
+ ~FuzzerFakeProducerThread() {
+ if (!runner_)
+ return;
+ runner_->PostTaskAndWaitForTesting([this]() { producer_.reset(); });
+ }
+
+ void Connect() {
+ runner_ = base::ThreadTaskRunner::CreateAndStart("perfetto.prd.fake");
+ runner_->PostTaskAndWaitForTesting([this]() {
+ producer_.reset(new FakeProducer("android.perfetto.FakeProducer", data_,
+ size_, on_produced_and_committed_));
+ producer_->Connect(TEST_PRODUCER_SOCK_NAME, runner_->get());
+ });
}
private:
+ base::Optional<base::ThreadTaskRunner> runner_; // Keep first.
+
std::unique_ptr<FakeProducer> producer_;
const uint8_t* data_;
const size_t size_;
@@ -140,11 +148,10 @@
TestHelper helper(&task_runner);
helper.StartServiceIfRequired();
- TaskRunnerThread producer_thread("perfetto.prd");
- producer_thread.Start(std::unique_ptr<FakeProducerDelegate>(
- new FakeProducerDelegate(data, size,
- helper.WrapTask(task_runner.CreateCheckpoint(
- "produced.and.committed")))));
+ auto cp =
+ helper.WrapTask(task_runner.CreateCheckpoint("produced.and.committed"));
+ FuzzerFakeProducerThread producer_thread(data, size, cp);
+ producer_thread.Connect();
helper.ConnectConsumer();
helper.WaitForConsumerConnect();
diff --git a/test/fake_producer.cc b/test/fake_producer.cc
index 17f80f0..730ec00 100644
--- a/test/fake_producer.cc
+++ b/test/fake_producer.cc
@@ -16,7 +16,6 @@
#include "test/fake_producer.h"
-#include <condition_variable>
#include <mutex>
#include "perfetto/base/logging.h"
diff --git a/test/task_runner_thread.cc b/test/task_runner_thread.cc
deleted file mode 100644
index c625078..0000000
--- a/test/task_runner_thread.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2018 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 <pthread.h>
-#include <stdlib.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <condition_variable>
-#include <thread>
-
-#include "perfetto/base/time.h"
-#include "perfetto/ext/base/file_utils.h"
-#include "perfetto/ext/base/string_splitter.h"
-#include "test/task_runner_thread.h"
-
-namespace perfetto {
-
-TaskRunnerThread::TaskRunnerThread(const char* name) : name_(name) {}
-TaskRunnerThread::~TaskRunnerThread() {
- Stop();
-}
-
-void TaskRunnerThread::Start(std::unique_ptr<ThreadDelegate> delegate) {
- // Begin holding the lock for the condition variable.
- std::unique_lock<std::mutex> lock(mutex_);
-
- // Start the thread.
- PERFETTO_DCHECK(!runner_);
- thread_ = std::thread(&TaskRunnerThread::Run, this, std::move(delegate));
-
- // Wait for runner to be ready.
- ready_.wait_for(lock, std::chrono::seconds(10),
- [this]() { return runner_ != nullptr; });
-}
-
-void TaskRunnerThread::Stop() {
- {
- std::unique_lock<std::mutex> lock(mutex_);
- if (runner_)
- runner_->Quit();
- }
-
- if (thread_.joinable())
- thread_.join();
-}
-
-uint64_t TaskRunnerThread::GetThreadCPUTimeNs() {
- std::condition_variable cv;
- std::unique_lock<std::mutex> lock(mutex_);
- uint64_t thread_time_ns = 0;
-
- if (!runner_)
- return 0;
-
- runner_->PostTask([this, &thread_time_ns, &cv] {
- std::unique_lock<std::mutex> inner_lock(mutex_);
- thread_time_ns = static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
- cv.notify_one();
- });
-
- cv.wait(lock, [&thread_time_ns] { return thread_time_ns != 0; });
- return thread_time_ns;
-}
-
-void TaskRunnerThread::Run(std::unique_ptr<ThreadDelegate> delegate) {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
- pthread_setname_np(name_);
-#else
- pthread_setname_np(pthread_self(), name_);
-#endif
-
- // Create the task runner and execute the specicalised code.
- base::UnixTaskRunner task_runner;
- delegate->Initialize(&task_runner);
-
- // Pass the runner back to the main thread.
- {
- std::unique_lock<std::mutex> lock(mutex_);
- runner_ = &task_runner;
- }
-
- // Notify the main thread that the runner is ready.
- ready_.notify_one();
-
- // Spin the loop.
- task_runner.Run();
-
- // Ensure we clear out the delegate before runner goes out
- // of scope.
- delegate.reset();
-
- // Cleanup the runner.
- {
- std::unique_lock<std::mutex> lock(mutex_);
- runner_ = nullptr;
- }
-}
-
-ThreadDelegate::~ThreadDelegate() = default;
-
-} // namespace perfetto
diff --git a/test/task_runner_thread.h b/test/task_runner_thread.h
deleted file mode 100644
index 354c308..0000000
--- a/test/task_runner_thread.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 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 TEST_TASK_RUNNER_THREAD_H_
-#define TEST_TASK_RUNNER_THREAD_H_
-
-#include <condition_variable>
-#include <mutex>
-#include <thread>
-
-#include "perfetto/base/task_runner.h"
-#include "src/base/test/test_task_runner.h"
-
-namespace perfetto {
-
-// Used to perform initialization work on a background TaskRunnerThread.
-class ThreadDelegate {
- public:
- virtual ~ThreadDelegate();
-
- // Invoked on the target thread before the message loop is started.
- virtual void Initialize(base::TaskRunner* task_runner) = 0;
-};
-
-// Background thread which spins a task runner until completed or the thread is
-// destroyed. If the thread is destroyed before the task runner completes, the
-// task runner is quit and the thread is joined.
-class TaskRunnerThread {
- public:
- explicit TaskRunnerThread(const char* name);
- ~TaskRunnerThread();
-
- // Blocks until the thread has been created and Initialize() has been
- // called.
- void Start(std::unique_ptr<ThreadDelegate> delegate);
-
- // Blocks until the thread has been stopped and joined.
- void Stop();
-
- uint64_t GetThreadCPUTimeNs();
-
- private:
- void Run(std::unique_ptr<ThreadDelegate> delegate);
-
- const char* const name_;
- std::thread thread_;
- std::condition_variable ready_;
-
- // All variables below this point are protected by |mutex_|.
- std::mutex mutex_;
- base::UnixTaskRunner* runner_ = nullptr;
-};
-
-} // namespace perfetto
-
-#endif // TEST_TASK_RUNNER_THREAD_H_
diff --git a/test/task_runner_thread_delegates.cc b/test/task_runner_thread_delegates.cc
deleted file mode 100644
index 291482f..0000000
--- a/test/task_runner_thread_delegates.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "test/task_runner_thread_delegates.h"
-
-namespace perfetto {
-
-ServiceDelegate::~ServiceDelegate() = default;
-ProbesProducerDelegate::~ProbesProducerDelegate() = default;
-FakeProducerDelegate::~FakeProducerDelegate() = default;
-
-} // namespace perfetto
diff --git a/test/task_runner_thread_delegates.h b/test/task_runner_thread_delegates.h
deleted file mode 100644
index bea384a..0000000
--- a/test/task_runner_thread_delegates.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2018 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 TEST_TASK_RUNNER_THREAD_DELEGATES_H_
-#define TEST_TASK_RUNNER_THREAD_DELEGATES_H_
-
-#include "perfetto/ext/tracing/ipc/service_ipc_host.h"
-#include "src/traced/probes/probes_producer.h"
-#include "test/fake_producer.h"
-#include "test/task_runner_thread.h"
-
-namespace perfetto {
-// This is used only in daemon starting integrations tests.
-class ServiceDelegate : public ThreadDelegate {
- public:
- ServiceDelegate(const std::string& producer_socket,
- const std::string& consumer_socket)
- : producer_socket_(producer_socket), consumer_socket_(consumer_socket) {}
- ~ServiceDelegate() override;
-
- void Initialize(base::TaskRunner* task_runner) override {
- svc_ = ServiceIPCHost::CreateInstance(task_runner);
- unlink(producer_socket_.c_str());
- unlink(consumer_socket_.c_str());
- svc_->Start(producer_socket_.c_str(), consumer_socket_.c_str());
- }
-
- private:
- std::string producer_socket_;
- std::string consumer_socket_;
- std::unique_ptr<ServiceIPCHost> svc_;
-};
-
-// This is used only in daemon starting integrations tests.
-class ProbesProducerDelegate : public ThreadDelegate {
- public:
- ProbesProducerDelegate(const std::string& producer_socket)
- : producer_socket_(producer_socket) {}
- ~ProbesProducerDelegate() override;
-
- void Initialize(base::TaskRunner* task_runner) override {
- producer_.reset(new ProbesProducer);
- producer_->ConnectWithRetries(producer_socket_.c_str(), task_runner);
- }
-
- private:
- std::string producer_socket_;
- std::unique_ptr<ProbesProducer> producer_;
-};
-
-class FakeProducerDelegate : public ThreadDelegate {
- public:
- FakeProducerDelegate(const std::string& producer_socket,
- std::function<void()> setup_callback,
- std::function<void()> connect_callback)
- : producer_socket_(producer_socket),
- setup_callback_(std::move(setup_callback)),
- connect_callback_(std::move(connect_callback)) {}
- ~FakeProducerDelegate() override;
-
- void Initialize(base::TaskRunner* task_runner) override {
- producer_.reset(new FakeProducer("android.perfetto.FakeProducer"));
- producer_->Connect(producer_socket_.c_str(), task_runner,
- std::move(setup_callback_),
- std::move(connect_callback_));
- }
-
- FakeProducer* producer() { return producer_.get(); }
-
- private:
- std::string producer_socket_;
- std::unique_ptr<FakeProducer> producer_;
- std::function<void()> setup_callback_;
- std::function<void()> connect_callback_;
-};
-} // namespace perfetto
-
-#endif // TEST_TASK_RUNNER_THREAD_DELEGATES_H_
diff --git a/test/test_helper.cc b/test/test_helper.cc
index e716c07..51d9cb7 100644
--- a/test/test_helper.cc
+++ b/test/test_helper.cc
@@ -18,7 +18,6 @@
#include "perfetto/ext/traced/traced.h"
#include "perfetto/ext/tracing/core/trace_packet.h"
-#include "test/task_runner_thread_delegates.h"
#include "perfetto/ext/tracing/ipc/default_socket.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
@@ -41,8 +40,10 @@
TestHelper::TestHelper(base::TestTaskRunner* task_runner)
: instance_num_(next_instance_num_++),
task_runner_(task_runner),
- service_thread_("perfetto.svc"),
- producer_thread_("perfetto.prd") {}
+ service_thread_(TEST_PRODUCER_SOCK_NAME, TEST_CONSUMER_SOCK_NAME),
+ fake_producer_thread_(TEST_PRODUCER_SOCK_NAME,
+ WrapTask(CreateCheckpoint("producer.setup")),
+ WrapTask(CreateCheckpoint("producer.enabled"))) {}
void TestHelper::OnConnect() {
std::move(on_connect_callback_)();
@@ -77,19 +78,13 @@
void TestHelper::StartServiceIfRequired() {
#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- service_thread_.Start(std::unique_ptr<ServiceDelegate>(
- new ServiceDelegate(TEST_PRODUCER_SOCK_NAME, TEST_CONSUMER_SOCK_NAME)));
+ service_thread_.Start();
#endif
}
FakeProducer* TestHelper::ConnectFakeProducer() {
- std::unique_ptr<FakeProducerDelegate> producer_delegate(
- new FakeProducerDelegate(TEST_PRODUCER_SOCK_NAME,
- WrapTask(CreateCheckpoint("producer.setup")),
- WrapTask(CreateCheckpoint("producer.enabled"))));
- FakeProducerDelegate* producer_delegate_cached = producer_delegate.get();
- producer_thread_.Start(std::move(producer_delegate));
- return producer_delegate_cached->producer();
+ fake_producer_thread_.Connect();
+ return fake_producer_thread_.producer();
}
void TestHelper::ConnectConsumer() {
diff --git a/test/test_helper.h b/test/test_helper.h
index 11897e5..e18531e 100644
--- a/test/test_helper.h
+++ b/test/test_helper.h
@@ -18,18 +18,121 @@
#define TEST_TEST_HELPER_H_
#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/thread_task_runner.h"
#include "perfetto/ext/tracing/core/consumer.h"
#include "perfetto/ext/tracing/core/trace_packet.h"
#include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
+#include "perfetto/ext/tracing/ipc/service_ipc_host.h"
#include "perfetto/tracing/core/trace_config.h"
#include "src/base/test/test_task_runner.h"
+#include "src/traced/probes/probes_producer.h"
#include "test/fake_producer.h"
-#include "test/task_runner_thread.h"
#include "protos/perfetto/trace/trace_packet.gen.h"
namespace perfetto {
+// This is used only in daemon starting integrations tests.
+class ServiceThread {
+ public:
+ ServiceThread(const std::string& producer_socket,
+ const std::string& consumer_socket)
+ : producer_socket_(producer_socket), consumer_socket_(consumer_socket) {}
+
+ ~ServiceThread() {
+ if (!runner_)
+ return;
+ runner_->PostTaskAndWaitForTesting([this]() { svc_.reset(); });
+ }
+
+ void Start() {
+ runner_ = base::ThreadTaskRunner::CreateAndStart("perfetto.svc");
+ runner_->PostTaskAndWaitForTesting([this]() {
+ svc_ = ServiceIPCHost::CreateInstance(runner_->get());
+ unlink(producer_socket_.c_str());
+ unlink(consumer_socket_.c_str());
+
+ bool res =
+ svc_->Start(producer_socket_.c_str(), consumer_socket_.c_str());
+ PERFETTO_CHECK(res);
+ });
+ }
+
+ base::ThreadTaskRunner* runner() { return runner_ ? &*runner_ : nullptr; }
+
+ private:
+ base::Optional<base::ThreadTaskRunner> runner_; // Keep first.
+
+ std::string producer_socket_;
+ std::string consumer_socket_;
+ std::unique_ptr<ServiceIPCHost> svc_;
+};
+
+// This is used only in daemon starting integrations tests.
+class ProbesProducerThread {
+ public:
+ ProbesProducerThread(const std::string& producer_socket)
+ : producer_socket_(producer_socket) {}
+
+ ~ProbesProducerThread() {
+ if (!runner_)
+ return;
+ runner_->PostTaskAndWaitForTesting([this]() { producer_.reset(); });
+ }
+
+ void Connect() {
+ runner_ = base::ThreadTaskRunner::CreateAndStart("perfetto.prd.probes");
+ runner_->PostTaskAndWaitForTesting([this]() {
+ producer_.reset(new ProbesProducer());
+ producer_->ConnectWithRetries(producer_socket_.c_str(), runner_->get());
+ });
+ }
+
+ private:
+ base::Optional<base::ThreadTaskRunner> runner_; // Keep first.
+
+ std::string producer_socket_;
+ std::unique_ptr<ProbesProducer> producer_;
+};
+
+class FakeProducerThread {
+ public:
+ FakeProducerThread(const std::string& producer_socket,
+ std::function<void()> setup_callback,
+ std::function<void()> connect_callback)
+ : producer_socket_(producer_socket),
+ setup_callback_(std::move(setup_callback)),
+ connect_callback_(std::move(connect_callback)) {}
+
+ ~FakeProducerThread() {
+ if (!runner_)
+ return;
+ runner_->PostTaskAndWaitForTesting([this]() { producer_.reset(); });
+ }
+
+ void Connect() {
+ runner_ = base::ThreadTaskRunner::CreateAndStart("perfetto.prd.fake");
+ runner_->PostTaskAndWaitForTesting([this]() {
+ producer_.reset(new FakeProducer("android.perfetto.FakeProducer"));
+ producer_->Connect(producer_socket_.c_str(), runner_->get(),
+ std::move(setup_callback_),
+ std::move(connect_callback_));
+ });
+ }
+
+ base::ThreadTaskRunner* runner() { return runner_ ? &*runner_ : nullptr; }
+
+ FakeProducer* producer() { return producer_.get(); }
+
+ private:
+ base::Optional<base::ThreadTaskRunner> runner_; // Keep first.
+
+ std::string producer_socket_;
+ std::unique_ptr<FakeProducer> producer_;
+ std::function<void()> setup_callback_;
+ std::function<void()> connect_callback_;
+};
+
class TestHelper : public Consumer {
public:
static const char* GetConsumerSocketName();
@@ -79,8 +182,10 @@
std::function<void()> WrapTask(const std::function<void()>& function);
- TaskRunnerThread* service_thread() { return &service_thread_; }
- TaskRunnerThread* producer_thread() { return &producer_thread_; }
+ base::ThreadTaskRunner* service_thread() { return service_thread_.runner(); }
+ base::ThreadTaskRunner* producer_thread() {
+ return fake_producer_thread_.runner();
+ }
const std::vector<protos::gen::TracePacket>& trace() { return trace_; }
private:
@@ -97,8 +202,9 @@
std::vector<protos::gen::TracePacket> trace_;
- TaskRunnerThread service_thread_;
- TaskRunnerThread producer_thread_;
+ ServiceThread service_thread_;
+ FakeProducerThread fake_producer_thread_;
+
std::unique_ptr<TracingService::ConsumerEndpoint> endpoint_; // Keep last.
};
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index ebc440a..227c055 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -62,6 +62,7 @@
'//src/traced/probes:traced_probes',
'//src/traced/service:traced',
'//test/cts:perfetto_cts_deps',
+ '//test/cts:perfetto_cts_jni_deps',
]
# Host targets
diff --git a/tools/trace_to_text/pprof_builder.cc b/tools/trace_to_text/pprof_builder.cc
index 4da0d9d..7d72434 100644
--- a/tools/trace_to_text/pprof_builder.cc
+++ b/tools/trace_to_text/pprof_builder.cc
@@ -375,7 +375,9 @@
std::string frame_name = frame_it.Get(1).string_value;
int64_t mapping_id = frame_it.Get(2).long_value;
int64_t rel_pc = frame_it.Get(3).long_value;
- int64_t symbol_set_id = frame_it.Get(4).long_value;
+ base::Optional<int64_t> symbol_set_id;
+ if (!frame_it.Get(4).is_null())
+ symbol_set_id = frame_it.Get(4).long_value;
seen_mappings->emplace(mapping_id);
auto* glocation = result_->add_location();
@@ -386,7 +388,7 @@
// mapping.start_offset)).
glocation->set_address(static_cast<uint64_t>(rel_pc));
if (symbol_set_id) {
- for (const Line& line : LineForSymbolSetId(symbol_set_id)) {
+ for (const Line& line : LineForSymbolSetId(*symbol_set_id)) {
seen_symbol_ids->emplace(line.symbol_id);
auto* gline = glocation->add_line();
gline->set_line(line.line_number);