Add metatracing to trace perfetto itself.
Bug: 78765090
Change-Id: Ic1514d4040a78175cc9fd91526f26fc2d6937d5c
diff --git a/Android.bp b/Android.bp
index 59bc206..501bc8e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -31,6 +31,7 @@
":perfetto_protos_perfetto_trace_zero_gen",
":perfetto_src_ipc_wire_protocol_gen",
"src/base/file_utils.cc",
+ "src/base/metatrace.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
"src/base/string_utils.cc",
@@ -144,6 +145,7 @@
":perfetto_src_perfetto_cmd_protos_gen",
"src/base/android_task_runner.cc",
"src/base/file_utils.cc",
+ "src/base/metatrace.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
"src/base/string_utils.cc",
@@ -271,6 +273,7 @@
":perfetto_src_ipc_wire_protocol_gen",
"src/base/android_task_runner.cc",
"src/base/file_utils.cc",
+ "src/base/metatrace.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
"src/base/string_utils.cc",
@@ -3454,6 +3457,7 @@
":perfetto_protos_perfetto_trace_zero_gen",
":perfetto_src_ipc_wire_protocol_gen",
"src/base/file_utils.cc",
+ "src/base/metatrace.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
"src/base/string_utils.cc",
@@ -3626,6 +3630,7 @@
":perfetto_src_protozero_testing_messages_zero_gen",
"src/base/android_task_runner.cc",
"src/base/file_utils.cc",
+ "src/base/metatrace.cc",
"src/base/page_allocator.cc",
"src/base/page_allocator_unittest.cc",
"src/base/scoped_file_unittest.cc",
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index 985824c..41f075d 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -17,6 +17,7 @@
"build_config.h",
"file_utils.h",
"logging.h",
+ "metatrace.h",
"page_allocator.h",
"scoped_file.h",
"small_set.h",
diff --git a/include/perfetto/base/metatrace.h b/include/perfetto/base/metatrace.h
new file mode 100644
index 0000000..4bd38a1
--- /dev/null
+++ b/include/perfetto/base/metatrace.h
@@ -0,0 +1,77 @@
+/*
+ * 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 INCLUDE_PERFETTO_BASE_METATRACE_H_
+#define INCLUDE_PERFETTO_BASE_METATRACE_H_
+
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/utils.h"
+
+namespace perfetto {
+namespace base {
+
+template <typename T>
+std::string FormatJSON(T value) {
+ return std::to_string(value);
+}
+template <>
+std::string FormatJSON<std::string>(std::string value);
+template <>
+std::string FormatJSON<const char*>(const char* value);
+
+int MaybeOpenTraceFile();
+
+class MetaTrace {
+ public:
+ template <typename... Ts>
+ MetaTrace(Ts... args) {
+ AddElements(args...);
+ WriteEvent("B");
+ }
+
+ template <typename T, typename... Ts>
+ void AddElements(const char* name, T arg, Ts... args) {
+ trace_.emplace_back(FormatJSON(name), FormatJSON(std::move(arg)));
+ AddElements(args...);
+ }
+
+ template <typename T>
+ void AddElements(const char* name, T arg) {
+ trace_.emplace_back(FormatJSON(name), FormatJSON(std::move(arg)));
+ }
+
+ ~MetaTrace() { WriteEvent("E"); }
+
+ private:
+ void WriteEvent(std::string type);
+
+ std::vector<std::pair<std::string, std::string>> trace_;
+};
+
+#if PERFETTO_DCHECK_IS_ON() && !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
+#define PERFETTO_METATRACE(...) ::perfetto::base::MetaTrace(__VA_ARGS__)
+#else
+#define PERFETTO_METATRACE(...) ::perfetto::base::ignore_result(__VA_ARGS__)
+#endif
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_BASE_METATRACE_H_
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index 1d05b75..e62605a 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -24,12 +24,14 @@
]
sources = [
"file_utils.cc",
+ "metatrace.cc",
"string_splitter.cc",
"string_utils.cc",
"thread_checker.cc",
"time.cc",
"virtual_destructors.cc",
]
+
# TODO(brucedawson): Enable these for Windows when possible.
if (!is_win) {
sources += [
@@ -106,6 +108,7 @@
"../../gn:default_deps",
"../../gn:gtest_deps",
]
+
# TODO(brucedawson): Enable these for Windows when possible.
if (!is_win) {
deps += [ ":test_support" ]
@@ -120,6 +123,7 @@
"time_unittest.cc",
"weak_ptr_unittest.cc",
]
+
# TODO(brucedawson): Enable these for Windows when possible.
if (!is_win) {
sources += [
diff --git a/src/base/metatrace.cc b/src/base/metatrace.cc
new file mode 100644
index 0000000..ab86dd1
--- /dev/null
+++ b/src/base/metatrace.cc
@@ -0,0 +1,65 @@
+/*
+ * 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 "perfetto/base/metatrace.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include "perfetto/base/time.h"
+
+namespace perfetto {
+namespace base {
+
+int MaybeOpenTraceFile() {
+ static const char* tracing_path = getenv("PERFETTO_METATRACE_FILE");
+ if (tracing_path == nullptr)
+ return -1;
+ static int fd = open(tracing_path, O_WRONLY | O_CREAT | O_TRUNC, 0755);
+ return fd;
+}
+
+template <>
+std::string FormatJSON<std::string>(std::string value) {
+ return "\"" + value + "\"";
+}
+
+template <>
+std::string FormatJSON<const char*>(const char* value) {
+ return std::string("\"") + value + "\"";
+}
+
+void MetaTrace::WriteEvent(std::string type) {
+ int fd = MaybeOpenTraceFile();
+ if (fd == -1)
+ return;
+
+ std::string data = "{";
+ data.reserve(128);
+ for (size_t i = 0; i < trace_.size(); ++i) {
+ const std::pair<std::string, std::string>& p = trace_[i];
+ data += p.first;
+ data += ": ";
+ data += p.second;
+ data += ", ";
+ }
+ data += "\"ts\": " + std::to_string(GetWallTimeNs().count() / 1000.) +
+ ", \"cat\": \"PERF\", \"ph\": \"" + type + "\"},\n";
+ ignore_result(write(fd, data.c_str(), data.size()));
+}
+
+} // namespace base
+} // namespace perfetto
diff --git a/src/ftrace_reader/cpu_reader.cc b/src/ftrace_reader/cpu_reader.cc
index 3014bc4..0e718ab 100644
--- a/src/ftrace_reader/cpu_reader.cc
+++ b/src/ftrace_reader/cpu_reader.cc
@@ -26,6 +26,7 @@
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
+#include "perfetto/base/metatrace.h"
#include "perfetto/base/utils.h"
#include "src/ftrace_reader/proto_translation_table.h"
@@ -209,8 +210,12 @@
// First do a blocking splice which sleeps until there is at least one
// page of data available and enough space to write it into the staging
// pipe.
- ssize_t splice_res = splice(trace_fd, nullptr, staging_write_fd, nullptr,
- base::kPageSize, SPLICE_F_MOVE);
+ ssize_t splice_res;
+ {
+ PERFETTO_METATRACE("name", "splice_blocking", "pid", cpu);
+ splice_res = splice(trace_fd, nullptr, staging_write_fd, nullptr,
+ base::kPageSize, SPLICE_F_MOVE);
+ }
if (splice_res < 0) {
// The kernel ftrace code has its own splice() implementation that can
// occasionally fail with transient errors not reported in man 2 splice.
@@ -228,17 +233,22 @@
// pages from the trace pipe into the staging pipe as long as there is
// data in the former and space in the latter.
while (true) {
- splice_res = splice(trace_fd, nullptr, staging_write_fd, nullptr,
- base::kPageSize, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+ {
+ PERFETTO_METATRACE("name", "splice_nonblocking", "pid", cpu);
+ splice_res = splice(trace_fd, nullptr, staging_write_fd, nullptr,
+ base::kPageSize, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+ }
if (splice_res < 0) {
if (errno != EAGAIN && errno != ENOMEM && errno != EBUSY)
PERFETTO_PLOG("splice");
break;
}
}
-
- // This callback will block until we are allowed to read more data.
- on_data_available();
+ {
+ PERFETTO_METATRACE("name", "splice_waitcallback", "pid", cpu);
+ // This callback will block until we are allowed to read more data.
+ on_data_available();
+ }
}
#else
base::ignore_result(cpu);
diff --git a/tools/tmux b/tools/tmux
index 9a14356..c1e3366 100755
--- a/tools/tmux
+++ b/tools/tmux
@@ -108,6 +108,8 @@
push $OUT/libtraced_shared.so
fi
+PREFIX="$PREFIX PERFETTO_METATRACE_FILE=$DIR/mtrace"
+
CONFIG_DEVICE_PATH=$CONFIG
if [[ "$CONFIG" != ":test" ]]; then
CONFIG_DEVICE_PATH=$DIR/$CONFIG.protobuf
@@ -176,6 +178,11 @@
TRACE=$HOME/Downloads/trace
pull trace /tmp/trace.protobuf
+pull mtrace /tmp/mtrace.json
+# Add [ to beginning of file and replace trailing , with ] to turn into valid
+# JSON array.
+sed -i '$ s/.$/]/' /tmp/mtrace.json
+sed -i '1s/^/[/' /tmp/mtrace.json
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"