aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHector Dearman <hjd@google.com>2018-04-27 16:46:52 +0100
committerPrimiano Tucci <primiano@google.com>2018-05-01 10:08:23 +0100
commit13bd85c48007e0a9e4903a62558a329582c4ee4e (patch)
treecd6459762a99e87b3c776cdb58f447ba4f081b52
parent567a5111ff3fad730c1b9c8b1a77a09f187a7385 (diff)
downloadperfetto-13bd85c48007e0a9e4903a62558a329582c4ee4e.tar.gz
Add ftrace per_cpu/stats to beginning/end of the trace
This is to detect ftrace event going missing because the kernel buffer cannot keep up. Both the first and last snapshot are dumped at the end of the trace, during the flush. Bug: 78765090 Bug: 73886018 Change-Id: I9a806274532f0007f63f5e729c8b4c032495edaa Merged-In: I9a806274532f0007f63f5e729c8b4c032495edaa (cherry picked from commit 3afb1e0796d0b669d6172e4eb53be6f0824e75e3)
-rw-r--r--Android.bp18
-rw-r--r--include/perfetto/base/BUILD.gn1
-rw-r--r--include/perfetto/base/string_utils.h30
-rw-r--r--include/perfetto/ftrace_reader/ftrace_controller.h40
-rw-r--r--protos/perfetto/trace/ftrace/all_protos.gni1
-rw-r--r--protos/perfetto/trace/ftrace/ftrace_stats.proto42
-rw-r--r--protos/perfetto/trace/trace_packet.proto2
-rw-r--r--src/base/BUILD.gn2
-rw-r--r--src/base/string_utils.cc27
-rw-r--r--src/base/string_utils_unittest.cc39
-rw-r--r--src/ftrace_reader/BUILD.gn4
-rw-r--r--src/ftrace_reader/cpu_stats_parser.cc85
-rw-r--r--src/ftrace_reader/cpu_stats_parser.h33
-rw-r--r--src/ftrace_reader/cpu_stats_parser_unittest.cc36
-rw-r--r--src/ftrace_reader/ftrace_controller.cc30
-rw-r--r--src/ftrace_reader/ftrace_controller_unittest.cc26
-rw-r--r--src/ftrace_reader/ftrace_procfs.cc5
-rw-r--r--src/ftrace_reader/ftrace_procfs.h3
-rw-r--r--src/ftrace_reader/proto_translation_table.cc17
-rw-r--r--src/traced/probes/BUILD.gn2
-rw-r--r--src/traced/probes/probes_producer.cc26
-rw-r--r--src/traced/probes/probes_producer.h6
-rw-r--r--src/tracing/BUILD.gn18
23 files changed, 472 insertions, 21 deletions
diff --git a/Android.bp b/Android.bp
index bfd96aae3..f1d42cb0a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -32,6 +32,7 @@ cc_library_shared {
"src/base/file_utils.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
+ "src/base/string_utils.cc",
"src/base/temp_file.cc",
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
@@ -39,6 +40,7 @@ cc_library_shared {
"src/base/watchdog_posix.cc",
"src/ftrace_reader/atrace_wrapper.cc",
"src/ftrace_reader/cpu_reader.cc",
+ "src/ftrace_reader/cpu_stats_parser.cc",
"src/ftrace_reader/event_info.cc",
"src/ftrace_reader/event_info_constants.cc",
"src/ftrace_reader/format_parser.cc",
@@ -140,6 +142,7 @@ cc_binary {
"src/base/file_utils.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
+ "src/base/string_utils.cc",
"src/base/temp_file.cc",
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
@@ -263,6 +266,7 @@ cc_test {
"src/base/file_utils.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
+ "src/base/string_utils.cc",
"src/base/temp_file.cc",
"src/base/test/test_task_runner.cc",
"src/base/test/vm_test_utils.cc",
@@ -272,6 +276,7 @@ cc_test {
"src/base/watchdog_posix.cc",
"src/ftrace_reader/atrace_wrapper.cc",
"src/ftrace_reader/cpu_reader.cc",
+ "src/ftrace_reader/cpu_stats_parser.cc",
"src/ftrace_reader/end_to_end_integrationtest.cc",
"src/ftrace_reader/event_info.cc",
"src/ftrace_reader/event_info_constants.cc",
@@ -886,6 +891,7 @@ genrule {
"protos/perfetto/trace/ftrace/f2fs_write_end.proto",
"protos/perfetto/trace/ftrace/ftrace_event.proto",
"protos/perfetto/trace/ftrace/ftrace_event_bundle.proto",
+ "protos/perfetto/trace/ftrace/ftrace_stats.proto",
"protos/perfetto/trace/ftrace/i2c_read.proto",
"protos/perfetto/trace/ftrace/i2c_reply.proto",
"protos/perfetto/trace/ftrace/i2c_result.proto",
@@ -1155,6 +1161,7 @@ genrule {
"external/perfetto/protos/perfetto/trace/ftrace/f2fs_write_end.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event_bundle.pb.cc",
+ "external/perfetto/protos/perfetto/trace/ftrace/ftrace_stats.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_read.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_reply.pb.cc",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_result.pb.cc",
@@ -1425,6 +1432,7 @@ genrule {
"protos/perfetto/trace/ftrace/f2fs_write_end.proto",
"protos/perfetto/trace/ftrace/ftrace_event.proto",
"protos/perfetto/trace/ftrace/ftrace_event_bundle.proto",
+ "protos/perfetto/trace/ftrace/ftrace_stats.proto",
"protos/perfetto/trace/ftrace/i2c_read.proto",
"protos/perfetto/trace/ftrace/i2c_reply.proto",
"protos/perfetto/trace/ftrace/i2c_result.proto",
@@ -1694,6 +1702,7 @@ genrule {
"external/perfetto/protos/perfetto/trace/ftrace/f2fs_write_end.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event_bundle.pb.h",
+ "external/perfetto/protos/perfetto/trace/ftrace/ftrace_stats.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_read.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_reply.pb.h",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_result.pb.h",
@@ -1967,6 +1976,7 @@ genrule {
"protos/perfetto/trace/ftrace/f2fs_write_end.proto",
"protos/perfetto/trace/ftrace/ftrace_event.proto",
"protos/perfetto/trace/ftrace/ftrace_event_bundle.proto",
+ "protos/perfetto/trace/ftrace/ftrace_stats.proto",
"protos/perfetto/trace/ftrace/i2c_read.proto",
"protos/perfetto/trace/ftrace/i2c_reply.proto",
"protos/perfetto/trace/ftrace/i2c_result.proto",
@@ -2237,6 +2247,7 @@ genrule {
"external/perfetto/protos/perfetto/trace/ftrace/f2fs_write_end.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.cc",
+ "external/perfetto/protos/perfetto/trace/ftrace/ftrace_stats.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_read.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_reply.pbzero.cc",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_result.pbzero.cc",
@@ -2507,6 +2518,7 @@ genrule {
"protos/perfetto/trace/ftrace/f2fs_write_end.proto",
"protos/perfetto/trace/ftrace/ftrace_event.proto",
"protos/perfetto/trace/ftrace/ftrace_event_bundle.proto",
+ "protos/perfetto/trace/ftrace/ftrace_stats.proto",
"protos/perfetto/trace/ftrace/i2c_read.proto",
"protos/perfetto/trace/ftrace/i2c_reply.proto",
"protos/perfetto/trace/ftrace/i2c_result.proto",
@@ -2777,6 +2789,7 @@ genrule {
"external/perfetto/protos/perfetto/trace/ftrace/f2fs_write_end.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h",
+ "external/perfetto/protos/perfetto/trace/ftrace/ftrace_stats.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_read.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_reply.pbzero.h",
"external/perfetto/protos/perfetto/trace/ftrace/i2c_result.pbzero.h",
@@ -3400,6 +3413,7 @@ cc_library_static {
"src/base/file_utils.cc",
"src/base/page_allocator.cc",
"src/base/string_splitter.cc",
+ "src/base/string_utils.cc",
"src/base/temp_file.cc",
"src/base/thread_checker.cc",
"src/base/unix_task_runner.cc",
@@ -3570,6 +3584,8 @@ cc_test {
"src/base/scoped_file_unittest.cc",
"src/base/string_splitter.cc",
"src/base/string_splitter_unittest.cc",
+ "src/base/string_utils.cc",
+ "src/base/string_utils_unittest.cc",
"src/base/task_runner_unittest.cc",
"src/base/temp_file.cc",
"src/base/temp_file_unittest.cc",
@@ -3587,6 +3603,8 @@ cc_test {
"src/ftrace_reader/atrace_wrapper.cc",
"src/ftrace_reader/cpu_reader.cc",
"src/ftrace_reader/cpu_reader_unittest.cc",
+ "src/ftrace_reader/cpu_stats_parser.cc",
+ "src/ftrace_reader/cpu_stats_parser_unittest.cc",
"src/ftrace_reader/event_info.cc",
"src/ftrace_reader/event_info_constants.cc",
"src/ftrace_reader/event_info_unittest.cc",
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index 9d2981142..985824c9f 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -21,6 +21,7 @@ source_set("base") {
"scoped_file.h",
"small_set.h",
"string_splitter.h",
+ "string_utils.h",
"task_runner.h",
"thread_checker.h",
"time.h",
diff --git a/include/perfetto/base/string_utils.h b/include/perfetto/base/string_utils.h
new file mode 100644
index 000000000..9b4248a32
--- /dev/null
+++ b/include/perfetto/base/string_utils.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 INCLUDE_PERFETTO_BASE_STRING_UTILS_H_
+#define INCLUDE_PERFETTO_BASE_STRING_UTILS_H_
+
+#include <string>
+
+namespace perfetto {
+namespace base {
+
+bool StartsWith(const std::string& str, const std::string& prefix);
+
+} // namespace base
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_BASE_STRING_UTILS_H_
diff --git a/include/perfetto/ftrace_reader/ftrace_controller.h b/include/perfetto/ftrace_reader/ftrace_controller.h
index f01b885f1..7712dcc32 100644
--- a/include/perfetto/ftrace_reader/ftrace_controller.h
+++ b/include/perfetto/ftrace_reader/ftrace_controller.h
@@ -39,9 +39,37 @@
namespace perfetto {
+namespace protos {
+namespace pbzero {
+class FtraceEventBundle;
+class FtraceStats;
+class FtraceCpuStats;
+} // namespace pbzero
+} // namespace protos
+
using BlockDeviceID = decltype(stat::st_dev);
using Inode = decltype(stat::st_ino);
+struct FtraceCpuStats {
+ uint64_t cpu;
+ uint64_t entries;
+ uint64_t overrun;
+ uint64_t commit_overrun;
+ uint64_t bytes_read;
+ double oldest_event_ts;
+ double now_ts;
+ uint64_t dropped_events;
+ uint64_t read_events;
+
+ void Write(protos::pbzero::FtraceCpuStats*) const;
+};
+
+struct FtraceStats {
+ std::vector<FtraceCpuStats> cpu_stats;
+
+ void Write(protos::pbzero::FtraceStats*) const;
+};
+
struct FtraceMetadata {
FtraceMetadata();
@@ -64,12 +92,6 @@ struct FtraceMetadata {
void FinishEvent();
};
-namespace protos {
-namespace pbzero {
-class FtraceEventBundle;
-} // namespace pbzero
-} // namespace protos
-
constexpr size_t kMaxSinks = 32;
constexpr size_t kMaxCpus = 64;
@@ -92,6 +114,7 @@ class FtraceSink {
using FtraceEventBundle = protos::pbzero::FtraceEventBundle;
class Delegate {
public:
+ virtual void OnCreate(FtraceSink*) {}
virtual protozero::MessageHandle<FtraceEventBundle> GetBundleForCpu(
size_t) = 0;
virtual void OnBundleComplete(size_t,
@@ -107,6 +130,8 @@ class FtraceSink {
Delegate*);
~FtraceSink();
+ void DumpFtraceStats(FtraceStats*);
+
const FtraceConfig& config() const { return config_; }
private:
@@ -156,6 +181,9 @@ class FtraceController {
std::unique_ptr<FtraceConfigMuxer>,
base::TaskRunner*);
+ // Write
+ void DumpFtraceStats(FtraceStats*);
+
// Called to read data from the staging pipe for the given |cpu| and parse it
// into the sinks. Protected and virtual for testing.
virtual void OnRawFtraceDataAvailable(size_t cpu);
diff --git a/protos/perfetto/trace/ftrace/all_protos.gni b/protos/perfetto/trace/ftrace/all_protos.gni
index 8e22fc691..e975ae52d 100644
--- a/protos/perfetto/trace/ftrace/all_protos.gni
+++ b/protos/perfetto/trace/ftrace/all_protos.gni
@@ -156,6 +156,7 @@ ftrace_proto_names = [
"ext4_zero_range.proto",
"ftrace_event.proto",
"ftrace_event_bundle.proto",
+ "ftrace_stats.proto",
"i2c_read.proto",
"i2c_reply.proto",
"i2c_result.proto",
diff --git a/protos/perfetto/trace/ftrace/ftrace_stats.proto b/protos/perfetto/trace/ftrace/ftrace_stats.proto
new file mode 100644
index 000000000..7d0ed20a3
--- /dev/null
+++ b/protos/perfetto/trace/ftrace/ftrace_stats.proto
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+message FtraceCpuStats {
+ optional uint64 cpu = 1;
+ optional uint64 entries = 2;
+ optional uint64 overrun = 3;
+ optional uint64 commit_overrun = 4;
+ optional uint64 bytes_read = 5;
+ optional double oldest_event_ts = 6;
+ optional double now_ts = 7;
+ optional uint64 dropped_events = 8;
+ optional uint64 read_events = 9;
+}
+
+message FtraceStats {
+ enum Phase {
+ UNUSED = 0;
+ START_OF_TRACE = 1;
+ END_OF_TRACE = 2;
+ }
+ optional Phase phase = 1;
+ repeated FtraceCpuStats cpu_stats = 2;
+}
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index 9c38a8bfb..6fcee5ac5 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -22,6 +22,7 @@ import "perfetto/trace/chrome/chrome_trace_event.proto";
import "perfetto/trace/clock_snapshot.proto";
import "perfetto/trace/filesystem/inode_file_map.proto";
import "perfetto/trace/ftrace/ftrace_event_bundle.proto";
+import "perfetto/trace/ftrace/ftrace_stats.proto";
import "perfetto/trace/ps/process_tree.proto";
import "perfetto/trace/test_event.proto";
@@ -42,6 +43,7 @@ message TracePacket {
// IDs up to 32 are reserved for events that are quite frequent because they
// take only one byte to encode their preamble.
TraceConfig trace_config = 33;
+ FtraceStats ftrace_stats = 34;
// This field is only used for testing.
TestEvent for_testing = 536870911; // 2^29 - 1, max field id for protos.
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index 746f99914..18d11b638 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -26,6 +26,7 @@ source_set("base") {
"file_utils.cc",
"page_allocator.cc",
"string_splitter.cc",
+ "string_utils.cc",
"temp_file.cc",
"thread_checker.cc",
"unix_task_runner.cc",
@@ -106,6 +107,7 @@ source_set("unittests") {
"page_allocator_unittest.cc",
"scoped_file_unittest.cc",
"string_splitter_unittest.cc",
+ "string_utils_unittest.cc",
"task_runner_unittest.cc",
"temp_file_unittest.cc",
"thread_checker_unittest.cc",
diff --git a/src/base/string_utils.cc b/src/base/string_utils.cc
new file mode 100644
index 000000000..9a5b92bff
--- /dev/null
+++ b/src/base/string_utils.cc
@@ -0,0 +1,27 @@
+/*
+ * 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/string_utils.h"
+
+namespace perfetto {
+namespace base {
+
+bool StartsWith(const std::string& str, const std::string& prefix) {
+ return str.compare(0, prefix.length(), prefix) == 0;
+}
+
+} // namespace base
+} // namespace perfetto
diff --git a/src/base/string_utils_unittest.cc b/src/base/string_utils_unittest.cc
new file mode 100644
index 000000000..5362057fd
--- /dev/null
+++ b/src/base/string_utils_unittest.cc
@@ -0,0 +1,39 @@
+/*
+ * 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/string_utils.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace perfetto {
+namespace base {
+namespace {
+
+TEST(StringUtilsTest, StartsWith) {
+ EXPECT_TRUE(StartsWith("", ""));
+ EXPECT_TRUE(StartsWith("abc", ""));
+ EXPECT_TRUE(StartsWith("abc", "a"));
+ EXPECT_TRUE(StartsWith("abc", "ab"));
+ EXPECT_TRUE(StartsWith("abc", "abc"));
+ EXPECT_FALSE(StartsWith("abc", "abcd"));
+ EXPECT_FALSE(StartsWith("aa", "ab"));
+ EXPECT_FALSE(StartsWith("", "ab"));
+}
+
+} // namespace
+} // namespace base
+} // namespace perfetto
diff --git a/src/ftrace_reader/BUILD.gn b/src/ftrace_reader/BUILD.gn
index 46de5df04..d094da8d0 100644
--- a/src/ftrace_reader/BUILD.gn
+++ b/src/ftrace_reader/BUILD.gn
@@ -49,9 +49,11 @@ source_set("unittests") {
"../../gn:gtest_deps",
"../../protos/perfetto/trace/ftrace:lite",
"../base:test_support",
+ "../tracing:test_support",
]
sources = [
"cpu_reader_unittest.cc",
+ "cpu_stats_parser_unittest.cc",
"event_info_unittest.cc",
"format_parser_unittest.cc",
"ftrace_config_muxer_unittest.cc",
@@ -114,6 +116,8 @@ source_set("ftrace_reader") {
"atrace_wrapper.h",
"cpu_reader.cc",
"cpu_reader.h",
+ "cpu_stats_parser.cc",
+ "cpu_stats_parser.h",
"event_info.cc",
"event_info.h",
"event_info_constants.cc",
diff --git a/src/ftrace_reader/cpu_stats_parser.cc b/src/ftrace_reader/cpu_stats_parser.cc
new file mode 100644
index 000000000..e5f2e94b8
--- /dev/null
+++ b/src/ftrace_reader/cpu_stats_parser.cc
@@ -0,0 +1,85 @@
+/*
+ * 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/ftrace_reader/cpu_stats_parser.h"
+
+#include "perfetto/base/string_splitter.h"
+#include "perfetto/base/string_utils.h"
+#include "perfetto/ftrace_reader/ftrace_controller.h"
+#include "src/ftrace_reader/ftrace_procfs.h"
+
+namespace perfetto {
+namespace {
+
+uint32_t ExtractInt(const char* s) {
+ for (; *s != '\0'; s++) {
+ if (*s == ':') {
+ return static_cast<uint32_t>(atoi(s + 1));
+ }
+ }
+ return 0;
+}
+
+double ExtractDouble(const char* s) {
+ for (; *s != '\0'; s++) {
+ if (*s == ':') {
+ return strtod(s + 1, nullptr);
+ }
+ }
+ return 0;
+}
+
+} // namespace
+
+bool DumpCpuStats(std::string text, FtraceCpuStats* stats) {
+ if (text.empty())
+ return false;
+
+ base::StringSplitter splitter(std::move(text), '\n');
+ while (splitter.Next()) {
+ if (base::StartsWith(splitter.cur_token(), "entries")) {
+ stats->entries = ExtractInt(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "overrun")) {
+ stats->overrun = ExtractInt(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "commit overrun")) {
+ stats->commit_overrun = ExtractInt(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "bytes")) {
+ stats->bytes_read = ExtractInt(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "oldest event ts")) {
+ stats->oldest_event_ts = ExtractDouble(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "now ts")) {
+ stats->now_ts = ExtractDouble(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "dropped events")) {
+ stats->dropped_events = ExtractInt(splitter.cur_token());
+ } else if (base::StartsWith(splitter.cur_token(), "read events")) {
+ stats->read_events = ExtractInt(splitter.cur_token());
+ }
+ }
+
+ return true;
+}
+
+bool DumpAllCpuStats(FtraceProcfs* ftrace, FtraceStats* stats) {
+ stats->cpu_stats.resize(ftrace->NumberOfCpus(), {});
+ for (size_t cpu = 0; cpu < ftrace->NumberOfCpus(); cpu++) {
+ stats->cpu_stats[cpu].cpu = cpu;
+ if (!DumpCpuStats(ftrace->ReadCpuStats(cpu), &stats->cpu_stats[cpu]))
+ return false;
+ }
+ return true;
+}
+
+} // namespace perfetto
diff --git a/src/ftrace_reader/cpu_stats_parser.h b/src/ftrace_reader/cpu_stats_parser.h
new file mode 100644
index 000000000..5cb4b154e
--- /dev/null
+++ b/src/ftrace_reader/cpu_stats_parser.h
@@ -0,0 +1,33 @@
+/*
+ * 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_FTRACE_READER_CPU_STATS_PARSER_H_
+#define SRC_FTRACE_READER_CPU_STATS_PARSER_H_
+
+#include <string>
+
+namespace perfetto {
+
+class FtraceProcfs;
+struct FtraceStats;
+struct FtraceCpuStats;
+
+bool DumpCpuStats(std::string text, FtraceCpuStats*);
+bool DumpAllCpuStats(FtraceProcfs*, FtraceStats*);
+
+} // namespace perfetto
+
+#endif // SRC_FTRACE_READER_CPU_STATS_PARSER_H_
diff --git a/src/ftrace_reader/cpu_stats_parser_unittest.cc b/src/ftrace_reader/cpu_stats_parser_unittest.cc
new file mode 100644
index 000000000..0bb6a4699
--- /dev/null
+++ b/src/ftrace_reader/cpu_stats_parser_unittest.cc
@@ -0,0 +1,36 @@
+#include "src/ftrace_reader/cpu_stats_parser.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "perfetto/ftrace_reader/ftrace_controller.h"
+
+namespace perfetto {
+namespace {
+
+TEST(CpuStatsParserTest, DumpCpu) {
+ std::string text = R"(entries: 1
+overrun: 2
+commit overrun: 3
+bytes: 4
+oldest event ts: 5123.000
+now ts: 6123.123
+dropped events :7
+read events: 8
+)";
+
+ FtraceCpuStats stats{};
+ EXPECT_TRUE(DumpCpuStats(text, &stats));
+
+ EXPECT_EQ(stats.entries, 1);
+ EXPECT_EQ(stats.overrun, 2);
+ EXPECT_EQ(stats.commit_overrun, 3);
+ EXPECT_EQ(stats.bytes_read, 4);
+ EXPECT_EQ(stats.oldest_event_ts, 5123.000);
+ EXPECT_EQ(stats.now_ts, 6123.123);
+ EXPECT_EQ(stats.dropped_events, 7);
+ EXPECT_EQ(stats.read_events, 8);
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/src/ftrace_reader/ftrace_controller.cc b/src/ftrace_reader/ftrace_controller.cc
index c3a4f4366..b3f81c32c 100644
--- a/src/ftrace_reader/ftrace_controller.cc
+++ b/src/ftrace_reader/ftrace_controller.cc
@@ -33,12 +33,14 @@
#include "perfetto/base/time.h"
#include "perfetto/base/utils.h"
#include "src/ftrace_reader/cpu_reader.h"
+#include "src/ftrace_reader/cpu_stats_parser.h"
#include "src/ftrace_reader/event_info.h"
#include "src/ftrace_reader/ftrace_config_muxer.h"
#include "src/ftrace_reader/ftrace_procfs.h"
#include "src/ftrace_reader/proto_translation_table.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
+#include "perfetto/trace/ftrace/ftrace_stats.pbzero.h"
namespace perfetto {
namespace {
@@ -290,6 +292,7 @@ std::unique_ptr<FtraceSink> FtraceController::CreateSink(
new FtraceSink(std::move(controller_weak), id, std::move(config),
std::move(filter), delegate));
Register(sink.get());
+ delegate->OnCreate(sink.get());
return sink;
}
@@ -339,6 +342,10 @@ void FtraceController::Unregister(FtraceSink* sink) {
StopIfNeeded();
}
+void FtraceController::DumpFtraceStats(FtraceStats* stats) {
+ DumpAllCpuStats(ftrace_procfs_.get(), stats);
+}
+
FtraceSink::FtraceSink(base::WeakPtr<FtraceController> controller_weak,
FtraceConfigId id,
FtraceConfig config,
@@ -359,6 +366,29 @@ const std::set<std::string>& FtraceSink::enabled_events() {
return filter_->enabled_names();
}
+void FtraceSink::DumpFtraceStats(FtraceStats* stats) {
+ if (controller_weak_)
+ controller_weak_->DumpFtraceStats(stats);
+}
+
+void FtraceStats::Write(protos::pbzero::FtraceStats* writer) const {
+ for (const FtraceCpuStats& cpu_specific_stats : cpu_stats) {
+ cpu_specific_stats.Write(writer->add_cpu_stats());
+ }
+}
+
+void FtraceCpuStats::Write(protos::pbzero::FtraceCpuStats* writer) const {
+ writer->set_cpu(cpu);
+ writer->set_entries(entries);
+ writer->set_overrun(overrun);
+ writer->set_commit_overrun(commit_overrun);
+ writer->set_bytes_read(bytes_read);
+ writer->set_oldest_event_ts(oldest_event_ts);
+ writer->set_now_ts(now_ts);
+ writer->set_dropped_events(dropped_events);
+ writer->set_read_events(read_events);
+}
+
FtraceMetadata::FtraceMetadata() {
// A lot of the time there will only be a small number of inodes.
inode_and_device.reserve(10);
diff --git a/src/ftrace_reader/ftrace_controller_unittest.cc b/src/ftrace_reader/ftrace_controller_unittest.cc
index 5ffad09a8..5e3163d9e 100644
--- a/src/ftrace_reader/ftrace_controller_unittest.cc
+++ b/src/ftrace_reader/ftrace_controller_unittest.cc
@@ -22,10 +22,13 @@
#include "perfetto/ftrace_reader/ftrace_config.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
+#include "perfetto/trace/trace_packet.pb.h"
+#include "perfetto/trace/trace_packet.pbzero.h"
#include "src/ftrace_reader/cpu_reader.h"
#include "src/ftrace_reader/ftrace_config_muxer.h"
#include "src/ftrace_reader/ftrace_procfs.h"
#include "src/ftrace_reader/proto_translation_table.h"
+#include "src/tracing/core/trace_writer_for_testing.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -650,4 +653,27 @@ TEST(FtraceMetadataTest, AddPid) {
EXPECT_THAT(metadata.pids, ElementsAre(1, 2, 3));
}
+TEST(FtraceStatsTest, Write) {
+ FtraceStats stats{};
+ FtraceCpuStats cpu_stats{};
+ cpu_stats.cpu = 0;
+ cpu_stats.entries = 1;
+ cpu_stats.overrun = 2;
+ stats.cpu_stats.push_back(cpu_stats);
+
+ std::unique_ptr<TraceWriterForTesting> writer =
+ std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
+ {
+ auto packet = writer->NewTracePacket();
+ auto* out = packet->set_ftrace_stats();
+ stats.Write(out);
+ }
+
+ std::unique_ptr<protos::TracePacket> result_packet = writer->ParseProto();
+ auto result = result_packet->ftrace_stats().cpu_stats(0);
+ EXPECT_EQ(result.cpu(), 0);
+ EXPECT_EQ(result.entries(), 1);
+ EXPECT_EQ(result.overrun(), 2);
+}
+
} // namespace perfetto
diff --git a/src/ftrace_reader/ftrace_procfs.cc b/src/ftrace_reader/ftrace_procfs.cc
index 95294bc5e..70aa050e0 100644
--- a/src/ftrace_reader/ftrace_procfs.cc
+++ b/src/ftrace_reader/ftrace_procfs.cc
@@ -88,6 +88,11 @@ std::string FtraceProcfs::ReadEventFormat(const std::string& group,
return ReadFileIntoString(path);
}
+std::string FtraceProcfs::ReadCpuStats(size_t cpu) const {
+ std::string path = root_ + "per_cpu/cpu" + std::to_string(cpu) + "/stats";
+ return ReadFileIntoString(path);
+}
+
size_t FtraceProcfs::NumberOfCpus() const {
static size_t num_cpus = static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
return num_cpus;
diff --git a/src/ftrace_reader/ftrace_procfs.h b/src/ftrace_reader/ftrace_procfs.h
index faaca88a0..df3729301 100644
--- a/src/ftrace_reader/ftrace_procfs.h
+++ b/src/ftrace_reader/ftrace_procfs.h
@@ -47,6 +47,9 @@ class FtraceProcfs {
virtual std::string ReadEventFormat(const std::string& group,
const std::string& name) const;
+ // Read the "/per_cpu/cpuXX/stats" file for the given |cpu|.
+ std::string ReadCpuStats(size_t cpu) const;
+
// Set ftrace buffer size in pages.
// This size is *per cpu* so for the total size you have to multiply
// by the number of CPUs.
diff --git a/src/ftrace_reader/proto_translation_table.cc b/src/ftrace_reader/proto_translation_table.cc
index 5ce772aff..739e60939 100644
--- a/src/ftrace_reader/proto_translation_table.cc
+++ b/src/ftrace_reader/proto_translation_table.cc
@@ -20,6 +20,7 @@
#include <algorithm>
+#include "perfetto/base/string_utils.h"
#include "perfetto/ftrace_reader/format_parser.h"
#include "src/ftrace_reader/event_info.h"
#include "src/ftrace_reader/ftrace_procfs.h"
@@ -124,10 +125,6 @@ uint16_t MergeFields(const std::vector<FtraceEvent::Field>& ftrace_fields,
return fields_end;
}
-bool StartsWith(const std::string& str, const std::string& prefix) {
- return str.compare(0, prefix.length(), prefix) == 0;
-}
-
bool Contains(const std::string& haystack, const std::string& needle) {
return haystack.find(needle) != std::string::npos;
}
@@ -179,18 +176,18 @@ bool InferFtraceType(const std::string& type_and_name,
}
// Variable length strings: "char foo" + size: 0 (as in 'print').
- if (StartsWith(type_and_name, "char ") && size == 0) {
+ if (base::StartsWith(type_and_name, "char ") && size == 0) {
*out = kFtraceCString;
return true;
}
- if (StartsWith(type_and_name, "bool ")) {
+ if (base::StartsWith(type_and_name, "bool ")) {
*out = kFtraceBool;
return true;
}
- if (StartsWith(type_and_name, "ino_t ") ||
- StartsWith(type_and_name, "i_ino ")) {
+ if (base::StartsWith(type_and_name, "ino_t ") ||
+ base::StartsWith(type_and_name, "i_ino ")) {
if (size == 4) {
*out = kFtraceInode32;
return true;
@@ -200,7 +197,7 @@ bool InferFtraceType(const std::string& type_and_name,
}
}
- if (StartsWith(type_and_name, "dev_t ")) {
+ if (base::StartsWith(type_and_name, "dev_t ")) {
if (size == 4) {
*out = kFtraceDevId32;
return true;
@@ -211,7 +208,7 @@ bool InferFtraceType(const std::string& type_and_name,
}
// Pids (as in 'sched_switch').
- if (StartsWith(type_and_name, "pid_t ") && size == 4) {
+ if (base::StartsWith(type_and_name, "pid_t ") && size == 4) {
*out = kFtracePid32;
return true;
}
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 43b4d0e28..5d0ae5d9a 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -50,7 +50,7 @@ source_set("unittests") {
":probes_src",
"../../../gn:default_deps",
"../../../gn:gtest_deps",
- "../../tracing:unittests",
+ "../../tracing:test_support",
]
sources = [
"process_stats_data_source_unittest.cc",
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 6131d440b..be97d1260 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -35,6 +35,7 @@
#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
+#include "perfetto/trace/ftrace/ftrace_stats.pbzero.h"
#include "perfetto/trace/trace_packet.pbzero.h"
namespace perfetto {
@@ -313,13 +314,36 @@ ProbesProducer::SinkDelegate::SinkDelegate(TracingSessionID id,
ProbesProducer::SinkDelegate::~SinkDelegate() = default;
+void ProbesProducer::SinkDelegate::OnCreate(FtraceSink* sink) {
+ sink->DumpFtraceStats(&stats_before_);
+}
+
void ProbesProducer::SinkDelegate::Flush() {
// TODO(primiano): this still doesn't flush data from the kernel ftrace
// buffers (see b/73886018). We should do that and delay the
// NotifyFlushComplete() until the ftrace data has been drained from the
// kernel ftrace buffer and written in the SMB.
- if (writer_ && (!trace_packet_ || trace_packet_->is_finalized()))
+ if (writer_ && (!trace_packet_ || trace_packet_->is_finalized())) {
+ WriteStats();
writer_->Flush();
+ }
+}
+
+void ProbesProducer::SinkDelegate::WriteStats() {
+ {
+ auto before_packet = writer_->NewTracePacket();
+ auto out = before_packet->set_ftrace_stats();
+ out->set_phase(protos::pbzero::FtraceStats_Phase_START_OF_TRACE);
+ stats_before_.Write(out);
+ }
+ {
+ FtraceStats stats_after{};
+ sink_->DumpFtraceStats(&stats_after);
+ auto after_packet = writer_->NewTracePacket();
+ auto out = after_packet->set_ftrace_stats();
+ out->set_phase(protos::pbzero::FtraceStats_Phase_END_OF_TRACE);
+ stats_after.Write(out);
+ }
}
ProbesProducer::FtraceBundleHandle
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index 7d9d1e093..cefa582f3 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -70,6 +70,8 @@ class ProbesProducer : public Producer {
private:
using FtraceBundleHandle =
protozero::MessageHandle<protos::pbzero::FtraceEventBundle>;
+ using FtraceStatsHandle =
+ protozero::MessageHandle<protos::pbzero::FtraceStats>;
class SinkDelegate : public FtraceSink::Delegate {
public:
@@ -87,6 +89,9 @@ class ProbesProducer : public Producer {
void OnBundleComplete(size_t cpu,
FtraceBundleHandle bundle,
const FtraceMetadata& metadata) override;
+ void OnCreate(FtraceSink*) override;
+
+ void WriteStats();
void set_sink(std::unique_ptr<FtraceSink> sink) { sink_ = std::move(sink); }
@@ -109,6 +114,7 @@ class ProbesProducer : public Producer {
base::TaskRunner* task_runner_;
std::unique_ptr<FtraceSink> sink_ = nullptr;
std::unique_ptr<TraceWriter> writer_;
+ FtraceStats stats_before_ = {};
base::WeakPtr<ProcessStatsDataSource> ps_source_;
base::WeakPtr<InodeFileDataSource> file_source_;
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index 3c181ccad..9fd8db3b2 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -121,6 +121,7 @@ source_set("unittests") {
testonly = true
deps = [
":ipc",
+ ":test_support",
":tracing",
"../../gn:default_deps",
"../../gn:gtest_deps",
@@ -128,7 +129,6 @@ source_set("unittests") {
"../../protos/perfetto/trace:zero",
"../base",
"../base:test_support",
- "../ftrace_reader:test_support",
]
sources = [
"core/id_allocator_unittest.cc",
@@ -141,8 +141,6 @@ source_set("unittests") {
"core/sliced_protobuf_input_stream_unittest.cc",
"core/trace_buffer_unittest.cc",
"core/trace_packet_unittest.cc",
- "core/trace_writer_for_testing.cc",
- "core/trace_writer_for_testing.h",
"core/trace_writer_impl_unittest.cc",
"ipc/posix_shared_memory_unittest.cc",
"test/aligned_buffer_test.cc",
@@ -159,6 +157,20 @@ source_set("unittests") {
]
}
+source_set("test_support") {
+ testonly = true
+ public_deps = [
+ "../../gn:default_deps",
+ "../../protos/perfetto/trace:lite",
+ "../../protos/perfetto/trace:zero",
+ "../ftrace_reader:test_support",
+ ]
+ sources = [
+ "core/trace_writer_for_testing.cc",
+ "core/trace_writer_for_testing.h",
+ ]
+}
+
if (!build_with_chromium) {
source_set("tracing_benchmarks") {
testonly = true