Merge "Revert "Rollback DAC_READ_SEARCH capability""
diff --git a/.travis.yml b/.travis.yml
index 3e89e9e..69f9cdb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -140,7 +140,7 @@
for TEST_TARGET in $TEST_TARGETS; do
"out/dist/$TEST_TARGET"
done
- bash -c "out/dist/perfetto_benchmarks --benchmark_filter=\"(\$(out/dist/perfetto_benchmarks --benchmark_list_tests | sed \"/BM_EndToEnd\/.....*\//d\" | xargs | tr \" \" \"|\"))\""
+ BENCHMARK_FUNCTIONAL_TEST_ONLY=true out/dist/perfetto_benchmarks
if [[ "$CFG" == *-libfuzzer ]]; then
# Run a single iteration each to make sure they are not crashing.
out/dist/end_to_end_shared_memory_fuzzer -runs=1
@@ -152,7 +152,7 @@
for TEST_TARGET in $TEST_TARGETS; do
tools/run_android_test out/dist "$TEST_TARGET"
done
- tools/run_android_test out/dist "perfetto_benchmarks" "--benchmark_filter=\"(\$(perfetto_benchmarks --benchmark_list_tests | sed \"/BM_EndToEnd\/.....*\//d\" | xargs | tr \" \" \"|\"))\""
+ tools/run_android_test --env BENCHMARK_FUNCTIONAL_TEST_ONLY=true out/dist "perfetto_benchmarks"
fi
after_script:
diff --git a/Android.bp b/Android.bp
index de7759d..44ab92c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,7 +61,9 @@
"src/protozero/message.cc",
"src/protozero/message_handle.cc",
"src/protozero/proto_utils.cc",
+ "src/protozero/scattered_stream_null_delegate.cc",
"src/protozero/scattered_stream_writer.cc",
+ "src/traced/probes/filesystem/file_scanner.cc",
"src/traced/probes/filesystem/fs_mount.cc",
"src/traced/probes/filesystem/inode_file_data_source.cc",
"src/traced/probes/filesystem/lru_inode_cache.cc",
@@ -77,7 +79,10 @@
"src/tracing/core/data_source_descriptor.cc",
"src/tracing/core/ftrace_config.cc",
"src/tracing/core/id_allocator.cc",
+ "src/tracing/core/inode_file_config.cc",
+ "src/tracing/core/null_trace_writer.cc",
"src/tracing/core/packet_stream_validator.cc",
+ "src/tracing/core/process_stats_config.cc",
"src/tracing/core/service_impl.cc",
"src/tracing/core/shared_memory_abi.cc",
"src/tracing/core/shared_memory_arbiter_impl.cc",
@@ -162,6 +167,7 @@
"src/protozero/message.cc",
"src/protozero/message_handle.cc",
"src/protozero/proto_utils.cc",
+ "src/protozero/scattered_stream_null_delegate.cc",
"src/protozero/scattered_stream_writer.cc",
"src/tracing/core/chrome_config.cc",
"src/tracing/core/commit_data_request.cc",
@@ -169,7 +175,10 @@
"src/tracing/core/data_source_descriptor.cc",
"src/tracing/core/ftrace_config.cc",
"src/tracing/core/id_allocator.cc",
+ "src/tracing/core/inode_file_config.cc",
+ "src/tracing/core/null_trace_writer.cc",
"src/tracing/core/packet_stream_validator.cc",
+ "src/tracing/core/process_stats_config.cc",
"src/tracing/core/service_impl.cc",
"src/tracing/core/shared_memory_abi.cc",
"src/tracing/core/shared_memory_arbiter_impl.cc",
@@ -284,7 +293,6 @@
"src/ftrace_reader/proto_translation_table.cc",
"src/ftrace_reader/test/cpu_reader_support.cc",
"src/ftrace_reader/test/scattered_stream_delegate_for_testing.cc",
- "src/ftrace_reader/test/scattered_stream_null_delegate.cc",
"src/ipc/buffered_frame_deserializer.cc",
"src/ipc/client_impl.cc",
"src/ipc/deferred.cc",
@@ -296,7 +304,9 @@
"src/protozero/message.cc",
"src/protozero/message_handle.cc",
"src/protozero/proto_utils.cc",
+ "src/protozero/scattered_stream_null_delegate.cc",
"src/protozero/scattered_stream_writer.cc",
+ "src/traced/probes/filesystem/file_scanner.cc",
"src/traced/probes/filesystem/fs_mount.cc",
"src/traced/probes/filesystem/inode_file_data_source.cc",
"src/traced/probes/filesystem/lru_inode_cache.cc",
@@ -310,7 +320,10 @@
"src/tracing/core/data_source_descriptor.cc",
"src/tracing/core/ftrace_config.cc",
"src/tracing/core/id_allocator.cc",
+ "src/tracing/core/inode_file_config.cc",
+ "src/tracing/core/null_trace_writer.cc",
"src/tracing/core/packet_stream_validator.cc",
+ "src/tracing/core/process_stats_config.cc",
"src/tracing/core/service_impl.cc",
"src/tracing/core/shared_memory_abi.cc",
"src/tracing/core/shared_memory_arbiter_impl.cc",
@@ -321,9 +334,9 @@
"src/tracing/core/trace_packet.cc",
"src/tracing/core/trace_writer_impl.cc",
"test/end_to_end_integrationtest.cc",
- "test/fake_consumer.cc",
"test/fake_producer.cc",
"test/task_runner_thread.cc",
+ "test/test_helper.cc",
],
shared_libs: [
"libandroid",
@@ -408,6 +421,8 @@
"protos/perfetto/config/data_source_config.proto",
"protos/perfetto/config/data_source_descriptor.proto",
"protos/perfetto/config/ftrace/ftrace_config.proto",
+ "protos/perfetto/config/inode_file/inode_file_config.proto",
+ "protos/perfetto/config/process_stats/process_stats_config.proto",
"protos/perfetto/config/test_config.proto",
"protos/perfetto/config/trace_config.proto",
],
@@ -420,6 +435,8 @@
"external/perfetto/protos/perfetto/config/data_source_config.pb.cc",
"external/perfetto/protos/perfetto/config/data_source_descriptor.pb.cc",
"external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pb.cc",
+ "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pb.cc",
+ "external/perfetto/protos/perfetto/config/process_stats/process_stats_config.pb.cc",
"external/perfetto/protos/perfetto/config/test_config.pb.cc",
"external/perfetto/protos/perfetto/config/trace_config.pb.cc",
],
@@ -433,6 +450,8 @@
"protos/perfetto/config/data_source_config.proto",
"protos/perfetto/config/data_source_descriptor.proto",
"protos/perfetto/config/ftrace/ftrace_config.proto",
+ "protos/perfetto/config/inode_file/inode_file_config.proto",
+ "protos/perfetto/config/process_stats/process_stats_config.proto",
"protos/perfetto/config/test_config.proto",
"protos/perfetto/config/trace_config.proto",
],
@@ -445,6 +464,8 @@
"external/perfetto/protos/perfetto/config/data_source_config.pb.h",
"external/perfetto/protos/perfetto/config/data_source_descriptor.pb.h",
"external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pb.h",
+ "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pb.h",
+ "external/perfetto/protos/perfetto/config/process_stats/process_stats_config.pb.h",
"external/perfetto/protos/perfetto/config/test_config.pb.h",
"external/perfetto/protos/perfetto/config/trace_config.pb.h",
],
@@ -461,6 +482,8 @@
"protos/perfetto/config/data_source_config.proto",
"protos/perfetto/config/data_source_descriptor.proto",
"protos/perfetto/config/ftrace/ftrace_config.proto",
+ "protos/perfetto/config/inode_file/inode_file_config.proto",
+ "protos/perfetto/config/process_stats/process_stats_config.proto",
"protos/perfetto/config/test_config.proto",
"protos/perfetto/config/trace_config.proto",
],
@@ -474,6 +497,8 @@
"external/perfetto/protos/perfetto/config/data_source_config.pbzero.cc",
"external/perfetto/protos/perfetto/config/data_source_descriptor.pbzero.cc",
"external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pbzero.cc",
+ "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pbzero.cc",
+ "external/perfetto/protos/perfetto/config/process_stats/process_stats_config.pbzero.cc",
"external/perfetto/protos/perfetto/config/test_config.pbzero.cc",
"external/perfetto/protos/perfetto/config/trace_config.pbzero.cc",
],
@@ -487,6 +512,8 @@
"protos/perfetto/config/data_source_config.proto",
"protos/perfetto/config/data_source_descriptor.proto",
"protos/perfetto/config/ftrace/ftrace_config.proto",
+ "protos/perfetto/config/inode_file/inode_file_config.proto",
+ "protos/perfetto/config/process_stats/process_stats_config.proto",
"protos/perfetto/config/test_config.proto",
"protos/perfetto/config/trace_config.proto",
],
@@ -500,6 +527,8 @@
"external/perfetto/protos/perfetto/config/data_source_config.pbzero.h",
"external/perfetto/protos/perfetto/config/data_source_descriptor.pbzero.h",
"external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pbzero.h",
+ "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pbzero.h",
+ "external/perfetto/protos/perfetto/config/process_stats/process_stats_config.pbzero.h",
"external/perfetto/protos/perfetto/config/test_config.pbzero.h",
"external/perfetto/protos/perfetto/config/trace_config.pbzero.h",
],
@@ -3119,6 +3148,7 @@
"src/protozero/message.cc",
"src/protozero/message_handle.cc",
"src/protozero/proto_utils.cc",
+ "src/protozero/scattered_stream_null_delegate.cc",
"src/protozero/scattered_stream_writer.cc",
"src/tracing/core/chrome_config.cc",
"src/tracing/core/commit_data_request.cc",
@@ -3126,7 +3156,10 @@
"src/tracing/core/data_source_descriptor.cc",
"src/tracing/core/ftrace_config.cc",
"src/tracing/core/id_allocator.cc",
+ "src/tracing/core/inode_file_config.cc",
+ "src/tracing/core/null_trace_writer.cc",
"src/tracing/core/packet_stream_validator.cc",
+ "src/tracing/core/process_stats_config.cc",
"src/tracing/core/service_impl.cc",
"src/tracing/core/shared_memory_abi.cc",
"src/tracing/core/shared_memory_arbiter_impl.cc",
@@ -3305,7 +3338,6 @@
"src/ftrace_reader/proto_translation_table_unittest.cc",
"src/ftrace_reader/test/cpu_reader_support.cc",
"src/ftrace_reader/test/scattered_stream_delegate_for_testing.cc",
- "src/ftrace_reader/test/scattered_stream_null_delegate.cc",
"src/ipc/buffered_frame_deserializer.cc",
"src/ipc/buffered_frame_deserializer_unittest.cc",
"src/ipc/client_impl.cc",
@@ -3329,10 +3361,12 @@
"src/protozero/message_unittest.cc",
"src/protozero/proto_utils.cc",
"src/protozero/proto_utils_unittest.cc",
+ "src/protozero/scattered_stream_null_delegate.cc",
"src/protozero/scattered_stream_writer.cc",
"src/protozero/scattered_stream_writer_unittest.cc",
"src/protozero/test/fake_scattered_buffer.cc",
"src/protozero/test/protozero_conformance_unittest.cc",
+ "src/traced/probes/filesystem/file_scanner.cc",
"src/traced/probes/filesystem/fs_mount.cc",
"src/traced/probes/filesystem/fs_mount_unittest.cc",
"src/traced/probes/filesystem/inode_file_data_source.cc",
@@ -3352,9 +3386,13 @@
"src/tracing/core/ftrace_config.cc",
"src/tracing/core/id_allocator.cc",
"src/tracing/core/id_allocator_unittest.cc",
+ "src/tracing/core/inode_file_config.cc",
+ "src/tracing/core/null_trace_writer.cc",
+ "src/tracing/core/null_trace_writer_unittest.cc",
"src/tracing/core/packet_stream_validator.cc",
"src/tracing/core/packet_stream_validator_unittest.cc",
"src/tracing/core/patch_list_unittest.cc",
+ "src/tracing/core/process_stats_config.cc",
"src/tracing/core/service_impl.cc",
"src/tracing/core/service_impl_unittest.cc",
"src/tracing/core/shared_memory_abi.cc",
@@ -3429,6 +3467,42 @@
},
}
+// GN target: //:trace_to_text
+cc_binary_host {
+ name: "trace_to_text",
+ srcs: [
+ ":perfetto_protos_perfetto_config_config_gen",
+ ":perfetto_protos_perfetto_trace_chrome_lite_gen",
+ ":perfetto_protos_perfetto_trace_filesystem_lite_gen",
+ ":perfetto_protos_perfetto_trace_ftrace_lite_gen",
+ ":perfetto_protos_perfetto_trace_lite_gen",
+ ":perfetto_protos_perfetto_trace_ps_lite_gen",
+ "tools/trace_to_text/ftrace_event_formatter.cc",
+ "tools/trace_to_text/ftrace_inode_handler.cc",
+ "tools/trace_to_text/main.cc",
+ ],
+ shared_libs: [
+ "liblog",
+ "libprotobuf-cpp-full",
+ "libprotobuf-cpp-lite",
+ ],
+ generated_headers: [
+ "perfetto_protos_perfetto_config_config_gen_headers",
+ "perfetto_protos_perfetto_trace_chrome_lite_gen_headers",
+ "perfetto_protos_perfetto_trace_filesystem_lite_gen_headers",
+ "perfetto_protos_perfetto_trace_ftrace_lite_gen_headers",
+ "perfetto_protos_perfetto_trace_lite_gen_headers",
+ "perfetto_protos_perfetto_trace_ps_lite_gen_headers",
+ ],
+ defaults: [
+ "perfetto_defaults",
+ ],
+ cflags: [
+ "-DGOOGLE_PROTOBUF_NO_RTTI",
+ "-DGOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
+ ],
+}
+
// GN target: //:traced
cc_binary {
name: "traced",
@@ -3475,10 +3549,10 @@
"src/ftrace_reader/ftrace_procfs.cc",
"src/ftrace_reader/proto_translation_table.cc",
"src/traced/probes/probes_producer.cc",
- "test/fake_producer.cc",
- "test/fake_consumer.cc",
- "test/task_runner_thread.cc",
"test/end_to_end_integrationtest.cc",
+ "test/fake_producer.cc",
+ "test/task_runner_thread.cc",
+ "test/test_helper.cc",
],
export_include_dirs: [
".",
diff --git a/Android.bp.extras b/Android.bp.extras
index a3f25d5..42c389c 100644
--- a/Android.bp.extras
+++ b/Android.bp.extras
@@ -11,10 +11,10 @@
"src/ftrace_reader/ftrace_procfs.cc",
"src/ftrace_reader/proto_translation_table.cc",
"src/traced/probes/probes_producer.cc",
- "test/fake_producer.cc",
- "test/fake_consumer.cc",
- "test/task_runner_thread.cc",
"test/end_to_end_integrationtest.cc",
+ "test/fake_producer.cc",
+ "test/task_runner_thread.cc",
+ "test/test_helper.cc",
],
export_include_dirs: [
".",
diff --git a/BUILD.gn b/BUILD.gn
index ce1eba4..1207331 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -26,20 +26,19 @@
testonly = true # allow to build also test targets
deps = [
":perfetto_unittests",
- "src/ipc/protoc_plugin:ipc_plugin($host_toolchain)",
"src/protozero/protoc_plugin($host_toolchain)",
- "tools/proto_to_cpp",
]
- if (is_linux || is_android) {
- deps += [ "tools/ftrace_proto_gen:ftrace_proto_gen" ]
- }
if (!build_with_chromium) {
deps += [
"protos/perfetto/config:merged_config", # For syntax-checking the proto.
+ "src/ipc/protoc_plugin:ipc_plugin($host_toolchain)",
"test/configs",
"tools:protoc_helper",
- "tools/trace_to_text",
+ "tools/proto_to_cpp",
]
+ if (!build_with_android) {
+ deps += [ "tools/trace_to_text" ]
+ }
if (is_linux || is_android) {
deps += [
":perfetto",
@@ -47,6 +46,7 @@
":perfetto_integrationtests",
":traced",
":traced_probes",
+ "tools/ftrace_proto_gen:ftrace_proto_gen",
"tools/skippy",
]
}
@@ -59,21 +59,24 @@
"gn:default_deps",
"gn:gtest_main",
"src/base:unittests",
- "src/ipc:unittests",
- "src/perfetto_cmd:unittests",
"src/protozero:unittests",
- "src/traced/probes/filesystem:unittests",
"src/tracing:unittests",
]
- if (is_linux || is_android) {
- deps += [
- "src/ftrace_reader:unittests",
- "src/traced/probes:unittests",
- "tools/ftrace_proto_gen:unittests",
- ]
- }
if (!build_with_chromium) {
- deps += [ "tools/sanitizers_unittests" ]
+ if (is_linux || is_android) {
+ deps += [
+ "src/ftrace_reader:unittests",
+ "src/traced/probes:unittests",
+ "tools/ftrace_proto_gen:unittests",
+ ]
+ }
+
+ deps += [
+ "src/ipc:unittests",
+ "src/perfetto_cmd:unittests",
+ "src/traced/probes/filesystem:unittests",
+ "tools/sanitizers_unittests",
+ ]
}
}
@@ -164,6 +167,16 @@
}
}
+ if (build_with_android) {
+ executable("trace_to_text") {
+ testonly = true
+ deps = [
+ "gn:default_deps",
+ "tools/trace_to_text:lib",
+ ]
+ }
+ }
+
# This target exports perfetto trace protos in the Android build system,
# allowing both host and device targets to implement custom parsers based on
# our protos.
diff --git a/docs/running_perfetto.md b/docs/running_perfetto.md
index ba59432..0763505 100644
--- a/docs/running_perfetto.md
+++ b/docs/running_perfetto.md
@@ -62,7 +62,7 @@
data_sources {
config {
- name: "com.google.perfetto.ftrace"
+ name: "linux.ftrace"
target_buffer: 0
ftrace_config {
buffer_size_kb: 40 # Kernel ftrace buffer size.
@@ -74,7 +74,7 @@
data_sources {
config {
- name: "com.google.perfetto.process_stats"
+ name: "linux.process_stats"
target_buffer: 0
}
}
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index d0b8a20..ce1088c 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -74,6 +74,7 @@
cflags += [
"-fcolor-diagnostics",
"-Wno-unknown-warning-option",
+ "-fdiagnostics-show-template-tree",
]
} else {
cflags += [ "-Wno-unknown-warning" ]
diff --git a/include/perfetto/base/build_config.h b/include/perfetto/base/build_config.h
index b04321d..de4a436 100644
--- a/include/perfetto/base/build_config.h
+++ b/include/perfetto/base/build_config.h
@@ -24,7 +24,7 @@
#define PERFETTO_BUILDFLAG(flag) \
(PERFETTO_BUILDFLAG_CAT(PERFETTO_BUILDFLAG_DEFINE_, flag)())
-#if defined(ANDROID)
+#if defined(__ANDROID__)
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_ANDROID() 1
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_MACOSX() 0
#define PERFETTO_BUILDFLAG_DEFINE_PERFETTO_OS_LINUX() 0
diff --git a/include/perfetto/base/time.h b/include/perfetto/base/time.h
index bd2498c..eb20fe5 100644
--- a/include/perfetto/base/time.h
+++ b/include/perfetto/base/time.h
@@ -21,20 +21,28 @@
#include <chrono>
+#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+#include <mach/mach_time.h>
+#endif
+
namespace perfetto {
namespace base {
using TimeSeconds = std::chrono::seconds;
using TimeMillis = std::chrono::milliseconds;
using TimeNanos = std::chrono::nanoseconds;
-constexpr clockid_t kWallTimeClockSource = CLOCK_MONOTONIC;
inline TimeNanos FromPosixTimespec(const struct timespec& ts) {
return TimeNanos(ts.tv_sec * 1000000000LL + ts.tv_nsec);
}
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+
+constexpr clockid_t kWallTimeClockSource = CLOCK_MONOTONIC;
+
inline TimeNanos GetTimeInternalNs(clockid_t clk_id) {
struct timespec ts = {};
PERFETTO_CHECK(clock_gettime(clk_id, &ts) == 0);
@@ -45,6 +53,25 @@
return GetTimeInternalNs(kWallTimeClockSource);
}
+inline TimeNanos GetThreadCPUTimeNs() {
+ return GetTimeInternalNs(CLOCK_THREAD_CPUTIME_ID);
+}
+
+#else // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+
+inline TimeNanos GetWallTimeNs() {
+ auto init_time_factor = []() -> uint64_t {
+ mach_timebase_info_data_t timebase_info;
+ mach_timebase_info(&timebase_info);
+ return timebase_info.numer / timebase_info.denom;
+ };
+
+ static uint64_t monotonic_timebase_factor = init_time_factor();
+ return TimeNanos(mach_absolute_time() * monotonic_timebase_factor);
+}
+
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+
inline TimeMillis GetWallTimeMs() {
return std::chrono::duration_cast<TimeMillis>(GetWallTimeNs());
}
@@ -53,10 +80,6 @@
return std::chrono::duration_cast<TimeSeconds>(GetWallTimeNs());
}
-inline TimeNanos GetThreadCPUTimeNs() {
- return GetTimeInternalNs(CLOCK_THREAD_CPUTIME_ID);
-}
-
inline struct timespec ToPosixTimespec(TimeMillis time) {
struct timespec ts {};
const long time_s = static_cast<long>(time.count() / 1000);
diff --git a/include/perfetto/ipc/basic_types.h b/include/perfetto/ipc/basic_types.h
index 1d8612f..10c4dc7 100644
--- a/include/perfetto/ipc/basic_types.h
+++ b/include/perfetto/ipc/basic_types.h
@@ -17,6 +17,7 @@
#ifndef INCLUDE_PERFETTO_IPC_BASIC_TYPES_H_
#define INCLUDE_PERFETTO_IPC_BASIC_TYPES_H_
+#include <stddef.h>
#include <stdint.h>
namespace google {
@@ -34,6 +35,10 @@
using ClientID = uint64_t;
using RequestID = uint64_t;
+// This determines the maximum size allowed for an IPC message. Trying to send
+// or receive a larger message will hit DCHECK(s) and auto-disconnect.
+constexpr size_t kIPCBufferSize = 128 * 1024;
+
} // namespace ipc
} // namespace perfetto
diff --git a/include/perfetto/protozero/BUILD.gn b/include/perfetto/protozero/BUILD.gn
index 7b91fe4..b97b137 100644
--- a/include/perfetto/protozero/BUILD.gn
+++ b/include/perfetto/protozero/BUILD.gn
@@ -21,6 +21,7 @@
"message.h",
"message_handle.h",
"proto_field_descriptor.h",
+ "scattered_stream_null_delegate.h",
"scattered_stream_writer.h",
]
}
diff --git a/src/ftrace_reader/test/scattered_stream_null_delegate.h b/include/perfetto/protozero/scattered_stream_null_delegate.h
similarity index 61%
rename from src/ftrace_reader/test/scattered_stream_null_delegate.h
rename to include/perfetto/protozero/scattered_stream_null_delegate.h
index 41e2bd8..8efb477 100644
--- a/src/ftrace_reader/test/scattered_stream_null_delegate.h
+++ b/include/perfetto/protozero/scattered_stream_null_delegate.h
@@ -14,31 +14,32 @@
* limitations under the License.
*/
-#ifndef SRC_FTRACE_READER_TEST_SCATTERED_STREAM_NULL_DELEGATE_H_
-#define SRC_FTRACE_READER_TEST_SCATTERED_STREAM_NULL_DELEGATE_H_
+#ifndef INCLUDE_PERFETTO_PROTOZERO_SCATTERED_STREAM_NULL_DELEGATE_H_
+#define INCLUDE_PERFETTO_PROTOZERO_SCATTERED_STREAM_NULL_DELEGATE_H_
#include <memory>
#include <vector>
#include "perfetto/base/logging.h"
+#include "perfetto/protozero/contiguous_memory_range.h"
#include "perfetto/protozero/scattered_stream_writer.h"
-namespace perfetto {
+namespace protozero {
-class ScatteredStreamNullDelegate
- : public protozero::ScatteredStreamWriter::Delegate {
+class ScatteredStreamWriterNullDelegate
+ : public ScatteredStreamWriter::Delegate {
public:
- explicit ScatteredStreamNullDelegate(size_t chunk_size);
- ~ScatteredStreamNullDelegate() override;
+ explicit ScatteredStreamWriterNullDelegate(size_t chunk_size);
+ ~ScatteredStreamWriterNullDelegate() override;
// protozero::ScatteredStreamWriter::Delegate implementation.
- protozero::ContiguousMemoryRange GetNewBuffer() override;
+ ContiguousMemoryRange GetNewBuffer() override;
private:
const size_t chunk_size_;
std::unique_ptr<uint8_t[]> chunk_;
};
-} // namespace perfetto
+} // namespace protozero
-#endif // SRC_FTRACE_READER_TEST_SCATTERED_STREAM_NULL_DELEGATE_H_
+#endif // INCLUDE_PERFETTO_PROTOZERO_SCATTERED_STREAM_NULL_DELEGATE_H_
diff --git a/include/perfetto/tracing/core/basic_types.h b/include/perfetto/tracing/core/basic_types.h
index c5a3020..112f58a 100644
--- a/include/perfetto/tracing/core/basic_types.h
+++ b/include/perfetto/tracing/core/basic_types.h
@@ -29,9 +29,6 @@
using ProducerID = uint16_t;
// Unique within the scope of the tracing service.
-using DataSourceID = uint64_t;
-
-// Unique within the scope of the tracing service.
using DataSourceInstanceID = uint64_t;
// Unique within the scope of a Producer.
diff --git a/include/perfetto/tracing/core/data_source_config.h b/include/perfetto/tracing/core/data_source_config.h
index 9b41045..619168b 100644
--- a/include/perfetto/tracing/core/data_source_config.h
+++ b/include/perfetto/tracing/core/data_source_config.h
@@ -37,6 +37,8 @@
#include "perfetto/tracing/core/chrome_config.h"
#include "perfetto/tracing/core/ftrace_config.h"
+#include "perfetto/tracing/core/inode_file_config.h"
+#include "perfetto/tracing/core/process_stats_config.h"
#include "perfetto/tracing/core/test_config.h"
// Forward declarations for protobuf types.
@@ -45,6 +47,9 @@
class DataSourceConfig;
class FtraceConfig;
class ChromeConfig;
+class InodeFileConfig;
+class InodeFileConfig_MountPointMappingEntry;
+class ProcessStatsConfig;
class TestConfig;
} // namespace protos
} // namespace perfetto
@@ -79,6 +84,21 @@
const ChromeConfig& chrome_config() const { return chrome_config_; }
ChromeConfig* mutable_chrome_config() { return &chrome_config_; }
+ const InodeFileConfig& inode_file_config() const {
+ return inode_file_config_;
+ }
+ InodeFileConfig* mutable_inode_file_config() { return &inode_file_config_; }
+
+ const ProcessStatsConfig& process_stats_config() const {
+ return process_stats_config_;
+ }
+ ProcessStatsConfig* mutable_process_stats_config() {
+ return &process_stats_config_;
+ }
+
+ const std::string& legacy_config() const { return legacy_config_; }
+ void set_legacy_config(const std::string& value) { legacy_config_ = value; }
+
const TestConfig& for_testing() const { return for_testing_; }
TestConfig* mutable_for_testing() { return &for_testing_; }
@@ -88,6 +108,9 @@
uint32_t trace_duration_ms_ = {};
FtraceConfig ftrace_config_ = {};
ChromeConfig chrome_config_ = {};
+ InodeFileConfig inode_file_config_ = {};
+ ProcessStatsConfig process_stats_config_ = {};
+ std::string legacy_config_ = {};
TestConfig for_testing_ = {};
// Allows to preserve unknown protobuf fields for compatibility
diff --git a/include/perfetto/tracing/core/inode_file_config.h b/include/perfetto/tracing/core/inode_file_config.h
new file mode 100644
index 0000000..7704fcd
--- /dev/null
+++ b/include/perfetto/tracing/core/inode_file_config.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*******************************************************************************
+ * AUTOGENERATED - DO NOT EDIT
+ *******************************************************************************
+ * This file has been generated from the protobuf message
+ * perfetto/config/inode_file/inode_file_config.proto
+ * by
+ * ../../tools/proto_to_cpp/proto_to_cpp.cc.
+ * If you need to make changes here, change the .proto file and then run
+ * ./tools/gen_tracing_cpp_headers_from_protos.py
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_CORE_INODE_FILE_CONFIG_H_
+#define INCLUDE_PERFETTO_TRACING_CORE_INODE_FILE_CONFIG_H_
+
+#include <stdint.h>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "perfetto/base/export.h"
+
+// Forward declarations for protobuf types.
+namespace perfetto {
+namespace protos {
+class InodeFileConfig;
+class InodeFileConfig_MountPointMappingEntry;
+} // namespace protos
+} // namespace perfetto
+
+namespace perfetto {
+
+class PERFETTO_EXPORT InodeFileConfig {
+ public:
+ class PERFETTO_EXPORT MountPointMappingEntry {
+ public:
+ MountPointMappingEntry();
+ ~MountPointMappingEntry();
+ MountPointMappingEntry(MountPointMappingEntry&&) noexcept;
+ MountPointMappingEntry& operator=(MountPointMappingEntry&&);
+ MountPointMappingEntry(const MountPointMappingEntry&);
+ MountPointMappingEntry& operator=(const MountPointMappingEntry&);
+
+ // Conversion methods from/to the corresponding protobuf types.
+ void FromProto(
+ const perfetto::protos::InodeFileConfig_MountPointMappingEntry&);
+ void ToProto(
+ perfetto::protos::InodeFileConfig_MountPointMappingEntry*) const;
+
+ const std::string& mountpoint() const { return mountpoint_; }
+ void set_mountpoint(const std::string& value) { mountpoint_ = value; }
+
+ int scan_roots_size() const { return static_cast<int>(scan_roots_.size()); }
+ const std::vector<std::string>& scan_roots() const { return scan_roots_; }
+ std::string* add_scan_roots() {
+ scan_roots_.emplace_back();
+ return &scan_roots_.back();
+ }
+
+ private:
+ std::string mountpoint_ = {};
+ std::vector<std::string> scan_roots_;
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+ };
+
+ InodeFileConfig();
+ ~InodeFileConfig();
+ InodeFileConfig(InodeFileConfig&&) noexcept;
+ InodeFileConfig& operator=(InodeFileConfig&&);
+ InodeFileConfig(const InodeFileConfig&);
+ InodeFileConfig& operator=(const InodeFileConfig&);
+
+ // Conversion methods from/to the corresponding protobuf types.
+ void FromProto(const perfetto::protos::InodeFileConfig&);
+ void ToProto(perfetto::protos::InodeFileConfig*) const;
+
+ uint64_t scan_interval_ms() const { return scan_interval_ms_; }
+ void set_scan_interval_ms(uint64_t value) { scan_interval_ms_ = value; }
+
+ uint64_t scan_delay_ms() const { return scan_delay_ms_; }
+ void set_scan_delay_ms(uint64_t value) { scan_delay_ms_ = value; }
+
+ uint64_t scan_batch_size() const { return scan_batch_size_; }
+ void set_scan_batch_size(uint64_t value) { scan_batch_size_ = value; }
+
+ bool do_not_scan() const { return do_not_scan_; }
+ void set_do_not_scan(bool value) { do_not_scan_ = value; }
+
+ int scan_mount_points_size() const {
+ return static_cast<int>(scan_mount_points_.size());
+ }
+ const std::vector<std::string>& scan_mount_points() const {
+ return scan_mount_points_;
+ }
+ std::string* add_scan_mount_points() {
+ scan_mount_points_.emplace_back();
+ return &scan_mount_points_.back();
+ }
+
+ int mount_point_mapping_size() const {
+ return static_cast<int>(mount_point_mapping_.size());
+ }
+ const std::vector<MountPointMappingEntry>& mount_point_mapping() const {
+ return mount_point_mapping_;
+ }
+ MountPointMappingEntry* add_mount_point_mapping() {
+ mount_point_mapping_.emplace_back();
+ return &mount_point_mapping_.back();
+ }
+
+ private:
+ uint64_t scan_interval_ms_ = {};
+ uint64_t scan_delay_ms_ = {};
+ uint64_t scan_batch_size_ = {};
+ bool do_not_scan_ = {};
+ std::vector<std::string> scan_mount_points_;
+ std::vector<MountPointMappingEntry> mount_point_mapping_;
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+};
+
+} // namespace perfetto
+#endif // INCLUDE_PERFETTO_TRACING_CORE_INODE_FILE_CONFIG_H_
diff --git a/include/perfetto/tracing/core/process_stats_config.h b/include/perfetto/tracing/core/process_stats_config.h
new file mode 100644
index 0000000..2601ca0
--- /dev/null
+++ b/include/perfetto/tracing/core/process_stats_config.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*******************************************************************************
+ * AUTOGENERATED - DO NOT EDIT
+ *******************************************************************************
+ * This file has been generated from the protobuf message
+ * perfetto/config/process_stats/process_stats_config.proto
+ * by
+ * ../../tools/proto_to_cpp/proto_to_cpp.cc.
+ * If you need to make changes here, change the .proto file and then run
+ * ./tools/gen_tracing_cpp_headers_from_protos.py
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_CORE_PROCESS_STATS_CONFIG_H_
+#define INCLUDE_PERFETTO_TRACING_CORE_PROCESS_STATS_CONFIG_H_
+
+#include <stdint.h>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "perfetto/base/export.h"
+
+// Forward declarations for protobuf types.
+namespace perfetto {
+namespace protos {
+class ProcessStatsConfig;
+}
+} // namespace perfetto
+
+namespace perfetto {
+
+class PERFETTO_EXPORT ProcessStatsConfig {
+ public:
+ enum Quirks {
+ QUIRKS_UNSPECIFIED = 0,
+ DISABLE_INITIAL_DUMP = 1,
+ DISABLE_ON_DEMAND = 2,
+ };
+ ProcessStatsConfig();
+ ~ProcessStatsConfig();
+ ProcessStatsConfig(ProcessStatsConfig&&) noexcept;
+ ProcessStatsConfig& operator=(ProcessStatsConfig&&);
+ ProcessStatsConfig(const ProcessStatsConfig&);
+ ProcessStatsConfig& operator=(const ProcessStatsConfig&);
+
+ // Conversion methods from/to the corresponding protobuf types.
+ void FromProto(const perfetto::protos::ProcessStatsConfig&);
+ void ToProto(perfetto::protos::ProcessStatsConfig*) const;
+
+ int quirks_size() const { return static_cast<int>(quirks_.size()); }
+ const std::vector<Quirks>& quirks() const { return quirks_; }
+ Quirks* add_quirks() {
+ quirks_.emplace_back();
+ return &quirks_.back();
+ }
+
+ private:
+ std::vector<Quirks> quirks_;
+
+ // Allows to preserve unknown protobuf fields for compatibility
+ // with future versions of .proto files.
+ std::string unknown_fields_;
+};
+
+} // namespace perfetto
+#endif // INCLUDE_PERFETTO_TRACING_CORE_PROCESS_STATS_CONFIG_H_
diff --git a/include/perfetto/tracing/core/service.h b/include/perfetto/tracing/core/service.h
index ed810ec..250308e 100644
--- a/include/perfetto/tracing/core/service.h
+++ b/include/perfetto/tracing/core/service.h
@@ -66,14 +66,10 @@
public:
virtual ~ProducerEndpoint() = default;
- // Called by the Producer to (un)register data sources. The Services returns
- // asynchronousy the ID for the data source.
- // TODO(primiano): thinking twice there is no reason why the service choses
- // ID rather than the Producer. Update in upcoming CLs.
- using RegisterDataSourceCallback = std::function<void(DataSourceID)>;
- virtual void RegisterDataSource(const DataSourceDescriptor&,
- RegisterDataSourceCallback) = 0;
- virtual void UnregisterDataSource(DataSourceID) = 0;
+ // Called by the Producer to (un)register data sources. Data sources are
+ // identified by their name (i.e. DataSourceDescriptor.name)
+ virtual void RegisterDataSource(const DataSourceDescriptor&) = 0;
+ virtual void UnregisterDataSource(const std::string& name) = 0;
// Called by the Producer to signal that some pages in the shared memory
// buffer (shared between Service and Producer) have changed.
diff --git a/include/perfetto/tracing/core/shared_memory_abi.h b/include/perfetto/tracing/core/shared_memory_abi.h
index 4d85f1b..303deff 100644
--- a/include/perfetto/tracing/core/shared_memory_abi.h
+++ b/include/perfetto/tracing/core/shared_memory_abi.h
@@ -142,6 +142,9 @@
class SharedMemoryABI {
public:
+ // This is due to Chunk::size being 16 bits.
+ static constexpr size_t kMaxPageSize = 64 * 1024;
+
// "14" is the max number that can be encoded in a 32 bit atomic word using
// 2 state bits per Chunk and leaving 4 bits for the page layout.
// See PageLayout below.
diff --git a/include/perfetto/tracing/core/shared_memory_arbiter.h b/include/perfetto/tracing/core/shared_memory_arbiter.h
index 9efbba8..2cd336c 100644
--- a/include/perfetto/tracing/core/shared_memory_arbiter.h
+++ b/include/perfetto/tracing/core/shared_memory_arbiter.h
@@ -46,8 +46,7 @@
// Creates a new TraceWriter and assigns it a new WriterID. The WriterID is
// written in each chunk header owned by a given TraceWriter and is used by
// the Service to reconstruct TracePackets written by the same TraceWriter.
- // Returns nullptr if all WriterID slots are exhausted.
- // TODO(primiano): instead of nullptr this should return a NoopWriter.
+ // Returns null impl of TraceWriter if all WriterID slots are exhausted.
virtual std::unique_ptr<TraceWriter> CreateTraceWriter(
BufferID target_buffer) = 0;
diff --git a/include/perfetto/tracing/core/slice.h b/include/perfetto/tracing/core/slice.h
index f845ebc..954e58d 100644
--- a/include/perfetto/tracing/core/slice.h
+++ b/include/perfetto/tracing/core/slice.h
@@ -21,6 +21,7 @@
#include <string.h>
#include <memory>
+#include <string>
#include <vector>
#include "perfetto/base/logging.h"
@@ -32,6 +33,11 @@
struct Slice {
Slice() : start(nullptr), size(0) {}
Slice(const void* st, size_t sz) : start(st), size(sz) {}
+
+ // Used to inherit ownership of a buffer from a protobuf via release_str().
+ explicit Slice(std::unique_ptr<std::string> str)
+ : start(&(*str)[0]), size(str->size()), moved_str_data_(std::move(str)) {}
+
Slice(Slice&& other) noexcept = default;
// Create a Slice which owns |size| bytes of memory.
@@ -56,6 +62,7 @@
void operator=(const Slice&) = delete;
std::unique_ptr<uint8_t[]> own_data_;
+ std::unique_ptr<std::string> moved_str_data_;
};
// TODO(primiano): most TracePacket(s) fit in a slice or two. We need something
diff --git a/include/perfetto/tracing/core/test_config.h b/include/perfetto/tracing/core/test_config.h
index 48f4629..95af155 100644
--- a/include/perfetto/tracing/core/test_config.h
+++ b/include/perfetto/tracing/core/test_config.h
@@ -60,6 +60,11 @@
uint32_t message_count() const { return message_count_; }
void set_message_count(uint32_t value) { message_count_ = value; }
+ uint32_t max_messages_per_second() const { return max_messages_per_second_; }
+ void set_max_messages_per_second(uint32_t value) {
+ max_messages_per_second_ = value;
+ }
+
uint32_t seed() const { return seed_; }
void set_seed(uint32_t value) { seed_ = value; }
@@ -68,6 +73,7 @@
private:
uint32_t message_count_ = {};
+ uint32_t max_messages_per_second_ = {};
uint32_t seed_ = {};
uint64_t message_size_ = {};
diff --git a/include/perfetto/tracing/core/trace_config.h b/include/perfetto/tracing/core/trace_config.h
index 2d5bde6..2097906 100644
--- a/include/perfetto/tracing/core/trace_config.h
+++ b/include/perfetto/tracing/core/trace_config.h
@@ -46,6 +46,9 @@
class DataSourceConfig;
class FtraceConfig;
class ChromeConfig;
+class InodeFileConfig;
+class InodeFileConfig_MountPointMappingEntry;
+class ProcessStatsConfig;
class TestConfig;
class TraceConfig_ProducerConfig;
class TraceConfig_StatsdMetadata;
diff --git a/include/perfetto/tracing/core/trace_packet.h b/include/perfetto/tracing/core/trace_packet.h
index 14c4e0d..0536d70 100644
--- a/include/perfetto/tracing/core/trace_packet.h
+++ b/include/perfetto/tracing/core/trace_packet.h
@@ -88,6 +88,10 @@
size_t size_ = 0; // SUM(slice.size for slice in slices_).
char preamble_[8]; // Deliberately not initialized.
std::unique_ptr<DecodedTracePacket> decoded_packet_;
+
+ // Remember to update the move operators and their unittest if adding new
+ // fields. ConsumerIPCClientImpl::OnReadBuffersResponse() relies on
+ // std::move(TracePacket) to clear up the moved-from instance.
};
} // namespace perfetto
diff --git a/protos/perfetto/config/BUILD.gn b/protos/perfetto/config/BUILD.gn
index 77dc8613..74fa6c1 100644
--- a/protos/perfetto/config/BUILD.gn
+++ b/protos/perfetto/config/BUILD.gn
@@ -25,6 +25,8 @@
"data_source_config.proto",
"data_source_descriptor.proto",
"ftrace/ftrace_config.proto",
+ "inode_file/inode_file_config.proto",
+ "process_stats/process_stats_config.proto",
"test_config.proto",
"trace_config.proto",
]
@@ -38,6 +40,8 @@
"data_source_config.proto",
"data_source_descriptor.proto",
"ftrace/ftrace_config.proto",
+ "inode_file/inode_file_config.proto",
+ "process_stats/process_stats_config.proto",
"test_config.proto",
"trace_config.proto",
]
diff --git a/protos/perfetto/config/data_source_config.proto b/protos/perfetto/config/data_source_config.proto
index 3c33a10..c7b2f21 100644
--- a/protos/perfetto/config/data_source_config.proto
+++ b/protos/perfetto/config/data_source_config.proto
@@ -21,6 +21,8 @@
import "perfetto/config/chrome/chrome_config.proto";
import "perfetto/config/ftrace/ftrace_config.proto";
+import "perfetto/config/inode_file/inode_file_config.proto";
+import "perfetto/config/process_stats/process_stats_config.proto";
import "perfetto/config/test_config.proto";
// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
// to reflect changes in the corresponding C++ headers.
@@ -49,6 +51,17 @@
optional FtraceConfig ftrace_config = 100;
optional ChromeConfig chrome_config = 101;
+ optional InodeFileConfig inode_file_config = 102;
+ optional ProcessStatsConfig process_stats_config = 103;
+
+ // This is a fallback mechanism to send a free-form text config to the
+ // producer. In theory this should never be needed. All the code that
+ // is part of the platform (i.e. traced service) is supposed to *not* truncate
+ // the trace config proto and propagate unknown fields. However, if anything
+ // in the pipeline (client or backend) ends up breaking this forward compat
+ // plan, this field will become the escape hatch to allow future data sources
+ // to get some meaningful configuration.
+ optional string legacy_config = 1000;
// This field is only used for testing.
optional TestConfig for_testing =
diff --git a/protos/perfetto/config/inode_file/inode_file_config.proto b/protos/perfetto/config/inode_file/inode_file_config.proto
new file mode 100644
index 0000000..a1127ff
--- /dev/null
+++ b/protos/perfetto/config/inode_file/inode_file_config.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package perfetto.protos;
+
+// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
+// to reflect changes in the corresponding C++ headers.
+
+message InodeFileConfig {
+ message MountPointMappingEntry {
+ optional string mountpoint = 1;
+ repeated string scan_roots = 2;
+ }
+
+ // How long to pause between batches.
+ optional uint64 scan_interval_ms = 1;
+
+ // How long to wait before the first scan in order to accumulate inodes.
+ optional uint64 scan_delay_ms = 2;
+
+ // How many inodes to scan in one batch.
+ optional uint64 scan_batch_size = 3;
+
+ // Do not scan for inodes not found in the static map.
+ optional bool do_not_scan = 4;
+
+ // If non-empty, only scan inodes corresponding to block devices named in
+ // this list.
+ repeated string scan_mount_points = 5;
+
+ // When encountering an inode belonging to a block device corresponding
+ // to one of the mount points in this map, scan its scan_roots instead.
+ repeated MountPointMappingEntry mount_point_mapping = 6;
+}
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index e149b49..4efae27 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -22,6 +22,58 @@
// End of protos/perfetto/config/chrome/chrome_config.proto
+// Begin of protos/perfetto/config/inode_file/inode_file_config.proto
+
+// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
+// to reflect changes in the corresponding C++ headers.
+
+message InodeFileConfig {
+ message MountPointMappingEntry {
+ optional string mountpoint = 1;
+ repeated string scan_roots = 2;
+ }
+
+ // How long to pause between batches.
+ optional uint64 scan_interval_ms = 1;
+
+ // How long to wait before the first scan in order to accumulate inodes.
+ optional uint64 scan_delay_ms = 2;
+
+ // How many inodes to scan in one batch.
+ optional uint64 scan_batch_size = 3;
+
+ // Do not scan for inodes not found in the static map.
+ optional bool do_not_scan = 4;
+
+ // If non-empty, only scan inodes corresponding to block devices named in
+ // this list.
+ repeated string scan_mount_points = 5;
+
+ // When encountering an inode belonging to a block device corresponding
+ // to one of the mount points in this map, scan its scan_roots instead.
+ repeated MountPointMappingEntry mount_point_mapping = 6;
+}
+
+// End of protos/perfetto/config/inode_file/inode_file_config.proto
+
+// Begin of protos/perfetto/config/process_stats/process_stats_config.proto
+
+// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
+// to reflect changes in the corresponding C++ headers.
+
+message ProcessStatsConfig {
+ enum Quirks {
+ QUIRKS_UNSPECIFIED = 0;
+ DISABLE_INITIAL_DUMP = 1;
+ // TODO(taylori) Not implemented.
+ DISABLE_ON_DEMAND = 2;
+ }
+
+ repeated Quirks quirks = 1;
+}
+
+// End of protos/perfetto/config/process_stats/process_stats_config.proto
+
// Begin of protos/perfetto/config/data_source_config.proto
// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
@@ -51,6 +103,17 @@
optional FtraceConfig ftrace_config = 100;
optional ChromeConfig chrome_config = 101;
+ optional InodeFileConfig inode_file_config = 102;
+ optional ProcessStatsConfig process_stats_config = 103;
+
+ // This is a fallback mechanism to send a free-form text config to the
+ // producer. In theory this should never be needed. All the code that
+ // is part of the platform (i.e. traced service) is supposed to *not* truncate
+ // the trace config proto and propagate unknown fields. However, if anything
+ // in the pipeline (client or backend) ends up breaking this forward compat
+ // plan, this field will become the escape hatch to allow future data sources
+ // to get some meaningful configuration.
+ optional string legacy_config = 1000;
// This field is only used for testing.
optional TestConfig for_testing =
@@ -85,14 +148,20 @@
// The number of messages the fake producer should send.
optional uint32 message_count = 1;
+ // The maximum number of messages which should be sent each second.
+ // The actual obserced speed may be lower if the producer is unable to
+ // work fast enough.
+ // If this is zero or unset, the producer will send as fast as possible.
+ optional uint32 max_messages_per_second = 2;
+
// The seed value for a simple multiplicative congruential pseudo-random
// number sequence.
- optional uint32 seed = 2;
+ optional uint32 seed = 3;
// The size of each message in bytes. Should be greater than or equal 5 to
// account for the number of bytes needed to encode the random number and a
// null byte for the string.
- optional uint64 message_size = 3;
+ optional uint64 message_size = 4;
}
// End of protos/perfetto/config/test_config.proto
@@ -115,7 +184,6 @@
reserved 2; // |page_size|, now deprecated.
reserved 3; // |optimize_for|, now deprecated.
- // Keep include/perfetto/tracing/core/trace_config.h in sync.
enum FillPolicy {
UNSPECIFIED = 0;
RING_BUFFER = 1;
diff --git a/protos/perfetto/config/process_stats/process_stats_config.proto b/protos/perfetto/config/process_stats/process_stats_config.proto
new file mode 100644
index 0000000..bce97e7
--- /dev/null
+++ b/protos/perfetto/config/process_stats/process_stats_config.proto
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+package perfetto.protos;
+
+// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
+// to reflect changes in the corresponding C++ headers.
+
+message ProcessStatsConfig {
+ enum Quirks {
+ QUIRKS_UNSPECIFIED = 0;
+ DISABLE_INITIAL_DUMP = 1;
+ // TODO(taylori) Not implemented.
+ DISABLE_ON_DEMAND = 2;
+ }
+
+ repeated Quirks quirks = 1;
+}
diff --git a/protos/perfetto/config/test_config.proto b/protos/perfetto/config/test_config.proto
index b679235..8f0045d 100644
--- a/protos/perfetto/config/test_config.proto
+++ b/protos/perfetto/config/test_config.proto
@@ -27,12 +27,18 @@
// The number of messages the fake producer should send.
optional uint32 message_count = 1;
+ // The maximum number of messages which should be sent each second.
+ // The actual obserced speed may be lower if the producer is unable to
+ // work fast enough.
+ // If this is zero or unset, the producer will send as fast as possible.
+ optional uint32 max_messages_per_second = 2;
+
// The seed value for a simple multiplicative congruential pseudo-random
// number sequence.
- optional uint32 seed = 2;
+ optional uint32 seed = 3;
// The size of each message in bytes. Should be greater than or equal 5 to
// account for the number of bytes needed to encode the random number and a
// null byte for the string.
- optional uint64 message_size = 3;
+ optional uint64 message_size = 4;
}
diff --git a/protos/perfetto/config/trace_config.proto b/protos/perfetto/config/trace_config.proto
index c5d057a..36a02bb 100644
--- a/protos/perfetto/config/trace_config.proto
+++ b/protos/perfetto/config/trace_config.proto
@@ -37,7 +37,6 @@
reserved 2; // |page_size|, now deprecated.
reserved 3; // |optimize_for|, now deprecated.
- // Keep include/perfetto/tracing/core/trace_config.h in sync.
enum FillPolicy {
UNSPECIFIED = 0;
RING_BUFFER = 1;
diff --git a/protos/perfetto/ipc/consumer_port.proto b/protos/perfetto/ipc/consumer_port.proto
index abad343..d9b1db5 100644
--- a/protos/perfetto/ipc/consumer_port.proto
+++ b/protos/perfetto/ipc/consumer_port.proto
@@ -77,22 +77,21 @@
message ReadBuffersResponse {
// TODO: uint32 buffer_id = 1;
- // Each streaming reply returns one or more trace packets (see
- // trace_packet.proto).
- // Why "bytes" below? If we just return the full TracePacket object, that will
- // force the Consumer to deserialize it. In many occasions, the Consumer will
- // not consume the TracePacket(s) locally but will just forward them over
- // the network or save them to a file. Deserializing them on-device would be
- // a waste of time, memory and energy.
+ // Each streaming reply returns one or more slices for one or more trace
+ // packets, or even just a portion of it (if it's too big to fit within one
+ // IPC). The returned slices are ordered and contiguous: packets' slices are
+ // not interleaved and slices are sent only once all slices for a packet are
+ // available (i.e. the consumer will never see any gap).
+ message Slice {
+ optional bytes data = 1;
- // TODO: in the past we agreed that a TracePacket can be very large (MBs).
- // However here it will hit the limit of the IPC layer in order to keep
- // the socket buffer bounded. On one side we could upgrade this protocol to
- // support chunks, so we could directly propagate the chunked TracePacket
- // stored in the log buffer. On the other side, this will likely just move
- // the problem on the consumer, that will need larger buffers for reassembly.
- // Perhaps we should just cap the size of a TracePacket to a lower size?
- repeated bytes trace_packets = 2;
+ // When true, this is the last slice for the packet. A ReadBufferResponse
+ // might have no slices marked as |last_slice_for_packet|==true, in the case
+ // of a very large packet that gets chunked into several IPCs (in which case
+ // only the last IPC for the packet will have this flag set).
+ optional bool last_slice_for_packet = 2;
+ }
+ repeated Slice slices = 2;
}
// Arguments for rpc FreeBuffers().
diff --git a/protos/perfetto/ipc/producer_port.proto b/protos/perfetto/ipc/producer_port.proto
index 4665071..f151fd5 100644
--- a/protos/perfetto/ipc/producer_port.proto
+++ b/protos/perfetto/ipc/producer_port.proto
@@ -76,19 +76,16 @@
}
message RegisterDataSourceResponse {
- // The ID assigned by the service to this data source. 0 in case of errors.
- optional uint64 data_source_id = 1;
-
// Only set in case of errors, when |data_source_id| == 0.
- optional string error = 2;
+ optional string error = 1;
};
// Arguments for rpc UnregisterDataSource().
message UnregisterDataSourceRequest {
- // The ID of the data source to unregister, as previously returned in
- // |RegisterDataSourceResponse.data_source_id|.
- optional uint64 data_source_id = 1;
+ // The name of the data source to unregister, as previously passed in
+ // |RegisterDataSourceRequest.name|.
+ optional string data_source_name = 1;
}
message UnregisterDataSourceResponse {}
diff --git a/src/ftrace_reader/BUILD.gn b/src/ftrace_reader/BUILD.gn
index 7e2a6a6..46de5df 100644
--- a/src/ftrace_reader/BUILD.gn
+++ b/src/ftrace_reader/BUILD.gn
@@ -35,8 +35,6 @@
"test/cpu_reader_support.h",
"test/scattered_stream_delegate_for_testing.cc",
"test/scattered_stream_delegate_for_testing.h",
- "test/scattered_stream_null_delegate.cc",
- "test/scattered_stream_null_delegate.h",
]
}
diff --git a/src/ftrace_reader/cpu_reader_benchmark.cc b/src/ftrace_reader/cpu_reader_benchmark.cc
index 8771bac..80ca016 100644
--- a/src/ftrace_reader/cpu_reader_benchmark.cc
+++ b/src/ftrace_reader/cpu_reader_benchmark.cc
@@ -16,16 +16,15 @@
#include "src/ftrace_reader/cpu_reader.h"
+#include "perfetto/base/utils.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
#include "perfetto/protozero/scattered_stream_writer.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
#include "test/cpu_reader_support.h"
-#include "test/scattered_stream_null_delegate.h"
namespace {
-constexpr size_t kPageSize = 4096;
-
perfetto::ExamplePage g_full_page_sched_switch{
"synthetic",
R"(
@@ -293,7 +292,8 @@
using perfetto::ExamplePage;
using perfetto::EventFilter;
using perfetto::ProtoTranslationTable;
-using perfetto::ScatteredStreamNullDelegate;
+using protozero::ScatteredStreamWriterNullDelegate;
+using protozero::ScatteredStreamWriter;
using perfetto::GetTable;
using perfetto::PageFromXxd;
using perfetto::protos::pbzero::FtraceEventBundle;
@@ -303,8 +303,8 @@
static void BM_ParsePageFullOfSchedSwitch(benchmark::State& state) {
const ExamplePage* test_case = &g_full_page_sched_switch;
- ScatteredStreamNullDelegate delegate(kPageSize);
- protozero::ScatteredStreamWriter stream(&delegate);
+ ScatteredStreamWriterNullDelegate delegate(perfetto::base::kPageSize);
+ ScatteredStreamWriter stream(&delegate);
FtraceEventBundle writer;
ProtoTranslationTable* table = GetTable(test_case->name);
diff --git a/src/ftrace_reader/cpu_reader_fuzzer.cc b/src/ftrace_reader/cpu_reader_fuzzer.cc
index c41b528..e1ebae1 100644
--- a/src/ftrace_reader/cpu_reader_fuzzer.cc
+++ b/src/ftrace_reader/cpu_reader_fuzzer.cc
@@ -21,11 +21,11 @@
#include "perfetto/base/logging.h"
#include "perfetto/base/utils.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
#include "perfetto/protozero/scattered_stream_writer.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
#include "src/ftrace_reader/cpu_reader.h"
#include "test/cpu_reader_support.h"
-#include "test/scattered_stream_null_delegate.h"
namespace perfetto {
namespace {
@@ -39,7 +39,7 @@
void FuzzCpuReaderParsePage(const uint8_t* data, size_t size);
void FuzzCpuReaderParsePage(const uint8_t* data, size_t size) {
- ScatteredStreamNullDelegate delegate(base::kPageSize);
+ protozero::ScatteredStreamWriterNullDelegate delegate(base::kPageSize);
protozero::ScatteredStreamWriter stream(&delegate);
FtraceEventBundle writer;
diff --git a/src/ftrace_reader/ftrace_config_muxer.cc b/src/ftrace_reader/ftrace_config_muxer.cc
index 641bd28..2f221b7 100644
--- a/src/ftrace_reader/ftrace_config_muxer.cc
+++ b/src/ftrace_reader/ftrace_config_muxer.cc
@@ -236,8 +236,6 @@
return 0;
// If we're about to turn tracing on use this opportunity do some setup:
- if (RequiresAtrace(request))
- EnableAtrace(request);
SetupClock(request);
SetupBufferSize(request);
} else {
@@ -248,6 +246,9 @@
std::set<std::string> events = GetFtraceEvents(request, table_);
+ if (RequiresAtrace(request))
+ UpdateAtrace(request);
+
for (auto& name : events) {
const Event* event = table_->GetEventByName(name);
if (!event) {
@@ -341,14 +342,13 @@
current_state_.cpu_buffer_size_pages = pages;
}
-void FtraceConfigMuxer::EnableAtrace(const FtraceConfig& request) {
- PERFETTO_DCHECK(!current_state_.atrace_on);
-
- PERFETTO_DLOG("Start atrace...");
+void FtraceConfigMuxer::UpdateAtrace(const FtraceConfig& request) {
+ PERFETTO_DLOG("Update atrace config...");
std::vector<std::string> args;
args.push_back("atrace"); // argv0 for exec()
args.push_back("--async_start");
+ args.push_back("--only_userspace");
for (const auto& category : request.atrace_categories())
args.push_back(category);
if (!request.atrace_apps().empty()) {
@@ -368,7 +368,7 @@
PERFETTO_DLOG("Stop atrace...");
- if (RunAtrace({"atrace", "--async_stop"}))
+ if (RunAtrace({"atrace", "--async_stop", "--only_userspace"}))
current_state_.atrace_on = false;
PERFETTO_DLOG("...done");
diff --git a/src/ftrace_reader/ftrace_config_muxer.h b/src/ftrace_reader/ftrace_config_muxer.h
index de2a7b0..82f51c4 100644
--- a/src/ftrace_reader/ftrace_config_muxer.h
+++ b/src/ftrace_reader/ftrace_config_muxer.h
@@ -80,7 +80,7 @@
void SetupClock(const FtraceConfig& request);
void SetupBufferSize(const FtraceConfig& request);
- void EnableAtrace(const FtraceConfig& request);
+ void UpdateAtrace(const FtraceConfig& request);
void DisableAtrace();
FtraceConfigId GetNextId();
diff --git a/src/ftrace_reader/ftrace_config_muxer_unittest.cc b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
index e3be7aa..1833fbd 100644
--- a/src/ftrace_reader/ftrace_config_muxer_unittest.cc
+++ b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
@@ -212,7 +212,8 @@
EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
.WillOnce(Return('0'));
EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "sched"})))
+ RunAtrace(ElementsAreArray(
+ {"atrace", "--async_start", "--only_userspace", "sched"})))
.WillOnce(Return(true));
FtraceConfigId id = model.RequestConfig(config);
@@ -223,7 +224,8 @@
EXPECT_THAT(actual_config->ftrace_events(), Contains("sched_switch"));
EXPECT_THAT(actual_config->ftrace_events(), Contains("print"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_stop"})))
+ EXPECT_CALL(atrace, RunAtrace(ElementsAreArray(
+ {"atrace", "--async_stop", "--only_userspace"})))
.WillOnce(Return(true));
ASSERT_TRUE(model.RemoveConfig(id));
}
diff --git a/src/ftrace_reader/ftrace_controller.cc b/src/ftrace_reader/ftrace_controller.cc
index ba2d4ec..ee322ec 100644
--- a/src/ftrace_reader/ftrace_controller.cc
+++ b/src/ftrace_reader/ftrace_controller.cc
@@ -307,9 +307,7 @@
if (cpus_to_drain_.none()) {
// If this was the first CPU to wake up, schedule a drain for the next drain
// interval.
- uint64_t delay_ms = NowMs() % drain_period_ms;
- if (!delay_ms)
- delay_ms = drain_period_ms;
+ uint64_t delay_ms = drain_period_ms - (NowMs() % drain_period_ms);
task_runner_->PostDelayedTask(
std::bind(&FtraceController::DrainCPUs, weak_this, generation),
static_cast<int>(delay_ms));
diff --git a/src/ftrace_reader/test/cpu_reader_support.cc b/src/ftrace_reader/test/cpu_reader_support.cc
index 7554346..0a778ca 100644
--- a/src/ftrace_reader/test/cpu_reader_support.cc
+++ b/src/ftrace_reader/test/cpu_reader_support.cc
@@ -16,6 +16,7 @@
#include "src/ftrace_reader/test/cpu_reader_support.h"
+#include "perfetto/base/utils.h"
#include "src/ftrace_reader/ftrace_procfs.h"
#include <string.h>
@@ -23,8 +24,6 @@
namespace perfetto {
namespace {
-constexpr size_t kPageSize = 4096;
-
std::map<std::string, std::unique_ptr<ProtoTranslationTable>>* g_tables;
} // namespace
@@ -44,9 +43,9 @@
}
std::unique_ptr<uint8_t[]> PageFromXxd(const std::string& text) {
- auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[kPageSize]);
+ auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[base::kPageSize]);
const char* ptr = text.data();
- memset(buffer.get(), 0xfa, kPageSize);
+ memset(buffer.get(), 0xfa, base::kPageSize);
uint8_t* out = buffer.get();
while (*ptr != '\0') {
if (*(ptr++) != ':')
diff --git a/src/ipc/buffered_frame_deserializer.cc b/src/ipc/buffered_frame_deserializer.cc
index 9665398..472b302 100644
--- a/src/ipc/buffered_frame_deserializer.cc
+++ b/src/ipc/buffered_frame_deserializer.cc
@@ -184,6 +184,8 @@
frame.AppendToString(&buf);
const uint32_t payload_size = static_cast<uint32_t>(buf.size() - kHeaderSize);
PERFETTO_DCHECK(payload_size == static_cast<uint32_t>(frame.GetCachedSize()));
+ // Don't send messages larger than what the receiver can handle.
+ PERFETTO_DCHECK(kHeaderSize + payload_size <= kIPCBufferSize);
char header[kHeaderSize];
memcpy(header, base::AssumeLittleEndian(&payload_size), kHeaderSize);
buf.replace(0, kHeaderSize, header, kHeaderSize);
diff --git a/src/ipc/buffered_frame_deserializer.h b/src/ipc/buffered_frame_deserializer.h
index 40e1a64..52a5f5f 100644
--- a/src/ipc/buffered_frame_deserializer.h
+++ b/src/ipc/buffered_frame_deserializer.h
@@ -25,6 +25,7 @@
#include <sys/mman.h>
#include "perfetto/base/page_allocator.h"
+#include "perfetto/ipc/basic_types.h"
namespace perfetto {
namespace ipc {
@@ -81,7 +82,8 @@
size_t size;
};
- explicit BufferedFrameDeserializer(size_t max_capacity = 128 * 1024);
+ // |max_capacity| is overridable only for tests.
+ explicit BufferedFrameDeserializer(size_t max_capacity = kIPCBufferSize);
~BufferedFrameDeserializer();
// This function doesn't really belong here as it does Serialization, unlike
diff --git a/src/ipc/unix_socket.cc b/src/ipc/unix_socket.cc
index 463682b..fa5fc2e 100644
--- a/src/ipc/unix_socket.cc
+++ b/src/ipc/unix_socket.cc
@@ -351,15 +351,16 @@
if (blocking_mode == BlockingMode::kBlocking)
SetBlockingIO(false);
- if (sz >= 0) {
- // There should be no way a non-blocking socket returns < |len|.
- // If the queueing fails, sendmsg() must return -1 + errno = EWOULDBLOCK.
- PERFETTO_CHECK(static_cast<size_t>(sz) == len);
+ if (sz == static_cast<ssize_t>(len)) {
last_error_ = 0;
return true;
}
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ // If sendmsg() succeds but the returned size is < |len| it means that the
+ // endpoint disconnected in the middle of the read, and we managed to send
+ // only a portion of the buffer. In this case we should just give up.
+
+ if (sz < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
// A genuine out-of-buffer. The client should retry or give up.
// Man pages specify that EAGAIN and EWOULDBLOCK have the same semantic here
// and clients should check for both.
diff --git a/src/ipc/unix_socket_unittest.cc b/src/ipc/unix_socket_unittest.cc
index 0c07094..efc8063 100644
--- a/src/ipc/unix_socket_unittest.cc
+++ b/src/ipc/unix_socket_unittest.cc
@@ -478,6 +478,55 @@
tx_thread.join();
}
+// Regression test for b/76155349 . If the receiver end disconnects while the
+// sender is in the middle of a large send(), the socket should gracefully give
+// up (i.e. Shutdown()) but not crash.
+TEST_F(UnixSocketTest, ReceiverDisconnectsDuringSend) {
+ auto srv = UnixSocket::Listen(kSocketName, &event_listener_, &task_runner_);
+ ASSERT_TRUE(srv->is_listening());
+ const int kTimeoutMs = 30000;
+
+ auto receive_done = task_runner_.CreateCheckpoint("receive_done");
+ EXPECT_CALL(event_listener_, OnNewIncomingConnection(srv.get(), _))
+ .WillOnce(Invoke([this, receive_done](UnixSocket*, UnixSocket* srv_conn) {
+ EXPECT_CALL(event_listener_, OnDataAvailable(srv_conn))
+ .WillOnce(Invoke([receive_done](UnixSocket* s) {
+ char buf[1024];
+ size_t res = s->Receive(buf, sizeof(buf));
+ ASSERT_EQ(1024u, res);
+ s->Shutdown(false /*notify*/);
+ receive_done();
+ }));
+ }));
+
+ // Perform the blocking send form another thread.
+ std::thread tx_thread([] {
+ base::TestTaskRunner tx_task_runner;
+ MockEventListener tx_events;
+ auto cli = UnixSocket::Connect(kSocketName, &tx_events, &tx_task_runner);
+
+ auto cli_connected = tx_task_runner.CreateCheckpoint("cli_connected");
+ EXPECT_CALL(tx_events, OnConnect(cli.get(), true))
+ .WillOnce(InvokeWithoutArgs(cli_connected));
+ tx_task_runner.RunUntilCheckpoint("cli_connected");
+
+ auto send_done = tx_task_runner.CreateCheckpoint("send_done");
+ // We need a
+ static constexpr size_t kBufSize = 32 * 1024 * 1024;
+ std::unique_ptr<char[]> buf(new char[kBufSize]());
+ tx_task_runner.PostTask([&cli, &buf, send_done] {
+ bool send_res = cli->Send(buf.get(), kBufSize, -1 /*fd*/,
+ UnixSocket::BlockingMode::kBlocking);
+ ASSERT_FALSE(send_res);
+ send_done();
+ });
+
+ tx_task_runner.RunUntilCheckpoint("send_done", kTimeoutMs);
+ });
+ task_runner_.RunUntilCheckpoint("receive_done", kTimeoutMs);
+ tx_thread.join();
+}
+
// TODO(primiano): add a test to check that in the case of a peer sending a fd
// and the other end just doing a recv (without taking it), the fd is closed and
// not left around.
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 144b008..5a86919 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -130,7 +130,7 @@
test_config.add_buffers()->set_size_kb(4096);
test_config.set_duration_ms(2000);
auto* ds_config = test_config.add_data_sources()->mutable_config();
- ds_config->set_name("com.google.perfetto.ftrace");
+ ds_config->set_name("linux.ftrace");
ds_config->mutable_ftrace_config()->add_ftrace_events("sched_switch");
ds_config->mutable_ftrace_config()->add_ftrace_events("cpu_idle");
ds_config->mutable_ftrace_config()->add_ftrace_events("cpu_frequency");
@@ -275,14 +275,14 @@
void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
for (TracePacket& packet : packets) {
+ uint8_t preamble[16];
+ uint8_t* pos = preamble;
+ pos = WriteVarInt(MakeTagLengthDelimited(protos::Trace::kPacketFieldNumber),
+ pos);
+ pos = WriteVarInt(static_cast<uint32_t>(packet.size()), pos);
+ fwrite(reinterpret_cast<const char*>(preamble), pos - preamble, 1,
+ trace_out_stream_.get());
for (const Slice& slice : packet.slices()) {
- uint8_t preamble[16];
- uint8_t* pos = preamble;
- pos = WriteVarInt(
- MakeTagLengthDelimited(protos::Trace::kPacketFieldNumber), pos);
- pos = WriteVarInt(static_cast<uint32_t>(slice.size), pos);
- fwrite(reinterpret_cast<const char*>(preamble), pos - preamble, 1,
- trace_out_stream_.get());
fwrite(reinterpret_cast<const char*>(slice.start), slice.size, 1,
trace_out_stream_.get());
}
diff --git a/src/process_stats/procfs_utils.cc b/src/process_stats/procfs_utils.cc
index a0a9cbd..98b949e 100644
--- a/src/process_stats/procfs_utils.cc
+++ b/src/process_stats/procfs_utils.cc
@@ -67,7 +67,9 @@
std::unique_ptr<ProcessInfo> ReadProcessInfo(int pid) {
ProcessInfo* process = new ProcessInfo();
process->pid = pid;
- char cmdline_buf[256];
+ // It's not enough to just null terminate this since cmdline uses null as
+ // the argument seperator:
+ char cmdline_buf[256]{};
ReadProcString(pid, "cmdline", cmdline_buf, sizeof(cmdline_buf));
if (cmdline_buf[0] == 0) {
// Nothing in cmdline_buf so read name from /comm instead.
diff --git a/src/protozero/BUILD.gn b/src/protozero/BUILD.gn
index 0d67278..c7f3d95 100644
--- a/src/protozero/BUILD.gn
+++ b/src/protozero/BUILD.gn
@@ -30,6 +30,7 @@
"message.cc",
"message_handle.cc",
"proto_utils.cc",
+ "scattered_stream_null_delegate.cc",
"scattered_stream_writer.cc",
]
}
diff --git a/src/ftrace_reader/test/scattered_stream_null_delegate.cc b/src/protozero/scattered_stream_null_delegate.cc
similarity index 60%
rename from src/ftrace_reader/test/scattered_stream_null_delegate.cc
rename to src/protozero/scattered_stream_null_delegate.cc
index 562a3db..3587dba 100644
--- a/src/ftrace_reader/test/scattered_stream_null_delegate.cc
+++ b/src/protozero/scattered_stream_null_delegate.cc
@@ -14,22 +14,24 @@
* limitations under the License.
*/
-#include "src/ftrace_reader/test/scattered_stream_null_delegate.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
-namespace perfetto {
+namespace protozero {
// An implementation of ScatteredStreamWriter::Delegate which always returns
-// the same bit of memory (to better measure performance of users of
-// ScatteredStreamWriter without noisy allocations).
-
-ScatteredStreamNullDelegate::ScatteredStreamNullDelegate(size_t chunk_size)
+// the same piece of memory.
+// This is used when we need to no-op the writers (e.g. during teardown or in
+// case of resource exhaustion), avoiding that the clients have to deal with
+// nullptr checks.
+ScatteredStreamWriterNullDelegate::ScatteredStreamWriterNullDelegate(
+ size_t chunk_size)
: chunk_size_(chunk_size),
chunk_(std::unique_ptr<uint8_t[]>(new uint8_t[chunk_size_])){};
-ScatteredStreamNullDelegate::~ScatteredStreamNullDelegate() {}
+ScatteredStreamWriterNullDelegate::~ScatteredStreamWriterNullDelegate() {}
-protozero::ContiguousMemoryRange ScatteredStreamNullDelegate::GetNewBuffer() {
+ContiguousMemoryRange ScatteredStreamWriterNullDelegate::GetNewBuffer() {
return {chunk_.get(), chunk_.get() + chunk_size_};
}
-} // namespace perfetto
+} // namespace protozero
diff --git a/src/traced/probes/filesystem/BUILD.gn b/src/traced/probes/filesystem/BUILD.gn
index ce481d6..6beb973 100644
--- a/src/traced/probes/filesystem/BUILD.gn
+++ b/src/traced/probes/filesystem/BUILD.gn
@@ -22,6 +22,8 @@
"../../../base",
]
sources = [
+ "file_scanner.cc",
+ "file_scanner.h",
"fs_mount.cc",
"fs_mount.h",
"inode_file_data_source.cc",
diff --git a/src/traced/probes/filesystem/file_scanner.cc b/src/traced/probes/filesystem/file_scanner.cc
new file mode 100644
index 0000000..8369e50
--- /dev/null
+++ b/src/traced/probes/filesystem/file_scanner.cc
@@ -0,0 +1,153 @@
+/*
+ * 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 "src/traced/probes/filesystem/file_scanner.h"
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "src/traced/probes/filesystem/inode_file_data_source.h"
+
+namespace perfetto {
+namespace {
+
+std::string JoinPaths(const std::string& one, const std::string& other) {
+ std::string result;
+ result.reserve(one.size() + other.size() + 1);
+ result += one;
+ if (!result.empty() && result.back() != '/')
+ result += '/';
+ result += other;
+ return result;
+}
+
+} // namespace
+
+FileScanner::FileScanner(std::vector<std::string> root_directories,
+ Delegate* delegate,
+ uint64_t scan_interval_ms,
+ uint64_t scan_steps)
+ : delegate_(delegate),
+ scan_interval_ms_(scan_interval_ms),
+ scan_steps_(scan_steps),
+ queue_(std::move(root_directories)),
+ weak_factory_(this) {}
+
+FileScanner::FileScanner(std::vector<std::string> root_directories,
+ Delegate* delegate)
+ : FileScanner(std::move(root_directories),
+ delegate,
+ 0 /* scan_interval_ms */,
+ 0 /* scan_steps */) {}
+
+void FileScanner::Scan() {
+ while (!Done())
+ Step();
+}
+void FileScanner::Scan(base::TaskRunner* task_runner) {
+ PERFETTO_DCHECK(scan_interval_ms_ && scan_steps_);
+ Steps(scan_steps_);
+ if (Done())
+ return delegate_->OnInodeScanDone();
+ auto weak_this = weak_factory_.GetWeakPtr();
+ task_runner->PostDelayedTask(
+ [weak_this, task_runner] {
+ if (!weak_this)
+ return;
+ weak_this->Scan(task_runner);
+ },
+ scan_interval_ms_);
+}
+
+void FileScanner::NextDirectory() {
+ std::string directory = std::move(queue_.back());
+ queue_.pop_back();
+ current_dir_handle_.reset(opendir(directory.c_str()));
+ if (!current_dir_handle_) {
+ PERFETTO_DPLOG("opendir %s", directory.c_str());
+ current_directory_.clear();
+ return;
+ }
+ current_directory_ = std::move(directory);
+
+ struct stat buf;
+ if (fstat(dirfd(current_dir_handle_.get()), &buf) != 0) {
+ PERFETTO_DPLOG("fstat %s", current_directory_.c_str());
+ current_dir_handle_.reset();
+ current_directory_.clear();
+ return;
+ }
+
+ if (S_ISLNK(buf.st_mode)) {
+ current_dir_handle_.reset();
+ current_directory_.clear();
+ return;
+ }
+ current_block_device_id_ = buf.st_dev;
+}
+
+void FileScanner::Step() {
+ if (!current_dir_handle_) {
+ if (queue_.empty())
+ return;
+ NextDirectory();
+ }
+
+ if (!current_dir_handle_)
+ return;
+
+ struct dirent* entry = readdir(current_dir_handle_.get());
+ if (entry == nullptr) {
+ current_dir_handle_.reset();
+ return;
+ }
+
+ std::string filename = entry->d_name;
+ if (filename == "." || filename == "..")
+ return;
+
+ std::string filepath = JoinPaths(current_directory_, filename);
+
+ protos::pbzero::InodeFileMap_Entry_Type type =
+ protos::pbzero::InodeFileMap_Entry_Type_UNKNOWN;
+ // Readdir and stat not guaranteed to have directory info for all systems
+ if (entry->d_type == DT_DIR) {
+ // Continue iterating through files if current entry is a directory
+ queue_.emplace_back(filepath);
+ type = protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY;
+ } else if (entry->d_type == DT_REG) {
+ type = protos::pbzero::InodeFileMap_Entry_Type_FILE;
+ }
+
+ if (!delegate_->OnInodeFound(current_block_device_id_, entry->d_ino, filepath,
+ type)) {
+ queue_.clear();
+ current_dir_handle_.reset();
+ }
+}
+
+void FileScanner::Steps(uint64_t n) {
+ for (uint64_t i = 0; i < n && !Done(); ++i)
+ Step();
+}
+
+bool FileScanner::Done() {
+ return !current_dir_handle_ && queue_.empty();
+}
+
+} // namespace perfetto
diff --git a/src/traced/probes/filesystem/file_scanner.h b/src/traced/probes/filesystem/file_scanner.h
new file mode 100644
index 0000000..bf193e4
--- /dev/null
+++ b/src/traced/probes/filesystem/file_scanner.h
@@ -0,0 +1,75 @@
+/*
+ * 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 SRC_TRACED_PROBES_FILESYSTEM_FILE_SCANNER_H_
+#define SRC_TRACED_PROBES_FILESYSTEM_FILE_SCANNER_H_
+
+#include <string>
+#include <vector>
+
+#include "perfetto/base/scoped_file.h"
+#include "perfetto/base/task_runner.h"
+#include "perfetto/base/weak_ptr.h"
+#include "perfetto/traced/data_source_types.h"
+
+namespace perfetto {
+
+class FileScanner {
+ public:
+ class Delegate {
+ public:
+ virtual bool OnInodeFound(BlockDeviceID,
+ Inode,
+ const std::string&,
+ protos::pbzero::InodeFileMap_Entry_Type) = 0;
+ virtual void OnInodeScanDone() = 0;
+ virtual ~Delegate() {}
+ };
+
+ FileScanner(std::vector<std::string> root_directories,
+ Delegate* delegate,
+ uint64_t scan_interval_ms,
+ uint64_t scan_steps);
+
+ // Ctor when only the blocking version of Scan is used.
+ FileScanner(std::vector<std::string> root_directories, Delegate* delegate);
+
+ FileScanner(const FileScanner&) = delete;
+ FileScanner& operator=(const FileScanner&) = delete;
+
+ void Scan(base::TaskRunner* task_runner);
+ void Scan();
+
+ private:
+ void NextDirectory();
+ void Step();
+ void Steps(uint64_t n);
+ bool Done();
+
+ Delegate* delegate_;
+ const uint64_t scan_interval_ms_;
+ const uint64_t scan_steps_;
+
+ std::vector<std::string> queue_;
+ base::ScopedDir current_dir_handle_;
+ std::string current_directory_;
+ BlockDeviceID current_block_device_id_;
+ base::WeakPtrFactory<FileScanner> weak_factory_; // Keep last.
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACED_PROBES_FILESYSTEM_FILE_SCANNER_H_
diff --git a/src/traced/probes/filesystem/inode_file_data_source.cc b/src/traced/probes/filesystem/inode_file_data_source.cc
index 3186b3f..fd70ff7 100644
--- a/src/traced/probes/filesystem/inode_file_data_source.cc
+++ b/src/traced/probes/filesystem/inode_file_data_source.cc
@@ -29,77 +29,73 @@
#include "perfetto/tracing/core/trace_writer.h"
#include "perfetto/trace/trace_packet.pbzero.h"
+#include "src/traced/probes/filesystem/file_scanner.h"
namespace perfetto {
+namespace {
+constexpr uint64_t kScanIntervalMs = 10000; // 10s
+constexpr uint64_t kScanDelayMs = 10000; // 10s
+constexpr uint64_t kScanBatchSize = 15000;
-void ScanFilesDFS(
- const std::string& root_directory,
- const std::function<bool(BlockDeviceID block_device_id,
- Inode inode_number,
- const std::string& path,
- protos::pbzero::InodeFileMap_Entry_Type type)>&
- fn) {
- std::vector<std::string> queue{root_directory};
- while (!queue.empty()) {
- struct dirent* entry;
- std::string directory = queue.back();
- queue.pop_back();
- base::ScopedDir dir(opendir(directory.c_str()));
- directory += "/";
- if (!dir)
- continue;
-
- struct stat buf;
- if (lstat(directory.c_str(), &buf) != 0) {
- PERFETTO_DPLOG("lstat %s", directory.c_str());
- continue;
- }
- if (S_ISLNK(buf.st_mode))
- continue;
-
- BlockDeviceID block_device_id = buf.st_dev;
-
- while ((entry = readdir(dir.get())) != nullptr) {
- std::string filename = entry->d_name;
- if (filename == "." || filename == "..")
- continue;
- std::string filepath = directory + filename;
-
- Inode inode_number = entry->d_ino;
-
- protos::pbzero::InodeFileMap_Entry_Type type =
- protos::pbzero::InodeFileMap_Entry_Type_UNKNOWN;
- // Readdir and stat not guaranteed to have directory info for all systems
- if (entry->d_type == DT_DIR) {
- // Continue iterating through files if current entry is a directory
- queue.push_back(filepath);
- type = protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY;
- } else if (entry->d_type == DT_REG) {
- type = protos::pbzero::InodeFileMap_Entry_Type_FILE;
- }
-
- if (!fn(block_device_id, inode_number, filepath, type))
- return;
- }
- if (errno != 0)
- PERFETTO_DPLOG("readdir %s", directory.c_str());
- }
+uint64_t OrDefault(uint64_t value, uint64_t def) {
+ if (value != 0)
+ return value;
+ return def;
}
+std::string DbgFmt(const std::vector<std::string>& values) {
+ if (values.empty())
+ return "";
+
+ std::string result;
+ for (auto it = values.cbegin(); it != values.cend() - 1; ++it)
+ result += *it + ",";
+
+ result += values.back();
+ return result;
+}
+
+std::map<std::string, std::vector<std::string>> BuildMountpointMapping(
+ const DataSourceConfig& source_config) {
+ std::map<std::string, std::vector<std::string>> m;
+ for (const auto& map_entry :
+ source_config.inode_file_config().mount_point_mapping())
+ m.emplace(map_entry.mountpoint(), map_entry.scan_roots());
+
+ return m;
+}
+
+class StaticMapDelegate : public FileScanner::Delegate {
+ public:
+ StaticMapDelegate(
+ std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map)
+ : map_(map) {}
+ ~StaticMapDelegate() {}
+
+ private:
+ bool OnInodeFound(BlockDeviceID block_device_id,
+ Inode inode_number,
+ const std::string& path,
+ protos::pbzero::InodeFileMap_Entry_Type type) {
+ std::unordered_map<Inode, InodeMapValue>& inode_map =
+ (*map_)[block_device_id];
+ inode_map[inode_number].SetType(type);
+ inode_map[inode_number].AddPath(path);
+ return true;
+ }
+ void OnInodeScanDone() {}
+ std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>* map_;
+};
+
+} // namespace
+
void CreateStaticDeviceToInodeMap(
const std::string& root_directory,
std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
static_file_map) {
- ScanFilesDFS(root_directory,
- [static_file_map](BlockDeviceID block_device_id,
- Inode inode_number, const std::string& path,
- protos::pbzero::InodeFileMap_Entry_Type type) {
- std::unordered_map<Inode, InodeMapValue>& inode_map =
- (*static_file_map)[block_device_id];
- inode_map[inode_number].SetType(type);
- inode_map[inode_number].AddPath(path);
- return true;
- });
+ StaticMapDelegate delegate(static_file_map);
+ FileScanner scanner({root_directory}, &delegate);
+ scanner.Scan();
}
void FillInodeEntry(InodeFileMap* destination,
@@ -113,63 +109,28 @@
}
InodeFileDataSource::InodeFileDataSource(
+ DataSourceConfig source_config,
+ base::TaskRunner* task_runner,
TracingSessionID id,
std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
static_file_map,
LRUInodeCache* cache,
std::unique_ptr<TraceWriter> writer)
- : session_id_(id),
+ : source_config_(std::move(source_config)),
+ scan_mount_points_(
+ source_config_.inode_file_config().scan_mount_points().cbegin(),
+ source_config_.inode_file_config().scan_mount_points().cend()),
+ mount_point_mapping_(BuildMountpointMapping(source_config_)),
+ task_runner_(task_runner),
+ session_id_(id),
static_file_map_(static_file_map),
cache_(cache),
writer_(std::move(writer)),
weak_factory_(this) {}
-void InodeFileDataSource::AddInodesFromFilesystemScan(
- const std::string& root_directory,
- BlockDeviceID provided_block_device_id,
- std::set<Inode>* inode_numbers,
- LRUInodeCache* cache,
- InodeFileMap* destination) {
- if (inode_numbers->empty())
- return;
- ScanFilesDFS(
- root_directory,
- [provided_block_device_id, inode_numbers, cache, destination](
- BlockDeviceID block_device_id, Inode inode_number,
- const std::string& path,
- protos::pbzero::InodeFileMap_Entry_Type type) {
- if (provided_block_device_id != block_device_id)
- return true;
- if (inode_numbers->find(inode_number) == inode_numbers->end())
- return true;
- std::pair<BlockDeviceID, Inode> key{block_device_id, inode_number};
- auto cur_val = cache->Get(key);
- if (cur_val != nullptr) {
- cur_val->AddPath(path);
- FillInodeEntry(destination, inode_number, *cur_val);
- } else {
- InodeMapValue new_val(InodeMapValue(type, {path}));
- cache->Insert(key, new_val);
- FillInodeEntry(destination, inode_number, new_val);
- }
- inode_numbers->erase(inode_number);
- if (inode_numbers->empty())
- return false;
- return true;
- });
-
- // Could not be found, just add the inode number
- if (inode_numbers->size() != 0)
- PERFETTO_DLOG("%zu inodes not found", inode_numbers->size());
- for (const auto& unresolved_inode : *inode_numbers) {
- auto* entry = destination->add_entries();
- entry->set_inode_number(unresolved_inode);
- }
-}
-
-void InodeFileDataSource::AddInodesFromStaticMap(BlockDeviceID block_device_id,
- std::set<Inode>* inode_numbers,
- InodeFileMap* destination) {
+void InodeFileDataSource::AddInodesFromStaticMap(
+ BlockDeviceID block_device_id,
+ std::set<Inode>* inode_numbers) {
// Check if block device id exists in static file map
auto static_map_entry = static_file_map_->find(block_device_id);
if (static_map_entry == static_file_map_->end())
@@ -186,15 +147,16 @@
}
system_found_count++;
it = inode_numbers->erase(it);
- FillInodeEntry(destination, inode_number, inode_it->second);
+ FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
+ inode_it->second);
}
PERFETTO_DLOG("%" PRIu64 " inodes found in static file map",
system_found_count);
}
-void InodeFileDataSource::AddInodesFromLRUCache(BlockDeviceID block_device_id,
- std::set<Inode>* inode_numbers,
- InodeFileMap* destination) {
+void InodeFileDataSource::AddInodesFromLRUCache(
+ BlockDeviceID block_device_id,
+ std::set<Inode>* inode_numbers) {
uint64_t cache_found_count = 0;
for (auto it = inode_numbers->begin(); it != inode_numbers->end();) {
Inode inode_number = *it;
@@ -205,7 +167,8 @@
}
cache_found_count++;
it = inode_numbers->erase(it);
- FillInodeEntry(destination, inode_number, *value);
+ FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
+ *value);
}
if (cache_found_count > 0)
PERFETTO_DLOG("%" PRIu64 " inodes found in cache", cache_found_count);
@@ -223,37 +186,187 @@
BlockDeviceID block_device_id = inodes_pair.second;
inode_file_maps[block_device_id].emplace(inode_number);
}
- PERFETTO_DLOG("Saw %zu block devices.", inode_file_maps.size());
+ if (inode_file_maps.size() > 1)
+ PERFETTO_DLOG("Saw %zu block devices.", inode_file_maps.size());
// Write a TracePacket with an InodeFileMap proto for each block device id
- for (const auto& inode_file_map_data : inode_file_maps) {
+ for (auto& inode_file_map_data : inode_file_maps) {
BlockDeviceID block_device_id = inode_file_map_data.first;
- std::set<Inode> inode_numbers = inode_file_map_data.second;
+ std::set<Inode>& inode_numbers = inode_file_map_data.second;
PERFETTO_DLOG("Saw %zu unique inode numbers.", inode_numbers.size());
- // New TracePacket for each InodeFileMap
- auto trace_packet = writer_->NewTracePacket();
- auto inode_file_map = trace_packet->set_inode_file_map();
+ // Add entries to InodeFileMap as inodes are found and resolved to their
+ // paths/type
+ AddInodesFromStaticMap(block_device_id, &inode_numbers);
+ AddInodesFromLRUCache(block_device_id, &inode_numbers);
+
+ if (source_config_.inode_file_config().do_not_scan())
+ inode_numbers.clear();
+
+ // If we defined mount points we want to scan in the config,
+ // skip inodes on other mount points.
+ if (!scan_mount_points_.empty()) {
+ bool process = true;
+ auto range = mount_points_.equal_range(block_device_id);
+ for (auto it = range.first; it != range.second; ++it) {
+ if (scan_mount_points_.count(it->second) == 0) {
+ process = false;
+ break;
+ }
+ }
+ if (!process)
+ continue;
+ }
+
+ if (!inode_numbers.empty()) {
+ // Try to piggy back the current scan.
+ auto it = missing_inodes_.find(block_device_id);
+ if (it != missing_inodes_.end()) {
+ it->second.insert(inode_numbers.cbegin(), inode_numbers.cend());
+ }
+ next_missing_inodes_[block_device_id].insert(inode_numbers.cbegin(),
+ inode_numbers.cend());
+ if (!scan_running_) {
+ scan_running_ = true;
+ auto weak_this = GetWeakPtr();
+ task_runner_->PostDelayedTask(
+ [weak_this] {
+ if (!weak_this) {
+ PERFETTO_DLOG("Giving up filesystem scan.");
+ return;
+ }
+ weak_this.get()->FindMissingInodes();
+ },
+ GetScanDelayMs());
+ }
+ }
+ }
+}
+
+InodeFileMap* InodeFileDataSource::AddToCurrentTracePacket(
+ BlockDeviceID block_device_id) {
+ if (!has_current_trace_packet_ ||
+ current_block_device_id_ != block_device_id) {
+ if (has_current_trace_packet_)
+ current_trace_packet_->Finalize();
+ current_trace_packet_ = writer_->NewTracePacket();
+ current_file_map_ = current_trace_packet_->set_inode_file_map();
+ has_current_trace_packet_ = true;
// Add block device id to InodeFileMap
- inode_file_map->set_block_device_id(block_device_id);
-
+ current_file_map_->set_block_device_id(block_device_id);
// Add mount points to InodeFileMap
auto range = mount_points_.equal_range(block_device_id);
for (std::multimap<BlockDeviceID, std::string>::iterator it = range.first;
it != range.second; ++it)
- inode_file_map->add_mount_points(it->second.c_str());
-
- // Add entries to InodeFileMap as inodes are found and resolved to their
- // paths/type
- AddInodesFromStaticMap(block_device_id, &inode_numbers, inode_file_map);
- AddInodesFromLRUCache(block_device_id, &inode_numbers, inode_file_map);
- // TODO(azappone): Make root directory a mount point
- std::string root_directory = "/data";
- AddInodesFromFilesystemScan(root_directory, block_device_id, &inode_numbers,
- cache_, inode_file_map);
- trace_packet->Finalize();
+ current_file_map_->add_mount_points(it->second.c_str());
}
+ return current_file_map_;
+}
+
+bool InodeFileDataSource::OnInodeFound(
+ BlockDeviceID block_device_id,
+ Inode inode_number,
+ const std::string& path,
+ protos::pbzero::InodeFileMap_Entry_Type type) {
+ auto it = missing_inodes_.find(block_device_id);
+ if (it == missing_inodes_.end())
+ return true;
+
+ size_t n = it->second.erase(inode_number);
+ if (n == 0)
+ return true;
+
+ if (it->second.empty())
+ missing_inodes_.erase(it);
+
+ std::pair<BlockDeviceID, Inode> key{block_device_id, inode_number};
+ auto cur_val = cache_->Get(key);
+ if (cur_val) {
+ cur_val->AddPath(path);
+ FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
+ *cur_val);
+ } else {
+ InodeMapValue new_val(InodeMapValue(type, {path}));
+ cache_->Insert(key, new_val);
+ FillInodeEntry(AddToCurrentTracePacket(block_device_id), inode_number,
+ new_val);
+ }
+ PERFETTO_DLOG("Filled %s", path.c_str());
+ return !missing_inodes_.empty();
+}
+
+void InodeFileDataSource::OnInodeScanDone() {
+ // Finalize the accumulated trace packets.
+ current_block_device_id_ = 0;
+ current_file_map_ = nullptr;
+ if (has_current_trace_packet_)
+ current_trace_packet_->Finalize();
+ has_current_trace_packet_ = false;
+ file_scanner_.reset();
+ if (next_missing_inodes_.empty()) {
+ scan_running_ = false;
+ } else {
+ auto weak_this = GetWeakPtr();
+ PERFETTO_DLOG("Starting another filesystem scan.");
+ task_runner_->PostDelayedTask(
+ [weak_this] {
+ if (!weak_this) {
+ PERFETTO_DLOG("Giving up filesystem scan.");
+ return;
+ }
+ weak_this->FindMissingInodes();
+ },
+ GetScanDelayMs());
+ }
+}
+
+void InodeFileDataSource::AddRootsForBlockDevice(
+ BlockDeviceID block_device_id,
+ std::vector<std::string>* roots) {
+ auto range = mount_points_.equal_range(block_device_id);
+ for (auto it = range.first; it != range.second; ++it) {
+ PERFETTO_DLOG("Trying to replace %s", it->second.c_str());
+ auto replace_it = mount_point_mapping_.find(it->second);
+ if (replace_it != mount_point_mapping_.end()) {
+ roots->insert(roots->end(), replace_it->second.cbegin(),
+ replace_it->second.cend());
+ return;
+ }
+ }
+
+ for (auto it = range.first; it != range.second; ++it)
+ roots->emplace_back(it->second);
+}
+
+void InodeFileDataSource::FindMissingInodes() {
+ missing_inodes_ = std::move(next_missing_inodes_);
+ std::vector<std::string> roots;
+ for (auto& p : missing_inodes_)
+ AddRootsForBlockDevice(p.first, &roots);
+
+ PERFETTO_DCHECK(file_scanner_.get() == nullptr);
+ auto weak_this = GetWeakPtr();
+ PERFETTO_DLOG("Starting scan of %s", DbgFmt(roots).c_str());
+ file_scanner_ = std::unique_ptr<FileScanner>(new FileScanner(
+ std::move(roots), this, GetScanIntervalMs(), GetScanBatchSize()));
+
+ file_scanner_->Scan(task_runner_);
+}
+
+uint64_t InodeFileDataSource::GetScanIntervalMs() {
+ return OrDefault(source_config_.inode_file_config().scan_interval_ms(),
+ kScanIntervalMs);
+}
+
+uint64_t InodeFileDataSource::GetScanDelayMs() {
+ return OrDefault(source_config_.inode_file_config().scan_delay_ms(),
+ kScanDelayMs);
+}
+
+uint64_t InodeFileDataSource::GetScanBatchSize() {
+ return OrDefault(source_config_.inode_file_config().scan_batch_size(),
+ kScanBatchSize);
}
base::WeakPtr<InodeFileDataSource> InodeFileDataSource::GetWeakPtr() const {
diff --git a/src/traced/probes/filesystem/inode_file_data_source.h b/src/traced/probes/filesystem/inode_file_data_source.h
index af881d4..1f4197f 100644
--- a/src/traced/probes/filesystem/inode_file_data_source.h
+++ b/src/traced/probes/filesystem/inode_file_data_source.h
@@ -25,10 +25,13 @@
#include <string>
#include <unordered_map>
+#include "perfetto/base/task_runner.h"
#include "perfetto/base/weak_ptr.h"
#include "perfetto/traced/data_source_types.h"
#include "perfetto/tracing/core/basic_types.h"
+#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/trace_writer.h"
+#include "src/traced/probes/filesystem/file_scanner.h"
#include "src/traced/probes/filesystem/fs_mount.h"
#include "src/traced/probes/filesystem/lru_inode_cache.h"
@@ -56,9 +59,11 @@
Inode inode_number,
const InodeMapValue& inode_map_value);
-class InodeFileDataSource {
+class InodeFileDataSource : public FileScanner::Delegate {
public:
InodeFileDataSource(
+ DataSourceConfig,
+ base::TaskRunner*,
TracingSessionID,
std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
static_file_map,
@@ -71,32 +76,50 @@
// Called when Inodes are seen in the FtraceEventBundle
void OnInodes(const std::vector<std::pair<Inode, BlockDeviceID>>& inodes);
- // Filesystem scan starting from root directory to search for provided inode
- // numbers. Adds all inode numbers to the InodeFileMap proto. Fills in cache
- // for all inode numbers that get resolved from the scan.
- void AddInodesFromFilesystemScan(const std::string& root_directory,
- BlockDeviceID block_device_id,
- std::set<Inode>* inode_numbers,
- LRUInodeCache* cache,
- InodeFileMap* destination);
-
// Search in /system partition and add inodes to InodeFileMap proto if found
void AddInodesFromStaticMap(BlockDeviceID block_device_id,
- std::set<Inode>* inode_numbers,
- InodeFileMap* destination);
+ std::set<Inode>* inode_numbers);
// Search in LRUInodeCache and add inodes to InodeFileMap if found
void AddInodesFromLRUCache(BlockDeviceID block_device_id,
- std::set<Inode>* inode_numbers,
- InodeFileMap* destination);
+ std::set<Inode>* inode_numbers);
+
+ virtual ~InodeFileDataSource() {}
private:
+ InodeFileMap* AddToCurrentTracePacket(BlockDeviceID block_device_id);
+ void FindMissingInodes();
+ bool OnInodeFound(BlockDeviceID block_device_id,
+ Inode inode_number,
+ const std::string& path,
+ protos::pbzero::InodeFileMap_Entry_Type type);
+ void OnInodeScanDone();
+ void AddRootsForBlockDevice(BlockDeviceID block_device_id,
+ std::vector<std::string>* roots);
+
+ uint64_t GetScanIntervalMs();
+ uint64_t GetScanDelayMs();
+ uint64_t GetScanBatchSize();
+
+ const DataSourceConfig source_config_;
+ std::set<std::string> scan_mount_points_;
+ std::map<std::string, std::vector<std::string>> mount_point_mapping_;
+
+ base::TaskRunner* task_runner_;
const TracingSessionID session_id_;
std::map<BlockDeviceID, std::unordered_map<Inode, InodeMapValue>>*
static_file_map_;
LRUInodeCache* cache_;
std::multimap<BlockDeviceID, std::string> mount_points_;
std::unique_ptr<TraceWriter> writer_;
+ std::map<BlockDeviceID, std::set<Inode>> missing_inodes_;
+ std::map<BlockDeviceID, std::set<Inode>> next_missing_inodes_;
+ BlockDeviceID current_block_device_id_;
+ TraceWriter::TracePacketHandle current_trace_packet_;
+ InodeFileMap* current_file_map_;
+ bool has_current_trace_packet_ = false;
+ bool scan_running_ = false;
+ std::unique_ptr<FileScanner> file_scanner_;
base::WeakPtrFactory<InodeFileDataSource> weak_factory_; // Keep last.
};
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 5d29fd9..3c3a532 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -18,6 +18,8 @@
#include <stdio.h>
#include <sys/stat.h>
+
+#include <algorithm>
#include <queue>
#include <string>
@@ -40,9 +42,9 @@
uint64_t kInitialConnectionBackoffMs = 100;
uint64_t kMaxConnectionBackoffMs = 30 * 1000;
-constexpr char kFtraceSourceName[] = "com.google.perfetto.ftrace";
-constexpr char kProcessStatsSourceName[] = "com.google.perfetto.process_stats";
-constexpr char kInodeMapSourceName[] = "com.google.perfetto.inode_file_map";
+constexpr char kFtraceSourceName[] = "linux.ftrace";
+constexpr char kProcessStatsSourceName[] = "linux.process_stats";
+constexpr char kInodeMapSourceName[] = "linux.inode_file_map";
} // namespace.
@@ -65,17 +67,15 @@
DataSourceDescriptor ftrace_descriptor;
ftrace_descriptor.set_name(kFtraceSourceName);
- endpoint_->RegisterDataSource(ftrace_descriptor, [](DataSourceInstanceID) {});
+ endpoint_->RegisterDataSource(ftrace_descriptor);
DataSourceDescriptor process_stats_descriptor;
process_stats_descriptor.set_name(kProcessStatsSourceName);
- endpoint_->RegisterDataSource(process_stats_descriptor,
- [](DataSourceInstanceID) {});
+ endpoint_->RegisterDataSource(process_stats_descriptor);
DataSourceDescriptor inode_map_descriptor;
inode_map_descriptor.set_name(kInodeMapSourceName);
- endpoint_->RegisterDataSource(inode_map_descriptor,
- [](DataSourceInstanceID) {});
+ endpoint_->RegisterDataSource(inode_map_descriptor);
}
void ProbesProducer::OnDisconnect() {
@@ -182,16 +182,17 @@
void ProbesProducer::CreateInodeFileDataSourceInstance(
TracingSessionID session_id,
DataSourceInstanceID id,
- const DataSourceConfig& source_config) {
+ DataSourceConfig source_config) {
PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
id, source_config.target_buffer());
auto trace_writer = endpoint_->CreateTraceWriter(
static_cast<BufferID>(source_config.target_buffer()));
if (system_inodes_.empty())
- CreateStaticDeviceToInodeMap("/system/", &system_inodes_);
+ CreateStaticDeviceToInodeMap("/system", &system_inodes_);
auto file_map_source =
std::unique_ptr<InodeFileDataSource>(new InodeFileDataSource(
- session_id, &system_inodes_, &cache_, std::move(trace_writer)));
+ std::move(source_config), task_runner_, session_id, &system_inodes_,
+ &cache_, std::move(trace_writer)));
file_map_sources_.emplace(id, std::move(file_map_source));
AddWatchdogsTimer(id, source_config);
}
@@ -207,6 +208,13 @@
new ProcessStatsDataSource(session_id, std::move(trace_writer)));
auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
PERFETTO_DCHECK(it_and_inserted.second);
+ if (std::find(config.process_stats_config().quirks().begin(),
+ config.process_stats_config().quirks().end(),
+ ProcessStatsConfig::DISABLE_INITIAL_DUMP) !=
+ config.process_stats_config().quirks().end()) {
+ PERFETTO_DLOG("Initial process tree dump is disabled.");
+ return;
+ }
it_and_inserted.first->second->WriteAllProcesses();
}
@@ -241,7 +249,7 @@
PERFETTO_DCHECK(state_ == kNotConnected);
state_ = kConnecting;
endpoint_ = ProducerIPCClient::Connect(
- socket_name_, this, "com.google.perfetto.traced_probes", task_runner_);
+ socket_name_, this, "perfetto.traced_probes", task_runner_);
}
void ProbesProducer::IncreaseConnectionBackoff() {
@@ -276,6 +284,15 @@
const FtraceMetadata& metadata) {
trace_packet_->Finalize();
+ if (ps_source_ && !metadata.pids.empty()) {
+ const auto& pids = metadata.pids;
+ auto weak_ps_source = ps_source_;
+ task_runner_->PostTask([weak_ps_source, pids] {
+ if (weak_ps_source)
+ weak_ps_source->OnPids(pids);
+ });
+ }
+
if (file_source_ && !metadata.inode_and_device.empty()) {
auto inodes = metadata.inode_and_device;
auto weak_file_source = file_source_;
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index bd550c7..eb45935 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -60,7 +60,7 @@
const DataSourceConfig& config);
void CreateInodeFileDataSourceInstance(TracingSessionID session_id,
DataSourceInstanceID id,
- const DataSourceConfig& config);
+ DataSourceConfig config);
void OnMetadata(const FtraceMetadata& metadata);
diff --git a/src/traced/probes/process_stats_data_source.cc b/src/traced/probes/process_stats_data_source.cc
index 27f05ba..a1bffd8 100644
--- a/src/traced/probes/process_stats_data_source.cc
+++ b/src/traced/probes/process_stats_data_source.cc
@@ -20,7 +20,6 @@
#include "perfetto/trace/ps/process_tree.pbzero.h"
#include "perfetto/trace/trace_packet.pbzero.h"
-#include "perfetto/tracing/core/trace_packet.h"
#include "src/process_stats/file_utils.h"
#include "src/process_stats/procfs_utils.h"
@@ -39,36 +38,51 @@
}
void ProcessStatsDataSource::WriteAllProcesses() {
- procfs_utils::ProcessMap processes;
auto trace_packet = writer_->NewTracePacket();
- protos::pbzero::ProcessTree* process_tree = trace_packet->set_process_tree();
+ auto* trace_packet_ptr = &*trace_packet;
+ std::set<int32_t>* seen_pids = &seen_pids_;
- file_utils::ForEachPidInProcPath(
- "/proc", [&processes, process_tree](int pid) {
- // ForEachPid will list all processes and threads. Here we want to
- // iterate first only by processes (for which pid == thread group id)
- if (!processes.count(pid)) {
- if (procfs_utils::ReadTgid(pid) != pid)
- return;
- processes[pid] = procfs_utils::ReadProcessInfo(pid);
- }
- ProcessInfo* process = processes[pid].get();
- procfs_utils::ReadProcessThreads(process);
- auto* process_writer = process_tree->add_processes();
- process_writer->set_pid(process->pid);
- process_writer->set_ppid(process->ppid);
- for (const auto& field : process->cmdline)
- process_writer->add_cmdline(field.c_str());
- for (auto& thread : process->threads) {
- auto* thread_writer = process_writer->add_threads();
- thread_writer->set_tid(thread.second.tid);
- thread_writer->set_name(thread.second.name);
- }
- });
+ file_utils::ForEachPidInProcPath("/proc",
+ [trace_packet_ptr, seen_pids](int pid) {
+ // ForEachPid will list all processes and
+ // threads. Here we want to iterate first
+ // only by processes (for which pid ==
+ // thread group id)
+ if (procfs_utils::ReadTgid(pid) != pid)
+ return;
+
+ WriteProcess(pid, trace_packet_ptr);
+ seen_pids->insert(pid);
+ });
}
void ProcessStatsDataSource::OnPids(const std::vector<int32_t>& pids) {
- PERFETTO_DLOG("Saw FtraceBundle with %zu pids.", pids.size());
+ auto trace_packet = writer_->NewTracePacket();
+ for (int32_t pid : pids) {
+ auto it_and_inserted = seen_pids_.emplace(pid);
+ if (it_and_inserted.second)
+ WriteProcess(pid, &*trace_packet);
+ }
+}
+
+// static
+void ProcessStatsDataSource::WriteProcess(
+ int32_t pid,
+ protos::pbzero::TracePacket* trace_packet) {
+ auto* process_tree = trace_packet->set_process_tree();
+
+ std::unique_ptr<ProcessInfo> process = procfs_utils::ReadProcessInfo(pid);
+ procfs_utils::ReadProcessThreads(process.get());
+ auto* process_writer = process_tree->add_processes();
+ process_writer->set_pid(process->pid);
+ process_writer->set_ppid(process->ppid);
+ for (const auto& field : process->cmdline)
+ process_writer->add_cmdline(field.c_str());
+ for (auto& thread : process->threads) {
+ auto* thread_writer = process_writer->add_threads();
+ thread_writer->set_tid(thread.second.tid);
+ thread_writer->set_name(thread.second.name);
+ }
}
} // namespace perfetto
diff --git a/src/traced/probes/process_stats_data_source.h b/src/traced/probes/process_stats_data_source.h
index 2b691ab..f134bff 100644
--- a/src/traced/probes/process_stats_data_source.h
+++ b/src/traced/probes/process_stats_data_source.h
@@ -18,6 +18,7 @@
#define SRC_TRACED_PROBES_PROCESS_STATS_DATA_SOURCE_H_
#include <memory>
+#include <set>
#include <vector>
#include "perfetto/base/weak_ptr.h"
@@ -37,11 +38,15 @@
void OnPids(const std::vector<int32_t>& pids);
private:
+ static void WriteProcess(int32_t pid, protos::pbzero::TracePacket*);
+
ProcessStatsDataSource(const ProcessStatsDataSource&) = delete;
ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete;
const TracingSessionID session_id_;
std::unique_ptr<TraceWriter> writer_;
+ // TODO(b/76663469): Optimization: use a bitmap.
+ std::set<int32_t> seen_pids_;
base::WeakPtrFactory<ProcessStatsDataSource> weak_factory_; // Keep last.
};
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index eef490d..68eee89 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -37,9 +37,13 @@
"core/ftrace_config.cc",
"core/id_allocator.cc",
"core/id_allocator.h",
+ "core/inode_file_config.cc",
+ "core/null_trace_writer.cc",
+ "core/null_trace_writer.h",
"core/packet_stream_validator.cc",
"core/packet_stream_validator.h",
"core/patch_list.h",
+ "core/process_stats_config.cc",
"core/service_impl.cc",
"core/service_impl.h",
"core/shared_memory_abi.cc",
@@ -122,6 +126,7 @@
]
sources = [
"core/id_allocator_unittest.cc",
+ "core/null_trace_writer_unittest.cc",
"core/packet_stream_validator_unittest.cc",
"core/patch_list_unittest.cc",
"core/service_impl_unittest.cc",
diff --git a/src/tracing/core/data_source_config.cc b/src/tracing/core/data_source_config.cc
index 622eb4c..56192e8 100644
--- a/src/tracing/core/data_source_config.cc
+++ b/src/tracing/core/data_source_config.cc
@@ -30,6 +30,8 @@
#include "perfetto/config/chrome/chrome_config.pb.h"
#include "perfetto/config/data_source_config.pb.h"
#include "perfetto/config/ftrace/ftrace_config.pb.h"
+#include "perfetto/config/inode_file/inode_file_config.pb.h"
+#include "perfetto/config/process_stats/process_stats_config.pb.h"
#include "perfetto/config/test_config.pb.h"
namespace perfetto {
@@ -60,6 +62,14 @@
chrome_config_.FromProto(proto.chrome_config());
+ inode_file_config_.FromProto(proto.inode_file_config());
+
+ process_stats_config_.FromProto(proto.process_stats_config());
+
+ static_assert(sizeof(legacy_config_) == sizeof(proto.legacy_config()),
+ "size mismatch");
+ legacy_config_ = static_cast<decltype(legacy_config_)>(proto.legacy_config());
+
for_testing_.FromProto(proto.for_testing());
unknown_fields_ = proto.unknown_fields();
}
@@ -86,6 +96,15 @@
chrome_config_.ToProto(proto->mutable_chrome_config());
+ inode_file_config_.ToProto(proto->mutable_inode_file_config());
+
+ process_stats_config_.ToProto(proto->mutable_process_stats_config());
+
+ static_assert(sizeof(legacy_config_) == sizeof(proto->legacy_config()),
+ "size mismatch");
+ proto->set_legacy_config(
+ static_cast<decltype(proto->legacy_config())>(legacy_config_));
+
for_testing_.ToProto(proto->mutable_for_testing());
*(proto->mutable_unknown_fields()) = unknown_fields_;
}
diff --git a/src/tracing/core/ftrace_config.cc b/src/tracing/core/ftrace_config.cc
index 34d8ef4..cf0891f 100644
--- a/src/tracing/core/ftrace_config.cc
+++ b/src/tracing/core/ftrace_config.cc
@@ -84,19 +84,21 @@
proto->Clear();
for (const auto& it : ftrace_events_) {
- proto->add_ftrace_events(it);
+ proto->add_ftrace_events(
+ static_cast<decltype(proto->ftrace_events(0))>(it));
static_assert(sizeof(it) == sizeof(proto->ftrace_events(0)),
"size mismatch");
}
for (const auto& it : atrace_categories_) {
- proto->add_atrace_categories(it);
+ proto->add_atrace_categories(
+ static_cast<decltype(proto->atrace_categories(0))>(it));
static_assert(sizeof(it) == sizeof(proto->atrace_categories(0)),
"size mismatch");
}
for (const auto& it : atrace_apps_) {
- proto->add_atrace_apps(it);
+ proto->add_atrace_apps(static_cast<decltype(proto->atrace_apps(0))>(it));
static_assert(sizeof(it) == sizeof(proto->atrace_apps(0)), "size mismatch");
}
diff --git a/src/tracing/core/inode_file_config.cc b/src/tracing/core/inode_file_config.cc
new file mode 100644
index 0000000..bd831bc
--- /dev/null
+++ b/src/tracing/core/inode_file_config.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*******************************************************************************
+ * AUTOGENERATED - DO NOT EDIT
+ *******************************************************************************
+ * This file has been generated from the protobuf message
+ * perfetto/config/inode_file/inode_file_config.proto
+ * by
+ * ../../tools/proto_to_cpp/proto_to_cpp.cc.
+ * If you need to make changes here, change the .proto file and then run
+ * ./tools/gen_tracing_cpp_headers_from_protos.py
+ */
+
+#include "perfetto/tracing/core/inode_file_config.h"
+
+#include "perfetto/config/inode_file/inode_file_config.pb.h"
+
+namespace perfetto {
+
+InodeFileConfig::InodeFileConfig() = default;
+InodeFileConfig::~InodeFileConfig() = default;
+InodeFileConfig::InodeFileConfig(const InodeFileConfig&) = default;
+InodeFileConfig& InodeFileConfig::operator=(const InodeFileConfig&) = default;
+InodeFileConfig::InodeFileConfig(InodeFileConfig&&) noexcept = default;
+InodeFileConfig& InodeFileConfig::operator=(InodeFileConfig&&) = default;
+
+void InodeFileConfig::FromProto(
+ const perfetto::protos::InodeFileConfig& proto) {
+ static_assert(sizeof(scan_interval_ms_) == sizeof(proto.scan_interval_ms()),
+ "size mismatch");
+ scan_interval_ms_ =
+ static_cast<decltype(scan_interval_ms_)>(proto.scan_interval_ms());
+
+ static_assert(sizeof(scan_delay_ms_) == sizeof(proto.scan_delay_ms()),
+ "size mismatch");
+ scan_delay_ms_ = static_cast<decltype(scan_delay_ms_)>(proto.scan_delay_ms());
+
+ static_assert(sizeof(scan_batch_size_) == sizeof(proto.scan_batch_size()),
+ "size mismatch");
+ scan_batch_size_ =
+ static_cast<decltype(scan_batch_size_)>(proto.scan_batch_size());
+
+ static_assert(sizeof(do_not_scan_) == sizeof(proto.do_not_scan()),
+ "size mismatch");
+ do_not_scan_ = static_cast<decltype(do_not_scan_)>(proto.do_not_scan());
+
+ scan_mount_points_.clear();
+ for (const auto& field : proto.scan_mount_points()) {
+ scan_mount_points_.emplace_back();
+ static_assert(
+ sizeof(scan_mount_points_.back()) == sizeof(proto.scan_mount_points(0)),
+ "size mismatch");
+ scan_mount_points_.back() =
+ static_cast<decltype(scan_mount_points_)::value_type>(field);
+ }
+
+ mount_point_mapping_.clear();
+ for (const auto& field : proto.mount_point_mapping()) {
+ mount_point_mapping_.emplace_back();
+ mount_point_mapping_.back().FromProto(field);
+ }
+ unknown_fields_ = proto.unknown_fields();
+}
+
+void InodeFileConfig::ToProto(perfetto::protos::InodeFileConfig* proto) const {
+ proto->Clear();
+
+ static_assert(sizeof(scan_interval_ms_) == sizeof(proto->scan_interval_ms()),
+ "size mismatch");
+ proto->set_scan_interval_ms(
+ static_cast<decltype(proto->scan_interval_ms())>(scan_interval_ms_));
+
+ static_assert(sizeof(scan_delay_ms_) == sizeof(proto->scan_delay_ms()),
+ "size mismatch");
+ proto->set_scan_delay_ms(
+ static_cast<decltype(proto->scan_delay_ms())>(scan_delay_ms_));
+
+ static_assert(sizeof(scan_batch_size_) == sizeof(proto->scan_batch_size()),
+ "size mismatch");
+ proto->set_scan_batch_size(
+ static_cast<decltype(proto->scan_batch_size())>(scan_batch_size_));
+
+ static_assert(sizeof(do_not_scan_) == sizeof(proto->do_not_scan()),
+ "size mismatch");
+ proto->set_do_not_scan(
+ static_cast<decltype(proto->do_not_scan())>(do_not_scan_));
+
+ for (const auto& it : scan_mount_points_) {
+ proto->add_scan_mount_points(
+ static_cast<decltype(proto->scan_mount_points(0))>(it));
+ static_assert(sizeof(it) == sizeof(proto->scan_mount_points(0)),
+ "size mismatch");
+ }
+
+ for (const auto& it : mount_point_mapping_) {
+ auto* entry = proto->add_mount_point_mapping();
+ it.ToProto(entry);
+ }
+ *(proto->mutable_unknown_fields()) = unknown_fields_;
+}
+
+InodeFileConfig::MountPointMappingEntry::MountPointMappingEntry() = default;
+InodeFileConfig::MountPointMappingEntry::~MountPointMappingEntry() = default;
+InodeFileConfig::MountPointMappingEntry::MountPointMappingEntry(
+ const InodeFileConfig::MountPointMappingEntry&) = default;
+InodeFileConfig::MountPointMappingEntry&
+InodeFileConfig::MountPointMappingEntry::operator=(
+ const InodeFileConfig::MountPointMappingEntry&) = default;
+InodeFileConfig::MountPointMappingEntry::MountPointMappingEntry(
+ InodeFileConfig::MountPointMappingEntry&&) noexcept = default;
+InodeFileConfig::MountPointMappingEntry&
+InodeFileConfig::MountPointMappingEntry::operator=(
+ InodeFileConfig::MountPointMappingEntry&&) = default;
+
+void InodeFileConfig::MountPointMappingEntry::FromProto(
+ const perfetto::protos::InodeFileConfig_MountPointMappingEntry& proto) {
+ static_assert(sizeof(mountpoint_) == sizeof(proto.mountpoint()),
+ "size mismatch");
+ mountpoint_ = static_cast<decltype(mountpoint_)>(proto.mountpoint());
+
+ scan_roots_.clear();
+ for (const auto& field : proto.scan_roots()) {
+ scan_roots_.emplace_back();
+ static_assert(sizeof(scan_roots_.back()) == sizeof(proto.scan_roots(0)),
+ "size mismatch");
+ scan_roots_.back() = static_cast<decltype(scan_roots_)::value_type>(field);
+ }
+ unknown_fields_ = proto.unknown_fields();
+}
+
+void InodeFileConfig::MountPointMappingEntry::ToProto(
+ perfetto::protos::InodeFileConfig_MountPointMappingEntry* proto) const {
+ proto->Clear();
+
+ static_assert(sizeof(mountpoint_) == sizeof(proto->mountpoint()),
+ "size mismatch");
+ proto->set_mountpoint(
+ static_cast<decltype(proto->mountpoint())>(mountpoint_));
+
+ for (const auto& it : scan_roots_) {
+ proto->add_scan_roots(static_cast<decltype(proto->scan_roots(0))>(it));
+ static_assert(sizeof(it) == sizeof(proto->scan_roots(0)), "size mismatch");
+ }
+ *(proto->mutable_unknown_fields()) = unknown_fields_;
+}
+
+} // namespace perfetto
diff --git a/src/tracing/core/null_trace_writer.cc b/src/tracing/core/null_trace_writer.cc
new file mode 100644
index 0000000..36cddf4
--- /dev/null
+++ b/src/tracing/core/null_trace_writer.cc
@@ -0,0 +1,56 @@
+/*
+ * 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 "src/tracing/core/null_trace_writer.h"
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/utils.h"
+
+#include "perfetto/protozero/message.h"
+
+#include "perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+NullTraceWriter::NullTraceWriter()
+ : delegate_(base::kPageSize), stream_(&delegate_) {
+ cur_packet_.reset(new protos::pbzero::TracePacket());
+ cur_packet_->Finalize(); // To avoid the DCHECK in NewTracePacket().
+}
+
+NullTraceWriter::~NullTraceWriter() {}
+
+void NullTraceWriter::Flush(std::function<void()> callback) {
+ // Flush() cannot be called in the middle of a TracePacket.
+ PERFETTO_CHECK(cur_packet_->is_finalized());
+
+ if (callback)
+ callback();
+}
+
+NullTraceWriter::TracePacketHandle NullTraceWriter::NewTracePacket() {
+ // If we hit this, the caller is calling NewTracePacket() without having
+ // finalized the previous packet.
+ PERFETTO_DCHECK(cur_packet_->is_finalized());
+ cur_packet_->Reset(&stream_);
+ return TraceWriter::TracePacketHandle(cur_packet_.get());
+}
+
+WriterID NullTraceWriter::writer_id() const {
+ return 0;
+}
+
+} // namespace perfetto
diff --git a/src/tracing/core/null_trace_writer.h b/src/tracing/core/null_trace_writer.h
new file mode 100644
index 0000000..8f10819
--- /dev/null
+++ b/src/tracing/core/null_trace_writer.h
@@ -0,0 +1,54 @@
+/*
+ * 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 SRC_TRACING_CORE_NULL_TRACE_WRITER_H_
+#define SRC_TRACING_CORE_NULL_TRACE_WRITER_H_
+
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/protozero/scattered_stream_null_delegate.h"
+#include "perfetto/tracing/core/trace_writer.h"
+
+namespace perfetto {
+
+// A specialization of TraceWriter which no-ops all the writes routing them
+// into a fixed region of memory
+// See //include/perfetto/tracing/core/trace_writer.h for docs.
+class NullTraceWriter : public TraceWriter {
+ public:
+ NullTraceWriter();
+ ~NullTraceWriter() override;
+
+ // TraceWriter implementation. See documentation in trace_writer.h.
+ // TracePacketHandle is defined in trace_writer.h
+ TracePacketHandle NewTracePacket() override;
+ void Flush(std::function<void()> callback = {}) override;
+ WriterID writer_id() const override;
+
+ private:
+ NullTraceWriter(const NullTraceWriter&) = delete;
+ NullTraceWriter& operator=(const NullTraceWriter&) = delete;
+
+ protozero::ScatteredStreamWriterNullDelegate delegate_;
+ protozero::ScatteredStreamWriter stream_;
+
+ // The packet returned via NewTracePacket(). Its owned by this class,
+ // TracePacketHandle has just a pointer to it.
+ std::unique_ptr<protos::pbzero::TracePacket> cur_packet_;
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACING_CORE_NULL_TRACE_WRITER_H_
diff --git a/src/tracing/core/null_trace_writer_unittest.cc b/src/tracing/core/null_trace_writer_unittest.cc
new file mode 100644
index 0000000..f2d2f54
--- /dev/null
+++ b/src/tracing/core/null_trace_writer_unittest.cc
@@ -0,0 +1,52 @@
+/*
+ * 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 "src/tracing/core/null_trace_writer.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "perfetto/base/utils.h"
+#include "perfetto/tracing/core/trace_writer.h"
+
+#include "perfetto/trace/test_event.pbzero.h"
+#include "perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace {
+
+TEST(NullTraceWriterTest, WriterIdIsZero) {
+ NullTraceWriter writer;
+ EXPECT_EQ(writer.writer_id(), 0);
+}
+
+TEST(NullTraceWriterTest, Writing) {
+ NullTraceWriter writer;
+ for (size_t i = 0; i < 3 * base::kPageSize; i++) {
+ auto packet = writer.NewTracePacket();
+ packet->set_for_testing()->set_str("Hello, world!");
+ }
+}
+
+TEST(NullTraceWriterTest, FlushCallbackIsCalled) {
+ NullTraceWriter writer;
+ writer.Flush();
+ bool was_called = false;
+ writer.Flush([&was_called] { was_called = true; });
+ EXPECT_TRUE(was_called);
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/src/tracing/core/process_stats_config.cc b/src/tracing/core/process_stats_config.cc
new file mode 100644
index 0000000..fabf7d6
--- /dev/null
+++ b/src/tracing/core/process_stats_config.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*******************************************************************************
+ * AUTOGENERATED - DO NOT EDIT
+ *******************************************************************************
+ * This file has been generated from the protobuf message
+ * perfetto/config/process_stats/process_stats_config.proto
+ * by
+ * ../../tools/proto_to_cpp/proto_to_cpp.cc.
+ * If you need to make changes here, change the .proto file and then run
+ * ./tools/gen_tracing_cpp_headers_from_protos.py
+ */
+
+#include "perfetto/tracing/core/process_stats_config.h"
+
+#include "perfetto/config/process_stats/process_stats_config.pb.h"
+
+namespace perfetto {
+
+ProcessStatsConfig::ProcessStatsConfig() = default;
+ProcessStatsConfig::~ProcessStatsConfig() = default;
+ProcessStatsConfig::ProcessStatsConfig(const ProcessStatsConfig&) = default;
+ProcessStatsConfig& ProcessStatsConfig::operator=(const ProcessStatsConfig&) =
+ default;
+ProcessStatsConfig::ProcessStatsConfig(ProcessStatsConfig&&) noexcept = default;
+ProcessStatsConfig& ProcessStatsConfig::operator=(ProcessStatsConfig&&) =
+ default;
+
+void ProcessStatsConfig::FromProto(
+ const perfetto::protos::ProcessStatsConfig& proto) {
+ quirks_.clear();
+ for (const auto& field : proto.quirks()) {
+ quirks_.emplace_back();
+ static_assert(sizeof(quirks_.back()) == sizeof(proto.quirks(0)),
+ "size mismatch");
+ quirks_.back() = static_cast<decltype(quirks_)::value_type>(field);
+ }
+ unknown_fields_ = proto.unknown_fields();
+}
+
+void ProcessStatsConfig::ToProto(
+ perfetto::protos::ProcessStatsConfig* proto) const {
+ proto->Clear();
+
+ for (const auto& it : quirks_) {
+ proto->add_quirks(static_cast<decltype(proto->quirks(0))>(it));
+ static_assert(sizeof(it) == sizeof(proto->quirks(0)), "size mismatch");
+ }
+ *(proto->mutable_unknown_fields()) = unknown_fields_;
+}
+
+} // namespace perfetto
diff --git a/src/tracing/core/service_impl.cc b/src/tracing/core/service_impl.cc
index 04612ee..d7ab856 100644
--- a/src/tracing/core/service_impl.cc
+++ b/src/tracing/core/service_impl.cc
@@ -53,7 +53,6 @@
namespace {
constexpr size_t kDefaultShmSize = 256 * 1024ul;
constexpr size_t kMaxShmSize = 4096 * 1024 * 512ul;
-constexpr size_t kMaxShmPageSizeKb = 16ul;
constexpr size_t kDefaultShmPageSizeKb = base::kPageSize / 1024ul;
constexpr int kMaxBuffersPerConsumer = 128;
constexpr base::TimeMillis kClockSnapshotInterval(10 * 1000);
@@ -127,7 +126,7 @@
auto next = it;
next++;
if (it->second.producer_id == id)
- UnregisterDataSource(id, it->second.data_source_id);
+ UnregisterDataSource(id, it->second.descriptor.name());
it = next;
}
@@ -278,9 +277,9 @@
const size_t buf_size_bytes = buffer_cfg.size_kb() * 1024u;
total_buf_size_kb += buffer_cfg.size_kb();
auto it_and_inserted =
- buffers_.emplace(global_id, TraceBuffez::Create(buf_size_bytes));
+ buffers_.emplace(global_id, TraceBuffer::Create(buf_size_bytes));
PERFETTO_DCHECK(it_and_inserted.second); // buffers_.count(global_id) == 0.
- std::unique_ptr<TraceBuffez>& trace_buffer = it_and_inserted.first->second;
+ std::unique_ptr<TraceBuffer>& trace_buffer = it_and_inserted.first->second;
if (!trace_buffer) {
did_allocate_all_buffers = false;
break;
@@ -342,7 +341,7 @@
if (weak_this)
weak_this->ReadBuffers(tsid, nullptr);
},
- tracing_session->next_write_period_ms());
+ tracing_session->delay_to_next_write_period_ms());
}
tracing_session->tracing_enabled = true;
@@ -434,11 +433,18 @@
total_slices += packet.slices().size();
}
- // This is a rough threshold to determine how to split packets within each
- // IPC. This is not an upper bound, we just stop accumulating packets and send
- // an IPC out every time we cross this threshold (i.e. all IPCs % last one
- // will be >= kApproxBytesPerRead).
- static constexpr size_t kApproxBytesPerRead = 4096;
+ // This is a rough threshold to determine how much to read from the buffer in
+ // each task. This is to avoid executing a single huge sending task for too
+ // long and risk to hit the watchdog. This is *not* an upper bound: we just
+ // stop accumulating new packets and PostTask *after* we cross this threshold.
+ // This constant essentially balances the PostTask and IPC overhead vs the
+ // responsiveness of the service. An extremely small value will cause one IPC
+ // and one PostTask for each slice but will keep the service extremely
+ // responsive. An extremely large value will batch the send for the full
+ // buffer in one large task, will hit the blocking send() once the socket
+ // buffers are full and hang the service for a bit (until the consumer
+ // catches up).
+ static constexpr size_t kApproxBytesPerTask = 32768;
bool did_hit_threshold = false;
// TODO(primiano): Extend the ReadBuffers API to allow reading only some
@@ -451,7 +457,7 @@
PERFETTO_DCHECK(false);
continue;
}
- TraceBuffez& tbuf = *tbuf_iter->second;
+ TraceBuffer& tbuf = *tbuf_iter->second;
tbuf.BeginRead();
while (!did_hit_threshold) {
TracePacket packet;
@@ -486,7 +492,7 @@
// Append the packet (inclusive of the trusted uid) to |packets|.
packets_bytes += packet.size();
total_slices += packet.slices().size();
- did_hit_threshold = packets_bytes >= kApproxBytesPerRead &&
+ did_hit_threshold = packets_bytes >= kApproxBytesPerTask &&
!tracing_session->write_into_file;
packets.emplace_back(std::move(packet));
} // for(packets...)
@@ -569,7 +575,7 @@
if (weak_this)
weak_this->ReadBuffers(tsid, nullptr);
},
- tracing_session->next_write_period_ms());
+ tracing_session->delay_to_next_write_period_ms());
return;
} // if (tracing_session->write_into_file)
@@ -611,16 +617,14 @@
}
void ServiceImpl::RegisterDataSource(ProducerID producer_id,
- DataSourceID ds_id,
const DataSourceDescriptor& desc) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_DLOG("Producer %" PRIu16
- " registered data source \"%s\", ID: %" PRIu64,
- producer_id, desc.name().c_str(), ds_id);
+ PERFETTO_DLOG("Producer %" PRIu16 " registered data source \"%s\"",
+ producer_id, desc.name().c_str());
PERFETTO_DCHECK(!desc.name().empty());
- auto reg_ds = data_sources_.emplace(
- desc.name(), RegisteredDataSource{producer_id, ds_id, desc});
+ auto reg_ds = data_sources_.emplace(desc.name(),
+ RegisteredDataSource{producer_id, desc});
// If there are existing tracing sessions, we need to check if the new
// data source is enabled by any of them.
@@ -652,16 +656,15 @@
}
void ServiceImpl::UnregisterDataSource(ProducerID producer_id,
- DataSourceID ds_id) {
+ const std::string& name) {
PERFETTO_DCHECK_THREAD(thread_checker_);
PERFETTO_CHECK(producer_id);
- PERFETTO_CHECK(ds_id);
ProducerEndpointImpl* producer = GetProducer(producer_id);
PERFETTO_DCHECK(producer);
for (auto& session : tracing_sessions_) {
auto it = session.second.data_source_instances.begin();
while (it != session.second.data_source_instances.end()) {
- if (it->first == producer_id && it->second.data_source_id == ds_id) {
+ if (it->first == producer_id && it->second.data_source_name == name) {
producer->producer_->TearDownDataSourceInstance(it->second.instance_id);
it = session.second.data_source_instances.erase(it);
} else {
@@ -672,14 +675,16 @@
for (auto it = data_sources_.begin(); it != data_sources_.end(); ++it) {
if (it->second.producer_id == producer_id &&
- it->second.data_source_id == ds_id) {
+ it->second.descriptor.name() == name) {
data_sources_.erase(it);
return;
}
}
- PERFETTO_DLOG("Tried to unregister a non-existent data source %" PRIu64
- " for producer %" PRIu16,
- ds_id, producer_id);
+
+ PERFETTO_DLOG(
+ "Tried to unregister a non-existent data source \"%s\" for "
+ "producer %" PRIu16,
+ name.c_str(), producer_id);
PERFETTO_DCHECK(false);
}
@@ -697,8 +702,19 @@
PERFETTO_DLOG("Lockdown mode: not enabling producer %hu", producer->id_);
return;
}
- // TODO(primiano): match against |producer_name_filter| and add tests
- // for registration ordering (data sources vs consumers).
+ // TODO(primiano): Add tests for registration ordering
+ // (data sources vs consumers).
+ if (!cfg_data_source.producer_name_filter().empty()) {
+ if (std::find(cfg_data_source.producer_name_filter().begin(),
+ cfg_data_source.producer_name_filter().end(),
+ producer->name_) ==
+ cfg_data_source.producer_name_filter().end()) {
+ PERFETTO_DLOG("Data source: %s is filtered out for producer: %s",
+ cfg_data_source.config().name().c_str(),
+ producer->name_.c_str());
+ return;
+ }
+ }
// Create a copy of the DataSourceConfig specified in the trace config. This
// will be passed to the producer after translating the |target_buffer| id.
@@ -723,14 +739,15 @@
DataSourceInstanceID inst_id = ++last_data_source_instance_id_;
tracing_session->data_source_instances.emplace(
- producer->id_, DataSourceInstance{inst_id, data_source.data_source_id});
+ producer->id_,
+ DataSourceInstance{inst_id, data_source.descriptor.name()});
PERFETTO_DLOG("Starting data source %s with target buffer %" PRIu16,
ds_config.name().c_str(), global_id);
if (!producer->shared_memory()) {
producer->shared_buffer_page_size_kb_ = std::min<size_t>(
(producer_config.page_size_kb() == 0) ? kDefaultShmPageSizeKb
: producer_config.page_size_kb(),
- kMaxShmPageSizeKb);
+ SharedMemoryABI::kMaxPageSize);
size_t shm_size =
std::min<size_t>(producer_config.shm_size_kb() * 1024, kMaxShmSize);
@@ -765,7 +782,7 @@
const uint8_t* src,
size_t size) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- TraceBuffez* buf = GetBufferByID(buffer_id);
+ TraceBuffer* buf = GetBufferByID(buffer_id);
if (!buf) {
PERFETTO_DLOG("Could not find target buffer %" PRIu16
" for producer %" PRIu16,
@@ -791,7 +808,7 @@
for (const auto& chunk : chunks_to_patch) {
const ChunkID chunk_id = static_cast<ChunkID>(chunk.chunk_id());
const WriterID writer_id = static_cast<WriterID>(chunk.writer_id());
- TraceBuffez* buf =
+ TraceBuffer* buf =
GetBufferByID(static_cast<BufferID>(chunk.target_buffer()));
static_assert(std::numeric_limits<ChunkID>::max() == kMaxChunkID,
"Add a '|| chunk_id > kMaxChunkID' below if this fails");
@@ -804,7 +821,7 @@
}
// Speculate on the fact that there are going to be a limited amount of
// patches per request, so we can allocate the |patches| array on the stack.
- std::array<TraceBuffez::Patch, 1024> patches; // Uninitialized.
+ std::array<TraceBuffer::Patch, 1024> patches; // Uninitialized.
if (chunk.patches().size() > patches.size()) {
PERFETTO_DLOG("Too many patches (%zu) batched in the same request",
patches.size());
@@ -849,7 +866,7 @@
return last_producer_id_;
}
-TraceBuffez* ServiceImpl::GetBufferByID(BufferID buffer_id) {
+TraceBuffer* ServiceImpl::GetBufferByID(BufferID buffer_id) {
auto buf_iter = buffers_.find(buffer_id);
if (buf_iter == buffers_.end())
return nullptr;
@@ -885,34 +902,35 @@
if (now < tracing_session->last_clock_snapshot + kClockSnapshotInterval)
return;
tracing_session->last_clock_snapshot = now;
+
+ protos::TracePacket packet;
+ protos::ClockSnapshot* clock_snapshot = packet.mutable_clock_snapshot();
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
struct {
clockid_t id;
protos::ClockSnapshot::Clock::Type type;
struct timespec ts;
} clocks[] = {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
- {CLOCK_UPTIME_RAW, protos::ClockSnapshot::Clock::BOOTTIME, {0, 0}},
-#else
- {CLOCK_BOOTTIME, protos::ClockSnapshot::Clock::BOOTTIME, {0, 0}},
- {CLOCK_REALTIME_COARSE,
- protos::ClockSnapshot::Clock::REALTIME_COARSE,
- {0, 0}},
- {CLOCK_MONOTONIC_COARSE,
- protos::ClockSnapshot::Clock::MONOTONIC_COARSE,
- {0, 0}},
-#endif
- {CLOCK_REALTIME, protos::ClockSnapshot::Clock::REALTIME, {0, 0}},
- {CLOCK_MONOTONIC, protos::ClockSnapshot::Clock::MONOTONIC, {0, 0}},
- {CLOCK_MONOTONIC_RAW, protos::ClockSnapshot::Clock::MONOTONIC_RAW, {0, 0}},
- {CLOCK_PROCESS_CPUTIME_ID,
- protos::ClockSnapshot::Clock::PROCESS_CPUTIME,
- {0, 0}},
- {CLOCK_THREAD_CPUTIME_ID,
- protos::ClockSnapshot::Clock::THREAD_CPUTIME,
- {0, 0}},
+ {CLOCK_BOOTTIME, protos::ClockSnapshot::Clock::BOOTTIME, {0, 0}},
+ {CLOCK_REALTIME_COARSE,
+ protos::ClockSnapshot::Clock::REALTIME_COARSE,
+ {0, 0}},
+ {CLOCK_MONOTONIC_COARSE,
+ protos::ClockSnapshot::Clock::MONOTONIC_COARSE,
+ {0, 0}},
+ {CLOCK_REALTIME, protos::ClockSnapshot::Clock::REALTIME, {0, 0}},
+ {CLOCK_MONOTONIC, protos::ClockSnapshot::Clock::MONOTONIC, {0, 0}},
+ {CLOCK_MONOTONIC_RAW,
+ protos::ClockSnapshot::Clock::MONOTONIC_RAW,
+ {0, 0}},
+ {CLOCK_PROCESS_CPUTIME_ID,
+ protos::ClockSnapshot::Clock::PROCESS_CPUTIME,
+ {0, 0}},
+ {CLOCK_THREAD_CPUTIME_ID,
+ protos::ClockSnapshot::Clock::THREAD_CPUTIME,
+ {0, 0}},
};
- protos::TracePacket packet;
- protos::ClockSnapshot* clock_snapshot = packet.mutable_clock_snapshot();
// First snapshot all the clocks as atomically as we can.
for (auto& clock : clocks) {
if (clock_gettime(clock.id, &clock.ts) == -1)
@@ -923,6 +941,12 @@
c->set_type(clock.type);
c->set_timestamp(base::FromPosixTimespec(clock.ts).count());
}
+#else // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+ protos::ClockSnapshot::Clock* c = clock_snapshot->add_clocks();
+ c->set_type(protos::ClockSnapshot::Clock::MONOTONIC);
+ c->set_timestamp(base::GetWallTimeNs().count());
+#endif // !PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+
packet.set_trusted_uid(getuid());
Slice slice = Slice::Allocate(packet.ByteSize());
PERFETTO_CHECK(packet.SerializeWithCachedSizesToArray(slice.own_data()));
@@ -1040,24 +1064,20 @@
}
void ServiceImpl::ProducerEndpointImpl::RegisterDataSource(
- const DataSourceDescriptor& desc,
- RegisterDataSourceCallback callback) {
+ const DataSourceDescriptor& desc) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- DataSourceID ds_id = ++last_data_source_id_;
- if (!desc.name().empty()) {
- service_->RegisterDataSource(id_, ds_id, desc);
- } else {
+ if (desc.name().empty()) {
PERFETTO_DLOG("Received RegisterDataSource() with empty name");
- ds_id = 0;
+ return;
}
- task_runner_->PostTask(std::bind(std::move(callback), ds_id));
+
+ service_->RegisterDataSource(id_, desc);
}
void ServiceImpl::ProducerEndpointImpl::UnregisterDataSource(
- DataSourceID ds_id) {
+ const std::string& name) {
PERFETTO_DCHECK_THREAD(thread_checker_);
- PERFETTO_CHECK(ds_id);
- service_->UnregisterDataSource(id_, ds_id);
+ service_->UnregisterDataSource(id_, name);
}
void ServiceImpl::ProducerEndpointImpl::CommitData(
diff --git a/src/tracing/core/service_impl.h b/src/tracing/core/service_impl.h
index 4f7428c..baf9f73 100644
--- a/src/tracing/core/service_impl.h
+++ b/src/tracing/core/service_impl.h
@@ -46,7 +46,7 @@
class Producer;
class SharedMemory;
class SharedMemoryArbiterImpl;
-class TraceBuffez;
+class TraceBuffer;
class TraceConfig;
class TracePacket;
@@ -65,9 +65,8 @@
~ProducerEndpointImpl() override;
// Service::ProducerEndpoint implementation.
- void RegisterDataSource(const DataSourceDescriptor&,
- RegisterDataSourceCallback) override;
- void UnregisterDataSource(DataSourceID) override;
+ void RegisterDataSource(const DataSourceDescriptor&) override;
+ void UnregisterDataSource(const std::string& name) override;
void CommitData(const CommitDataRequest&, CommitDataCallback) override;
void SetSharedMemory(std::unique_ptr<SharedMemory>);
@@ -90,7 +89,6 @@
size_t shared_buffer_page_size_kb_ = 0;
SharedMemoryABI shmem_abi_;
size_t shared_memory_size_hint_bytes_ = 0;
- DataSourceID last_data_source_id_ = 0;
const std::string name_;
// This is used only in in-process configurations (mostly tests).
@@ -134,10 +132,8 @@
// Called by ProducerEndpointImpl.
void DisconnectProducer(ProducerID);
- void RegisterDataSource(ProducerID,
- DataSourceID,
- const DataSourceDescriptor&);
- void UnregisterDataSource(ProducerID, DataSourceID);
+ void RegisterDataSource(ProducerID, const DataSourceDescriptor&);
+ void UnregisterDataSource(ProducerID, const std::string& name);
void CopyProducerPageIntoLogBuffer(ProducerID,
uid_t,
WriterID,
@@ -178,14 +174,13 @@
struct RegisteredDataSource {
ProducerID producer_id;
- DataSourceID data_source_id;
DataSourceDescriptor descriptor;
};
// Represents an active data source for a tracing session.
struct DataSourceInstance {
DataSourceInstanceID instance_id;
- DataSourceID data_source_id;
+ std::string data_source_name;
};
// Holds the state of a tracing session. A tracing session is uniquely bound
@@ -195,10 +190,10 @@
size_t num_buffers() const { return buffers_index.size(); }
- int next_write_period_ms() const {
- PERFETTO_DCHECK(write_period_ms);
- // TODO(primiano): this will drift. Synchronize % period so it aligns.
- return write_period_ms;
+ int delay_to_next_write_period_ms() const {
+ PERFETTO_DCHECK(write_period_ms > 0);
+ return write_period_ms -
+ (base::GetWallTimeMs().count() % write_period_ms);
}
// The consumer that started the session.
@@ -257,7 +252,7 @@
void MaybeSnapshotClocks(TracingSession*, std::vector<TracePacket>*);
void MaybeEmitTraceConfig(TracingSession*, std::vector<TracePacket>*);
- TraceBuffez* GetBufferByID(BufferID);
+ TraceBuffer* GetBufferByID(BufferID);
base::TaskRunner* const task_runner_;
std::unique_ptr<SharedMemory::Factory> shm_factory_;
@@ -278,7 +273,7 @@
std::set<ConsumerEndpointImpl*> consumers_;
std::map<TracingSessionID, TracingSession> tracing_sessions_;
- std::map<BufferID, std::unique_ptr<TraceBuffez>> buffers_;
+ std::map<BufferID, std::unique_ptr<TraceBuffer>> buffers_;
bool lockdown_mode_ = false;
diff --git a/src/tracing/core/service_impl_unittest.cc b/src/tracing/core/service_impl_unittest.cc
index a10dea9..77256ac 100644
--- a/src/tracing/core/service_impl_unittest.cc
+++ b/src/tracing/core/service_impl_unittest.cc
@@ -110,23 +110,16 @@
DataSourceDescriptor ds_desc1;
ds_desc1.set_name("foo");
- producer_endpoint_1->RegisterDataSource(
- ds_desc1, [this, &producer_endpoint_1](DataSourceID id) {
- EXPECT_EQ(1u, id);
- task_runner.PostTask(
- std::bind(&Service::ProducerEndpoint::UnregisterDataSource,
- producer_endpoint_1.get(), id));
- });
+ producer_endpoint_1->RegisterDataSource(ds_desc1);
DataSourceDescriptor ds_desc2;
ds_desc2.set_name("bar");
- producer_endpoint_2->RegisterDataSource(
- ds_desc2, [this, &producer_endpoint_2](DataSourceID id) {
- EXPECT_EQ(1u, id);
- task_runner.PostTask(
- std::bind(&Service::ProducerEndpoint::UnregisterDataSource,
- producer_endpoint_2.get(), id));
- });
+ producer_endpoint_2->RegisterDataSource(ds_desc2);
+
+ task_runner.RunUntilIdle();
+
+ producer_endpoint_1->UnregisterDataSource("foo");
+ producer_endpoint_2->UnregisterDataSource("bar");
task_runner.RunUntilIdle();
@@ -161,7 +154,7 @@
DataSourceDescriptor ds_desc;
ds_desc.set_name("foo");
- producer_endpoint->RegisterDataSource(ds_desc, [](DataSourceID) {});
+ producer_endpoint->RegisterDataSource(ds_desc);
task_runner.RunUntilIdle();
@@ -247,7 +240,7 @@
DataSourceDescriptor ds_desc;
ds_desc.set_name("foo");
- producer_endpoint->RegisterDataSource(ds_desc, [](DataSourceID) {});
+ producer_endpoint->RegisterDataSource(ds_desc);
task_runner.RunUntilIdle();
// Disconnecting the consumer while tracing should trigger data source
@@ -287,7 +280,7 @@
DataSourceDescriptor ds_desc;
ds_desc.set_name("foo");
- producer_endpoint->RegisterDataSource(ds_desc, [](DataSourceID) {});
+ producer_endpoint->RegisterDataSource(ds_desc);
task_runner.RunUntilIdle();
// Disconnecting the producer while tracing should trigger data source
@@ -312,7 +305,7 @@
task_runner.RunUntilIdle();
EXPECT_CALL(mock_producer, CreateDataSourceInstance(_, _));
EXPECT_CALL(mock_producer, TearDownDataSourceInstance(_));
- producer_endpoint->RegisterDataSource(ds_desc, [](DataSourceID) {});
+ producer_endpoint->RegisterDataSource(ds_desc);
task_runner.RunUntilIdle();
EXPECT_CALL(mock_consumer, OnDisconnect());
@@ -403,7 +396,7 @@
DataSourceDescriptor ds_desc;
ds_desc.set_name("datasource");
- producer_endpoint->RegisterDataSource(ds_desc, [](DataSourceID) {});
+ producer_endpoint->RegisterDataSource(ds_desc);
task_runner.RunUntilIdle();
static const char kPayload[] = "1234567890abcdef-";
diff --git a/src/tracing/core/shared_memory_abi.cc b/src/tracing/core/shared_memory_abi.cc
index 70021a8..9d2964a 100644
--- a/src/tracing/core/shared_memory_abi.cc
+++ b/src/tracing/core/shared_memory_abi.cc
@@ -23,6 +23,17 @@
namespace perfetto {
namespace {
+
+constexpr int kRetryAttempts = 64;
+
+inline void WaitBeforeNextAttempt(int attempt) {
+ if (attempt < kRetryAttempts / 2) {
+ std::this_thread::yield();
+ } else {
+ usleep((attempt / 10) * 1000);
+ }
+}
+
// Returns the largest 4-bytes aligned chunk size <= |page_size| / |divider|
// for each divider in PageLayout.
constexpr size_t GetChunkSize(size_t page_size, size_t divider) {
@@ -51,6 +62,7 @@
constexpr size_t SharedMemoryABI::kNumChunksForLayout[];
constexpr const char* SharedMemoryABI::kChunkStateStr[];
constexpr const size_t SharedMemoryABI::kInvalidPageIdx;
+constexpr const size_t SharedMemoryABI::kMaxPageSize;
SharedMemoryABI::SharedMemoryABI() = default;
@@ -109,9 +121,10 @@
chunk_header.writer_id = -1;
PERFETTO_CHECK(kMaxWriterID <= chunk_header.writer_id);
- PERFETTO_CHECK(page_size >= 4096);
- PERFETTO_CHECK(page_size % 4096 == 0);
- PERFETTO_CHECK(reinterpret_cast<uintptr_t>(start) % 4096 == 0);
+ PERFETTO_CHECK(page_size >= base::kPageSize);
+ PERFETTO_CHECK(page_size <= kMaxPageSize);
+ PERFETTO_CHECK(page_size % base::kPageSize == 0);
+ PERFETTO_CHECK(reinterpret_cast<uintptr_t>(start) % base::kPageSize == 0);
PERFETTO_CHECK(size % page_size == 0);
}
@@ -138,45 +151,44 @@
PERFETTO_DCHECK(desired_chunk_state == kChunkBeingRead ||
desired_chunk_state == kChunkBeingWritten);
PageHeader* phdr = page_header(page_idx);
- uint32_t layout = phdr->layout.load(std::memory_order_acquire);
- const size_t num_chunks = GetNumChunksForLayout(layout);
+ for (int attempt = 0; attempt < kRetryAttempts; attempt++) {
+ uint32_t layout = phdr->layout.load(std::memory_order_acquire);
+ const size_t num_chunks = GetNumChunksForLayout(layout);
- // The page layout has changed (or the page is free).
- if (chunk_idx >= num_chunks)
- return Chunk();
+ // The page layout has changed (or the page is free).
+ if (chunk_idx >= num_chunks)
+ return Chunk();
- // Verify that the chunk is still in a state that allows the transition to
- // |desired_chunk_state|. The only allowed transitions are:
- // 1. kChunkFree -> kChunkBeingWritten (Producer).
- // 2. kChunkComplete -> kChunkBeingRead (Service).
- ChunkState expected_chunk_state =
- desired_chunk_state == kChunkBeingWritten ? kChunkFree : kChunkComplete;
- auto cur_chunk_state = (layout >> (chunk_idx * kChunkShift)) & kChunkMask;
- if (cur_chunk_state != expected_chunk_state)
- return Chunk();
+ // Verify that the chunk is still in a state that allows the transition to
+ // |desired_chunk_state|. The only allowed transitions are:
+ // 1. kChunkFree -> kChunkBeingWritten (Producer).
+ // 2. kChunkComplete -> kChunkBeingRead (Service).
+ ChunkState expected_chunk_state =
+ desired_chunk_state == kChunkBeingWritten ? kChunkFree : kChunkComplete;
+ auto cur_chunk_state = (layout >> (chunk_idx * kChunkShift)) & kChunkMask;
+ if (cur_chunk_state != expected_chunk_state)
+ return Chunk();
- uint32_t next_layout = layout;
- next_layout &= ~(kChunkMask << (chunk_idx * kChunkShift));
- next_layout |= (desired_chunk_state << (chunk_idx * kChunkShift));
- if (!phdr->layout.compare_exchange_strong(layout, next_layout,
- std::memory_order_acq_rel)) {
- // TODO(fmayer): returning here is too pessimistic. We should look at the
- // returned |layout| to figure out if some other writer thread took the same
- // chunk (in which case we should immediately return false) or if they took
- // another chunk in the same page (in which case we should just retry).
- return Chunk();
+ uint32_t next_layout = layout;
+ next_layout &= ~(kChunkMask << (chunk_idx * kChunkShift));
+ next_layout |= (desired_chunk_state << (chunk_idx * kChunkShift));
+ if (phdr->layout.compare_exchange_strong(layout, next_layout,
+ std::memory_order_acq_rel)) {
+ // Compute the chunk virtual address and write it into |chunk|.
+ Chunk chunk = GetChunkUnchecked(page_idx, layout, chunk_idx);
+ if (desired_chunk_state == kChunkBeingWritten) {
+ PERFETTO_DCHECK(header);
+ ChunkHeader* new_header = chunk.header();
+ new_header->packets.store(header->packets, std::memory_order_relaxed);
+ new_header->writer_id.store(header->writer_id,
+ std::memory_order_relaxed);
+ new_header->chunk_id.store(header->chunk_id, std::memory_order_release);
+ }
+ return chunk;
+ }
+ WaitBeforeNextAttempt(attempt);
}
-
- // Compute the chunk virtual address and write it into |chunk|.
- Chunk chunk = GetChunkUnchecked(page_idx, layout, chunk_idx);
- if (desired_chunk_state == kChunkBeingWritten) {
- PERFETTO_DCHECK(header);
- ChunkHeader* new_header = chunk.header();
- new_header->packets.store(header->packets, std::memory_order_relaxed);
- new_header->writer_id.store(header->writer_id, std::memory_order_relaxed);
- new_header->chunk_id.store(header->chunk_id, std::memory_order_release);
- }
- return chunk;
+ return Chunk(); // All our attempts failed.
}
bool SharedMemoryABI::TryPartitionPage(size_t page_idx, PageLayout layout) {
@@ -212,7 +224,7 @@
size_t chunk_idx;
std::tie(page_idx, chunk_idx) = GetPageAndChunkIndex(chunk);
- for (int attempt = 0; attempt < 64; attempt++) {
+ for (int attempt = 0; attempt < kRetryAttempts; attempt++) {
PageHeader* phdr = page_header(page_idx);
uint32_t layout = phdr->layout.load(std::memory_order_relaxed);
const size_t page_chunk_size = GetChunkSizeForLayout(layout);
@@ -250,11 +262,7 @@
std::memory_order_acq_rel)) {
return page_idx;
}
- if (attempt < 32) {
- std::this_thread::yield();
- } else {
- usleep((attempt / 10) * 1000);
- }
+ WaitBeforeNextAttempt(attempt);
}
// Too much contention on this page. Give up. This page will be left pending
// forever but there isn't much more we can do at this point.
diff --git a/src/tracing/core/shared_memory_arbiter_impl.cc b/src/tracing/core/shared_memory_arbiter_impl.cc
index c1b7e23..b6c6fd9 100644
--- a/src/tracing/core/shared_memory_arbiter_impl.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl.cc
@@ -20,6 +20,7 @@
#include "perfetto/base/task_runner.h"
#include "perfetto/tracing/core/commit_data_request.h"
#include "perfetto/tracing/core/shared_memory.h"
+#include "src/tracing/core/null_trace_writer.h"
#include "src/tracing/core/trace_writer_impl.h"
#include <limits>
@@ -214,7 +215,6 @@
PERFETTO_DCHECK_THREAD(thread_checker_);
std::unique_ptr<CommitDataRequest> req;
- std::vector<uint32_t> pages_to_notify;
{
std::lock_guard<std::mutex> scoped_lock(lock_);
req = std::move(commit_data_req_);
@@ -240,8 +240,10 @@
std::lock_guard<std::mutex> scoped_lock(lock_);
id = active_writer_ids_.Allocate();
}
+ if (!id)
+ return std::unique_ptr<TraceWriter>(new NullTraceWriter());
return std::unique_ptr<TraceWriter>(
- id ? new TraceWriterImpl(this, id, target_buffer) : nullptr);
+ new TraceWriterImpl(this, id, target_buffer));
}
void SharedMemoryArbiterImpl::ReleaseWriterID(WriterID id) {
diff --git a/src/tracing/core/shared_memory_arbiter_impl_unittest.cc b/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
index 8505876..ed96226 100644
--- a/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
+++ b/src/tracing/core/shared_memory_arbiter_impl_unittest.cc
@@ -35,9 +35,8 @@
class MockProducerEndpoint : public Service::ProducerEndpoint {
public:
- void RegisterDataSource(const DataSourceDescriptor&,
- RegisterDataSourceCallback) override {}
- void UnregisterDataSource(DataSourceID) override {}
+ void RegisterDataSource(const DataSourceDescriptor&) override {}
+ void UnregisterDataSource(const std::string&) override {}
SharedMemory* shared_memory() const override { return nullptr; }
size_t shared_buffer_page_size_kb() const override { return 0; }
std::unique_ptr<TraceWriter> CreateTraceWriter(BufferID) override {
@@ -137,8 +136,9 @@
ASSERT_TRUE(writers.emplace(writer_id, std::move(writer)).second);
}
- // A further call should fail as we exhausted writer IDs.
- ASSERT_EQ(nullptr, arbiter_->CreateTraceWriter(0).get());
+ // A further call should return a null impl of trace writer as we exhausted
+ // writer IDs.
+ ASSERT_EQ(arbiter_->CreateTraceWriter(0)->writer_id(), 0);
}
// TODO(primiano): add multi-threaded tests.
diff --git a/src/tracing/core/test_config.cc b/src/tracing/core/test_config.cc
index e352ec3..d58cbce 100644
--- a/src/tracing/core/test_config.cc
+++ b/src/tracing/core/test_config.cc
@@ -43,6 +43,12 @@
"size mismatch");
message_count_ = static_cast<decltype(message_count_)>(proto.message_count());
+ static_assert(sizeof(max_messages_per_second_) ==
+ sizeof(proto.max_messages_per_second()),
+ "size mismatch");
+ max_messages_per_second_ = static_cast<decltype(max_messages_per_second_)>(
+ proto.max_messages_per_second());
+
static_assert(sizeof(seed_) == sizeof(proto.seed()), "size mismatch");
seed_ = static_cast<decltype(seed_)>(proto.seed());
@@ -60,6 +66,13 @@
proto->set_message_count(
static_cast<decltype(proto->message_count())>(message_count_));
+ static_assert(sizeof(max_messages_per_second_) ==
+ sizeof(proto->max_messages_per_second()),
+ "size mismatch");
+ proto->set_max_messages_per_second(
+ static_cast<decltype(proto->max_messages_per_second())>(
+ max_messages_per_second_));
+
static_assert(sizeof(seed_) == sizeof(proto->seed()), "size mismatch");
proto->set_seed(static_cast<decltype(proto->seed())>(seed_));
diff --git a/src/tracing/core/trace_buffer.cc b/src/tracing/core/trace_buffer.cc
index 1a7a554..fb5b7b3 100644
--- a/src/tracing/core/trace_buffer.cc
+++ b/src/tracing/core/trace_buffer.cc
@@ -59,27 +59,27 @@
SharedMemoryABI::ChunkHeader::kChunkNeedsPatching;
} // namespace.
-constexpr size_t TraceBuffez::ChunkRecord::kMaxSize;
-constexpr size_t TraceBuffez::InlineChunkHeaderSize = sizeof(ChunkRecord);
+constexpr size_t TraceBuffer::ChunkRecord::kMaxSize;
+constexpr size_t TraceBuffer::InlineChunkHeaderSize = sizeof(ChunkRecord);
// static
-std::unique_ptr<TraceBuffez> TraceBuffez::Create(size_t size_in_bytes) {
- std::unique_ptr<TraceBuffez> trace_buffer(new TraceBuffez());
+std::unique_ptr<TraceBuffer> TraceBuffer::Create(size_t size_in_bytes) {
+ std::unique_ptr<TraceBuffer> trace_buffer(new TraceBuffer());
if (!trace_buffer->Initialize(size_in_bytes))
return nullptr;
return trace_buffer;
}
-TraceBuffez::TraceBuffez() {
+TraceBuffer::TraceBuffer() {
// See comments in ChunkRecord for the rationale of this.
static_assert(sizeof(ChunkRecord) == sizeof(SharedMemoryABI::PageHeader) +
sizeof(SharedMemoryABI::ChunkHeader),
"ChunkRecord out of sync with the layout of SharedMemoryABI");
}
-TraceBuffez::~TraceBuffez() = default;
+TraceBuffer::~TraceBuffer() = default;
-bool TraceBuffez::Initialize(size_t size) {
+bool TraceBuffer::Initialize(size_t size) {
static_assert(
base::kPageSize % sizeof(ChunkRecord) == 0,
"sizeof(ChunkRecord) must be an integer divider of a page size");
@@ -101,7 +101,7 @@
// Note: |src| points to a shmem region that is shared with the producer. Assume
// that the producer is malicious and will change the content of |src|
// while we execute here. Don't do any processing on it other than memcpy().
-void TraceBuffez::CopyChunkUntrusted(ProducerID producer_id_trusted,
+void TraceBuffer::CopyChunkUntrusted(ProducerID producer_id_trusted,
uid_t producer_uid_trusted,
WriterID writer_id,
ChunkID chunk_id,
@@ -195,7 +195,7 @@
AddPaddingRecord(padding_size);
}
-size_t TraceBuffez::DeleteNextChunksFor(size_t bytes_to_clear) {
+size_t TraceBuffer::DeleteNextChunksFor(size_t bytes_to_clear) {
// Find the position of the first chunk which begins at or after
// (|wptr_| + |bytes|). Note that such a chunk might not exist and we might
// either reach the end of the buffer or a zeroed region of the buffer.
@@ -247,7 +247,7 @@
return next_chunk_ptr - search_end;
}
-void TraceBuffez::AddPaddingRecord(size_t size) {
+void TraceBuffer::AddPaddingRecord(size_t size) {
PERFETTO_DCHECK(size >= sizeof(ChunkRecord) && size <= ChunkRecord::kMaxSize);
ChunkRecord record(size);
record.is_padding = 1;
@@ -257,7 +257,7 @@
// |wptr_| is deliberately not advanced when writing a padding record.
}
-bool TraceBuffez::TryPatchChunkContents(ProducerID producer_id,
+bool TraceBuffer::TryPatchChunkContents(ProducerID producer_id,
WriterID writer_id,
ChunkID chunk_id,
const Patch* patches,
@@ -320,14 +320,14 @@
return true;
}
-void TraceBuffez::BeginRead() {
+void TraceBuffer::BeginRead() {
read_iter_ = GetReadIterForSequence(index_.begin());
#if PERFETTO_DCHECK_IS_ON()
changed_since_last_read_ = false;
#endif
}
-TraceBuffez::SequenceIterator TraceBuffez::GetReadIterForSequence(
+TraceBuffer::SequenceIterator TraceBuffer::GetReadIterForSequence(
ChunkMap::iterator seq_begin) {
SequenceIterator iter;
iter.seq_begin = seq_begin;
@@ -369,7 +369,7 @@
return iter;
}
-void TraceBuffez::SequenceIterator::MoveNext() {
+void TraceBuffer::SequenceIterator::MoveNext() {
// Note: |seq_begin| might be == |seq_end|.
if (cur == seq_end || cur->first.chunk_id == wrapping_id) {
cur = seq_end;
@@ -379,7 +379,7 @@
cur = seq_begin;
}
-bool TraceBuffez::ReadNextTracePacket(TracePacket* packet,
+bool TraceBuffer::ReadNextTracePacket(TracePacket* packet,
uid_t* producer_uid) {
// Note: MoveNext() moves only within the next chunk within the same
// {ProducerID, WriterID} sequence. Here we want to:
@@ -523,7 +523,7 @@
} // for(;;MoveNext()) [iterate over chunks].
}
-TraceBuffez::ReadAheadResult TraceBuffez::ReadAhead(TracePacket* packet) {
+TraceBuffer::ReadAheadResult TraceBuffer::ReadAhead(TracePacket* packet) {
static_assert(static_cast<ChunkID>(kMaxChunkID + 1) == 0,
"relying on kMaxChunkID to wrap naturally");
TRACE_BUFFER_DLOG(" readahead start @ chunk %u", read_iter_.chunk_id());
@@ -600,7 +600,7 @@
return ReadAheadResult::kFailedMoveToNextSequence;
}
-bool TraceBuffez::ReadNextPacketInChunk(ChunkMeta* chunk_meta,
+bool TraceBuffer::ReadNextPacketInChunk(ChunkMeta* chunk_meta,
TracePacket* packet) {
PERFETTO_DCHECK(chunk_meta->num_fragments_read < chunk_meta->num_fragments);
PERFETTO_DCHECK(!(chunk_meta->flags & kChunkNeedsPatching));
diff --git a/src/tracing/core/trace_buffer.h b/src/tracing/core/trace_buffer.h
index 2aea918..a66a4db 100644
--- a/src/tracing/core/trace_buffer.h
+++ b/src/tracing/core/trace_buffer.h
@@ -123,10 +123,7 @@
// Reads guarantee that packets for the same sequence are read in FIFO order
// (according to their ChunkID), but don't give any guarantee about the read
// order of packets from different sequences (see ReadPacket() comments below).
-//
-// TODO(primiano): the name of this class is deliberately typo-ed as a temporary
-// situation until we replace TraceBuffer within service_impl.cc.
-class TraceBuffez {
+class TraceBuffer {
public:
static const size_t InlineChunkHeaderSize; // For test/fake_packet.{cc,h}.
@@ -151,9 +148,9 @@
};
// Can return nullptr if the memory allocation fails.
- static std::unique_ptr<TraceBuffez> Create(size_t size_in_bytes);
+ static std::unique_ptr<TraceBuffer> Create(size_t size_in_bytes);
- ~TraceBuffez();
+ ~TraceBuffer();
// Copies a Chunk from a producer Shared Memory Buffer into the trace buffer.
// |src| points to the first packet in the SharedMemoryABI's chunk shared
@@ -399,9 +396,9 @@
kFailedStayOnSameSequence,
};
- TraceBuffez();
- TraceBuffez(const TraceBuffez&) = delete;
- TraceBuffez& operator=(const TraceBuffez&) = delete;
+ TraceBuffer();
+ TraceBuffer(const TraceBuffer&) = delete;
+ TraceBuffer& operator=(const TraceBuffer&) = delete;
bool Initialize(size_t size);
diff --git a/src/tracing/core/trace_buffer_unittest.cc b/src/tracing/core/trace_buffer_unittest.cc
index c12c8e3..3031b3b 100644
--- a/src/tracing/core/trace_buffer_unittest.cc
+++ b/src/tracing/core/trace_buffer_unittest.cc
@@ -39,9 +39,9 @@
class TraceBufferTest : public testing::Test {
public:
- using SequenceIterator = TraceBuffez::SequenceIterator;
- using ChunkMetaKey = TraceBuffez::ChunkMeta::Key;
- using ChunkRecord = TraceBuffez::ChunkRecord;
+ using SequenceIterator = TraceBuffer::SequenceIterator;
+ using ChunkMetaKey = TraceBuffer::ChunkMeta::Key;
+ using ChunkRecord = TraceBuffer::ChunkRecord;
static constexpr uint8_t kContFromPrevChunk =
SharedMemoryABI::ChunkHeader::kFirstPacketContinuesFromPrevChunk;
@@ -55,14 +55,14 @@
}
void ResetBuffer(size_t size_) {
- trace_buffer_ = TraceBuffez::Create(size_);
+ trace_buffer_ = TraceBuffer::Create(size_);
ASSERT_TRUE(trace_buffer_);
}
bool TryPatchChunkContents(ProducerID p,
WriterID w,
ChunkID c,
- std::vector<TraceBuffez::Patch> patches,
+ std::vector<TraceBuffer::Patch> patches,
bool other_patches_pending = false) {
return trace_buffer_->TryPatchChunkContents(
p, w, c, patches.data(), patches.size(), other_patches_pending);
@@ -109,7 +109,7 @@
}
SequenceIterator GetReadIterForSequence(ProducerID p, WriterID w) {
- TraceBuffez::ChunkMeta::Key key(p, w, 0);
+ TraceBuffer::ChunkMeta::Key key(p, w, 0);
return trace_buffer_->GetReadIterForSequence(
trace_buffer_->index_.lower_bound(key));
}
@@ -126,11 +126,11 @@
return keys;
}
- TraceBuffez* trace_buffer() { return trace_buffer_.get(); }
+ TraceBuffer* trace_buffer() { return trace_buffer_.get(); }
size_t size_to_end() { return trace_buffer_->size_to_end(); }
private:
- std::unique_ptr<TraceBuffez> trace_buffer_;
+ std::unique_ptr<TraceBuffer> trace_buffer_;
};
// ----------------------
diff --git a/src/tracing/core/trace_config.cc b/src/tracing/core/trace_config.cc
index 68d371b..f3bfca5 100644
--- a/src/tracing/core/trace_config.cc
+++ b/src/tracing/core/trace_config.cc
@@ -220,7 +220,8 @@
config_.ToProto(proto->mutable_config());
for (const auto& it : producer_name_filter_) {
- proto->add_producer_name_filter(it);
+ proto->add_producer_name_filter(
+ static_cast<decltype(proto->producer_name_filter(0))>(it));
static_assert(sizeof(it) == sizeof(proto->producer_name_filter(0)),
"size mismatch");
}
diff --git a/src/tracing/core/trace_packet.cc b/src/tracing/core/trace_packet.cc
index 9ebcc47..5e72695 100644
--- a/src/tracing/core/trace_packet.cc
+++ b/src/tracing/core/trace_packet.cc
@@ -28,8 +28,20 @@
TracePacket::TracePacket() = default;
TracePacket::~TracePacket() = default;
-TracePacket::TracePacket(TracePacket&&) noexcept = default;
-TracePacket& TracePacket::operator=(TracePacket&&) = default;
+TracePacket::TracePacket(TracePacket&& other) noexcept {
+ *this = std::move(other);
+}
+
+TracePacket& TracePacket::operator=(TracePacket&& other) {
+ slices_ = std::move(other.slices_);
+ other.slices_.clear();
+
+ size_ = other.size_;
+ other.size_ = 0;
+
+ decoded_packet_ = std::move(other.decoded_packet_);
+ return *this;
+}
bool TracePacket::Decode() {
if (decoded_packet_)
diff --git a/src/tracing/core/trace_packet_unittest.cc b/src/tracing/core/trace_packet_unittest.cc
index ef5c41b..9e3e4ed 100644
--- a/src/tracing/core/trace_packet_unittest.cc
+++ b/src/tracing/core/trace_packet_unittest.cc
@@ -43,16 +43,6 @@
ASSERT_NE(nullptr, tp.operator->());
ASSERT_EQ(proto.for_testing().str(), tp->for_testing().str());
ASSERT_EQ(proto.for_testing().str(), (*tp).for_testing().str());
-
- // Check move operators.
- TracePacket moved_tp(std::move(tp));
- ASSERT_NE(nullptr, moved_tp.operator->());
- ASSERT_EQ(proto.for_testing().str(), moved_tp->for_testing().str());
-
- TracePacket moved_tp_2;
- moved_tp_2 = std::move(moved_tp);
- ASSERT_NE(nullptr, moved_tp_2.operator->());
- ASSERT_EQ(proto.for_testing().str(), moved_tp_2->for_testing().str());
}
TEST(TracePacketTest, Sliced) {
@@ -131,5 +121,29 @@
ASSERT_EQ(payload, trace.packet(0).for_testing().str());
}
+TEST(TracePacketTest, MoveOperators) {
+ char buf1[5]{};
+ char buf2[7]{};
+
+ TracePacket tp;
+ tp.AddSlice(buf1, sizeof(buf1));
+ tp.AddSlice(buf2, sizeof(buf2));
+ tp.AddSlice(Slice::Allocate(11));
+ tp.AddSlice(Slice(std::unique_ptr<std::string>(new std::string("foobar"))));
+
+ TracePacket moved_tp(std::move(tp));
+ ASSERT_EQ(0u, tp.size());
+ ASSERT_TRUE(tp.slices().empty());
+ ASSERT_EQ(4u, moved_tp.slices().size());
+ ASSERT_EQ(5u + 7u + 11u + 6u, moved_tp.size());
+
+ TracePacket moved_tp_2;
+ moved_tp_2 = std::move(moved_tp);
+ ASSERT_EQ(0u, moved_tp.size());
+ ASSERT_TRUE(moved_tp.slices().empty());
+ ASSERT_EQ(4u, moved_tp_2.slices().size());
+ ASSERT_EQ(5u + 7u + 11u + 6u, moved_tp_2.size());
+}
+
} // namespace
} // namespace perfetto
diff --git a/src/tracing/core/trace_writer_impl.cc b/src/tracing/core/trace_writer_impl.cc
index ded5909..bfdf1f4 100644
--- a/src/tracing/core/trace_writer_impl.cc
+++ b/src/tracing/core/trace_writer_impl.cc
@@ -197,7 +197,7 @@
WriterID TraceWriterImpl::writer_id() const {
return id_;
-};
+}
// Base class ctor/dtor definition.
TraceWriter::TraceWriter() = default;
diff --git a/src/tracing/core/trace_writer_impl.h b/src/tracing/core/trace_writer_impl.h
index 28fa95f..3ba878d 100644
--- a/src/tracing/core/trace_writer_impl.h
+++ b/src/tracing/core/trace_writer_impl.h
@@ -36,7 +36,7 @@
TraceWriterImpl(SharedMemoryArbiterImpl*, WriterID, BufferID);
~TraceWriterImpl() override;
- // TraceWriter implementation. See documentation in trace_writer.h .
+ // TraceWriter implementation. See documentation in trace_writer.h.
TracePacketHandle NewTracePacket() override;
void Flush(std::function<void()> callback = {}) override;
WriterID writer_id() const override;
diff --git a/src/tracing/core/trace_writer_impl_unittest.cc b/src/tracing/core/trace_writer_impl_unittest.cc
index 5acf403..ad9156a 100644
--- a/src/tracing/core/trace_writer_impl_unittest.cc
+++ b/src/tracing/core/trace_writer_impl_unittest.cc
@@ -32,9 +32,8 @@
namespace {
class FakeProducerEndpoint : public Service::ProducerEndpoint {
- void RegisterDataSource(const DataSourceDescriptor&,
- RegisterDataSourceCallback) override {}
- void UnregisterDataSource(DataSourceID) override {}
+ void RegisterDataSource(const DataSourceDescriptor&) override {}
+ void UnregisterDataSource(const std::string&) override {}
void CommitData(const CommitDataRequest&, CommitDataCallback) override {}
SharedMemory* shared_memory() const override { return nullptr; }
size_t shared_buffer_page_size_kb() const override { return 0; }
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
index a0db4e5..c671779 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
@@ -23,7 +23,6 @@
#include "perfetto/ipc/client.h"
#include "perfetto/tracing/core/consumer.h"
#include "perfetto/tracing/core/trace_config.h"
-#include "perfetto/tracing/core/trace_packet.h"
// TODO(fmayer): Add a test to check to what happens when ConsumerIPCClientImpl
// gets destroyed w.r.t. the Consumer pointer. Also think to lifetime of the
@@ -71,8 +70,6 @@
return;
}
- // Serialize the |trace_config| into a EnableTracingRequest protobuf.
- // Keep this in sync with changes in consumer_port.proto.
protos::EnableTracingRequest req;
trace_config.ToProto(req.mutable_trace_config());
ipc::Deferred<protos::EnableTracingResponse> async_response;
@@ -132,16 +129,15 @@
PERFETTO_DLOG("ReadBuffers() failed");
return;
}
- // TODO(primiano): We have to guarantee that the log buffer stays alive at
- // least as long as these requests are on flights.
std::vector<TracePacket> trace_packets;
- trace_packets.reserve(response->trace_packets().size());
- for (const std::string& bytes : response->trace_packets()) {
- trace_packets.emplace_back();
- trace_packets.back().AddSlice(
- Slice(reinterpret_cast<const void*>(bytes.data()), bytes.size()));
+ for (auto& resp_slice : *response->mutable_slices()) {
+ partial_packet_.AddSlice(
+ Slice(std::unique_ptr<std::string>(resp_slice.release_data())));
+ if (resp_slice.last_slice_for_packet())
+ trace_packets.emplace_back(std::move(partial_packet_));
}
- consumer_->OnTraceData(std::move(trace_packets), response.has_more());
+ if (!trace_packets.empty() || !response.has_more())
+ consumer_->OnTraceData(std::move(trace_packets), response.has_more());
}
void ConsumerIPCClientImpl::FreeBuffers() {
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.h b/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
index 57038ce..d94b658 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
@@ -26,6 +26,7 @@
#include "perfetto/ipc/service_proxy.h"
#include "perfetto/tracing/core/basic_types.h"
#include "perfetto/tracing/core/service.h"
+#include "perfetto/tracing/core/trace_packet.h"
#include "perfetto/tracing/ipc/consumer_ipc_client.h"
#include "perfetto/ipc/consumer_port.ipc.h"
@@ -84,6 +85,13 @@
bool connected_ = false;
+ // When a packet is too big to fit into a ReadBuffersResponse IPC, the service
+ // will chunk it into several IPCs, each containing few slices of the packet
+ // (a packet's slice is always guaranteed to be << kIPCBufferSize). When
+ // chunking happens this field accumulates the slices received until the
+ // one with |last_slice_for_packet| == true is received.
+ TracePacket partial_packet_;
+
base::WeakPtrFactory<ConsumerIPCClientImpl> weak_ptr_factory_;
};
diff --git a/src/tracing/ipc/producer/producer_ipc_client_impl.cc b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
index ee4431e..10b36d4 100644
--- a/src/tracing/ipc/producer/producer_ipc_client_impl.cc
+++ b/src/tracing/ipc/producer/producer_ipc_client_impl.cc
@@ -109,7 +109,6 @@
const protos::GetAsyncCommandResponse& cmd) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (cmd.cmd_case() == protos::GetAsyncCommandResponse::kStartDataSource) {
- // Keep this in sync with chages in data_source_config.proto.
const auto& req = cmd.start_data_source();
const DataSourceInstanceID dsid = req.new_instance_id();
DataSourceConfig cfg;
@@ -149,38 +148,24 @@
}
void ProducerIPCClientImpl::RegisterDataSource(
- const DataSourceDescriptor& descriptor,
- RegisterDataSourceCallback callback) {
+ const DataSourceDescriptor& descriptor) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (!connected_) {
PERFETTO_DLOG(
"Cannot RegisterDataSource(), not connected to tracing service");
- return task_runner_->PostTask(std::bind(callback, 0));
}
protos::RegisterDataSourceRequest req;
descriptor.ToProto(req.mutable_data_source_descriptor());
ipc::Deferred<protos::RegisterDataSourceResponse> async_response;
- // TODO(fmayer): add a test that destroys the IPC channel soon after this call
- // and checks that the callback(0) is invoked.
- // TODO(fmayer): add a test that destroys ProducerIPCClientImpl soon after
- // this call and checks that the callback is dropped.
async_response.Bind(
- [callback](
- ipc::AsyncResult<protos::RegisterDataSourceResponse> response) {
- if (!response) {
+ [](ipc::AsyncResult<protos::RegisterDataSourceResponse> response) {
+ if (!response)
PERFETTO_DLOG("RegisterDataSource() failed: connection reset");
- return callback(0);
- }
- if (response->data_source_id() == 0) {
- PERFETTO_DLOG("RegisterDataSource() failed: %s",
- response->error().c_str());
- }
- callback(response->data_source_id());
});
producer_port_.RegisterDataSource(req, std::move(async_response));
}
-void ProducerIPCClientImpl::UnregisterDataSource(DataSourceID id) {
+void ProducerIPCClientImpl::UnregisterDataSource(const std::string& name) {
PERFETTO_DCHECK_THREAD(thread_checker_);
if (!connected_) {
PERFETTO_DLOG(
@@ -188,7 +173,7 @@
return;
}
protos::UnregisterDataSourceRequest req;
- req.set_data_source_id(id);
+ req.set_data_source_name(name);
producer_port_.UnregisterDataSource(
req, ipc::Deferred<protos::UnregisterDataSourceResponse>());
}
diff --git a/src/tracing/ipc/producer/producer_ipc_client_impl.h b/src/tracing/ipc/producer/producer_ipc_client_impl.h
index a088d25..1f4ec68 100644
--- a/src/tracing/ipc/producer/producer_ipc_client_impl.h
+++ b/src/tracing/ipc/producer/producer_ipc_client_impl.h
@@ -60,9 +60,8 @@
// Service::ProducerEndpoint implementation.
// These methods are invoked by the actual Producer(s) code by clients of the
// tracing library, which know nothing about the IPC transport.
- void RegisterDataSource(const DataSourceDescriptor&,
- RegisterDataSourceCallback) override;
- void UnregisterDataSource(DataSourceID) override;
+ void RegisterDataSource(const DataSourceDescriptor&) override;
+ void UnregisterDataSource(const std::string& name) override;
void CommitData(const CommitDataRequest&, CommitDataCallback) override;
std::unique_ptr<TraceWriter> CreateTraceWriter(
BufferID target_buffer) override;
diff --git a/src/tracing/ipc/service/consumer_ipc_service.cc b/src/tracing/ipc/service/consumer_ipc_service.cc
index e84d83b..24643d0 100644
--- a/src/tracing/ipc/service/consumer_ipc_service.cc
+++ b/src/tracing/ipc/service/consumer_ipc_service.cc
@@ -21,8 +21,10 @@
#include "perfetto/base/logging.h"
#include "perfetto/base/scoped_file.h"
#include "perfetto/base/task_runner.h"
+#include "perfetto/ipc/basic_types.h"
#include "perfetto/ipc/host.h"
#include "perfetto/tracing/core/service.h"
+#include "perfetto/tracing/core/shared_memory_abi.h"
#include "perfetto/tracing/core/slice.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
@@ -120,16 +122,49 @@
return;
auto result = ipc::AsyncResult<protos::ReadBuffersResponse>::Create();
- result.set_has_more(has_more);
- // TODO(primiano): Expose the slices to the Consumer rather than stitching
- // them and wasting cpu time to hide this detail.
+
+ // A TracePacket might be too big to fit into a single IPC message (max
+ // kIPCBufferSize). However a TracePacket is made of slices and each slice
+ // is way smaller than kIPCBufferSize (a slice size is effectively bounded by
+ // the max chunk size of the SharedMemoryABI). When sending a TracePacket,
+ // if its slices don't fit within one IPC, chunk them over several contiguous
+ // IPCs using the |last_slice_for_packet| for glueing on the other side.
+ static_assert(ipc::kIPCBufferSize >= SharedMemoryABI::kMaxPageSize * 2,
+ "kIPCBufferSize too small given the max possible slice size");
+
+ auto send_ipc_reply = [this, &result](bool more) {
+ result.set_has_more(more);
+ read_buffers_response.Resolve(std::move(result));
+ result = ipc::AsyncResult<protos::ReadBuffersResponse>::Create();
+ };
+
+ size_t approx_reply_size = 0;
for (const TracePacket& trace_packet : trace_packets) {
- std::string* dst = result->add_trace_packets();
- dst->reserve(trace_packet.size());
- for (const Slice& slice : trace_packet.slices())
- dst->append(reinterpret_cast<const char*>(slice.start), slice.size);
+ size_t num_slices_left_for_packet = trace_packet.slices().size();
+ for (const Slice& slice : trace_packet.slices()) {
+ // Check if this slice would cause the IPC to overflow its max size and,
+ // if that is the case, split the IPCs. The "16" and "64" below are
+ // over-estimations of, respectively:
+ // 16: the preamble that prefixes each slice (there are 2 x size fields
+ // in the proto + the |last_slice_for_packet| bool).
+ // 64: the overhead of the IPC InvokeMethodReply + wire_protocol's frame.
+ // If these estimations are wrong, BufferedFrameDeserializer::Serialize()
+ // will hit a DCHECK anyways.
+ const size_t approx_slice_size = slice.size + 16;
+ if (approx_reply_size + approx_slice_size > ipc::kIPCBufferSize - 64) {
+ // If we hit this CHECK we got a single slice that is > kIPCBufferSize.
+ PERFETTO_CHECK(result->slices_size() > 0);
+ send_ipc_reply(/*has_more=*/true);
+ approx_reply_size = 0;
+ }
+ approx_reply_size += approx_slice_size;
+
+ auto* res_slice = result->add_slices();
+ res_slice->set_last_slice_for_packet(--num_slices_left_for_packet == 0);
+ res_slice->set_data(slice.start, slice.size);
+ }
}
- read_buffers_response.Resolve(std::move(result));
+ send_ipc_reply(has_more);
}
} // namespace perfetto
diff --git a/src/tracing/ipc/service/producer_ipc_service.cc b/src/tracing/ipc/service/producer_ipc_service.cc
index 3132967..565076d 100644
--- a/src/tracing/ipc/service/producer_ipc_service.cc
+++ b/src/tracing/ipc/service/producer_ipc_service.cc
@@ -93,54 +93,13 @@
return response.Reject();
}
- const std::string data_source_name = req.data_source_descriptor().name();
- if (producer->pending_data_sources.count(data_source_name)) {
- PERFETTO_DLOG(
- "A RegisterDataSource() request for \"%s\" is already pending",
- data_source_name.c_str());
- return response.Reject();
- }
-
- // Deserialize IPC proto -> core DataSourceDescriptor. Keep this in sync with
- // changes to data_source_descriptor.proto.
DataSourceDescriptor dsd;
- dsd.set_name(data_source_name);
- producer->pending_data_sources[data_source_name] = std::move(response);
- auto weak_this = weak_ptr_factory_.GetWeakPtr();
+ dsd.FromProto(req.data_source_descriptor());
+ GetProducerForCurrentRequest()->service_endpoint->RegisterDataSource(dsd);
- // TODO(fmayer): add test to cover the case of IPC going away before the
- // RegisterDataSource callback is received.
- const ipc::ClientID ipc_client_id = ipc::Service::client_info().client_id();
- GetProducerForCurrentRequest()->service_endpoint->RegisterDataSource(
- dsd, [weak_this, ipc_client_id, data_source_name](DataSourceID id) {
- if (!weak_this)
- return;
- weak_this->OnDataSourceRegistered(ipc_client_id, data_source_name, id);
- });
-}
-
-// Called by the Service business logic.
-void ProducerIPCService::OnDataSourceRegistered(
- ipc::ClientID ipc_client_id,
- const std::string& data_source_name,
- DataSourceID id) {
- auto producer_it = producers_.find(ipc_client_id);
- if (producer_it == producers_.end())
- return; // The producer died in the meantime.
- RemoteProducer* producer = producer_it->second.get();
-
- auto it = producer->pending_data_sources.find(data_source_name);
- PERFETTO_CHECK(it != producer->pending_data_sources.end());
-
- PERFETTO_DLOG("Data source %s registered, Client:%" PRIu64 " ID: %" PRIu64,
- data_source_name.c_str(), ipc_client_id, id);
-
- DeferredRegisterDataSourceResponse ipc_response = std::move(it->second);
- producer->pending_data_sources.erase(it);
- auto response =
- ipc::AsyncResult<protos::RegisterDataSourceResponse>::Create();
- response->set_data_source_id(id);
- ipc_response.Resolve(std::move(response));
+ // RegisterDataSource doesn't expect any meaningful response.
+ response.Resolve(
+ ipc::AsyncResult<protos::RegisterDataSourceResponse>::Create());
}
// Called by the IPC layer.
@@ -165,7 +124,7 @@
"InitializeConnection()");
return response.Reject();
}
- producer->service_endpoint->UnregisterDataSource(req.data_source_id());
+ producer->service_endpoint->UnregisterDataSource(req.data_source_name());
// UnregisterDataSource doesn't expect any meaningful response.
response.Resolve(
diff --git a/src/tracing/ipc/service/producer_ipc_service.h b/src/tracing/ipc/service/producer_ipc_service.h
index 128a30b..289c036 100644
--- a/src/tracing/ipc/service/producer_ipc_service.h
+++ b/src/tracing/ipc/service/producer_ipc_service.h
@@ -75,10 +75,6 @@
void OnTracingStart() override;
void OnTracingStop() override;
- // RegisterDataSource requests that haven't been replied yet.
- std::map<std::string, DeferredRegisterDataSourceResponse>
- pending_data_sources;
-
// The interface obtained from the core service business logic through
// Service::ConnectProducer(this). This allows to invoke methods for a
// specific Producer on the Service business logic.
@@ -97,10 +93,6 @@
// the current IPC request.
RemoteProducer* GetProducerForCurrentRequest();
- // Called back by the |core_service_| business logic, soon after a call to
- // RegisterDataSource().
- void OnDataSourceRegistered(ipc::ClientID, const std::string&, DataSourceID);
-
Service* const core_service_;
// Maps IPC clients to ProducerEndpoint instances registered on the
diff --git a/src/tracing/test/fake_packet.cc b/src/tracing/test/fake_packet.cc
index fd5ca05..2a254da 100644
--- a/src/tracing/test/fake_packet.cc
+++ b/src/tracing/test/fake_packet.cc
@@ -103,7 +103,7 @@
<< packet.payload() << "\"}";
}
-FakeChunk::FakeChunk(TraceBuffez* t, ProducerID p, WriterID w, ChunkID c)
+FakeChunk::FakeChunk(TraceBuffer* t, ProducerID p, WriterID w, ChunkID c)
: trace_buffer_{t}, producer_id{p}, writer_id{w}, chunk_id{c} {}
FakeChunk& FakeChunk::AddPacket(size_t size, char seed, uint8_t packet_flag) {
@@ -141,7 +141,7 @@
trace_buffer_->CopyChunkUntrusted(producer_id, uid, writer_id, chunk_id,
num_packets, flags, data.data(),
data.size());
- return data.size() + TraceBuffez::InlineChunkHeaderSize;
+ return data.size() + TraceBuffer::InlineChunkHeaderSize;
}
} // namespace perfetto
diff --git a/src/tracing/test/fake_packet.h b/src/tracing/test/fake_packet.h
index daab5e8..b3e56d8 100644
--- a/src/tracing/test/fake_packet.h
+++ b/src/tracing/test/fake_packet.h
@@ -28,7 +28,7 @@
namespace perfetto {
-class TraceBuffez;
+class TraceBuffer;
class FakePacketFragment {
public:
@@ -51,7 +51,7 @@
class FakeChunk {
public:
- FakeChunk(TraceBuffez* t, ProducerID p, WriterID w, ChunkID c);
+ FakeChunk(TraceBuffer* t, ProducerID p, WriterID w, ChunkID c);
// Appends a packet of exactly |size| bytes (including the varint header
// that states the size of the packet itself. The payload of the packet is
@@ -70,7 +70,7 @@
size_t CopyIntoTraceBuffer();
private:
- TraceBuffez* trace_buffer_;
+ TraceBuffer* trace_buffer_;
ProducerID producer_id;
WriterID writer_id;
ChunkID chunk_id;
diff --git a/src/tracing/test/tracing_integration_test.cc b/src/tracing/test/tracing_integration_test.cc
index 426f469..0f8dba6 100644
--- a/src/tracing/test/tracing_integration_test.cc
+++ b/src/tracing/test/tracing_integration_test.cc
@@ -93,7 +93,7 @@
// Create and connect a Producer.
producer_endpoint_ = ProducerIPCClient::Connect(
- kProducerSockName, &producer_, "com.google.perfetto.mock_producer",
+ kProducerSockName, &producer_, "perfetto.mock_producer",
task_runner_.get());
auto on_producer_connect =
task_runner_->CreateCheckpoint("on_producer_connect");
@@ -103,14 +103,7 @@
// Register a data source.
DataSourceDescriptor ds_desc;
ds_desc.set_name("perfetto.test");
- auto on_data_source_registered =
- task_runner_->CreateCheckpoint("on_data_source_registered");
- producer_endpoint_->RegisterDataSource(
- ds_desc, [on_data_source_registered](DataSourceID dsid) {
- PERFETTO_DLOG("Registered data source with ID: %" PRIu64, dsid);
- on_data_source_registered();
- });
- task_runner_->RunUntilCheckpoint("on_data_source_registered");
+ producer_endpoint_->RegisterDataSource(ds_desc);
// Create and connect a Consumer.
consumer_endpoint_ = ConsumerIPCClient::Connect(
@@ -218,6 +211,12 @@
Invoke([&num_pack_rx, all_packets_rx, &trace_config,
&saw_clock_snapshot, &saw_trace_config](
std::vector<TracePacket>* packets, bool has_more) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+ const int kExpectedMinNumberOfClocks = 1;
+#else
+ const int kExpectedMinNumberOfClocks = 6;
+#endif
+
for (auto& packet : *packets) {
ASSERT_TRUE(packet.Decode());
if (packet->has_for_testing()) {
@@ -225,7 +224,8 @@
sprintf(buf, "evt_%zu", num_pack_rx++);
EXPECT_EQ(std::string(buf), packet->for_testing().str());
} else if (packet->has_clock_snapshot()) {
- EXPECT_GE(packet->clock_snapshot().clocks_size(), 6);
+ EXPECT_GE(packet->clock_snapshot().clocks_size(),
+ kExpectedMinNumberOfClocks);
saw_clock_snapshot = true;
} else if (packet->has_trace_config()) {
protos::TraceConfig config_proto;
diff --git a/test/BUILD.gn b/test/BUILD.gn
index 7e27608..de7c72c 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -25,9 +25,9 @@
source_set("end_to_end_integrationtests") {
testonly = true
deps = [
- ":fake_consumer",
":task_runner_thread",
":task_runner_thread_delegates",
+ ":test_helper",
"../gn:default_deps",
"../gn:gtest_deps",
"../protos/perfetto/trace:lite",
@@ -52,9 +52,9 @@
]
testonly = true
deps = [
- ":fake_consumer",
":task_runner_thread",
":task_runner_thread_delegates",
+ ":test_helper",
"../gn:default_deps",
"../src/base:test_support",
"../src/protozero",
@@ -65,22 +65,6 @@
}
}
-source_set("fake_consumer") {
- testonly = true
- deps = [
- "../gn:default_deps",
- "../gn:gtest_deps",
- "../protos/perfetto/trace:lite",
- "../protos/perfetto/trace:zero",
- "../src/base:base",
- "../src/base:test_support",
- ]
- sources = [
- "fake_consumer.cc",
- "fake_consumer.h",
- ]
-}
-
source_set("task_runner_thread") {
testonly = true
deps = [
@@ -109,13 +93,31 @@
]
}
+source_set("test_helper") {
+ testonly = true
+ deps = [
+ ":task_runner_thread",
+ ":task_runner_thread_delegates",
+ "../gn:default_deps",
+ "../protos/perfetto/trace:lite",
+ "../src/base:test_support",
+ ]
+ sources = [
+ "test_helper.cc",
+ "test_helper.h",
+ ]
+ if (start_daemons_for_testing) {
+ cflags = [ "-DPERFETTO_START_DAEMONS_FOR_TESTING" ]
+ }
+}
+
if (!build_with_chromium) {
source_set("end_to_end_benchmarks") {
testonly = true
deps = [
- ":fake_consumer",
":task_runner_thread",
":task_runner_thread_delegates",
+ ":test_helper",
"../../gn:default_deps",
"../gn:gtest_deps",
"../protos/perfetto/trace:lite",
diff --git a/test/configs/BUILD.gn b/test/configs/BUILD.gn
index 3923c02..485d4f6 100644
--- a/test/configs/BUILD.gn
+++ b/test/configs/BUILD.gn
@@ -27,6 +27,7 @@
"atrace.cfg",
"ftrace.cfg",
"long_trace.cfg",
+ "processes.cfg",
]
outputs = [
diff --git a/test/configs/atrace.cfg b/test/configs/atrace.cfg
index dde7f38..1362a20 100644
--- a/test/configs/atrace.cfg
+++ b/test/configs/atrace.cfg
@@ -6,10 +6,10 @@
# TODO(hjd): Add some atrace config here.
data_sources {
config {
- name: "com.google.perfetto.ftrace"
+ name: "linux.ftrace"
target_buffer: 0
ftrace_config {
- ftrace_events: "sched_switch"
+ atrace_categories: "input"
buffer_size_kb: 168 # 4 (page size) * 42
drain_period_ms: 42
}
diff --git a/test/configs/ftrace.cfg b/test/configs/ftrace.cfg
index 2bb2810..4fbc0a5 100644
--- a/test/configs/ftrace.cfg
+++ b/test/configs/ftrace.cfg
@@ -5,7 +5,7 @@
data_sources {
config {
- name: "com.google.perfetto.ftrace"
+ name: "linux.ftrace"
target_buffer: 0
ftrace_config {
buffer_size_kb: 40 # 4 (page size) * 10
@@ -245,20 +245,30 @@
data_sources {
config {
- name: "com.google.perfetto.process_stats"
+ name: "linux.process_stats"
target_buffer: 0
}
}
data_sources {
config {
- name: "com.google.perfetto.inode_file_map"
+ name: "linux.inode_file_map"
target_buffer: 0
+ inode_file_config {
+ scan_delay_ms: 1000
+ scan_interval_ms: 1000
+ scan_batch_size: 100000
+ mount_point_mapping: {
+ mountpoint: "/data"
+ scan_roots: "/data/app"
+ scan_roots: "/data/dalvik-cache"
+ }
+ }
}
}
producers {
- producer_name: "com.google.perfetto.traced_probes"
+ producer_name: "perfetto.traced_probes"
shm_size_kb: 4096
page_size_kb: 4
}
diff --git a/test/configs/long_trace.cfg b/test/configs/long_trace.cfg
index ee62800..e81ecab 100644
--- a/test/configs/long_trace.cfg
+++ b/test/configs/long_trace.cfg
@@ -10,7 +10,7 @@
data_sources {
config {
- name: "com.google.perfetto.ftrace"
+ name: "linux.ftrace"
target_buffer: 1
ftrace_config {
buffer_size_kb: 40 # 4 (page size) * 10
@@ -141,20 +141,20 @@
data_sources {
config {
- name: "com.google.perfetto.process_stats"
+ name: "linux.process_stats"
target_buffer: 0
}
}
data_sources {
config {
- name: "com.google.perfetto.inode_file_map"
+ name: "linux.inode_file_map"
target_buffer: 0
}
}
producers {
- producer_name: "com.google.perfetto.traced_probes"
+ producer_name: "perfetto.traced_probes"
shm_size_kb: 4096
page_size_kb: 4
}
diff --git a/test/configs/processes.cfg b/test/configs/processes.cfg
new file mode 100644
index 0000000..f8c24b8
--- /dev/null
+++ b/test/configs/processes.cfg
@@ -0,0 +1,57 @@
+buffers {
+ size_kb: 100024
+ fill_policy: RING_BUFFER
+}
+
+data_sources {
+ config {
+ name: "com.google.perfetto.ftrace"
+ target_buffer: 0
+ ftrace_config {
+ buffer_size_kb: 40 # 4 (page size) * 10
+ drain_period_ms: 200
+ ftrace_events: "sched_process_exec"
+ ftrace_events: "sched_process_exit"
+ ftrace_events: "sched_process_fork"
+ ftrace_events: "sched_process_free"
+ ftrace_events: "sched_process_hang"
+ ftrace_events: "sched_process_wait"
+ ftrace_events: "sched_wakeup_new"
+ ftrace_events: "sched_wakeup"
+ ftrace_events: "sched_waking"
+ ftrace_events: "smbus_read"
+ ftrace_events: "smbus_reply"
+ ftrace_events: "smbus_result"
+ ftrace_events: "smbus_write"
+ ftrace_events: "softirq_entry"
+ ftrace_events: "softirq_exit"
+ ftrace_events: "softirq_raise"
+ ftrace_events: "suspend_resume"
+ ftrace_events: "sync_pt"
+ ftrace_events: "sync_timeline"
+ ftrace_events: "sync_wait"
+ ftrace_events: "task_newtask"
+ ftrace_events: "task_rename"
+ ftrace_events: "tracing_mark_write"
+ ftrace_events: "workqueue_activate_work"
+ ftrace_events: "workqueue_execute_end"
+ ftrace_events: "workqueue_execute_start"
+ ftrace_events: "workqueue_queue_work"
+ }
+ }
+}
+
+data_sources {
+ config {
+ name: "com.google.perfetto.process_stats"
+ target_buffer: 0
+ }
+}
+
+producers {
+ producer_name: "com.google.perfetto.traced_probes"
+ shm_size_kb: 4096
+ page_size_kb: 4
+}
+
+duration_ms: 10000
diff --git a/test/cts/end_to_end_integrationtest_cts.cc b/test/cts/end_to_end_integrationtest_cts.cc
index d6531ec..426458b 100644
--- a/test/cts/end_to_end_integrationtest_cts.cc
+++ b/test/cts/end_to_end_integrationtest_cts.cc
@@ -22,7 +22,8 @@
#include "perfetto/trace/trace_packet.pbzero.h"
#include "perfetto/traced/traced.h"
#include "perfetto/tracing/core/trace_packet.h"
-#include "test/fake_consumer.h"
+#include "src/base/test/test_task_runner.h"
+#include "test/test_helper.h"
namespace perfetto {
@@ -31,65 +32,45 @@
void TestMockProducer(const std::string& producer_name) {
base::TestTaskRunner task_runner;
- // Setup the trace config.
+ TestHelper helper(&task_runner);
+ helper.ConnectConsumer();
+
TraceConfig trace_config;
- trace_config.add_buffers()->set_size_kb(4096 * 10);
+ trace_config.add_buffers()->set_size_kb(1024);
trace_config.set_duration_ms(200);
auto* ds_config = trace_config.add_data_sources()->mutable_config();
ds_config->set_name(producer_name);
ds_config->set_target_buffer(0);
- // The parameters for the producer.
static constexpr uint32_t kRandomSeed = 42;
static constexpr uint32_t kEventCount = 10;
static constexpr uint32_t kMessageSizeBytes = 1024;
-
- // Setup the test to use a random number generator.
ds_config->mutable_for_testing()->set_seed(kRandomSeed);
ds_config->mutable_for_testing()->set_message_count(kEventCount);
ds_config->mutable_for_testing()->set_message_size(kMessageSizeBytes);
- // Create the random generator with the same seed.
- std::minstd_rand0 rnd_engine(kRandomSeed);
+ auto producer_enabled = task_runner.CreateCheckpoint("producer.enabled");
+ task_runner.PostTask(producer_enabled);
+ helper.StartTracing(trace_config);
- // Setip the function.
- uint64_t total = 0;
+ size_t packets_seen = 0;
+ std::minstd_rand0 rnd_engine(kRandomSeed);
+ auto on_consumer_data = [&packets_seen, &rnd_engine](
+ const TracePacket::DecodedTracePacket& packet) {
+ ASSERT_TRUE(packet.has_for_testing());
+ ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
+ packets_seen++;
+ };
auto on_readback_complete =
task_runner.CreateCheckpoint("readback.complete");
- auto function = [&total, &on_readback_complete, &rnd_engine](
- std::vector<TracePacket> packets, bool has_more) {
- for (auto& packet : packets) {
- ASSERT_TRUE(packet.Decode());
- ASSERT_TRUE(packet->has_for_testing() || packet->has_clock_snapshot() ||
- packet->has_trace_config());
- if (packet->has_clock_snapshot() || packet->has_trace_config()) {
- continue;
- }
- ASSERT_EQ(protos::TracePacket::kTrustedUid,
- packet->optional_trusted_uid_case());
- ASSERT_EQ(packet->for_testing().seq_value(), rnd_engine());
- }
- total += packets.size();
-
- if (!has_more) {
- // Extra packets for the clock snapshot and trace config.
- ASSERT_EQ(total, kEventCount + 2);
- on_readback_complete();
- }
- };
-
- // Finally, make the consumer connect to the service.
- auto on_connect = task_runner.CreateCheckpoint("consumer.connected");
- FakeConsumer consumer(trace_config, std::move(on_connect),
- std::move(function), &task_runner);
- consumer.Connect(PERFETTO_CONSUMER_SOCK_NAME);
- task_runner.RunUntilCheckpoint("consumer.connected");
-
- consumer.EnableTracing();
- task_runner.PostDelayedTask([&consumer]() { consumer.ReadTraceData(); },
- 1000);
+ task_runner.PostDelayedTask(
+ [&on_consumer_data, &on_readback_complete, &helper]() {
+ helper.ReadData(on_consumer_data, on_readback_complete);
+ },
+ 1000);
task_runner.RunUntilCheckpoint("readback.complete");
+ ASSERT_EQ(packets_seen, kEventCount);
}
};
diff --git a/test/end_to_end_benchmark.cc b/test/end_to_end_benchmark.cc
index 57f9cae..429711a 100644
--- a/test/end_to_end_benchmark.cc
+++ b/test/end_to_end_benchmark.cc
@@ -23,42 +23,26 @@
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
#include "src/base/test/test_task_runner.h"
-#include "test/fake_consumer.h"
#include "test/task_runner_thread.h"
#include "test/task_runner_thread_delegates.h"
+#include "test/test_helper.h"
namespace perfetto {
-// If we're building on Android and starting the daemons ourselves,
-// create the sockets in a world-writable location.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
- PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
-#define TEST_PRODUCER_SOCK_NAME "/data/local/tmp/traced_producer"
-#define TEST_CONSUMER_SOCK_NAME "/data/local/tmp/traced_consumer"
-#else
-#define TEST_PRODUCER_SOCK_NAME PERFETTO_PRODUCER_SOCK_NAME
-#define TEST_CONSUMER_SOCK_NAME PERFETTO_CONSUMER_SOCK_NAME
-#endif
+namespace {
-static void BM_EndToEnd(benchmark::State& state) {
+bool IsBenchmarkFunctionalOnly() {
+ return getenv("BENCHMARK_FUNCTIONAL_TEST_ONLY") != nullptr;
+}
+
+void BenchmarkCommon(benchmark::State& state) {
base::TestTaskRunner task_runner;
-#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- TaskRunnerThread service_thread("perfetto.svc");
- service_thread.Start(std::unique_ptr<ServiceDelegate>(
- new ServiceDelegate(TEST_PRODUCER_SOCK_NAME, TEST_CONSUMER_SOCK_NAME)));
-#endif
+ TestHelper helper(&task_runner);
+ helper.StartServiceIfRequired();
- TaskRunnerThread producer_thread("perfetto.prd");
- auto on_producer_enabled = task_runner.CreateCheckpoint("producer.enabled");
- auto posted_on_producer_enabled = [&task_runner, &on_producer_enabled] {
- task_runner.PostTask(on_producer_enabled);
- };
- std::unique_ptr<FakeProducerDelegate> producer_delegate(
- new FakeProducerDelegate(TEST_PRODUCER_SOCK_NAME,
- posted_on_producer_enabled));
- FakeProducerDelegate* producer_delegate_cached = producer_delegate.get();
- producer_thread.Start(std::move(producer_delegate));
+ FakeProducer* producer = helper.ConnectFakeProducer();
+ helper.ConnectConsumer();
// Setup the TraceConfig for the consumer.
TraceConfig trace_config;
@@ -71,85 +55,101 @@
// The parameters for the producer.
static constexpr uint32_t kRandomSeed = 42;
- uint32_t message_count = state.range(0);
- uint32_t message_size = state.range(1);
+ size_t message_count = state.range(0);
+ size_t message_bytes = state.range(1);
+ size_t mb_per_s = state.range(2);
+
+ size_t messages_per_s = mb_per_s * 1024 * 1024 / message_bytes;
+ size_t time_for_messages_ms =
+ 10000 + (messages_per_s == 0 ? 0 : message_count * 1000 / messages_per_s);
// Setup the test to use a random number generator.
ds_config->mutable_for_testing()->set_seed(kRandomSeed);
ds_config->mutable_for_testing()->set_message_count(message_count);
- ds_config->mutable_for_testing()->set_message_size(message_size);
+ ds_config->mutable_for_testing()->set_message_size(message_bytes);
+ ds_config->mutable_for_testing()->set_max_messages_per_second(messages_per_s);
+
+ helper.StartTracing(trace_config);
bool is_first_packet = true;
- auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
std::minstd_rand0 rnd_engine(kRandomSeed);
- auto on_consumer_data = [&is_first_packet, &on_readback_complete,
- &rnd_engine](std::vector<TracePacket> packets,
- bool has_more) {
- for (auto& packet : packets) {
- ASSERT_TRUE(packet.Decode());
- ASSERT_TRUE(packet->has_for_testing() || packet->has_clock_snapshot());
- if (packet->has_clock_snapshot()) {
- continue;
- }
- ASSERT_EQ(protos::TracePacket::kTrustedUid,
- packet->optional_trusted_uid_case());
- if (is_first_packet) {
- rnd_engine = std::minstd_rand0(packet->for_testing().seq_value());
- is_first_packet = false;
- } else {
- ASSERT_EQ(packet->for_testing().seq_value(), rnd_engine());
- }
- }
-
- if (!has_more) {
- is_first_packet = true;
- on_readback_complete();
+ auto on_consumer_data = [&is_first_packet, &rnd_engine](
+ const TracePacket::DecodedTracePacket& packet) {
+ ASSERT_TRUE(packet.has_for_testing());
+ if (is_first_packet) {
+ rnd_engine = std::minstd_rand0(packet.for_testing().seq_value());
+ is_first_packet = false;
+ } else {
+ ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
}
};
- // Finally, make the consumer connect to the service.
- auto on_connect = task_runner.CreateCheckpoint("consumer.connected");
- FakeConsumer consumer(trace_config, std::move(on_connect),
- std::move(on_consumer_data), &task_runner);
- consumer.Connect(TEST_CONSUMER_SOCK_NAME);
- task_runner.RunUntilCheckpoint("consumer.connected");
-
- consumer.EnableTracing();
- task_runner.RunUntilCheckpoint("producer.enabled");
-
uint64_t wall_start_ns = base::GetWallTimeNs().count();
- uint64_t thread_start_ns = service_thread.GetThreadCPUTimeNs();
+ uint64_t service_start_ns = helper.service_thread()->GetThreadCPUTimeNs();
+ uint64_t producer_start_ns = helper.producer_thread()->GetThreadCPUTimeNs();
uint64_t iterations = 0;
for (auto _ : state) {
auto cname = "produced.and.committed." + std::to_string(iterations++);
auto on_produced_and_committed = task_runner.CreateCheckpoint(cname);
- auto posted_on_produced_and_committed = [&task_runner,
- &on_produced_and_committed] {
- task_runner.PostTask(on_produced_and_committed);
- };
- FakeProducer* producer = producer_delegate_cached->producer();
- producer->ProduceEventBatch(posted_on_produced_and_committed);
- task_runner.RunUntilCheckpoint(cname);
+ producer->ProduceEventBatch(helper.WrapTask(on_produced_and_committed));
+ task_runner.RunUntilCheckpoint(cname, time_for_messages_ms);
}
- uint64_t thread_ns = service_thread.GetThreadCPUTimeNs() - thread_start_ns;
+ uint64_t service_ns =
+ helper.service_thread()->GetThreadCPUTimeNs() - service_start_ns;
+ uint64_t producer_ns =
+ helper.producer_thread()->GetThreadCPUTimeNs() - producer_start_ns;
uint64_t wall_ns = base::GetWallTimeNs().count() - wall_start_ns;
- state.counters["Ser CPU"] = benchmark::Counter(100.0 * thread_ns / wall_ns);
+ state.counters["Pro CPU"] = benchmark::Counter(100.0 * producer_ns / wall_ns);
+ state.counters["Ser CPU"] = benchmark::Counter(100.0 * service_ns / wall_ns);
state.counters["Ser ns/m"] =
- benchmark::Counter(1.0 * thread_ns / message_count);
+ benchmark::Counter(1.0 * service_ns / message_count);
// Read back the buffer just to check correctness.
- consumer.ReadTraceData();
+ auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
+ helper.ReadData(on_consumer_data, on_readback_complete);
task_runner.RunUntilCheckpoint("readback.complete");
- state.SetBytesProcessed(int64_t(state.iterations()) * message_size *
- message_count);
-
- consumer.Disconnect();
+ state.SetBytesProcessed(iterations * message_bytes * message_count);
}
-BENCHMARK(BM_EndToEnd)
+void SaturateCpuArgs(benchmark::internal::Benchmark* b) {
+ int min_message_count = 16;
+ int max_message_count = IsBenchmarkFunctionalOnly() ? 1024 : 1024 * 1024;
+ int min_payload = 8;
+ int max_payload = IsBenchmarkFunctionalOnly() ? 256 : 2048;
+ for (int count = min_message_count; count <= max_message_count; count *= 2) {
+ for (int bytes = min_payload; bytes <= max_payload; bytes *= 2) {
+ b->Args({count, bytes, 0 /* speed */});
+ }
+ }
+}
+
+void ConstantRateArgs(benchmark::internal::Benchmark* b) {
+ int message_count = IsBenchmarkFunctionalOnly() ? 2 * 1024 : 128 * 1024;
+ int min_speed = IsBenchmarkFunctionalOnly() ? 64 : 8;
+ int max_speed = IsBenchmarkFunctionalOnly() ? 128 : 128;
+ for (int speed = min_speed; speed <= max_speed; speed *= 2) {
+ b->Args({message_count, 128, speed});
+ b->Args({message_count, 256, speed});
+ }
+}
+} // namespace
+
+static void BM_EndToEnd_SaturateCpu(benchmark::State& state) {
+ BenchmarkCommon(state);
+}
+
+BENCHMARK(BM_EndToEnd_SaturateCpu)
->Unit(benchmark::kMicrosecond)
->UseRealTime()
- ->RangeMultiplier(2)
- ->Ranges({{16, 1024 * 1024}, {8, 2048}});
+ ->Apply(SaturateCpuArgs);
+
+static void BM_EndToEnd_ConstantRate(benchmark::State& state) {
+ BenchmarkCommon(state);
}
+
+BENCHMARK(BM_EndToEnd_ConstantRate)
+ ->Unit(benchmark::kMicrosecond)
+ ->UseRealTime()
+ ->Apply(ConstantRateArgs);
+} // namespace perfetto
diff --git a/test/end_to_end_integrationtest.cc b/test/end_to_end_integrationtest.cc
index daff489..14f8c3b 100644
--- a/test/end_to_end_integrationtest.cc
+++ b/test/end_to_end_integrationtest.cc
@@ -27,36 +27,22 @@
#include "perfetto/trace/trace_packet.pb.h"
#include "perfetto/trace/trace_packet.pbzero.h"
#include "perfetto/traced/traced.h"
-#include "perfetto/tracing/core/consumer.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
-#include "perfetto/tracing/ipc/consumer_ipc_client.h"
#include "src/base/test/test_task_runner.h"
-#include "test/fake_consumer.h"
#include "test/task_runner_thread.h"
#include "test/task_runner_thread_delegates.h"
-
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-#include "perfetto/base/android_task_runner.h"
-#endif
+#include "test/test_helper.h"
namespace perfetto {
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
-using PlatformTaskRunner = base::AndroidTaskRunner;
-#else
-using PlatformTaskRunner = base::UnixTaskRunner;
-#endif
-
// If we're building on Android and starting the daemons ourselves,
// create the sockets in a world-writable location.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
#define TEST_PRODUCER_SOCK_NAME "/data/local/tmp/traced_producer"
-#define TEST_CONSUMER_SOCK_NAME "/data/local/tmp/traced_consumer"
#else
#define TEST_PRODUCER_SOCK_NAME PERFETTO_PRODUCER_SOCK_NAME
-#define TEST_CONSUMER_SOCK_NAME PERFETTO_CONSUMER_SOCK_NAME
#endif
// TODO(b/73453011): reenable this on more platforms (including standalone
@@ -69,161 +55,141 @@
TEST(PerfettoTest, MAYBE_TestFtraceProducer) {
base::TestTaskRunner task_runner;
-#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- TaskRunnerThread service_thread("perfetto.svc");
- service_thread.Start(std::unique_ptr<ServiceDelegate>(
- new ServiceDelegate(TEST_PRODUCER_SOCK_NAME, TEST_CONSUMER_SOCK_NAME)));
+ TestHelper helper(&task_runner);
+ 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)));
#endif
- // Setip the TraceConfig for the consumer.
+ helper.ConnectConsumer();
+
TraceConfig trace_config;
trace_config.add_buffers()->set_size_kb(1024);
trace_config.set_duration_ms(3000);
- // Create the buffer for ftrace.
auto* ds_config = trace_config.add_data_sources()->mutable_config();
- ds_config->set_name("com.google.perfetto.ftrace");
+ ds_config->set_name("linux.ftrace");
ds_config->set_target_buffer(0);
- // Setup the config for ftrace.
auto* ftrace_config = ds_config->mutable_ftrace_config();
*ftrace_config->add_ftrace_events() = "sched_switch";
*ftrace_config->add_ftrace_events() = "bar";
- // Create the function to handle packets as they come in.
- uint64_t total = 0;
+ auto producer_enabled = task_runner.CreateCheckpoint("producer.enabled");
+ task_runner.PostDelayedTask(producer_enabled, 100);
+ helper.StartTracing(trace_config);
+
+ size_t packets_seen = 0;
+ auto on_consumer_data =
+ [&packets_seen](const TracePacket::DecodedTracePacket& packet) {
+ for (int ev = 0; ev < packet.ftrace_events().event_size(); ev++) {
+ ASSERT_TRUE(packet.ftrace_events().event(ev).has_sched_switch());
+ }
+ packets_seen++;
+ };
auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
- auto on_consumer_data = [&total, &on_readback_complete](
- std::vector<TracePacket> packets, bool has_more) {
- for (auto& packet : packets) {
- ASSERT_TRUE(packet.Decode());
- ASSERT_TRUE(packet->has_ftrace_events() || packet->has_clock_snapshot() ||
- packet->has_trace_config());
- if (packet->has_clock_snapshot() || packet->has_trace_config())
- continue;
- for (int ev = 0; ev < packet->ftrace_events().event_size(); ev++) {
- ASSERT_TRUE(packet->ftrace_events().event(ev).has_sched_switch());
- }
- }
- total += packets.size();
-
- if (!has_more) {
- ASSERT_GT(total, 0u);
- on_readback_complete();
- }
- };
-
- auto on_connect = task_runner.CreateCheckpoint("consumer.connected");
- FakeConsumer consumer(trace_config, std::move(on_connect),
- std::move(on_consumer_data), &task_runner);
-
- consumer.Connect(TEST_CONSUMER_SOCK_NAME);
- task_runner.RunUntilCheckpoint("consumer.connected");
-
- // Traced probes should flush data as it produces it.
- consumer.EnableTracing();
- task_runner.PostDelayedTask([&consumer] { consumer.ReadTraceData(); }, 3000);
-
- task_runner.RunUntilCheckpoint("readback.complete", 10000);
-
- consumer.Disconnect();
+ task_runner.PostDelayedTask(
+ [&helper, &on_consumer_data, &on_readback_complete] {
+ helper.ReadData(on_consumer_data, on_readback_complete);
+ },
+ 3000);
+ task_runner.RunUntilCheckpoint("readback.complete");
+ ASSERT_GT(packets_seen, 0u);
}
TEST(PerfettoTest, TestFakeProducer) {
base::TestTaskRunner task_runner;
-#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
- TaskRunnerThread service_thread("perfetto.svc");
- service_thread.Start(std::unique_ptr<ServiceDelegate>(
- new ServiceDelegate(TEST_PRODUCER_SOCK_NAME, TEST_CONSUMER_SOCK_NAME)));
-#endif
+ TestHelper helper(&task_runner);
+ helper.StartServiceIfRequired();
- auto on_producer_enabled = task_runner.CreateCheckpoint("producer.enabled");
- auto posted_on_producer_enabled = [&task_runner, &on_producer_enabled] {
- task_runner.PostTask(on_producer_enabled);
- };
- TaskRunnerThread producer_thread("perfetto.prd");
- std::unique_ptr<FakeProducerDelegate> producer_delegate(
- new FakeProducerDelegate(TEST_PRODUCER_SOCK_NAME,
- posted_on_producer_enabled));
- FakeProducerDelegate* producer_delegate_cached = producer_delegate.get();
- producer_thread.Start(std::move(producer_delegate));
+ FakeProducer* producer = helper.ConnectFakeProducer();
+ helper.ConnectConsumer();
- // Setup the TraceConfig for the consumer.
TraceConfig trace_config;
trace_config.add_buffers()->set_size_kb(1024);
trace_config.set_duration_ms(200);
- // Create the buffer for ftrace.
auto* ds_config = trace_config.add_data_sources()->mutable_config();
ds_config->set_name("android.perfetto.FakeProducer");
ds_config->set_target_buffer(0);
- // The parameters for the producer.
+ static constexpr size_t kNumPackets = 10;
static constexpr uint32_t kRandomSeed = 42;
- static constexpr uint32_t kEventCount = 10;
- static constexpr uint32_t kMessageSizeBytes = 1024;
-
- // Setup the test to use a random number generator.
+ static constexpr uint32_t kMsgSize = 1024;
ds_config->mutable_for_testing()->set_seed(kRandomSeed);
- ds_config->mutable_for_testing()->set_message_count(kEventCount);
- ds_config->mutable_for_testing()->set_message_size(kMessageSizeBytes);
+ ds_config->mutable_for_testing()->set_message_count(kNumPackets);
+ ds_config->mutable_for_testing()->set_message_size(kMsgSize);
- // Create the random generator with the same seed.
- std::minstd_rand0 random(kRandomSeed);
+ helper.StartTracing(trace_config);
- // Create the function to handle packets as they come in.
- uint64_t total = 0;
- auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
- auto on_consumer_data = [&total, &on_readback_complete, &random](
- std::vector<TracePacket> packets, bool has_more) {
- for (auto& packet : packets) {
- ASSERT_TRUE(packet.Decode());
- if (packet->has_clock_snapshot() || packet->has_trace_config())
- continue;
- ASSERT_TRUE(packet->has_for_testing());
- ASSERT_EQ(protos::TracePacket::kTrustedUid,
- packet->optional_trusted_uid_case());
- ASSERT_EQ(packet->for_testing().seq_value(), random());
- }
- total += packets.size();
-
- if (!has_more) {
- // One extra packet for the clock snapshot and another for the trace
- // config.
- ASSERT_EQ(total, kEventCount + 2);
- on_readback_complete();
- }
- };
-
- auto on_connect = task_runner.CreateCheckpoint("consumer.connected");
- FakeConsumer consumer(trace_config, std::move(on_connect),
- std::move(on_consumer_data), &task_runner);
-
- consumer.Connect(TEST_CONSUMER_SOCK_NAME);
- task_runner.RunUntilCheckpoint("consumer.connected");
-
- consumer.EnableTracing();
- task_runner.RunUntilCheckpoint("producer.enabled");
-
- auto on_produced_and_committed =
- task_runner.CreateCheckpoint("produced.and.committed");
- auto posted_on_produced_and_committed = [&task_runner,
- &on_produced_and_committed] {
- task_runner.PostTask(on_produced_and_committed);
- };
- FakeProducer* producer = producer_delegate_cached->producer();
- producer->ProduceEventBatch(posted_on_produced_and_committed);
+ producer->ProduceEventBatch(
+ helper.WrapTask(task_runner.CreateCheckpoint("produced.and.committed")));
task_runner.RunUntilCheckpoint("produced.and.committed");
- consumer.ReadTraceData();
+ size_t packets_seen = 0;
+ std::minstd_rand0 rnd_engine(kRandomSeed);
+ auto on_consumer_data = [&packets_seen, &rnd_engine](
+ const TracePacket::DecodedTracePacket& packet) {
+ ASSERT_TRUE(packet.has_for_testing());
+ ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
+ packets_seen++;
+ };
+ auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
+ helper.ReadData(on_consumer_data, on_readback_complete);
task_runner.RunUntilCheckpoint("readback.complete");
+ ASSERT_EQ(packets_seen, kNumPackets);
+}
- consumer.Disconnect();
+TEST(PerfettoTest, VeryLargePackets) {
+ base::TestTaskRunner task_runner;
+
+ TestHelper helper(&task_runner);
+ helper.StartServiceIfRequired();
+
+ FakeProducer* producer = helper.ConnectFakeProducer();
+ helper.ConnectConsumer();
+
+ // Setup the TraceConfig for the consumer.
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096 * 10);
+
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("android.perfetto.FakeProducer");
+ ds_config->set_target_buffer(0);
+
+ static constexpr size_t kNumPackets = 5;
+ static constexpr uint32_t kRandomSeed = 42;
+ static constexpr uint32_t kMsgSize = 1024 * 1024 - 42;
+ ds_config->mutable_for_testing()->set_seed(kRandomSeed);
+ ds_config->mutable_for_testing()->set_message_count(kNumPackets);
+ ds_config->mutable_for_testing()->set_message_size(kMsgSize);
+
+ helper.StartTracing(trace_config);
+
+ producer->ProduceEventBatch(
+ helper.WrapTask(task_runner.CreateCheckpoint("produced.and.committed")));
+ task_runner.RunUntilCheckpoint("produced.and.committed");
+
+ size_t packets_seen = 0;
+ std::minstd_rand0 rnd_engine(kRandomSeed);
+ auto on_consumer_data = [&packets_seen, &rnd_engine](
+ const TracePacket::DecodedTracePacket& packet) {
+ ASSERT_TRUE(packet.has_for_testing());
+ ASSERT_EQ(packet.for_testing().seq_value(), rnd_engine());
+ size_t msg_size = packet.for_testing().str().size();
+ ASSERT_EQ(kMsgSize, msg_size);
+ for (size_t i = 0; i < msg_size; i++)
+ ASSERT_EQ(i < msg_size - 1 ? '.' : 0, packet.for_testing().str()[i]);
+ packets_seen++;
+ };
+ auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
+ helper.ReadData(on_consumer_data, on_readback_complete);
+ task_runner.RunUntilCheckpoint("readback.complete");
+ ASSERT_EQ(packets_seen, kNumPackets);
}
} // namespace perfetto
diff --git a/test/end_to_end_shared_memory_fuzzer.cc b/test/end_to_end_shared_memory_fuzzer.cc
index 37689f7..521fe86 100644
--- a/test/end_to_end_shared_memory_fuzzer.cc
+++ b/test/end_to_end_shared_memory_fuzzer.cc
@@ -25,6 +25,7 @@
#include "perfetto/trace/test_event.pbzero.h"
#include "perfetto/trace/trace_packet.pb.h"
#include "perfetto/trace/trace_packet.pbzero.h"
+#include "perfetto/traced/traced.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/data_source_descriptor.h"
#include "perfetto/tracing/core/producer.h"
@@ -32,15 +33,21 @@
#include "perfetto/tracing/ipc/producer_ipc_client.h"
#include "perfetto/tracing/ipc/service_ipc_host.h"
#include "src/base/test/test_task_runner.h"
-#include "test/fake_consumer.h"
#include "test/task_runner_thread.h"
#include "test/task_runner_thread_delegates.h"
+#include "test/test_helper.h"
namespace perfetto {
namespace shm_fuzz {
-static const char* kProducerSocket = tempnam("/tmp", "perfetto-producer");
-static const char* kConsumerSocket = tempnam("/tmp", "perfetto-consumer");
+// If we're building on Android and starting the daemons ourselves,
+// create the sockets in a world-writable location.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
+ PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
+#define TEST_PRODUCER_SOCK_NAME "/data/local/tmp/traced_producer"
+#else
+#define TEST_PRODUCER_SOCK_NAME PERFETTO_PRODUCER_SOCK_NAME
+#endif
// Fake producer writing a protozero message of data into shared memory
// buffer, followed by a sentinel message to signal completion to the
@@ -57,14 +64,14 @@
on_produced_and_committed_(on_produced_and_committed) {}
void Connect(const char* socket_name, base::TaskRunner* task_runner) {
- endpoint_ = ProducerIPCClient::Connect(socket_name, this, task_runner);
+ endpoint_ = ProducerIPCClient::Connect(
+ socket_name, this, "android.perfetto.FakeProducer", task_runner);
}
void OnConnect() override {
DataSourceDescriptor descriptor;
descriptor.set_name(name_);
- endpoint_->RegisterDataSource(descriptor,
- [this](DataSourceID id) { id_ = id; });
+ endpoint_->RegisterDataSource(descriptor);
}
void OnDisconnect() override {}
@@ -95,7 +102,6 @@
const std::string name_;
const uint8_t* data_;
const size_t size_;
- DataSourceID id_ = 0;
std::unique_ptr<Service::ProducerEndpoint> endpoint_;
std::function<void()> on_produced_and_committed_;
};
@@ -113,7 +119,7 @@
void Initialize(base::TaskRunner* task_runner) override {
producer_.reset(new FakeProducer("android.perfetto.FakeProducer", data_,
size_, on_produced_and_committed_));
- producer_->Connect(kProducerSocket, task_runner);
+ producer_->Connect(TEST_PRODUCER_SOCK_NAME, task_runner);
}
private:
@@ -128,9 +134,8 @@
int FuzzSharedMemory(const uint8_t* data, size_t size) {
base::TestTaskRunner task_runner;
- TaskRunnerThread service_thread("perfetto.svc");
- service_thread.Start(std::unique_ptr<ServiceDelegate>(
- new ServiceDelegate(kProducerSocket, kConsumerSocket)));
+ TestHelper helper(&task_runner);
+ helper.StartServiceIfRequired();
auto on_produced_and_committed =
task_runner.CreateCheckpoint("produced.and.committed");
@@ -142,40 +147,29 @@
producer_thread.Start(std::unique_ptr<FakeProducerDelegate>(
new FakeProducerDelegate(data, size, posted_on_produced_and_committed)));
- // Setup the TraceConfig for the consumer.
+ helper.ConnectConsumer();
+
TraceConfig trace_config;
trace_config.add_buffers()->set_size_kb(8);
- // Create the buffer for the fake producer.
auto* ds_config = trace_config.add_data_sources()->mutable_config();
ds_config->set_name("android.perfetto.FakeProducer");
ds_config->set_target_buffer(0);
- auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
- auto on_consumer_data = [&on_readback_complete](
- std::vector<TracePacket> packets, bool has_more) {
- for (auto& p : packets) {
- p.Decode();
- if (p->for_testing().str() == "end")
- on_readback_complete();
- }
- };
-
- auto on_connect = task_runner.CreateCheckpoint("consumer.connected");
- FakeConsumer consumer(trace_config, std::move(on_connect),
- std::move(on_consumer_data), &task_runner);
-
- consumer.Connect(kConsumerSocket);
- task_runner.RunUntilCheckpoint("consumer.connected");
-
- consumer.EnableTracing();
+ auto producer_enabled = task_runner.CreateCheckpoint("producer.enabled");
+ task_runner.PostTask(producer_enabled);
+ helper.StartTracing(trace_config);
task_runner.RunUntilCheckpoint("produced.and.committed");
- consumer.ReadTraceData();
+ auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
+ auto on_consumer_data =
+ [&on_readback_complete](const TracePacket::DecodedTracePacket& packet) {
+ if (packet.for_testing().str() == "end")
+ on_readback_complete();
+ };
+ helper.ReadData(on_consumer_data, [] {});
task_runner.RunUntilCheckpoint("readback.complete");
- consumer.Disconnect();
-
return 0;
}
diff --git a/test/fake_consumer.cc b/test/fake_consumer.cc
deleted file mode 100644
index d1837c7..0000000
--- a/test/fake_consumer.cc
+++ /dev/null
@@ -1,77 +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 "test/fake_consumer.h"
-
-#include <utility>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "perfetto/base/logging.h"
-#include "perfetto/trace/test_event.pbzero.h"
-#include "perfetto/trace/trace_packet.pbzero.h"
-#include "perfetto/traced/traced.h"
-#include "perfetto/tracing/core/trace_packet.h"
-#include "perfetto/tracing/core/trace_writer.h"
-
-namespace perfetto {
-
-FakeConsumer::FakeConsumer(
- const TraceConfig& trace_config,
- std::function<void()> on_connect,
- std::function<void(std::vector<TracePacket>, bool)> packet_callback,
- base::TaskRunner* task_runner)
- : task_runner_(task_runner),
- trace_config_(trace_config),
- on_connect_(on_connect),
- packet_callback_(std::move(packet_callback)) {}
-FakeConsumer::~FakeConsumer() = default;
-
-void FakeConsumer::Connect(const char* socket_name) {
- endpoint_ = ConsumerIPCClient::Connect(socket_name, this, task_runner_);
-}
-
-void FakeConsumer::Disconnect() {
- endpoint_.reset();
-}
-
-void FakeConsumer::OnConnect() {
- on_connect_();
-}
-
-void FakeConsumer::EnableTracing() {
- endpoint_->EnableTracing(trace_config_);
-}
-
-void FakeConsumer::FreeBuffers() {
- endpoint_->FreeBuffers();
-}
-
-void FakeConsumer::ReadTraceData() {
- endpoint_->ReadBuffers();
-}
-
-void FakeConsumer::OnDisconnect() {
- FAIL() << "Consumer unexpectedly disconnected from the service";
-}
-
-void FakeConsumer::OnTracingStop() {}
-
-void FakeConsumer::OnTraceData(std::vector<TracePacket> data, bool has_more) {
- packet_callback_(std::move(data), has_more);
-}
-
-} // namespace perfetto
diff --git a/test/fake_consumer.h b/test/fake_consumer.h
deleted file mode 100644
index d36dbba..0000000
--- a/test/fake_consumer.h
+++ /dev/null
@@ -1,63 +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_FAKE_CONSUMER_H_
-#define TEST_FAKE_CONSUMER_H_
-
-#include <memory>
-#include <vector>
-
-#include "perfetto/tracing/core/consumer.h"
-#include "perfetto/tracing/core/trace_config.h"
-#include "perfetto/tracing/core/trace_packet.h"
-#include "perfetto/tracing/ipc/consumer_ipc_client.h"
-
-#include "src/base/test/test_task_runner.h"
-
-namespace perfetto {
-
-class FakeConsumer : public Consumer {
- public:
- FakeConsumer(
- const TraceConfig& trace_config,
- std::function<void()> on_connect,
- std::function<void(std::vector<TracePacket>, bool)> packet_callback,
- base::TaskRunner* task_runner);
- ~FakeConsumer() override;
-
- void EnableTracing();
- void FreeBuffers();
- void Connect(const char* socket_name);
- void Disconnect();
- void ReadTraceData();
-
- // Consumer implementation.
- void OnConnect() override;
- void OnDisconnect() override;
- void OnTracingStop() override;
- void OnTraceData(std::vector<TracePacket> packets, bool has_more) override;
-
- private:
- base::TaskRunner* const task_runner_;
- const TraceConfig trace_config_;
- std::function<void()> on_connect_;
- std::function<void(std::vector<TracePacket>, bool)> packet_callback_;
- std::unique_ptr<Service::ConsumerEndpoint> endpoint_; // Keep last.
-};
-
-} // namespace perfetto
-
-#endif // TEST_FAKE_CONSUMER_H_
diff --git a/test/fake_producer.cc b/test/fake_producer.cc
index 9dadf52..a81f656 100644
--- a/test/fake_producer.cc
+++ b/test/fake_producer.cc
@@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "perfetto/base/logging.h"
+#include "perfetto/base/time.h"
#include "perfetto/base/utils.h"
#include "perfetto/trace/test_event.pbzero.h"
#include "perfetto/trace/trace_packet.pbzero.h"
@@ -40,7 +41,7 @@
PERFETTO_DCHECK_THREAD(thread_checker_);
task_runner_ = task_runner;
endpoint_ = ProducerIPCClient::Connect(
- socket_name, this, "com.google.perfetto.fake_producer", task_runner);
+ socket_name, this, "android.perfetto.FakeProducer", task_runner);
on_create_data_source_instance_ = std::move(on_create_data_source_instance);
}
@@ -48,8 +49,7 @@
PERFETTO_DCHECK_THREAD(thread_checker_);
DataSourceDescriptor descriptor;
descriptor.set_name(name_);
- endpoint_->RegisterDataSource(descriptor,
- [this](DataSourceID id) { id_ = id; });
+ endpoint_->RegisterDataSource(descriptor);
}
void FakeProducer::OnDisconnect() {
@@ -66,6 +66,8 @@
rnd_engine_ = std::minstd_rand0(source_config.for_testing().seed());
message_count_ = source_config.for_testing().message_count();
message_size_ = source_config.for_testing().message_size();
+ max_messages_per_second_ =
+ source_config.for_testing().max_messages_per_second();
task_runner_->PostTask(on_create_data_source_instance_);
}
@@ -78,18 +80,39 @@
void FakeProducer::ProduceEventBatch(std::function<void()> callback) {
task_runner_->PostTask([this, callback] {
PERFETTO_CHECK(trace_writer_);
-
- size_t payload_size = message_size_ - sizeof(uint32_t);
- PERFETTO_CHECK(payload_size >= sizeof(char));
-
+ PERFETTO_CHECK(message_size_ > 1);
std::unique_ptr<char, base::FreeDeleter> payload(
- static_cast<char*>(malloc(payload_size)));
- memset(payload.get(), '.', payload_size);
- payload.get()[payload_size - 1] = 0;
- for (size_t i = 0; i < message_count_; i++) {
- auto handle = trace_writer_->NewTracePacket();
- handle->set_for_testing()->set_seq_value(rnd_engine_());
- handle->set_for_testing()->set_str(payload.get(), payload_size);
+ static_cast<char*>(malloc(message_size_)));
+ memset(payload.get(), '.', message_size_);
+ payload.get()[message_size_ - 1] = 0;
+
+ base::TimeMillis start = base::GetWallTimeMs();
+ int64_t iterations = 0;
+ size_t messages_to_emit = message_count_;
+ while (messages_to_emit > 0) {
+ size_t messages_in_minibatch =
+ max_messages_per_second_ == 0
+ ? messages_to_emit
+ : std::min(max_messages_per_second_, messages_to_emit);
+ PERFETTO_DCHECK(messages_to_emit >= messages_in_minibatch);
+
+ for (size_t i = 0; i < messages_in_minibatch; i++) {
+ auto handle = trace_writer_->NewTracePacket();
+ handle->set_for_testing()->set_seq_value(rnd_engine_());
+ handle->set_for_testing()->set_str(payload.get(), message_size_);
+ }
+ messages_to_emit -= messages_in_minibatch;
+
+ // Pause until the second boundary to make sure that we are adhering to
+ // the speed limitation.
+ if (max_messages_per_second_ > 0) {
+ int64_t expected_time_taken = ++iterations * 1000;
+ base::TimeMillis time_taken = base::GetWallTimeMs() - start;
+ while (time_taken.count() < expected_time_taken) {
+ usleep((expected_time_taken - time_taken.count()) * 1000);
+ time_taken = base::GetWallTimeMs() - start;
+ }
+ }
}
trace_writer_->Flush(callback);
});
diff --git a/test/fake_producer.h b/test/fake_producer.h
index 568c09b..2495518 100644
--- a/test/fake_producer.h
+++ b/test/fake_producer.h
@@ -58,10 +58,10 @@
base::ThreadChecker thread_checker_;
base::TaskRunner* task_runner_ = nullptr;
std::string name_;
- DataSourceID id_ = 0;
std::minstd_rand0 rnd_engine_;
size_t message_size_ = 0;
size_t message_count_ = 0;
+ size_t max_messages_per_second_ = 0;
std::function<void()> on_create_data_source_instance_;
std::unique_ptr<Service::ProducerEndpoint> endpoint_;
std::unique_ptr<TraceWriter> trace_writer_;
diff --git a/test/test_helper.cc b/test/test_helper.cc
new file mode 100644
index 0000000..24f814b
--- /dev/null
+++ b/test/test_helper.cc
@@ -0,0 +1,112 @@
+/*
+ * 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 "test/test_helper.h"
+
+#include "gtest/gtest.h"
+#include "perfetto/trace/trace_packet.pb.h"
+#include "perfetto/trace/trace_packet.pbzero.h"
+#include "perfetto/traced/traced.h"
+#include "perfetto/tracing/core/trace_packet.h"
+#include "test/task_runner_thread_delegates.h"
+
+namespace perfetto {
+
+// If we're building on Android and starting the daemons ourselves,
+// create the sockets in a world-writable location.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
+ PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
+#define TEST_PRODUCER_SOCK_NAME "/data/local/tmp/traced_producer"
+#define TEST_CONSUMER_SOCK_NAME "/data/local/tmp/traced_consumer"
+#else
+#define TEST_PRODUCER_SOCK_NAME PERFETTO_PRODUCER_SOCK_NAME
+#define TEST_CONSUMER_SOCK_NAME PERFETTO_CONSUMER_SOCK_NAME
+#endif
+
+TestHelper::TestHelper(base::TestTaskRunner* task_runner)
+ : task_runner_(task_runner),
+ service_thread_("perfetto.svc"),
+ producer_thread_("perfetto.prd") {}
+
+void TestHelper::OnConnect() {
+ std::move(continuation_callack_)();
+}
+
+void TestHelper::OnDisconnect() {
+ FAIL() << "Consumer unexpectedly disconnected from the service";
+}
+
+void TestHelper::OnTracingStop() {}
+
+void TestHelper::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
+ for (auto& packet : packets) {
+ ASSERT_TRUE(packet.Decode());
+ if (packet->has_clock_snapshot() || packet->has_trace_config())
+ continue;
+ ASSERT_EQ(protos::TracePacket::kTrustedUid,
+ packet->optional_trusted_uid_case());
+ packet_callback_(*packet);
+ }
+
+ if (!has_more) {
+ packet_callback_ = {};
+ std::move(continuation_callack_)();
+ }
+}
+
+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)));
+#endif
+}
+
+FakeProducer* TestHelper::ConnectFakeProducer() {
+ std::unique_ptr<FakeProducerDelegate> producer_delegate(
+ new FakeProducerDelegate(
+ TEST_PRODUCER_SOCK_NAME,
+ WrapTask(task_runner_->CreateCheckpoint("producer.enabled"))));
+ FakeProducerDelegate* producer_delegate_cached = producer_delegate.get();
+ producer_thread_.Start(std::move(producer_delegate));
+ return producer_delegate_cached->producer();
+}
+
+void TestHelper::ConnectConsumer() {
+ continuation_callack_ = task_runner_->CreateCheckpoint("consumer.connected");
+ endpoint_ =
+ ConsumerIPCClient::Connect(TEST_CONSUMER_SOCK_NAME, this, task_runner_);
+ task_runner_->RunUntilCheckpoint("consumer.connected");
+}
+
+void TestHelper::StartTracing(const TraceConfig& config) {
+ endpoint_->EnableTracing(config);
+ task_runner_->RunUntilCheckpoint("producer.enabled");
+}
+
+void TestHelper::ReadData(
+ std::function<void(const TracePacket::DecodedTracePacket&)> packet_callback,
+ std::function<void()> on_finish_callback) {
+ packet_callback_ = packet_callback;
+ continuation_callack_ = on_finish_callback;
+ endpoint_->ReadBuffers();
+}
+
+std::function<void()> TestHelper::WrapTask(
+ const std::function<void()>& function) {
+ return [this, function] { task_runner_->PostTask(function); };
+}
+
+} // namespace perfetto
diff --git a/test/test_helper.h b/test/test_helper.h
new file mode 100644
index 0000000..87a9be5
--- /dev/null
+++ b/test/test_helper.h
@@ -0,0 +1,66 @@
+/*
+ * 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_TEST_HELPER_H_
+#define TEST_TEST_HELPER_H_
+
+#include "perfetto/tracing/core/consumer.h"
+#include "perfetto/tracing/core/trace_config.h"
+#include "perfetto/tracing/core/trace_packet.h"
+#include "perfetto/tracing/ipc/consumer_ipc_client.h"
+#include "src/base/test/test_task_runner.h"
+#include "test/fake_producer.h"
+#include "test/task_runner_thread.h"
+
+namespace perfetto {
+
+class TestHelper : public Consumer {
+ public:
+ explicit TestHelper(base::TestTaskRunner* task_runner);
+
+ // Consumer implementation.
+ void OnConnect() override;
+ void OnDisconnect() override;
+ void OnTracingStop() override;
+ void OnTraceData(std::vector<TracePacket> packets, bool has_more) override;
+
+ void StartServiceIfRequired();
+ FakeProducer* ConnectFakeProducer();
+ void ConnectConsumer();
+ void StartTracing(const TraceConfig& config);
+ void ReadData(std::function<void(const TracePacket::DecodedTracePacket&)>
+ packet_callback,
+ std::function<void()> on_finish_callback);
+
+ std::function<void()> WrapTask(const std::function<void()>& function);
+
+ TaskRunnerThread* service_thread() { return &service_thread_; }
+ TaskRunnerThread* producer_thread() { return &producer_thread_; }
+
+ private:
+ base::TestTaskRunner* task_runner_ = nullptr;
+
+ std::function<void(const TracePacket::DecodedTracePacket&)> packet_callback_;
+ std::function<void()> continuation_callack_;
+
+ TaskRunnerThread service_thread_;
+ TaskRunnerThread producer_thread_;
+ std::unique_ptr<Service::ConsumerEndpoint> endpoint_; // Keep last.
+};
+
+} // namespace perfetto
+
+#endif // TEST_TEST_HELPER_H_
diff --git a/tools/ftrace_proto_gen/ftrace_proto_gen.cc b/tools/ftrace_proto_gen/ftrace_proto_gen.cc
index 4a1df78..3c25934 100644
--- a/tools/ftrace_proto_gen/ftrace_proto_gen.cc
+++ b/tools/ftrace_proto_gen/ftrace_proto_gen.cc
@@ -103,10 +103,10 @@
}
}
-void PrintTraceToTextMain(const std::set<std::string>& events) {
+void PrintEventFormatterMain(const std::set<std::string>& events) {
printf(
- "\nAdd output to TraceToSystrace for loop in "
- "tools/ftrace_proto_gen/main.cc\n");
+ "\nAdd output to FormatEventText in "
+ "tools/ftrace_proto_gen/ftrace_event_formatter.cc\n");
for (auto event : events) {
printf(
"else if (event.has_%s()) {\nconst auto& inner = event.%s();\nline = "
@@ -115,17 +115,30 @@
}
}
-void PrintTraceToTextUsingStatements(const std::set<std::string>& events) {
- printf("\nAdd output to tools/ftrace_proto_gen/main.cc\n");
+// Add output to ParseInode in ftrace_inode_handler
+void PrintInodeHandlerMain(const std::string& event_name,
+ const perfetto::Proto& proto) {
+ for (const auto& field : proto.fields) {
+ if (Contains(field.name, "ino") && !Contains(field.name, "minor"))
+ printf(
+ "else if (event.has_%s() && event.%s().%s()) {\n*inode = "
+ "static_cast<uint64_t>(event.%s().%s());\n return true;\n} ",
+ event_name.c_str(), event_name.c_str(), field.name.c_str(),
+ event_name.c_str(), field.name.c_str());
+ }
+}
+
+void PrintEventFormatterUsingStatements(const std::set<std::string>& events) {
+ printf("\nAdd output to tools/ftrace_proto_gen/ftrace_event_formatter.cc\n");
for (auto event : events) {
printf("using protos::%sFtraceEvent;\n", ToCamelCase(event).c_str());
}
}
-void PrintTraceToTextFunctions(const std::set<std::string>& events) {
+void PrintEventFormatterFunctions(const std::set<std::string>& events) {
printf(
- "\nAdd output to tools/ftrace_proto_gen/main.cc and then manually go "
- "through format files to match fields\n");
+ "\nAdd output to tools/ftrace_proto_gen/ftrace_event_formatter.cc and "
+ "then manually go through format files to match fields\n");
for (auto event : events) {
printf(
"std::string Format%s(const %sFtraceEvent& event) {"
diff --git a/tools/ftrace_proto_gen/ftrace_proto_gen.h b/tools/ftrace_proto_gen/ftrace_proto_gen.h
index a5be4f4..11cf5cf 100644
--- a/tools/ftrace_proto_gen/ftrace_proto_gen.h
+++ b/tools/ftrace_proto_gen/ftrace_proto_gen.h
@@ -38,9 +38,11 @@
};
void PrintFtraceEventProtoAdditions(const std::set<std::string>& events);
-void PrintTraceToTextMain(const std::set<std::string>& events);
-void PrintTraceToTextUsingStatements(const std::set<std::string>& events);
-void PrintTraceToTextFunctions(const std::set<std::string>& events);
+void PrintEventFormatterMain(const std::set<std::string>& events);
+void PrintEventFormatterUsingStatements(const std::set<std::string>& events);
+void PrintEventFormatterFunctions(const std::set<std::string>& events);
+void PrintInodeHandlerMain(const std::string& event_name,
+ const perfetto::Proto& proto);
bool GenerateProto(const FtraceEvent& format, Proto* proto_out);
std::string InferProtoType(const FtraceEvent::Field& field);
diff --git a/tools/ftrace_proto_gen/main.cc b/tools/ftrace_proto_gen/main.cc
index 33d8abb..c701d39 100644
--- a/tools/ftrace_proto_gen/main.cc
+++ b/tools/ftrace_proto_gen/main.cc
@@ -62,9 +62,12 @@
if (!new_events.empty()) {
perfetto::PrintFtraceEventProtoAdditions(new_events);
- perfetto::PrintTraceToTextMain(new_events);
- perfetto::PrintTraceToTextUsingStatements(new_events);
- perfetto::PrintTraceToTextFunctions(new_events);
+ perfetto::PrintEventFormatterMain(new_events);
+ perfetto::PrintEventFormatterUsingStatements(new_events);
+ perfetto::PrintEventFormatterFunctions(new_events);
+ printf(
+ "\nAdd output to ParseInode in "
+ "tools/ftrace_proto_gen/ftrace_inode_handler.cc\n");
}
for (auto event : events) {
@@ -105,6 +108,9 @@
return 1;
}
+ if (!new_events.empty())
+ PrintInodeHandlerMain(format.name, proto);
+
events_info.push_back(
perfetto::SingleEventInfo(format, proto, group, proto_field_id));
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 728ed23..f71e001 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -43,6 +43,7 @@
'//:perfetto',
'//:traced',
'//:traced_probes',
+ '//:trace_to_text',
]
# Defines a custom init_rc argument to be applied to the corresponding output
@@ -55,6 +56,10 @@
'//:perfetto_trace_protos',
]
+target_host_only = [
+ '//:trace_to_text',
+]
+
# Arguments for the GN output directory.
gn_args = 'target_os="android" target_cpu="arm" is_debug=false build_with_android=true'
@@ -470,7 +475,7 @@
"""
target = desc[target_name]
if target['type'] == 'executable':
- if 'host' in target['toolchain']:
+ if 'host' in target['toolchain'] or target_name in target_host_only:
module_type = 'cc_binary_host'
elif target.get('testonly'):
module_type = 'cc_test'
diff --git a/tools/gen_merged_trace_config b/tools/gen_merged_trace_config
index 9a7abba..135fd02 100755
--- a/tools/gen_merged_trace_config
+++ b/tools/gen_merged_trace_config
@@ -20,6 +20,8 @@
PROTOS = (
'protos/perfetto/config/chrome/chrome_config.proto',
+ 'protos/perfetto/config/inode_file/inode_file_config.proto',
+ 'protos/perfetto/config/process_stats/process_stats_config.proto',
'protos/perfetto/config/data_source_config.proto',
'protos/perfetto/config/ftrace/ftrace_config.proto',
'protos/perfetto/config/test_config.proto',
diff --git a/tools/gen_tracing_cpp_headers_from_protos.py b/tools/gen_tracing_cpp_headers_from_protos.py
index 350c5ad..ce7fdb6 100755
--- a/tools/gen_tracing_cpp_headers_from_protos.py
+++ b/tools/gen_tracing_cpp_headers_from_protos.py
@@ -20,6 +20,8 @@
PROTOS = (
'perfetto/config/chrome/chrome_config.proto',
'perfetto/config/data_source_config.proto',
+ 'perfetto/config/inode_file/inode_file_config.proto',
+ 'perfetto/config/process_stats/process_stats_config.proto',
'perfetto/config/data_source_descriptor.proto',
'perfetto/config/ftrace/ftrace_config.proto',
'perfetto/config/trace_config.proto',
diff --git a/tools/proto_to_cpp/proto_to_cpp.cc b/tools/proto_to_cpp/proto_to_cpp.cc
index 82fe8c0..6696c57 100644
--- a/tools/proto_to_cpp/proto_to_cpp.cc
+++ b/tools/proto_to_cpp/proto_to_cpp.cc
@@ -451,7 +451,9 @@
p->Print(" auto* entry = proto->add_$n$();\n", "n", field->name());
p->Print(" it.ToProto(entry);\n");
} else {
- p->Print(" proto->add_$n$(it);\n", "n", field->name());
+ p->Print(
+ " proto->add_$n$(static_cast<decltype(proto->$n$(0))>(it));\n",
+ "n", field->name());
p->Print(
"static_assert(sizeof(it) == sizeof(proto->$n$(0)), \"size "
"mismatch\");\n",
diff --git a/tools/run_android_test b/tools/run_android_test
index bb92156..83f029d 100755
--- a/tools/run_android_test
+++ b/tools/run_android_test
@@ -114,6 +114,7 @@
parser = argparse.ArgumentParser()
parser.add_argument('--no-cleanup', '-n', action='store_true')
parser.add_argument('--no-data-deps', '-x', action='store_true')
+ parser.add_argument('--env', '-e', action='append')
parser.add_argument('out_dir', help='out/android/')
parser.add_argument('test_name', help='perfetto_unittests')
parser.add_argument('cmd_args', nargs=argparse.REMAINDER)
@@ -138,10 +139,10 @@
# LLVM sanitizers require to sideload a libclangrtXX.so on the device.
sanitizer_libs = os.path.join(args.out_dir, 'sanitizer_libs')
- env = ''
+ env = ' '.join(args.env if args.env is not None else []) + ' '
if os.path.exists(sanitizer_libs):
AdbCall('push', sanitizer_libs, target_dir)
- env = 'LD_LIBRARY_PATH="%s/sanitizer_libs" ' % (target_dir)
+ env += 'LD_LIBRARY_PATH="%s/sanitizer_libs" ' % (target_dir)
cmd = 'cd %s;' % target_dir;
binary = env + './%s' % args.test_name
cmd += binary
diff --git a/tools/tmux b/tools/tmux
index 568fc78..1e4b3d4 100755
--- a/tools/tmux
+++ b/tools/tmux
@@ -164,8 +164,12 @@
tmux select-pane -t 2
tmux -2 attach-session -t demo
-reset
-TRACE=$HOME/Downloads/trace.json
-echo -e "\n\x1b[32mPulling trace into $TRACE\x1b[0m"
-pull trace $TMPDIR/trace.protobuf
-$OUT/trace_to_text systrace < $TMPDIR/trace.protobuf > $TRACE
+
+reset_tracing
+
+TRACE=$HOME/Downloads/trace
+pull trace /tmp/trace.protobuf
+echo -e "\n\x1b[32mPulling trace into $TRACE.pbtext\x1b[0m"
+$OUT/trace_to_text text < /tmp/trace.protobuf > $TRACE.pbtext
+echo -e "\n\x1b[32mPulling trace into $TRACE.json\x1b[0m"
+$OUT/trace_to_text systrace < /tmp/trace.protobuf > $TRACE.json
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index 90e1233c..5de6da9 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -12,33 +12,48 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import("../../gn/perfetto.gni")
+
+source_set("lib") {
+ testonly = true
+ deps = [
+ "../../gn:default_deps",
+ "../../gn:protobuf_full_deps",
+ "../../protos/perfetto/trace:lite",
+ ]
+ sources = [
+ "ftrace_event_formatter.cc",
+ "ftrace_event_formatter.h",
+ "ftrace_inode_handler.cc",
+ "ftrace_inode_handler.h",
+ "main.cc",
+ ]
+}
+
if (current_toolchain == host_toolchain) {
executable("trace_to_text_host") {
testonly = true
deps = [
+ ":lib",
"../../gn:default_deps",
- "../../gn:protobuf_full_deps",
- "../../protos/perfetto/trace:lite",
- ]
- sources = [
- "ftrace_event_formatter.cc",
- "ftrace_event_formatter.h",
- "main.cc",
]
}
}
-copy("trace_to_text") {
- testonly = true
- host_out_dir_ =
- get_label_info(":trace_to_text_host($host_toolchain)", "root_out_dir")
- deps = [
- ":trace_to_text_host($host_toolchain)",
- ]
- sources = [
- "${host_out_dir_}/trace_to_text_host",
- ]
- outputs = [
- "${root_out_dir}/trace_to_text",
- ]
+# The one for the android tree is defined in the top-level BUILD.gn.
+if (!build_with_android) {
+ copy("trace_to_text") {
+ testonly = true
+ host_out_dir_ =
+ get_label_info(":trace_to_text_host($host_toolchain)", "root_out_dir")
+ deps = [
+ ":trace_to_text_host($host_toolchain)",
+ ]
+ sources = [
+ "${host_out_dir_}/trace_to_text_host",
+ ]
+ outputs = [
+ "${root_out_dir}/trace_to_text",
+ ]
+ }
}
diff --git a/tools/trace_to_text/ftrace_event_formatter.cc b/tools/trace_to_text/ftrace_event_formatter.cc
index 1120d7a..bdf7d88 100644
--- a/tools/trace_to_text/ftrace_event_formatter.cc
+++ b/tools/trace_to_text/ftrace_event_formatter.cc
@@ -17,6 +17,15 @@
#include "tools/trace_to_text/ftrace_event_formatter.h"
#include <inttypes.h>
+#include <algorithm>
+#include <string>
+
+#include "perfetto/base/build_config.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
+#include <sys/sysmacros.h> // For major() / minor()
+#endif
namespace perfetto {
namespace {
@@ -370,7 +379,7 @@
sprintf(line,
"sched_switch: prev_comm=%s "
"prev_pid=%d prev_prio=%d prev_state=%s ==> next_comm=%s next_pid=%d "
- "next_prio=%d\\n",
+ "next_prio=%d",
sched_switch.prev_comm().c_str(), sched_switch.prev_pid(),
sched_switch.prev_prio(),
GetSchedSwitchFlag(sched_switch.prev_state()),
@@ -383,7 +392,7 @@
char line[2048];
sprintf(line,
"sched_wakeup: comm=%s "
- "pid=%d prio=%d success=%d target_cpu=%03d\\n",
+ "pid=%d prio=%d success=%d target_cpu=%03d",
sched_wakeup.comm().c_str(), sched_wakeup.pid(), sched_wakeup.prio(),
sched_wakeup.success(), sched_wakeup.target_cpu());
return std::string(line);
@@ -392,24 +401,31 @@
std::string FormatSchedBlockedReason(
const SchedBlockedReasonFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_blocked_reason: pid=%d iowait=%d caller=%llxS\\n",
+ sprintf(line, "sched_blocked_reason: pid=%d iowait=%d caller=%llxS",
event.pid(), event.io_wait(), event.caller());
return std::string(line);
}
std::string FormatPrint(const PrintFtraceEvent& print) {
- char line[2048];
- std::string msg = print.buf();
+ std::string line = "tracing_mark_write: ";
+ size_t dst = line.size();
+ line.resize(2048);
+ const std::string& msg = print.buf();
+
// Remove any newlines in the message. It's not entirely clear what the right
// behaviour is here. Maybe we should escape them instead?
- msg.erase(std::remove(msg.begin(), msg.end(), '\n'), msg.end());
- sprintf(line, "tracing_mark_write: %s\\n", msg.c_str());
- return std::string(line);
+ for (size_t src = 0; src < msg.size() && dst < line.size() - 1; src++) {
+ char c = msg[src];
+ if (c != '\n')
+ line[dst++] = c;
+ }
+ line.resize(dst);
+ return line;
}
std::string FormatCpuFrequency(const CpuFrequencyFtraceEvent& event) {
char line[2048];
- sprintf(line, "cpu_frequency: state=%" PRIu32 " cpu_id=%" PRIu32 "\\n",
+ sprintf(line, "cpu_frequency: state=%" PRIu32 " cpu_id=%" PRIu32,
event.state(), event.cpu_id());
return std::string(line);
}
@@ -419,21 +435,21 @@
char line[2048];
sprintf(line,
"cpu_frequency_limits: min_freq=%" PRIu32 "max_freq=%" PRIu32
- " cpu_id=%" PRIu32 "\\n",
+ " cpu_id=%" PRIu32,
event.min_freq(), event.max_freq(), event.cpu_id());
return std::string(line);
}
std::string FormatCpuIdle(const CpuIdleFtraceEvent& event) {
char line[2048];
- sprintf(line, "cpu_idle: state=%" PRIu32 " cpu_id=%" PRIu32 "\\n",
- event.state(), event.cpu_id());
+ sprintf(line, "cpu_idle: state=%" PRIu32 " cpu_id=%" PRIu32, event.state(),
+ event.cpu_id());
return std::string(line);
}
std::string FormatClockSetRate(const ClockSetRateFtraceEvent& event) {
char line[2048];
- sprintf(line, "clock_set_rate: %s state=%llu cpu_id=%llu\\n",
+ sprintf(line, "clock_set_rate: %s state=%llu cpu_id=%llu",
event.name().empty() ? "todo" : event.name().c_str(), event.state(),
event.cpu_id());
return std::string(line);
@@ -441,7 +457,7 @@
std::string FormatClockEnable(const ClockEnableFtraceEvent& event) {
char line[2048];
- sprintf(line, "clock_enable: %s state=%llu cpu_id=%llu\\n",
+ sprintf(line, "clock_enable: %s state=%llu cpu_id=%llu",
event.name().empty() ? "todo" : event.name().c_str(), event.state(),
event.cpu_id());
return std::string(line);
@@ -449,7 +465,7 @@
std::string FormatClockDisable(const ClockDisableFtraceEvent& event) {
char line[2048];
- sprintf(line, "clock_disable: %s state=%llu cpu_id=%llu\\n",
+ sprintf(line, "clock_disable: %s state=%llu cpu_id=%llu",
event.name().empty() ? "todo" : event.name().c_str(), event.state(),
event.cpu_id());
return std::string(line);
@@ -457,27 +473,26 @@
std::string FormatTracingMarkWrite(const TracingMarkWriteFtraceEvent& event) {
char line[2048];
- sprintf(line, "tracing_mark_write: %s|%d|%s\\n",
- event.trace_begin() ? "B" : "E", event.pid(),
- event.trace_name().c_str());
+ sprintf(line, "tracing_mark_write: %s|%d|%s", event.trace_begin() ? "B" : "E",
+ event.pid(), event.trace_name().c_str());
return std::string(line);
}
std::string FormatBinderLocked(const BinderLockedFtraceEvent& event) {
char line[2048];
- sprintf(line, "binder_locked: tag=%s\\n", event.tag().c_str());
+ sprintf(line, "binder_locked: tag=%s", event.tag().c_str());
return std::string(line);
}
std::string FormatBinderUnlock(const BinderUnlockFtraceEvent& event) {
char line[2048];
- sprintf(line, "binder_unlock: tag=%s\\n", event.tag().c_str());
+ sprintf(line, "binder_unlock: tag=%s", event.tag().c_str());
return std::string(line);
}
std::string FormatBinderLock(const BinderLockFtraceEvent& event) {
char line[2048];
- sprintf(line, "binder_lock: tag=%s\\n", event.tag().c_str());
+ sprintf(line, "binder_lock: tag=%s", event.tag().c_str());
return std::string(line);
}
@@ -485,7 +500,7 @@
char line[2048];
sprintf(line,
"binder_transaction: transaction=%d dest_node=%d dest_proc=%d "
- "dest_thread=%d reply=%d flags=0x%x code=0x%x\\n",
+ "dest_thread=%d reply=%d flags=0x%x code=0x%x",
event.debug_id(), event.target_node(), event.to_proc(),
event.to_thread(), event.reply(), event.flags(), event.code());
return std::string(line);
@@ -494,7 +509,7 @@
std::string FormatBinderTransactionReceived(
const BinderTransactionReceivedFtraceEvent& event) {
char line[2048];
- sprintf(line, "binder_transaction_received: transaction=%d\\n",
+ sprintf(line, "binder_transaction_received: transaction=%d",
event.debug_id());
return std::string(line);
}
@@ -502,7 +517,7 @@
std::string FormatExt4SyncFileEnter(const Ext4SyncFileEnterFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_sync_file_enter: dev %d,%d ino %lu parent %lu datasync %d \\n",
+ "ext4_sync_file_enter: dev %d,%d ino %lu parent %lu datasync %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.parent(), event.datasync());
return std::string(line);
@@ -510,7 +525,7 @@
std::string FormatExt4SyncFileExit(const Ext4SyncFileExitFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_sync_file_exit: dev %d,%d ino %lu ret %d\\n",
+ sprintf(line, "ext4_sync_file_exit: dev %d,%d ino %lu ret %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.ret());
return std::string(line);
@@ -519,7 +534,7 @@
std::string FormatExt4DaWriteBegin(const Ext4DaWriteBeginFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_da_write_begin: dev %d,%d ino %lu pos %lld len %u flags %u\\n",
+ "ext4_da_write_begin: dev %d,%d ino %lu pos %lld len %u flags %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pos(), event.len(), event.flags());
return std::string(line);
@@ -528,7 +543,7 @@
std::string FormatExt4DaWriteEnd(const Ext4DaWriteEndFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_da_write_end: dev %d,%d ino %lu pos %lld len %u copied %u\\n",
+ "ext4_da_write_end: dev %d,%d ino %lu pos %lld len %u copied %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pos(), event.len(), event.copied());
return std::string(line);
@@ -536,39 +551,38 @@
std::string FormatBlockRqIssue(const BlockRqIssueFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_rq_issue: %d,%d %s %u (%s) %llu + %u [%s]\\n",
+ sprintf(line, "block_rq_issue: %d,%d %s %u (%s) %llu + %u [%s]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
event.bytes(), event.cmd().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatI2cRead(const I2cReadFtraceEvent& event) {
char line[2048];
- sprintf(line, "i2c_read: i2c-%d #%u a=%03x f=%04x l=%u\\n",
- event.adapter_nr(), event.msg_nr(), event.addr(), event.flags(),
- event.len());
+ sprintf(line, "i2c_read: i2c-%d #%u a=%03x f=%04x l=%u", event.adapter_nr(),
+ event.msg_nr(), event.addr(), event.flags(), event.len());
return std::string(line);
}
std::string FormatI2cResult(const I2cResultFtraceEvent& event) {
char line[2048];
- sprintf(line, "i2c_result: i2c-%d n=%u ret=%d\\n", event.adapter_nr(),
+ sprintf(line, "i2c_result: i2c-%d n=%u ret=%d", event.adapter_nr(),
event.nr_msgs(), event.ret());
return std::string(line);
}
std::string FormatIrqHandlerEntry(const IrqHandlerEntryFtraceEvent& event) {
char line[2048];
- sprintf(line, "irq_handler_entry: irq=%d name=%s\\n", event.irq(),
+ sprintf(line, "irq_handler_entry: irq=%d name=%s", event.irq(),
event.name().c_str());
return std::string(line);
}
std::string FormatIrqHandlerExit(const IrqHandlerExitFtraceEvent& event) {
char line[2048];
- sprintf(line, "irq_handler_exit: irq=%d ret=%s\\n", event.irq(),
+ sprintf(line, "irq_handler_exit: irq=%d ret=%s", event.irq(),
event.ret() ? "handled" : "unhandled");
return std::string(line);
}
@@ -576,7 +590,7 @@
std::string FormatMmVmscanKswapdWake(
const MmVmscanKswapdWakeFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_vmscan_kswapd_wake: nid=%d order=%d\\n", event.nid(),
+ sprintf(line, "mm_vmscan_kswapd_wake: nid=%d order=%d", event.nid(),
event.order());
return std::string(line);
}
@@ -584,77 +598,76 @@
std::string FormatMmVmscanKswapdSleep(
const MmVmscanKswapdSleepFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_vmscan_kswapd_sleep: nid=%d\\n", event.nid());
+ sprintf(line, "mm_vmscan_kswapd_sleep: nid=%d", event.nid());
return std::string(line);
}
std::string FormatRegulatorEnable(const RegulatorEnableFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_enable: name=%s\\n", event.name().c_str());
+ sprintf(line, "regulator_enable: name=%s", event.name().c_str());
return std::string(line);
}
std::string FormatRegulatorEnableDelay(
const RegulatorEnableDelayFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_enable_delay: name=%s\\n", event.name().c_str());
+ sprintf(line, "regulator_enable_delay: name=%s", event.name().c_str());
return std::string(line);
}
std::string FormatRegulatorEnableComplete(
const RegulatorEnableCompleteFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_enable_complete: name=%s\\n", event.name().c_str());
+ sprintf(line, "regulator_enable_complete: name=%s", event.name().c_str());
return std::string(line);
}
std::string FormatRegulatorDisable(const RegulatorDisableFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_disable: name=%s\\n", event.name().c_str());
+ sprintf(line, "regulator_disable: name=%s", event.name().c_str());
return std::string(line);
}
std::string FormatRegulatorDisableComplete(
const RegulatorDisableCompleteFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_disable_complete: name=%s\\n", event.name().c_str());
+ sprintf(line, "regulator_disable_complete: name=%s", event.name().c_str());
return std::string(line);
}
std::string FormatRegulatorSetVoltage(
const RegulatorSetVoltageFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_set_voltage: name=%s (%d-%d)\\n",
- event.name().c_str(), event.min(), event.max());
+ sprintf(line, "regulator_set_voltage: name=%s (%d-%d)", event.name().c_str(),
+ event.min(), event.max());
return std::string(line);
}
std::string FormatRegulatorSetVoltageComplete(
const RegulatorSetVoltageCompleteFtraceEvent& event) {
char line[2048];
- sprintf(line, "regulator_set_voltage_complete: name=%s, val=%u\\n",
+ sprintf(line, "regulator_set_voltage_complete: name=%s, val=%u",
event.name().c_str(), event.val());
return std::string(line);
}
std::string FormatSchedCpuHotplug(const SchedCpuHotplugFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_cpu_hotplug: cpu %d %s error=%d\\n",
- event.affected_cpu(), event.status() ? "online" : "offline",
- event.error());
+ sprintf(line, "sched_cpu_hotplug: cpu %d %s error=%d", event.affected_cpu(),
+ event.status() ? "online" : "offline", event.error());
return std::string(line);
}
std::string FormatSyncTimeline(const SyncTimelineFtraceEvent& event) {
char line[2048];
- sprintf(line, "sync_timeline: name=%s value=%s\\n", event.name().c_str(),
+ sprintf(line, "sync_timeline: name=%s value=%s", event.name().c_str(),
event.value().c_str());
return std::string(line);
}
std::string FormatSyncWait(const SyncWaitFtraceEvent& event) {
char line[2048];
- sprintf(line, "sync_wait: %s name=%s state=%d\\n",
+ sprintf(line, "sync_wait: %s name=%s state=%d",
event.begin() ? "begin" : "end", event.name().c_str(),
event.status());
return std::string(line);
@@ -662,28 +675,28 @@
std::string FormatSyncPt(const SyncPtFtraceEvent& event) {
char line[2048];
- sprintf(line, "sync_pt: name=%s value=%s\\n", event.timeline().c_str(),
+ sprintf(line, "sync_pt: name=%s value=%s", event.timeline().c_str(),
event.value().c_str());
return std::string(line);
}
std::string FormatSoftirqRaise(const SoftirqRaiseFtraceEvent& event) {
char line[2048];
- sprintf(line, "softirq_raise: vec=%u [action=%s]\\n", event.vec(),
+ sprintf(line, "softirq_raise: vec=%u [action=%s]", event.vec(),
SoftirqArray[event.vec()]);
return std::string(line);
}
std::string FormatSoftirqEntry(const SoftirqEntryFtraceEvent& event) {
char line[2048];
- sprintf(line, "softirq_entry: vec=%u [action=%s]\\n", event.vec(),
+ sprintf(line, "softirq_entry: vec=%u [action=%s]", event.vec(),
SoftirqArray[event.vec()]);
return std::string(line);
}
std::string FormatSoftirqExit(const SoftirqExitFtraceEvent& event) {
char line[2048];
- sprintf(line, "softirq_exit: vec=%u [action=%s]\\n", event.vec(),
+ sprintf(line, "softirq_exit: vec=%u [action=%s]", event.vec(),
SoftirqArray[event.vec()]);
return std::string(line);
}
@@ -691,18 +704,16 @@
std::string FormatI2cWrite(const I2cWriteFtraceEvent& event) {
char line[2048];
// TODO(hjd): Check event.buf().
- sprintf(line, "i2c_write: i2c-%d #%u a=%03x f=%04x l=%u\\n",
- event.adapter_nr(), event.msg_nr(), event.addr(), event.flags(),
- event.len());
+ sprintf(line, "i2c_write: i2c-%d #%u a=%03x f=%04x l=%u", event.adapter_nr(),
+ event.msg_nr(), event.addr(), event.flags(), event.len());
return std::string(line);
}
std::string FormatI2cReply(const I2cReplyFtraceEvent& event) {
char line[2048];
// TODO(hjd): Check event.buf().
- sprintf(line, "i2c_reply: i2c-%d #%u a=%03x f=%04x l=%u\\n",
- event.adapter_nr(), event.msg_nr(), event.addr(), event.flags(),
- event.len());
+ sprintf(line, "i2c_reply: i2c-%d #%u a=%03x f=%04x l=%u", event.adapter_nr(),
+ event.msg_nr(), event.addr(), event.flags(), event.len());
return std::string(line);
}
@@ -710,7 +721,7 @@
std::string FormatMmVmscanDirectReclaimBegin(
const MmVmscanDirectReclaimBeginFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_vmscan_direct_reclaim_begin: order=%d may_writepage=%d\\n",
+ sprintf(line, "mm_vmscan_direct_reclaim_begin: order=%d may_writepage=%d",
event.order(), event.may_writepage());
return std::string(line);
}
@@ -718,7 +729,7 @@
std::string FormatMmVmscanDirectReclaimEnd(
const MmVmscanDirectReclaimEndFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_vmscan_direct_reclaim_end: nr_reclaimed=%llu\\n",
+ sprintf(line, "mm_vmscan_direct_reclaim_end: nr_reclaimed=%llu",
event.nr_reclaimed());
return std::string(line);
}
@@ -727,7 +738,7 @@
char line[2048];
sprintf(line,
"lowmemory_kill: %s (%d), page cache %lldkB (limit %lldkB), free "
- "%lldKb\\n",
+ "%lldKb",
event.comm().c_str(), event.pid(), event.pagecache_size(),
event.pagecache_limit(), event.free());
return std::string(line);
@@ -736,7 +747,7 @@
std::string FormatWorkqueueExecuteStart(
const WorkqueueExecuteStartFtraceEvent& event) {
char line[2048];
- sprintf(line, "workqueue_execute_start: work struct %llx: function %llxf\\n",
+ sprintf(line, "workqueue_execute_start: work struct %llx: function %llxf",
event.work(), event.function());
return std::string(line);
}
@@ -744,7 +755,7 @@
std::string FormatWorkqueueExecuteEnd(
const WorkqueueExecuteEndFtraceEvent& event) {
char line[2048];
- sprintf(line, "workqueue_execute_end: work struct %llx\\n", event.work());
+ sprintf(line, "workqueue_execute_end: work struct %llx", event.work());
return std::string(line);
}
@@ -754,7 +765,7 @@
sprintf(
line,
"workqueue_queue_work: work struct=%llx function=%llxf workqueue=%llx "
- "req_cpu=%u cpu=%u\\n",
+ "req_cpu=%u cpu=%u",
event.work(), event.function(), event.workqueue(), event.req_cpu(),
event.cpu());
return std::string(line);
@@ -763,7 +774,7 @@
std::string FormatWorkqueueActivateWork(
const WorkqueueActivateWorkFtraceEvent& event) {
char line[2048];
- sprintf(line, "workqueue_activate_work: work struct %llx\\n", event.work());
+ sprintf(line, "workqueue_activate_work: work struct %llx", event.work());
return std::string(line);
}
@@ -771,7 +782,7 @@
char line[2048];
sprintf(line,
"mm_compaction_begin: zone_start=0x%llx migrate_pfn=0x%llx "
- "free_pfn=0x%llx zone_end=0x%llx, mode=%s\\n",
+ "free_pfn=0x%llx zone_end=0x%llx, mode=%s",
event.zone_start(), event.migrate_pfn(), event.free_pfn(),
event.zone_end(), event.sync() ? "sync" : "async");
return std::string(line);
@@ -782,7 +793,7 @@
char line[2048];
sprintf(line,
"mm_compaction_defer_compaction: node=%d zone=%-8s order=%d "
- "order_failed=%d consider=%u limit=%lu\\n",
+ "order_failed=%d consider=%u limit=%lu",
event.nid(), MmCompactionSuitableArray[event.idx()], event.order(),
event.order_failed(), event.considered(), 1UL << event.defer_shift());
return std::string(line);
@@ -793,7 +804,7 @@
char line[2048];
sprintf(line,
"mm_compaction_deferred: node=%d zone=%-8s order=%d order_failed=%d "
- "consider=%u limit=%lu\\n",
+ "consider=%u limit=%lu",
event.nid(), MmCompactionSuitableArray[event.idx()], event.order(),
event.order_failed(), event.considered(), 1UL << event.defer_shift());
return std::string(line);
@@ -804,7 +815,7 @@
char line[2048];
sprintf(line,
"mm_compaction_defer_reset: node=%d zone=%-8s order=%d "
- "order_failed=%d consider=%u limit=%lu\\n",
+ "order_failed=%d consider=%u limit=%lu",
event.nid(), MmCompactionSuitableArray[event.idx()], event.order(),
event.order_failed(), event.considered(), 1UL << event.defer_shift());
return std::string(line);
@@ -814,7 +825,7 @@
char line[2048];
sprintf(line,
"mm_compaction_end: zone_start=0x%llx migrate_pfn=0x%llx "
- "free_pfn=0x%llx zone_end=0x%llx, mode=%s status=%s\\n",
+ "free_pfn=0x%llx zone_end=0x%llx, mode=%s status=%s",
event.zone_start(), event.migrate_pfn(), event.free_pfn(),
event.zone_end(), event.sync() ? "sync" : "aysnc",
MmCompactionRetArray[event.status()]);
@@ -824,7 +835,7 @@
std::string FormatMmCompactionFinished(
const MmCompactionFinishedFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_compaction_finished: node=%d zone=%-8s order=%d ret=%s\\n",
+ sprintf(line, "mm_compaction_finished: node=%d zone=%-8s order=%d ret=%s",
event.nid(), MmCompactionSuitableArray[event.idx()], event.order(),
MmCompactionRetArray[event.ret()]);
return std::string(line);
@@ -835,7 +846,7 @@
char line[2048];
sprintf(line,
"mm_compaction_isolate_freepages: range=(0x%llx ~ 0x%llx) "
- "nr_scanned=%llu nr_taken=%llu\\n",
+ "nr_scanned=%llu nr_taken=%llu",
event.start_pfn(), event.end_pfn(), event.nr_scanned(),
event.nr_taken());
return std::string(line);
@@ -846,7 +857,7 @@
char line[2048];
sprintf(line,
"mm_compaction_isolate_migratepages: range=(0x%llx ~ 0x%llx) "
- "nr_scanned=%llu nr_taken=%llu\\n",
+ "nr_scanned=%llu nr_taken=%llu",
event.start_pfn(), event.end_pfn(), event.nr_scanned(),
event.nr_taken());
return std::string(line);
@@ -855,7 +866,7 @@
std::string FormatMmCompactionKcompactdSleep(
const MmCompactionKcompactdSleepFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_compaction_kcompactd_sleep: nid=%d\\n", event.nid());
+ sprintf(line, "mm_compaction_kcompactd_sleep: nid=%d", event.nid());
return std::string(line);
}
@@ -863,7 +874,7 @@
const MmCompactionKcompactdWakeFtraceEvent& event) {
char line[2048];
sprintf(line,
- "mm_compaction_kcompactd_wake: nid=%d order=%d classzone_idx=%-8s\\n",
+ "mm_compaction_kcompactd_wake: nid=%d order=%d classzone_idx=%-8s",
event.nid(), event.order(),
MmCompactionSuitableArray[event.classzone_idx()]);
return std::string(line);
@@ -872,8 +883,7 @@
std::string FormatMmCompactionMigratepages(
const MmCompactionMigratepagesFtraceEvent& event) {
char line[2048];
- sprintf(line,
- "mm_compaction_migratepages: nr_migrated=%llu nr_failed=%llu\\n",
+ sprintf(line, "mm_compaction_migratepages: nr_migrated=%llu nr_failed=%llu",
event.nr_migrated(), event.nr_failed());
return std::string(line);
}
@@ -881,7 +891,7 @@
std::string FormatMmCompactionSuitable(
const MmCompactionSuitableFtraceEvent& event) {
char line[2048];
- sprintf(line, "mm_compaction_suitable: node=%d zone=%-8s order=%d ret=%s\\n",
+ sprintf(line, "mm_compaction_suitable: node=%d zone=%-8s order=%d ret=%s",
event.nid(), MmCompactionSuitableArray[event.idx()], event.order(),
MmCompactionRetArray[event.ret()]);
return std::string(line);
@@ -890,48 +900,46 @@
std::string FormatMmCompactionTryToCompactPages(
const MmCompactionTryToCompactPagesFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "mm_compaction_try_to_compact_pages: order=%d gfp_mask=0x%x mode=%d\\n",
- event.order(), event.gfp_mask(),
- event.mode()); // convert to int?
+ sprintf(line,
+ "mm_compaction_try_to_compact_pages: order=%d gfp_mask=0x%x mode=%d",
+ event.order(), event.gfp_mask(),
+ event.mode()); // convert to int?
return std::string(line);
}
std::string FormatMmCompactionWakeupKcompactd(
const MmCompactionWakeupKcompactdFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "mm_compaction_wakeup_kcompactd: nid=%d order=%d classzone_idx=%-8s\\n",
- event.nid(), event.order(),
- MmCompactionSuitableArray[event.classzone_idx()]);
+ sprintf(line,
+ "mm_compaction_wakeup_kcompactd: nid=%d order=%d classzone_idx=%-8s",
+ event.nid(), event.order(),
+ MmCompactionSuitableArray[event.classzone_idx()]);
return std::string(line);
}
std::string FormatSuspendResume(const SuspendResumeFtraceEvent& event) {
char line[2048];
- sprintf(line, "suspend_resume: %s[%u] %s\\n", event.action().c_str(),
+ sprintf(line, "suspend_resume: %s[%u] %s", event.action().c_str(),
event.val(), event.start() ? "begin" : "end");
return std::string(line);
}
std::string FormatSchedWakeupNew(const SchedWakeupNewFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_wakeup_new: comm=%s pid=%d prio=%d target_cpu=%03d\\n",
+ sprintf(line, "sched_wakeup_new: comm=%s pid=%d prio=%d target_cpu=%03d",
event.comm().c_str(), event.pid(), event.prio(), event.target_cpu());
return std::string(line);
}
std::string FormatSchedProcessExec(const SchedProcessExecFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_process_exec: filename=%s pid=%d old_pid=%d\\n",
+ sprintf(line, "sched_process_exec: filename=%s pid=%d old_pid=%d",
event.filename().c_str(), event.pid(), event.old_pid());
return std::string(line);
}
std::string FormatSchedProcessExit(const SchedProcessExitFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_process_exit: comm=%s pid=%d tgid=%d prio=%d\\n",
+ sprintf(line, "sched_process_exit: comm=%s pid=%d tgid=%d prio=%d",
event.comm().c_str(), event.pid(), event.tgid(), event.prio());
return std::string(line);
}
@@ -939,27 +947,27 @@
char line[2048];
sprintf(line,
"sched_process_fork: parent_comm=%s parent_pid=%d child_comm=%s "
- "child_pid=%d\\n",
+ "child_pid=%d",
event.parent_comm().c_str(), event.parent_pid(),
event.child_comm().c_str(), event.child_pid());
return std::string(line);
}
std::string FormatSchedProcessFree(const SchedProcessFreeFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_process_free: comm=%s pid=%d prio=%d\\n",
+ sprintf(line, "sched_process_free: comm=%s pid=%d prio=%d",
event.comm().c_str(), event.pid(), event.prio());
return std::string(line);
}
std::string FormatSchedProcessHang(const SchedProcessHangFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_process_hang: comm=%s pid=%d\\n", event.comm().c_str(),
+ sprintf(line, "sched_process_hang: comm=%s pid=%d", event.comm().c_str(),
event.pid());
return std::string(line);
}
std::string FormatSchedProcessWait(const SchedProcessWaitFtraceEvent& event) {
char line[2048];
- sprintf(line, "sched_process_wait: comm=%s pid=%d\\n", event.comm().c_str(),
+ sprintf(line, "sched_process_wait: comm=%s pid=%d", event.comm().c_str(),
event.pid());
return std::string(line);
}
@@ -967,7 +975,7 @@
std::string FormatTaskNewtask(const TaskNewtaskFtraceEvent& event) {
char line[2048];
sprintf(line,
- "task_newtask: comm=%s pid=%d clone_flags=%llu oom_score_adj=%d\\n",
+ "task_newtask: comm=%s pid=%d clone_flags=%llu oom_score_adj=%d",
event.comm().c_str(), event.pid(), event.clone_flags(),
event.oom_score_adj());
return std::string(line);
@@ -975,7 +983,7 @@
std::string FormatTaskRename(const TaskRenameFtraceEvent& event) {
char line[2048];
- sprintf(line, "task_rename: pid=%d oldcomm=%s newcomm=%s oom_score_adj=%d\\n",
+ sprintf(line, "task_rename: pid=%d oldcomm=%s newcomm=%s oom_score_adj=%d",
event.pid(), event.newcomm().c_str(), event.oldcomm().c_str(),
event.oom_score_adj());
return std::string(line);
@@ -983,9 +991,9 @@
std::string FormatBlockBioBackmerge(const BlockBioBackmergeFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_bio_backmerge: %d,%d %s %llu + %u [%s]\\n",
+ sprintf(line, "block_bio_backmerge: %d,%d %s %llu + %u [%s]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
@@ -994,45 +1002,46 @@
char line[2048];
sprintf(line,
"block_bio_bounce:"
- "%d,%d %s %llu + %u [%s]\\n",
+ "%d,%d %s %llu + %u [%s]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatBlockBioComplete(const BlockBioCompleteFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_bio_complete: %d,%d %s %llu + %u [%d]\\n",
+ sprintf(line, "block_bio_complete: %d,%d %s %llu + %u [%d]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(), event.error());
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
+ event.error());
return std::string(line);
}
std::string FormatBlockBioFrontmerge(
const BlockBioFrontmergeFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_bio_frontmerge: %d,%d %s %llu + %u [%s]\\n",
+ sprintf(line, "block_bio_frontmerge: %d,%d %s %llu + %u [%s]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatBlockBioQueue(const BlockBioQueueFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_bio_queue: %d,%d %s %llu + %u [%s]\\n",
- major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ sprintf(line, "block_bio_queue: %d,%d %s %llu + %u [%s]", major(event.dev()),
+ minor(event.dev()), event.rwbs().c_str(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatBlockBioRemap(const BlockBioRemapFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_bio_remap: %d,%d %s %llu + %u <- (%d,%d) %llu\\n",
+ sprintf(line, "block_bio_remap: %d,%d %s %llu + %u <- (%d,%d) %llu",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
major(event.dev()), minor(event.dev()),
(unsigned long long)event.old_sector());
return std::string(line);
@@ -1040,60 +1049,61 @@
std::string FormatBlockDirtyBuffer(const BlockDirtyBufferFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_dirty_buffer: %d,%d sector=%llu size=%zu\\n",
+ sprintf(line, "block_dirty_buffer: %d,%d sector=%llu size=%zu",
major(event.dev()), minor(event.dev()),
- (unsigned long long)event.sector(), (unsigned long)event.size());
+ static_cast<unsigned long long>(event.sector()),
+ static_cast<size_t>(event.size()));
return std::string(line);
}
std::string FormatBlockGetrq(const BlockGetrqFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_getrq: %d,%d %s %llu + %u [%s]\\n", major(event.dev()),
+ sprintf(line, "block_getrq: %d,%d %s %llu + %u [%s]", major(event.dev()),
minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatBlockPlug(const BlockPlugFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_plug: comm=[%s]\\n", event.comm().c_str());
+ sprintf(line, "block_plug: comm=[%s]", event.comm().c_str());
return std::string(line);
}
std::string FormatBlockRqAbort(const BlockRqAbortFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_rq_abort: %d,%d %s (%s) %llu + %u [%d]\\n",
+ sprintf(line, "block_rq_abort: %d,%d %s (%s) %llu + %u [%d]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- event.cmd().c_str(), (unsigned long long)event.sector(),
+ event.cmd().c_str(), static_cast<unsigned long long>(event.sector()),
event.nr_sector(), event.errors());
return std::string(line);
}
std::string FormatBlockRqComplete(const BlockRqCompleteFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_rq_complete: %d,%d %s (%s) %llu + %u [%d]\\n",
+ sprintf(line, "block_rq_complete: %d,%d %s (%s) %llu + %u [%d]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- event.cmd().c_str(), (unsigned long long)event.sector(),
+ event.cmd().c_str(), static_cast<unsigned long long>(event.sector()),
event.nr_sector(), event.errors());
return std::string(line);
}
std::string FormatBlockRqInsert(const BlockRqInsertFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_rq_insert: %d,%d %s %u (%s) %llu + %u [%s]\\n",
+ sprintf(line, "block_rq_insert: %d,%d %s %u (%s) %llu + %u [%s]",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
event.bytes(), event.cmd().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatBlockRqRemap(const BlockRqRemapFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_rq_remap: %d,%d %s %llu + %u <- (%d,%d) %llu %u\\n",
+ sprintf(line, "block_rq_remap: %d,%d %s %llu + %u <- (%d,%d) %llu %u",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
major(event.dev()), minor(event.dev()),
(unsigned long long)event.old_sector(), event.nr_bios());
return std::string(line);
@@ -1101,43 +1111,43 @@
std::string FormatBlockRqRequeue(const BlockRqRequeueFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_rq_requeue: %d,%d %s (%s) %llu + %u [%d\\n",
+ sprintf(line, "block_rq_requeue: %d,%d %s (%s) %llu + %u [%d",
major(event.dev()), minor(event.dev()), event.rwbs().c_str(),
- event.cmd().c_str(), (unsigned long long)event.sector(),
+ event.cmd().c_str(), static_cast<unsigned long long>(event.sector()),
event.nr_sector(), event.errors());
return std::string(line);
}
std::string FormatBlockSleeprq(const BlockSleeprqFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_sleeprq: %d,%d %s %llu + %u [%s]\\n", major(event.dev()),
+ sprintf(line, "block_sleeprq: %d,%d %s %llu + %u [%s]", major(event.dev()),
minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(), event.nr_sector(),
+ static_cast<unsigned long long>(event.sector()), event.nr_sector(),
event.comm().c_str());
return std::string(line);
}
std::string FormatBlockSplit(const BlockSplitFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_split: %d,%d %s %llu / %llu [%s]\\n", major(event.dev()),
+ sprintf(line, "block_split: %d,%d %s %llu / %llu [%s]", major(event.dev()),
minor(event.dev()), event.rwbs().c_str(),
- (unsigned long long)event.sector(),
+ static_cast<unsigned long long>(event.sector()),
(unsigned long long)event.new_sector(), event.comm().c_str());
return std::string(line);
}
std::string FormatBlockTouchBuffer(const BlockTouchBufferFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_touch_buffer: %d,%d sector=%llu size=%zu\\n",
+ sprintf(line, "block_touch_buffer: %d,%d sector=%llu size=%zu",
major(event.dev()), minor(event.dev()),
- (unsigned long long)event.sector(), (unsigned long)event.size());
+ static_cast<unsigned long long>(event.sector()),
+ static_cast<size_t>(event.size()));
return std::string(line);
}
std::string FormatBlockUnplug(const BlockUnplugFtraceEvent& event) {
char line[2048];
- sprintf(line, "block_unplug: [%s] %d\\n", event.comm().c_str(),
- event.nr_rq());
+ sprintf(line, "block_unplug: [%s] %d", event.comm().c_str(), event.nr_rq());
return std::string(line);
}
@@ -1145,7 +1155,7 @@
char line[2048];
sprintf(line,
"ext4_alloc_da_blocks: dev %d,%d ino %lu data_blocks %u meta_blocks "
- "%u \\n",
+ "%u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.data_blocks(), event.meta_blocks());
return std::string(line);
@@ -1156,7 +1166,7 @@
char line[2048];
sprintf(line,
"ext4_allocate_blocks: dev %d,%d ino %lu flags %s len %u block %llu "
- "lblk %u goal %llu lleft %u lright %u pleft %llu pright %llu\\n",
+ "lblk %u goal %llu lleft %u lright %u pleft %llu pright %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
GetExt4HintFlag(event.flags()), event.len(), event.block(),
event.logical(), event.goal(), event.lleft(), event.lright(),
@@ -1166,7 +1176,7 @@
std::string FormatExt4AllocateInode(const Ext4AllocateInodeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_allocate_inode: dev %d,%d ino %lu dir %lu mode 0%o\\n",
+ sprintf(line, "ext4_allocate_inode: dev %d,%d ino %lu dir %lu mode 0%o",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.dir(), event.mode());
return std::string(line);
@@ -1175,8 +1185,7 @@
std::string FormatExt4BeginOrderedTruncate(
const Ext4BeginOrderedTruncateFtraceEvent& event) {
char line[2048];
- sprintf(line,
- "ext4_begin_ordered_truncate: dev %d,%d ino %lu new_size %lld\\n",
+ sprintf(line, "ext4_begin_ordered_truncate: dev %d,%d ino %lu new_size %lld",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.new_size());
return std::string(line);
@@ -1184,8 +1193,7 @@
std::string FormatExt4CollapseRange(const Ext4CollapseRangeFtraceEvent& event) {
char line[2048];
- sprintf(line,
- "ext4_collapse_range: dev %d,%d ino %lu offset %lld len %lld\\n",
+ sprintf(line, "ext4_collapse_range: dev %d,%d ino %lu offset %lld len %lld",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.offset(), event.len());
return std::string(line);
@@ -1197,7 +1205,7 @@
sprintf(line,
"ext4_da_release_space: dev %d,%d ino %lu mode 0%o i_blocks %llu "
"freed_blocks %d reserved_data_blocks %d reserved_meta_blocks %d "
- "allocated_meta_blocks %d\\n",
+ "allocated_meta_blocks %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.mode(), event.i_blocks(), event.freed_blocks(),
event.reserved_data_blocks(), event.reserved_meta_blocks(),
@@ -1210,7 +1218,7 @@
char line[2048];
sprintf(line,
"ext4_da_reserve_space:dev %d,%d ino %lu mode 0%o i_blocks %llu "
- "reserved_data_blocks %d reserved_meta_blocks %d \\n",
+ "reserved_data_blocks %d reserved_meta_blocks %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.mode(), event.i_blocks(), event.reserved_data_blocks(),
event.reserved_meta_blocks());
@@ -1223,7 +1231,7 @@
sprintf(line,
"ext4_da_update_reserve_space: dev %d,%d ino %lu mode 0%o i_blocks "
"%llu used_blocks %d reserved_data_blocks %d reserved_meta_blocks %d "
- "allocated_meta_blocks %d quota_claim %d\\n",
+ "allocated_meta_blocks %d quota_claim %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.mode(), event.i_blocks(), event.used_blocks(),
event.reserved_data_blocks(), event.reserved_meta_blocks(),
@@ -1235,7 +1243,7 @@
char line[2048];
sprintf(line,
"ext4_da_write_pages: dev %d,%d ino %lu first_page %lu nr_to_write "
- "%ld sync_mode %d\\n",
+ "%ld sync_mode %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.first_page(), (long)event.nr_to_write(),
event.sync_mode());
@@ -1247,7 +1255,7 @@
const Ext4DaWritePagesExtentFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_da_write_pages_extent: dev %d,%d ino %lu lblk %llu len %u \\n",
+ "ext4_da_write_pages_extent: dev %d,%d ino %lu lblk %llu len %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len());
return std::string(line);
@@ -1255,7 +1263,7 @@
std::string FormatExt4DiscardBlocks(const Ext4DiscardBlocksFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_discard_blocks: dev %d,%d blk %llu count %llu\\n",
+ sprintf(line, "ext4_discard_blocks: dev %d,%d blk %llu count %llu",
major(event.dev()), minor(event.dev()), event.blk(), event.count());
return std::string(line);
}
@@ -1263,14 +1271,14 @@
std::string FormatExt4DiscardPreallocations(
const Ext4DiscardPreallocationsFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_discard_preallocations: dev %d,%d ino %lu\\n",
+ sprintf(line, "ext4_discard_preallocations: dev %d,%d ino %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino());
return std::string(line);
}
std::string FormatExt4DropInode(const Ext4DropInodeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_drop_inode: dev %d,%d ino %lu drop %d\\n",
+ sprintf(line, "ext4_drop_inode: dev %d,%d ino %lu drop %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.drop());
return std::string(line);
@@ -1280,7 +1288,7 @@
std::string FormatExt4EsCacheExtent(const Ext4EsCacheExtentFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_es_cache_extent: dev %d,%d ino %lu es [%u/%u) mapped %llu \\n",
+ "ext4_es_cache_extent: dev %d,%d ino %lu es [%u/%u) mapped %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len(), event.pblk());
return std::string(line);
@@ -1289,11 +1297,10 @@
std::string FormatExt4EsFindDelayedExtentRangeEnter(
const Ext4EsFindDelayedExtentRangeEnterFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_es_find_delayed_extent_range_enter: dev %d,%d ino %lu lblk %u\\n",
- major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
- event.lblk());
+ sprintf(line,
+ "ext4_es_find_delayed_extent_range_enter: dev %d,%d ino %lu lblk %u",
+ major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
+ event.lblk());
return std::string(line);
}
@@ -1303,7 +1310,7 @@
char line[2048];
sprintf(line,
"ext4_es_find_delayed_extent_range_exit: dev %d,%d ino %lu es "
- "[%u/%u) mapped %llu\\n",
+ "[%u/%u) mapped %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len(), event.pblk());
return std::string(line);
@@ -1314,7 +1321,7 @@
const Ext4EsInsertExtentFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_es_insert_extent: dev %d,%d ino %lu es [%u/%u) mapped %llu \\n",
+ "ext4_es_insert_extent: dev %d,%d ino %lu es [%u/%u) mapped %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len(), event.pblk());
return std::string(line);
@@ -1323,7 +1330,7 @@
std::string FormatExt4EsLookupExtentEnter(
const Ext4EsLookupExtentEnterFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_es_lookup_extent_enter: dev %d,%d ino %lu lblk %u\\n",
+ sprintf(line, "ext4_es_lookup_extent_enter: dev %d,%d ino %lu lblk %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk());
return std::string(line);
@@ -1333,19 +1340,18 @@
std::string FormatExt4EsLookupExtentExit(
const Ext4EsLookupExtentExitFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_es_lookup_extent_exit: dev %d,%d ino %lu found %d [%u/%u) %llu\\n",
- major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
- event.found(), event.lblk(), event.len(),
- event.found() ? event.pblk() : 0);
+ sprintf(line,
+ "ext4_es_lookup_extent_exit: dev %d,%d ino %lu found %d [%u/%u) %llu",
+ major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
+ event.found(), event.lblk(), event.len(),
+ event.found() ? event.pblk() : 0);
return std::string(line);
}
std::string FormatExt4EsRemoveExtent(
const Ext4EsRemoveExtentFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_es_remove_extent: dev %d,%d ino %lu es [%lld/%lld)\\n",
+ sprintf(line, "ext4_es_remove_extent: dev %d,%d ino %lu es [%lld/%lld)",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len());
return std::string(line);
@@ -1355,7 +1361,7 @@
char line[2048];
sprintf(line,
"ext4_es_shrink: dev %d,%d nr_shrunk %d, scan_time %llu nr_skipped "
- "%d retried %d\\n",
+ "%d retried %d",
major(event.dev()), minor(event.dev()), event.nr_shrunk(),
event.scan_time(), event.nr_skipped(), event.retried());
return std::string(line);
@@ -1363,7 +1369,7 @@
std::string FormatExt4EsShrinkCount(const Ext4EsShrinkCountFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_es_shrink_count: dev %d,%d nr_to_scan %d cache_cnt %d\\n",
+ sprintf(line, "ext4_es_shrink_count: dev %d,%d nr_to_scan %d cache_cnt %d",
major(event.dev()), minor(event.dev()), event.nr_to_scan(),
event.cache_cnt());
return std::string(line);
@@ -1373,7 +1379,7 @@
const Ext4EsShrinkScanEnterFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_es_shrink_scan_enter: dev %d,%d nr_to_scan %d cache_cnt %d\\n",
+ "ext4_es_shrink_scan_enter: dev %d,%d nr_to_scan %d cache_cnt %d",
major(event.dev()), minor(event.dev()), event.nr_to_scan(),
event.cache_cnt());
return std::string(line);
@@ -1382,8 +1388,7 @@
std::string FormatExt4EsShrinkScanExit(
const Ext4EsShrinkScanExitFtraceEvent& event) {
char line[2048];
- sprintf(line,
- "ext4_es_shrink_scan_exit: dev %d,%d nr_shrunk %d cache_cnt %d\\n",
+ sprintf(line, "ext4_es_shrink_scan_exit: dev %d,%d nr_shrunk %d cache_cnt %d",
major(event.dev()), minor(event.dev()), event.nr_shrunk(),
event.cache_cnt());
return std::string(line);
@@ -1391,7 +1396,7 @@
std::string FormatExt4EvictInode(const Ext4EvictInodeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_evict_inode: dev %d,%d ino %lu nlink %d\\n",
+ sprintf(line, "ext4_evict_inode: dev %d,%d ino %lu nlink %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.nlink());
return std::string(line);
@@ -1402,7 +1407,7 @@
char line[2048];
sprintf(line,
"ext4_ext_convert_to_initialized_enter: dev %d,%d ino %lu m_lblk %u "
- "m_len %u u_lblk %u u_len %u u_pblk %llu\\n",
+ "m_len %u u_lblk %u u_len %u u_pblk %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.m_lblk(), event.m_len(), event.u_lblk(), event.u_len(),
event.u_pblk());
@@ -1415,7 +1420,7 @@
sprintf(line,
"ext4_ext_convert_to_initialized_fastpath: dev %d,%d ino %lu m_lblk "
"%u m_len %u u_lblk %u u_len %u u_pblk %llu i_lblk %u i_len %u "
- "i_pblk %llu\\n",
+ "i_pblk %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.m_lblk(), event.m_len(), event.u_lblk(), event.u_len(),
event.u_pblk(), event.i_lblk(), event.i_len(), event.i_pblk());
@@ -1427,7 +1432,7 @@
char line[2048];
sprintf(line,
"ext4_ext_handle_unwritten_extents: dev %d,%d ino %lu m_lblk %u "
- "m_pblk %llu m_len %u flags %s allocated %d newblock %llu\\n",
+ "m_pblk %llu m_len %u flags %s allocated %d newblock %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.lblk(), (unsigned long long)event.pblk(), event.len(),
GetExt4ExtFlag(event.flags()), (unsigned int)event.allocated(),
@@ -1437,7 +1442,7 @@
std::string FormatExt4ExtInCache(const Ext4ExtInCacheFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_ext_in_cache: dev %d,%d ino %lu lblk %u ret %d\\n",
+ sprintf(line, "ext4_ext_in_cache: dev %d,%d ino %lu lblk %u ret %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.lblk(), event.ret());
return std::string(line);
@@ -1445,7 +1450,7 @@
std::string FormatExt4ExtLoadExtent(const Ext4ExtLoadExtentFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_ext_load_extent: dev %d,%d ino %lu lblk %u pblk %llu\\n",
+ sprintf(line, "ext4_ext_load_extent: dev %d,%d ino %lu lblk %u pblk %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.pblk());
return std::string(line);
@@ -1456,7 +1461,7 @@
char line[2048];
sprintf(
line,
- "ext4_ext_map_blocks_enter: dev %d,%d ino %lu lblk %u len %u flags %s\\n",
+ "ext4_ext_map_blocks_enter: dev %d,%d ino %lu lblk %u len %u flags %s",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len(), GetExt4ExtFlag(event.flags()));
return std::string(line);
@@ -1467,7 +1472,7 @@
char line[2048];
sprintf(line,
"ext4_ext_map_blocks_exit: dev %d,%d ino %lu lblk %u pblk %llu len "
- "%u flags %x ret %d\\n",
+ "%u flags %x ret %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.pblk(), event.len(), event.flags(), event.ret());
return std::string(line);
@@ -1475,22 +1480,21 @@
std::string FormatExt4ExtPutInCache(const Ext4ExtPutInCacheFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_ext_put_in_cache: dev %d,%d ino %lu lblk %u len %u start %llu\\n",
- major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
- (unsigned)event.lblk(), event.len(), (unsigned long long)event.start());
+ sprintf(line,
+ "ext4_ext_put_in_cache: dev %d,%d ino %lu lblk %u len %u start %llu",
+ major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
+ (unsigned)event.lblk(), event.len(),
+ (unsigned long long)event.start());
return std::string(line);
}
std::string FormatExt4ExtRemoveSpace(
const Ext4ExtRemoveSpaceFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_ext_remove_space: dev %d,%d ino %lu since %u end %u depth %d\\n",
- major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
- (unsigned)event.start(), (unsigned)event.end(), event.depth());
+ sprintf(line,
+ "ext4_ext_remove_space: dev %d,%d ino %lu since %u end %u depth %d",
+ major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
+ (unsigned)event.start(), (unsigned)event.end(), event.depth());
return std::string(line);
}
@@ -1499,7 +1503,7 @@
char line[2048];
sprintf(line,
"ext4_ext_remove_space_done: dev %d,%d ino %lu since %u end %u depth "
- "%d partial %lld remaining_entries %u\\n",
+ "%d partial %lld remaining_entries %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.start(), (unsigned)event.end(), event.depth(),
(long long)event.partial(), (unsigned short)event.eh_entries());
@@ -1508,7 +1512,7 @@
std::string FormatExt4ExtRmIdx(const Ext4ExtRmIdxFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_ext_rm_idx: dev %d,%d ino %lu index_pblk %llu\\n",
+ sprintf(line, "ext4_ext_rm_idx: dev %d,%d ino %lu index_pblk %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long long)event.pblk());
return std::string(line);
@@ -1518,7 +1522,7 @@
char line[2048];
sprintf(line,
"ext4_ext_rm_leaf: dev %d,%d ino %lu start_lblk %u last_extent "
- "[%u(%llu), %u]partial_cluster %lld\\n",
+ "[%u(%llu), %u]partial_cluster %lld",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.start(), (unsigned)event.ee_lblk(),
(unsigned long long)event.ee_pblk(), (unsigned short)event.ee_len(),
@@ -1529,7 +1533,7 @@
std::string FormatExt4ExtShowExtent(const Ext4ExtShowExtentFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_ext_show_extent: dev %d,%d ino %lu lblk %u pblk %llu len %u\\n",
+ "ext4_ext_show_extent: dev %d,%d ino %lu lblk %u pblk %llu len %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.lblk(), (unsigned long long)event.pblk(),
(unsigned short)event.len());
@@ -1541,7 +1545,7 @@
char line[2048];
sprintf(
line,
- "ext4_fallocate_enter: dev %d,%d ino %lu offset %lld len %lld mode %s\\n",
+ "ext4_fallocate_enter: dev %d,%d ino %lu offset %lld len %lld mode %s",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.offset(), event.len(), GetExt4ModeFlag(event.mode()));
return std::string(line);
@@ -1550,7 +1554,7 @@
std::string FormatExt4FallocateExit(const Ext4FallocateExitFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_fallocate_exit: dev %d,%d ino %lu pos %lld blocks %u ret %d\\n",
+ "ext4_fallocate_exit: dev %d,%d ino %lu pos %lld blocks %u ret %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pos(), event.blocks(), event.ret());
return std::string(line);
@@ -1561,7 +1565,7 @@
char line[2048];
sprintf(line,
"ext4_find_delalloc_range: dev %d,%d ino %lu from %u to %u reverse "
- "%d found %d (blk = %u)\\n",
+ "%d found %d (blk = %u)",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.from(), (unsigned)event.to(), event.reverse(),
event.found(), (unsigned)event.found_blk());
@@ -1570,11 +1574,10 @@
std::string FormatExt4Forget(const Ext4ForgetFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_forget: dev %d,%d ino %lu mode 0%o is_metadata %d block %llu\\n",
- major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
- event.mode(), event.is_metadata(), event.block());
+ sprintf(line,
+ "ext4_forget: dev %d,%d ino %lu mode 0%o is_metadata %d block %llu",
+ major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
+ event.mode(), event.is_metadata(), event.block());
return std::string(line);
}
@@ -1582,7 +1585,7 @@
char line[2048];
sprintf(line,
"ext4_free_blocks: dev %d,%d ino %lu mode 0%o block %llu count %lu "
- "flags %s\\n",
+ "flags %s",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.mode(), event.block(), (unsigned long)event.count(),
GetExt4FreeBlocksFlag(event.flags()));
@@ -1593,7 +1596,7 @@
char line[2048];
sprintf(line,
"ext4_free_inode: dev %d,%d ino %lu mode 0%o uid %u gid %u blocks "
- "%llu\\n",
+ "%llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.mode(), event.uid(), event.gid(), event.blocks());
return std::string(line);
@@ -1604,7 +1607,7 @@
char line[2048];
sprintf(line,
"ext4_get_implied_cluster_alloc_exit: dev %d,%d m_lblk %u m_pblk "
- "%llu m_len %u m_flags %u ret %d\\n",
+ "%llu m_len %u m_flags %u ret %d",
major(event.dev()), minor(event.dev()), event.lblk(),
(unsigned long long)event.pblk(), event.len(), event.flags(),
event.ret());
@@ -1614,11 +1617,10 @@
std::string FormatExt4GetReservedClusterAlloc(
const Ext4GetReservedClusterAllocFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_get_reserved_cluster_alloc: dev %d,%d ino %lu lblk %u len %u\\n",
- major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
- (unsigned)event.lblk(), event.len());
+ sprintf(line,
+ "ext4_get_reserved_cluster_alloc: dev %d,%d ino %lu lblk %u len %u",
+ major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
+ (unsigned)event.lblk(), event.len());
return std::string(line);
}
@@ -1627,7 +1629,7 @@
char line[2048];
sprintf(
line,
- "ext4_ind_map_blocks_enter: dev %d,%d ino %lu lblk %u len %u flags %u\\n",
+ "ext4_ind_map_blocks_enter: dev %d,%d ino %lu lblk %u len %u flags %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.len(), event.flags());
return std::string(line);
@@ -1638,7 +1640,7 @@
char line[2048];
sprintf(line,
"ext4_ind_map_blocks_exit: dev %d,%d ino %lu lblk %u pblk %llu len "
- "%u flags %x ret %d\\n",
+ "%u flags %x ret %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.lblk(), event.pblk(), event.len(), event.flags(), event.ret());
return std::string(line);
@@ -1646,7 +1648,7 @@
std::string FormatExt4InsertRange(const Ext4InsertRangeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_insert_range: dev %d,%d ino %lu offset %lld len %lld\\n",
+ sprintf(line, "ext4_insert_range: dev %d,%d ino %lu offset %lld len %lld",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.offset(), event.len());
return std::string(line);
@@ -1657,7 +1659,7 @@
char line[2048];
sprintf(line,
"ext4_invalidatepage: dev %d,%d ino %lu page_index %lu offset %u "
- "length %u\\n",
+ "length %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.index(), event.offset(), event.length());
return std::string(line);
@@ -1665,19 +1667,17 @@
std::string FormatExt4JournalStart(const Ext4JournalStartFtraceEvent& event) {
char line[2048];
- sprintf(
- line,
- "ext4_journal_start: dev %d,%d blocks, %d rsv_blocks, %d caller %pS\\n",
- major(event.dev()), minor(event.dev()), event.blocks(),
- event.rsv_blocks(), (void*)event.ip());
+ sprintf(line,
+ "ext4_journal_start: dev %d,%d blocks, %d rsv_blocks, %d caller %pS",
+ major(event.dev()), minor(event.dev()), event.blocks(),
+ event.rsv_blocks(), (void*)event.ip());
return std::string(line);
}
std::string FormatExt4JournalStartReserved(
const Ext4JournalStartReservedFtraceEvent& event) {
char line[2048];
- sprintf(line,
- "ext4_journal_start_reserved: dev %d,%d blocks, %d caller %pS\\n",
+ sprintf(line, "ext4_journal_start_reserved: dev %d,%d blocks, %d caller %pS",
major(event.dev()), minor(event.dev()), event.blocks(),
(void*)event.ip());
return std::string(line);
@@ -1688,7 +1688,7 @@
char line[2048];
sprintf(line,
"ext4_journalled_invalidatepage: dev %d,%d ino %lu page_index %lu "
- "offset %u length %u\\n",
+ "offset %u length %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.index(), event.offset(), event.length());
return std::string(line);
@@ -1699,7 +1699,7 @@
char line[2048];
sprintf(line,
"ext4_journalled_write_end: dev %d,%d ino %lu pos %lld len %u copied "
- "%u\\n",
+ "%u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pos(), event.len(), event.copied());
return std::string(line);
@@ -1707,7 +1707,7 @@
std::string FormatExt4LoadInode(const Ext4LoadInodeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_load_inode: dev %d,%d ino %ld\\n", major(event.dev()),
+ sprintf(line, "ext4_load_inode: dev %d,%d ino %ld", major(event.dev()),
minor(event.dev()), (unsigned long)event.ino());
return std::string(line);
}
@@ -1715,7 +1715,7 @@
std::string FormatExt4LoadInodeBitmap(
const Ext4LoadInodeBitmapFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_load_inode_bitmap: dev %d,%d group %u\\n",
+ sprintf(line, "ext4_load_inode_bitmap: dev %d,%d group %u",
major(event.dev()), minor(event.dev()), event.group());
return std::string(line);
}
@@ -1723,7 +1723,7 @@
std::string FormatExt4MarkInodeDirty(
const Ext4MarkInodeDirtyFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mark_inode_dirty: dev %d,%d ino %lu caller %pS\\n",
+ sprintf(line, "ext4_mark_inode_dirty: dev %d,%d ino %lu caller %pS",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(void*)event.ip());
return std::string(line);
@@ -1731,15 +1731,15 @@
std::string FormatExt4MbBitmapLoad(const Ext4MbBitmapLoadFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mb_bitmap_load: dev %d,%d group %u\\n",
- major(event.dev()), minor(event.dev()), event.group());
+ sprintf(line, "ext4_mb_bitmap_load: dev %d,%d group %u", major(event.dev()),
+ minor(event.dev()), event.group());
return std::string(line);
}
std::string FormatExt4MbBuddyBitmapLoad(
const Ext4MbBuddyBitmapLoadFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mb_buddy_bitmap_load: dev %d,%d group %u\\n",
+ sprintf(line, "ext4_mb_buddy_bitmap_load: dev %d,%d group %u",
major(event.dev()), minor(event.dev()), event.group());
return std::string(line);
}
@@ -1747,7 +1747,7 @@
std::string FormatExt4MbDiscardPreallocations(
const Ext4MbDiscardPreallocationsFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mb_discard_preallocations: dev %d,%d needed %d\\n",
+ sprintf(line, "ext4_mb_discard_preallocations: dev %d,%d needed %d",
major(event.dev()), minor(event.dev()), event.needed());
return std::string(line);
}
@@ -1756,7 +1756,7 @@
char line[2048];
sprintf(line,
"ext4_mb_new_group_pa: dev %d,%d ino %lu pstart %llu len %u lstart "
- "%llu\\n",
+ "%llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pa_pstart(), event.pa_len(), event.pa_lstart());
return std::string(line);
@@ -1766,7 +1766,7 @@
char line[2048];
sprintf(line,
"ext4_mb_new_inode_pa: dev %d,%d ino %lu pstart %llu len %u lstart "
- "%llu\\n",
+ "%llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pa_pstart(), event.pa_len(), event.pa_lstart());
return std::string(line);
@@ -1775,7 +1775,7 @@
std::string FormatExt4MbReleaseGroupPa(
const Ext4MbReleaseGroupPaFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mb_release_group_pa: dev %d,%d pstart %llu len %u\\n",
+ sprintf(line, "ext4_mb_release_group_pa: dev %d,%d pstart %llu len %u",
major(event.dev()), minor(event.dev()), event.pa_pstart(),
event.pa_len());
return std::string(line);
@@ -1785,7 +1785,7 @@
const Ext4MbReleaseInodePaFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_mb_release_inode_pa: dev %d,%d ino %lu block %llu count %u\\n",
+ "ext4_mb_release_inode_pa: dev %d,%d ino %lu block %llu count %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.block(), event.count());
return std::string(line);
@@ -1796,7 +1796,7 @@
sprintf(line,
"ext4_mballoc_alloc: dev %d,%d inode %lu orig %u/%d/%u@%u goal "
"%u/%d/%u@%u result %u/%d/%u@%u blks %u grps %u cr %u flags %s tail "
- "%u broken %u\\n",
+ "%u broken %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.orig_group(), event.orig_start(), event.orig_len(),
event.orig_logical(), event.goal_group(), event.goal_start(),
@@ -1811,7 +1811,7 @@
std::string FormatExt4MballocDiscard(
const Ext4MballocDiscardFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mballoc_discard: dev %d,%d inode %lu extent %u/%d/%d \\n",
+ sprintf(line, "ext4_mballoc_discard: dev %d,%d inode %lu extent %u/%d/%d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.result_group(), event.result_start(), event.result_len());
return std::string(line);
@@ -1819,7 +1819,7 @@
std::string FormatExt4MballocFree(const Ext4MballocFreeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_mballoc_free: dev %d,%d inode %lu extent %u/%d/%d \\n",
+ sprintf(line, "ext4_mballoc_free: dev %d,%d inode %lu extent %u/%d/%d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.result_group(), event.result_start(), event.result_len());
return std::string(line);
@@ -1830,7 +1830,7 @@
char line[2048];
sprintf(line,
"ext4_mballoc_prealloc: dev %d,%d inode %lu orig %u/%d/%u@%u result "
- "%u/%d/%u@%u\\n",
+ "%u/%d/%u@%u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.orig_group(), event.orig_start(), event.orig_len(),
event.orig_logical(), event.result_group(), event.result_start(),
@@ -1843,7 +1843,7 @@
char line[2048];
sprintf(line,
"ext4_other_inode_update_time: dev %d,%d orig_ino %lu ino %lu mode "
- "0%o uid %u gid %u\\n",
+ "0%o uid %u gid %u",
major(event.dev()), minor(event.dev()),
(unsigned long)event.orig_ino(), (unsigned long)event.ino(),
event.mode(), event.uid(), event.gid());
@@ -1853,7 +1853,7 @@
std::string FormatExt4PunchHole(const Ext4PunchHoleFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_punch_hole: dev %d,%d ino %lu offset %lld len %lld mode %s\\n",
+ "ext4_punch_hole: dev %d,%d ino %lu offset %lld len %lld mode %s",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.offset(), event.len(), GetExt4ModeFlag(event.mode()));
return std::string(line);
@@ -1862,14 +1862,14 @@
std::string FormatExt4ReadBlockBitmapLoad(
const Ext4ReadBlockBitmapLoadFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_read_block_bitmap_load: dev %d,%d group %u\\n",
+ sprintf(line, "ext4_read_block_bitmap_load: dev %d,%d group %u",
major(event.dev()), minor(event.dev()), event.group());
return std::string(line);
}
std::string FormatExt4Readpage(const Ext4ReadpageFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_readpage: dev %d,%d ino %lu page_index %lu\\n",
+ sprintf(line, "ext4_readpage: dev %d,%d ino %lu page_index %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.index());
return std::string(line);
@@ -1877,7 +1877,7 @@
std::string FormatExt4Releasepage(const Ext4ReleasepageFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_releasepage: dev %d,%d ino %lu page_index %lu\\n",
+ sprintf(line, "ext4_releasepage: dev %d,%d ino %lu page_index %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.index());
return std::string(line);
@@ -1887,7 +1887,7 @@
char line[2048];
sprintf(line,
"ext4_remove_blocks: dev %d,%d ino %lu extent [%u(%llu), %u]from %u "
- "to %u partial_cluster %lld\\n",
+ "to %u partial_cluster %lld",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned)event.ee_lblk(), (unsigned long long)event.ee_pblk(),
(unsigned short)event.ee_len(), (unsigned)event.from(),
@@ -1899,7 +1899,7 @@
char line[2048];
sprintf(line,
"ext4_request_blocks: dev %d,%d ino %lu flags %s len %u lblk %u goal "
- "%llu lleft %u lright %u pleft %llu pright %llu \\n",
+ "%llu lleft %u lright %u pleft %llu pright %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
GetExt4HintFlag(event.flags()), event.len(), event.logical(),
event.goal(), event.lleft(), event.lright(), event.pleft(),
@@ -1909,7 +1909,7 @@
std::string FormatExt4RequestInode(const Ext4RequestInodeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_request_inode: dev %d,%d dir %lu mode 0%o\\n",
+ sprintf(line, "ext4_request_inode: dev %d,%d dir %lu mode 0%o",
major(event.dev()), minor(event.dev()), (unsigned long)event.dir(),
event.mode());
return std::string(line);
@@ -1917,14 +1917,14 @@
std::string FormatExt4SyncFs(const Ext4SyncFsFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_sync_fs: dev %d,%d wait %d\\n", major(event.dev()),
+ sprintf(line, "ext4_sync_fs: dev %d,%d wait %d", major(event.dev()),
minor(event.dev()), event.wait());
return std::string(line);
}
std::string FormatExt4TrimAllFree(const Ext4TrimAllFreeFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_trim_all_free: dev %d,%d group %u, start %d, len %d\\n",
+ sprintf(line, "ext4_trim_all_free: dev %d,%d group %u, start %d, len %d",
event.dev_major(), event.dev_minor(), event.group(), event.start(),
event.len());
return std::string(line);
@@ -1932,7 +1932,7 @@
std::string FormatExt4TrimExtent(const Ext4TrimExtentFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_trim_extent: dev %d,%d group %u, start %d, len %d\\n",
+ sprintf(line, "ext4_trim_extent: dev %d,%d group %u, start %d, len %d",
event.dev_major(), event.dev_minor(), event.group(), event.start(),
event.len());
return std::string(line);
@@ -1940,7 +1940,7 @@
std::string FormatExt4TruncateEnter(const Ext4TruncateEnterFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_truncate_enter: dev %d,%d ino %lu blocks %llu\\n",
+ sprintf(line, "ext4_truncate_enter: dev %d,%d ino %lu blocks %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.blocks());
return std::string(line);
@@ -1948,7 +1948,7 @@
std::string FormatExt4TruncateExit(const Ext4TruncateExitFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_truncate_exit: dev %d,%d ino %lu blocks %llu\\n",
+ sprintf(line, "ext4_truncate_exit: dev %d,%d ino %lu blocks %llu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.blocks());
return std::string(line);
@@ -1956,7 +1956,7 @@
std::string FormatExt4UnlinkEnter(const Ext4UnlinkEnterFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_unlink_enter: dev %d,%d ino %lu size %lld parent %lu\\n",
+ sprintf(line, "ext4_unlink_enter: dev %d,%d ino %lu size %lld parent %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.size(), (unsigned long)event.parent());
return std::string(line);
@@ -1964,7 +1964,7 @@
std::string FormatExt4UnlinkExit(const Ext4UnlinkExitFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_unlink_exit: dev %d,%d ino %lu ret %d\\n",
+ sprintf(line, "ext4_unlink_exit: dev %d,%d ino %lu ret %d",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.ret());
return std::string(line);
@@ -1972,8 +1972,7 @@
std::string FormatExt4WriteBegin(const Ext4WriteBeginFtraceEvent& event) {
char line[2048];
- sprintf(line,
- "ext4_write_begin: dev %d,%d ino %lu pos %lld len %u flags %u\\n",
+ sprintf(line, "ext4_write_begin: dev %d,%d ino %lu pos %lld len %u flags %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pos(), event.len(), event.flags());
return std::string(line);
@@ -1981,7 +1980,7 @@
std::string FormatExt4WriteEnd(const Ext4WriteEndFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_write_end: %d,%d ino %lu pos %lld len %u copied %u\\n",
+ sprintf(line, "ext4_write_end: %d,%d ino %lu pos %lld len %u copied %u",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.pos(), event.len(), event.copied());
return std::string(line);
@@ -1989,7 +1988,7 @@
std::string FormatExt4Writepage(const Ext4WritepageFtraceEvent& event) {
char line[2048];
- sprintf(line, "ext4_writepage: dev %d,%d ino %lu page_index %lu\\n",
+ sprintf(line, "ext4_writepage: dev %d,%d ino %lu page_index %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(unsigned long)event.index());
return std::string(line);
@@ -2000,7 +1999,7 @@
sprintf(line,
"ext4_writepages: dev %d,%d ino %lu nr_to_write %ld pages_skipped "
"%ld range_start %lld range_end %lld sync_mode %d for_kupdate %d "
- "range_cyclic %d writeback_index %lu\\n",
+ "range_cyclic %d writeback_index %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
(long)event.nr_to_write(), (long)event.pages_skipped(),
event.range_start(), event.range_end(), event.sync_mode(),
@@ -2014,7 +2013,7 @@
char line[2048];
sprintf(line,
"ext4_writepages_result: dev %d,%d ino %lu ret %d pages_written %d "
- "pages_skipped %ld sync_mode %d writeback_index %lu \\n",
+ "pages_skipped %ld sync_mode %d writeback_index %lu",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.ret(), event.pages_written(), (long)event.pages_skipped(),
event.sync_mode(), (unsigned long)event.writeback_index());
@@ -2024,7 +2023,7 @@
std::string FormatExt4ZeroRange(const Ext4ZeroRangeFtraceEvent& event) {
char line[2048];
sprintf(line,
- "ext4_zero_range: dev %d,%d ino %lu offset %lld len %lld mode %s\\n ",
+ "ext4_zero_range: dev %d,%d ino %lu offset %lld len %lld mode %s",
major(event.dev()), minor(event.dev()), (unsigned long)event.ino(),
event.offset(), event.len(), GetExt4ModeFlag(event.mode()));
return std::string(line);
diff --git a/tools/trace_to_text/ftrace_inode_handler.cc b/tools/trace_to_text/ftrace_inode_handler.cc
new file mode 100644
index 0000000..ad0d9b2
--- /dev/null
+++ b/tools/trace_to_text/ftrace_inode_handler.cc
@@ -0,0 +1,333 @@
+/*
+ * 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 "tools/trace_to_text/ftrace_inode_handler.h"
+
+namespace perfetto {
+
+bool ParseInode(const protos::FtraceEvent& event, uint64_t* inode) {
+ if (event.has_ext4_alloc_da_blocks() && event.ext4_alloc_da_blocks().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_alloc_da_blocks().ino());
+ return true;
+ } else if (event.has_ext4_allocate_blocks() &&
+ event.ext4_allocate_blocks().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_allocate_blocks().ino());
+ return true;
+ } else if (event.has_ext4_allocate_inode() &&
+ event.ext4_allocate_inode().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_allocate_inode().ino());
+ return true;
+ } else if (event.has_ext4_begin_ordered_truncate() &&
+ event.ext4_begin_ordered_truncate().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_begin_ordered_truncate().ino());
+ return true;
+ } else if (event.has_ext4_collapse_range() &&
+ event.ext4_collapse_range().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_collapse_range().ino());
+ return true;
+ } else if (event.has_ext4_da_release_space() &&
+ event.ext4_da_release_space().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_release_space().ino());
+ return true;
+ } else if (event.has_ext4_da_reserve_space() &&
+ event.ext4_da_reserve_space().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_reserve_space().ino());
+ return true;
+ } else if (event.has_ext4_da_update_reserve_space() &&
+ event.ext4_da_update_reserve_space().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_update_reserve_space().ino());
+ return true;
+ } else if (event.has_ext4_da_write_begin() &&
+ event.ext4_da_write_begin().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_write_begin().ino());
+ return true;
+ } else if (event.has_ext4_da_write_end() && event.ext4_da_write_end().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_write_end().ino());
+ return true;
+ } else if (event.has_ext4_da_write_pages() &&
+ event.ext4_da_write_pages().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_write_pages().ino());
+ return true;
+ } else if (event.has_ext4_da_write_pages_extent() &&
+ event.ext4_da_write_pages_extent().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_da_write_pages_extent().ino());
+ return true;
+ } else if (event.has_ext4_direct_io_enter() &&
+ event.ext4_direct_io_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_direct_io_enter().ino());
+ return true;
+ } else if (event.has_ext4_direct_io_exit() &&
+ event.ext4_direct_io_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_direct_io_exit().ino());
+ return true;
+ } else if (event.has_ext4_discard_preallocations() &&
+ event.ext4_discard_preallocations().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_discard_preallocations().ino());
+ return true;
+ } else if (event.has_ext4_drop_inode() && event.ext4_drop_inode().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_drop_inode().ino());
+ return true;
+ } else if (event.has_ext4_es_cache_extent() &&
+ event.ext4_es_cache_extent().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_es_cache_extent().ino());
+ return true;
+ } else if (event.has_ext4_es_find_delayed_extent_range_enter() &&
+ event.ext4_es_find_delayed_extent_range_enter().ino()) {
+ *inode = static_cast<uint64_t>(
+ event.ext4_es_find_delayed_extent_range_enter().ino());
+ return true;
+ } else if (event.has_ext4_es_find_delayed_extent_range_exit() &&
+ event.ext4_es_find_delayed_extent_range_exit().ino()) {
+ *inode = static_cast<uint64_t>(
+ event.ext4_es_find_delayed_extent_range_exit().ino());
+ return true;
+ } else if (event.has_ext4_es_insert_extent() &&
+ event.ext4_es_insert_extent().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_es_insert_extent().ino());
+ return true;
+ } else if (event.has_ext4_es_lookup_extent_enter() &&
+ event.ext4_es_lookup_extent_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_es_lookup_extent_enter().ino());
+ return true;
+ } else if (event.has_ext4_es_lookup_extent_exit() &&
+ event.ext4_es_lookup_extent_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_es_lookup_extent_exit().ino());
+ return true;
+ } else if (event.has_ext4_es_remove_extent() &&
+ event.ext4_es_remove_extent().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_es_remove_extent().ino());
+ return true;
+ } else if (event.has_ext4_evict_inode() && event.ext4_evict_inode().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_evict_inode().ino());
+ return true;
+ } else if (event.has_ext4_ext_convert_to_initialized_enter() &&
+ event.ext4_ext_convert_to_initialized_enter().ino()) {
+ *inode = static_cast<uint64_t>(
+ event.ext4_ext_convert_to_initialized_enter().ino());
+ return true;
+ } else if (event.has_ext4_ext_convert_to_initialized_fastpath() &&
+ event.ext4_ext_convert_to_initialized_fastpath().ino()) {
+ *inode = static_cast<uint64_t>(
+ event.ext4_ext_convert_to_initialized_fastpath().ino());
+ return true;
+ } else if (event.has_ext4_ext_handle_unwritten_extents() &&
+ event.ext4_ext_handle_unwritten_extents().ino()) {
+ *inode =
+ static_cast<uint64_t>(event.ext4_ext_handle_unwritten_extents().ino());
+ return true;
+ } else if (event.has_ext4_ext_in_cache() && event.ext4_ext_in_cache().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_in_cache().ino());
+ return true;
+ } else if (event.has_ext4_ext_load_extent() &&
+ event.ext4_ext_load_extent().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_load_extent().ino());
+ return true;
+ } else if (event.has_ext4_ext_map_blocks_enter() &&
+ event.ext4_ext_map_blocks_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_map_blocks_enter().ino());
+ return true;
+ } else if (event.has_ext4_ext_map_blocks_exit() &&
+ event.ext4_ext_map_blocks_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_map_blocks_exit().ino());
+ return true;
+ } else if (event.has_ext4_ext_put_in_cache() &&
+ event.ext4_ext_put_in_cache().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_put_in_cache().ino());
+ return true;
+ } else if (event.has_ext4_ext_remove_space() &&
+ event.ext4_ext_remove_space().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_remove_space().ino());
+ return true;
+ } else if (event.has_ext4_ext_remove_space_done() &&
+ event.ext4_ext_remove_space_done().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_remove_space_done().ino());
+ return true;
+ } else if (event.has_ext4_ext_rm_idx() && event.ext4_ext_rm_idx().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_rm_idx().ino());
+ return true;
+ } else if (event.has_ext4_ext_rm_leaf() && event.ext4_ext_rm_leaf().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_rm_leaf().ino());
+ return true;
+ } else if (event.has_ext4_ext_show_extent() &&
+ event.ext4_ext_show_extent().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ext_show_extent().ino());
+ return true;
+ } else if (event.has_ext4_fallocate_enter() &&
+ event.ext4_fallocate_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_fallocate_enter().ino());
+ return true;
+ } else if (event.has_ext4_fallocate_exit() &&
+ event.ext4_fallocate_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_fallocate_exit().ino());
+ return true;
+ } else if (event.has_ext4_find_delalloc_range() &&
+ event.ext4_find_delalloc_range().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_find_delalloc_range().ino());
+ return true;
+ } else if (event.has_ext4_forget() && event.ext4_forget().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_forget().ino());
+ return true;
+ } else if (event.has_ext4_free_blocks() && event.ext4_free_blocks().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_free_blocks().ino());
+ return true;
+ } else if (event.has_ext4_free_inode() && event.ext4_free_inode().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_free_inode().ino());
+ return true;
+ } else if (event.has_ext4_get_reserved_cluster_alloc() &&
+ event.ext4_get_reserved_cluster_alloc().ino()) {
+ *inode =
+ static_cast<uint64_t>(event.ext4_get_reserved_cluster_alloc().ino());
+ return true;
+ } else if (event.has_ext4_ind_map_blocks_enter() &&
+ event.ext4_ind_map_blocks_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ind_map_blocks_enter().ino());
+ return true;
+ } else if (event.has_ext4_ind_map_blocks_exit() &&
+ event.ext4_ind_map_blocks_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_ind_map_blocks_exit().ino());
+ return true;
+ } else if (event.has_ext4_insert_range() && event.ext4_insert_range().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_insert_range().ino());
+ return true;
+ } else if (event.has_ext4_invalidatepage() &&
+ event.ext4_invalidatepage().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_invalidatepage().ino());
+ return true;
+ } else if (event.has_ext4_journalled_invalidatepage() &&
+ event.ext4_journalled_invalidatepage().ino()) {
+ *inode =
+ static_cast<uint64_t>(event.ext4_journalled_invalidatepage().ino());
+ return true;
+ } else if (event.has_ext4_journalled_write_end() &&
+ event.ext4_journalled_write_end().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_journalled_write_end().ino());
+ return true;
+ } else if (event.has_ext4_load_inode() && event.ext4_load_inode().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_load_inode().ino());
+ return true;
+ } else if (event.has_ext4_mark_inode_dirty() &&
+ event.ext4_mark_inode_dirty().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mark_inode_dirty().ino());
+ return true;
+ } else if (event.has_ext4_mb_new_group_pa() &&
+ event.ext4_mb_new_group_pa().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mb_new_group_pa().ino());
+ return true;
+ } else if (event.has_ext4_mb_new_inode_pa() &&
+ event.ext4_mb_new_inode_pa().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mb_new_inode_pa().ino());
+ return true;
+ } else if (event.has_ext4_mb_release_inode_pa() &&
+ event.ext4_mb_release_inode_pa().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mb_release_inode_pa().ino());
+ return true;
+ } else if (event.has_ext4_mballoc_alloc() &&
+ event.ext4_mballoc_alloc().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mballoc_alloc().ino());
+ return true;
+ } else if (event.has_ext4_mballoc_discard() &&
+ event.ext4_mballoc_discard().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mballoc_discard().ino());
+ return true;
+ } else if (event.has_ext4_mballoc_free() && event.ext4_mballoc_free().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mballoc_free().ino());
+ return true;
+ } else if (event.has_ext4_mballoc_prealloc() &&
+ event.ext4_mballoc_prealloc().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_mballoc_prealloc().ino());
+ return true;
+ } else if (event.has_ext4_other_inode_update_time() &&
+ event.ext4_other_inode_update_time().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_other_inode_update_time().ino());
+ return true;
+ } else if (event.has_ext4_other_inode_update_time() &&
+ event.ext4_other_inode_update_time().orig_ino()) {
+ *inode =
+ static_cast<uint64_t>(event.ext4_other_inode_update_time().orig_ino());
+ return true;
+ } else if (event.has_ext4_punch_hole() && event.ext4_punch_hole().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_punch_hole().ino());
+ return true;
+ } else if (event.has_ext4_readpage() && event.ext4_readpage().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_readpage().ino());
+ return true;
+ } else if (event.has_ext4_releasepage() && event.ext4_releasepage().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_releasepage().ino());
+ return true;
+ } else if (event.has_ext4_remove_blocks() &&
+ event.ext4_remove_blocks().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_remove_blocks().ino());
+ return true;
+ } else if (event.has_ext4_request_blocks() &&
+ event.ext4_request_blocks().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_request_blocks().ino());
+ return true;
+ } else if (event.has_ext4_sync_file_enter() &&
+ event.ext4_sync_file_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_sync_file_enter().ino());
+ return true;
+ } else if (event.has_ext4_sync_file_exit() &&
+ event.ext4_sync_file_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_sync_file_exit().ino());
+ return true;
+ } else if (event.has_ext4_truncate_enter() &&
+ event.ext4_truncate_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_truncate_enter().ino());
+ return true;
+ } else if (event.has_ext4_truncate_exit() &&
+ event.ext4_truncate_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_truncate_exit().ino());
+ return true;
+ } else if (event.has_ext4_unlink_enter() && event.ext4_unlink_enter().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_unlink_enter().ino());
+ return true;
+ } else if (event.has_ext4_unlink_exit() && event.ext4_unlink_exit().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_unlink_exit().ino());
+ return true;
+ } else if (event.has_ext4_write_begin() && event.ext4_write_begin().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_write_begin().ino());
+ return true;
+ } else if (event.has_ext4_write_end() && event.ext4_write_end().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_write_end().ino());
+ return true;
+ } else if (event.has_ext4_writepage() && event.ext4_writepage().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_writepage().ino());
+ return true;
+ } else if (event.has_ext4_writepages() && event.ext4_writepages().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_writepages().ino());
+ return true;
+ } else if (event.has_ext4_writepages_result() &&
+ event.ext4_writepages_result().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_writepages_result().ino());
+ return true;
+ } else if (event.has_ext4_zero_range() && event.ext4_zero_range().ino()) {
+ *inode = static_cast<uint64_t>(event.ext4_zero_range().ino());
+ return true;
+ } else if (event.has_mm_filemap_add_to_page_cache() &&
+ event.mm_filemap_add_to_page_cache().i_ino()) {
+ *inode =
+ static_cast<uint64_t>(event.mm_filemap_add_to_page_cache().i_ino());
+ return true;
+ } else if (event.has_mm_filemap_delete_from_page_cache() &&
+ event.mm_filemap_delete_from_page_cache().i_ino()) {
+ *inode = static_cast<uint64_t>(
+ event.mm_filemap_delete_from_page_cache().i_ino());
+ return true;
+ }
+ return false;
+}
+
+} // namespace perfetto
diff --git a/tools/trace_to_text/ftrace_inode_handler.h b/tools/trace_to_text/ftrace_inode_handler.h
new file mode 100644
index 0000000..77b5a8a
--- /dev/null
+++ b/tools/trace_to_text/ftrace_inode_handler.h
@@ -0,0 +1,30 @@
+/*
+ * 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 TOOLS_TRACE_TO_TEXT_FTRACE_INODE_HANDLER_H_
+#define TOOLS_TRACE_TO_TEXT_FTRACE_INODE_HANDLER_H_
+
+#include "tools/trace_to_text/ftrace_inode_handler.h"
+
+#include "perfetto/trace/trace_packet.pb.h"
+
+namespace perfetto {
+
+bool ParseInode(const protos::FtraceEvent&, uint64_t* inode);
+
+} // namespace perfetto
+
+#endif // TOOLS_TRACE_TO_TEXT_FTRACE_INODE_HANDLER_H_
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index 8769466..bd29756 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -22,6 +22,7 @@
#include <algorithm>
#include <fstream>
+#include <functional>
#include <iostream>
#include <istream>
#include <limits>
@@ -29,7 +30,6 @@
#include <memory>
#include <ostream>
#include <sstream>
-#include <string>
#include <utility>
#include <google/protobuf/compiler/importer.h>
@@ -43,6 +43,7 @@
#include "perfetto/trace/trace.pb.h"
#include "perfetto/trace/trace_packet.pb.h"
#include "tools/trace_to_text/ftrace_event_formatter.h"
+#include "tools/trace_to_text/ftrace_inode_handler.h"
namespace perfetto {
namespace {
@@ -70,8 +71,6 @@
"# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION\\n"
"# | | | | |||| | |\\n";
-constexpr const char* inodeFileTypeArray[] = {"UNKNOWN", "FILE", "DIRECTORY"};
-
using google::protobuf::Descriptor;
using google::protobuf::DynamicMessageFactory;
using google::protobuf::FileDescriptor;
@@ -120,61 +119,6 @@
}
};
-uint64_t TimestampToSeconds(uint64_t timestamp) {
- return timestamp / 1000000000ul;
-}
-
-uint64_t TimestampToMicroseconds(uint64_t timestamp) {
- return (timestamp / 1000) % 1000000ul;
-}
-
-std::string FormatPrefix(uint64_t timestamp, uint64_t cpu) {
- char line[2048];
- uint64_t seconds = TimestampToSeconds(timestamp);
- uint64_t useconds = TimestampToMicroseconds(timestamp);
- sprintf(line,
- "<idle>-0 (-----) [%03" PRIu64 "] d..3 %" PRIu64 ".%.6" PRIu64
- ": ",
- cpu, seconds, useconds);
- return std::string(line);
-}
-
-// TODO(taylori): Confirm correct format for this.
-// Calling this breaks loading into chrome://tracing
-std::string FormatProcess(const Process& process) {
- char line[2048];
- sprintf(line, "process: pid=%d ppid=%d cmdline=", process.pid(),
- process.ppid());
- std::string output = std::string(line);
- for (auto field : process.cmdline()) {
- char cmd[2048];
- sprintf(cmd, "%s ", field.c_str());
- output += std::string(cmd);
- }
- output += "\\n";
- for (auto thread : process.threads()) {
- char thread_line[2048];
- sprintf(thread_line, "thread: tid=%d name=%s\\n", thread.tid(),
- thread.name().c_str());
- output += thread_line;
- }
- return output;
-}
-
-// Calling this breaks loading into chrome://tracing
-std::string FormatInodeFileMap(const Entry& entry) {
- char line[2048];
- sprintf(line, "inode_file_map: ino=%llu type=%s path=", entry.inode_number(),
- inodeFileTypeArray[entry.type()]);
- std::string output = std::string(line);
- for (auto field : entry.paths()) {
- char path[2048];
- sprintf(path, "%s", field.c_str());
- output += std::string(path);
- }
- return output;
-}
-
void ForEachPacketInTrace(
std::istream* input,
const std::function<void(const protos::TracePacket&)>& f) {
@@ -220,7 +164,9 @@
}
}
-int TraceToSystrace(std::istream* input, std::ostream* output) {
+int TraceToSystrace(std::istream* input,
+ std::ostream* output,
+ bool wrap_in_json) {
std::multimap<uint64_t, std::string> sorted;
ForEachPacketInTrace(input, [&sorted](const protos::TracePacket& packet) {
@@ -237,22 +183,25 @@
}
});
- *output << kTraceHeader;
- *output << kFtraceHeader;
+ if (wrap_in_json) {
+ *output << kTraceHeader;
+ *output << kFtraceHeader;
+ }
fprintf(stderr, "\n");
size_t total_events = sorted.size();
size_t written_events = 0;
for (auto it = sorted.begin(); it != sorted.end(); it++) {
- *output << it->second;
- if (written_events++ % 100 == 0) {
+ *output << it->second << (wrap_in_json ? "\\n" : "\n");
+ if (written_events++ % 100 == 0 && !isatty(STDOUT_FILENO)) {
fprintf(stderr, "Writing trace: %.2f %%\r",
written_events * 100.0 / total_events);
fflush(stderr);
}
}
- *output << kTraceFooter;
+ if (wrap_in_json)
+ *output << kTraceFooter;
return 0;
}
@@ -279,33 +228,10 @@
return 0;
}
-int TraceToSummary(std::istream* input, std::ostream* output) {
- uint64_t start = std::numeric_limits<uint64_t>::max();
- uint64_t end = 0;
- std::multiset<uint64_t> ftrace_timestamps;
-
- ForEachPacketInTrace(input, [&start, &end, &ftrace_timestamps](
- const protos::TracePacket& packet) {
- if (!packet.has_ftrace_events())
- return;
-
- const FtraceEventBundle& bundle = packet.ftrace_events();
-
- for (const FtraceEvent& event : bundle.event()) {
- if (event.timestamp()) {
- start = std::min<uint64_t>(start, event.timestamp());
- end = std::max<uint64_t>(end, event.timestamp());
- ftrace_timestamps.insert(event.timestamp());
- }
- }
- });
-
- fprintf(stderr, "\n");
-
- char line[2048];
- sprintf(line, "Duration: %" PRIu64 "ms\n", (end - start) / (1000 * 1000));
- *output << std::string(line);
-
+void PrintFtraceTrack(std::ostream* output,
+ const uint64_t& start,
+ const uint64_t& end,
+ const std::multiset<uint64_t>& ftrace_timestamps) {
constexpr char kFtraceTrackName[] = "ftrace ";
size_t width = GetWidth();
size_t bucket_count = width - strlen(kFtraceTrackName);
@@ -321,14 +247,159 @@
std::vector<std::string> out =
std::vector<std::string>({" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇"});
- *output << kFtraceTrackName;
+ *output << "-------------------- " << kFtraceTrackName
+ << "--------------------\n";
+ char line[2048];
for (size_t i = 0; i < bucket_count; i++) {
sprintf(
line, "%s",
out[std::min(buckets[i] / (max / out.size()), out.size() - 1)].c_str());
*output << std::string(line);
}
+ *output << "\n\n";
+}
+
+void PrintInodeStats(std::ostream* output,
+ const std::set<uint64_t>& ftrace_inodes,
+ const uint64_t& ftrace_inode_count,
+ const std::set<uint64_t>& resolved_map_inodes,
+ const std::set<uint64_t>& resolved_scan_inodes) {
+ *output << "--------------------Inode Stats-------------------\n";
+ char line[2048];
+
+ sprintf(line, "Events with inodes: %" PRIu64 "\n", ftrace_inode_count);
+ *output << std::string(line);
+
+ sprintf(line, "Unique inodes from events: %zu\n", ftrace_inodes.size());
+ *output << std::string(line);
+
+ sprintf(line, "Resolved inodes from static map: %zu\n",
+ resolved_map_inodes.size());
+ *output << std::string(line);
+
+ sprintf(line, "Resolved inodes from scan and cache: %zu\n",
+ resolved_scan_inodes.size());
+ *output << std::string(line);
+
+ std::set<uint64_t> resolved_inodes;
+ set_union(resolved_map_inodes.begin(), resolved_map_inodes.end(),
+ resolved_scan_inodes.begin(), resolved_scan_inodes.end(),
+ std::inserter(resolved_inodes, resolved_inodes.begin()));
+
+ sprintf(line, "Total resolved inodes: %zu\n", resolved_inodes.size());
+ *output << std::string(line);
+
+ std::set<uint64_t> intersect;
+ set_intersection(resolved_inodes.begin(), resolved_inodes.end(),
+ ftrace_inodes.begin(), ftrace_inodes.end(),
+ std::inserter(intersect, intersect.begin()));
+
+ sprintf(line, "Unresolved inodes: %zu\n",
+ ftrace_inodes.size() - intersect.size());
+
+ sprintf(line, "Unexpected inodes from filesystem: %zu\n",
+ resolved_inodes.size() - intersect.size());
+ *output << std::string(line);
+
*output << "\n";
+}
+
+void PrintProcessStats(std::ostream* output,
+ const std::set<pid_t>& tids_in_tree,
+ const std::set<pid_t>& tids_in_events) {
+ *output << "----------------Process Tree Stats----------------\n";
+
+ char tid[2048];
+ sprintf(tid, "Unique thread ids in process tree: %zu\n", tids_in_tree.size());
+ *output << std::string(tid);
+
+ char tid_event[2048];
+ sprintf(tid_event, "Unique thread ids in ftrace events: %zu\n",
+ tids_in_events.size());
+ *output << std::string(tid_event);
+
+ std::set<pid_t> intersect;
+ set_intersection(tids_in_tree.begin(), tids_in_tree.end(),
+ tids_in_events.begin(), tids_in_events.end(),
+ std::inserter(intersect, intersect.begin()));
+
+ char matching[2048];
+ sprintf(matching, "Thread ids with process info: %zu/%zu -> %zu %%\n\n",
+ intersect.size(), tids_in_events.size(),
+ (intersect.size() * 100) / tids_in_events.size());
+ *output << std::string(matching);
+ *output << "\n";
+}
+
+int TraceToSummary(std::istream* input, std::ostream* output) {
+ uint64_t start = std::numeric_limits<uint64_t>::max();
+ uint64_t end = 0;
+ std::multiset<uint64_t> ftrace_timestamps;
+ std::set<pid_t> tids_in_tree;
+ std::set<pid_t> tids_in_events;
+ std::set<uint64_t> ftrace_inodes;
+ uint64_t ftrace_inode_count = 0;
+ std::set<uint64_t> resolved_map_inodes;
+ std::set<uint64_t> resolved_scan_inodes;
+
+ ForEachPacketInTrace(
+ input, [&start, &end, &ftrace_timestamps, &tids_in_tree, &tids_in_events,
+ &ftrace_inodes, &ftrace_inode_count, &resolved_map_inodes,
+ &resolved_scan_inodes](const protos::TracePacket& packet) {
+
+ if (packet.has_process_tree()) {
+ const ProcessTree& tree = packet.process_tree();
+ for (Process process : tree.processes()) {
+ for (ProcessTree::Thread thread : process.threads()) {
+ tids_in_tree.insert(thread.tid());
+ }
+ }
+ }
+
+ if (packet.has_inode_file_map()) {
+ const InodeFileMap& inode_file_map = packet.inode_file_map();
+ const auto& mount_points = inode_file_map.mount_points();
+ bool from_scan = std::find(mount_points.begin(), mount_points.end(),
+ "/data") != mount_points.end();
+ for (const auto& entry : inode_file_map.entries())
+ if (from_scan)
+ resolved_scan_inodes.insert(entry.inode_number());
+ else
+ resolved_map_inodes.insert(entry.inode_number());
+ }
+
+ if (!packet.has_ftrace_events())
+ return;
+
+ const FtraceEventBundle& bundle = packet.ftrace_events();
+ uint64_t inode_number = 0;
+ for (const FtraceEvent& event : bundle.event()) {
+ if (ParseInode(event, &inode_number)) {
+ ftrace_inodes.insert(inode_number);
+ ftrace_inode_count++;
+ }
+ if (event.pid()) {
+ tids_in_events.insert(event.pid());
+ }
+ if (event.timestamp()) {
+ start = std::min<uint64_t>(start, event.timestamp());
+ end = std::max<uint64_t>(end, event.timestamp());
+ ftrace_timestamps.insert(event.timestamp());
+ }
+ }
+ });
+
+ fprintf(stderr, "\n");
+
+ char line[2048];
+ sprintf(line, "Duration: %" PRIu64 "ms\n", (end - start) / (1000 * 1000));
+ *output << std::string(line);
+
+ PrintFtraceTrack(output, start, end, ftrace_timestamps);
+ PrintProcessStats(output, tids_in_tree, tids_in_events);
+ PrintInodeStats(output, ftrace_inodes, ftrace_inode_count,
+ resolved_map_inodes, resolved_scan_inodes);
+
return 0;
}
@@ -338,7 +409,7 @@
namespace {
int Usage(int argc, char** argv) {
- printf("Usage: %s [systrace|text|summary] < trace.proto > trace.txt\n",
+ printf("Usage: %s [systrace|json|text|summary] < trace.proto > trace.txt\n",
argv[0]);
return 1;
}
@@ -351,15 +422,15 @@
std::string format(argv[1]);
- bool is_systrace = format == "systrace";
- bool is_text = format == "text";
- bool is_summary = format == "summary";
-
- if (is_systrace)
- return perfetto::TraceToSystrace(&std::cin, &std::cout);
- if (is_text)
+ if (format == "json")
+ return perfetto::TraceToSystrace(&std::cin, &std::cout,
+ /*wrap_in_json=*/true);
+ if (format == "systrace")
+ return perfetto::TraceToSystrace(&std::cin, &std::cout,
+ /*wrap_in_json=*/false);
+ if (format == "text")
return perfetto::TraceToText(&std::cin, &std::cout);
- if (is_summary)
+ if (format == "summary")
return perfetto::TraceToSummary(&std::cin, &std::cout);
return Usage(argc, argv);
}