aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsabelle Taylor <taylori@google.com>2018-04-12 07:29:40 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-04-12 07:29:40 -0700
commit90ba107f673996697fe76b640c7ecd686927ce1d (patch)
treea85d1d6f47d09eeb5f4b7f4b76dfe2ab2f467ee0
parent9b180bff85e010b7a3eab8770e0bfd6fcc843350 (diff)
parentc0af5300057eb4f9b04fe575e3648d20407b9855 (diff)
downloadperfetto-90ba107f673996697fe76b640c7ecd686927ce1d.tar.gz
Merge "ProcessStatsDataSource test"
am: c0af530005 Change-Id: I2bd6b4b0fe4e94cbe5389a8bf12a63cf94cb6c89
-rw-r--r--Android.bp1
-rw-r--r--src/traced/probes/BUILD.gn2
-rw-r--r--src/traced/probes/process_stats_data_source.cc29
-rw-r--r--src/traced/probes/process_stats_data_source.h10
-rw-r--r--src/traced/probes/process_stats_data_source_unittest.cc57
-rw-r--r--src/tracing/BUILD.gn3
-rw-r--r--src/tracing/core/trace_writer_for_testing.cc70
-rw-r--r--src/tracing/core/trace_writer_for_testing.h58
8 files changed, 214 insertions, 16 deletions
diff --git a/Android.bp b/Android.bp
index 91d8a967d..2406d006a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3680,6 +3680,7 @@ cc_test {
"src/tracing/core/trace_config.cc",
"src/tracing/core/trace_packet.cc",
"src/tracing/core/trace_packet_unittest.cc",
+ "src/tracing/core/trace_writer_for_testing.cc",
"src/tracing/core/trace_writer_impl.cc",
"src/tracing/core/trace_writer_impl_unittest.cc",
"src/tracing/core/virtual_destructors.cc",
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 976657c2f..a823fcfd0 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -51,6 +51,8 @@ source_set("unittests") {
":probes_src",
"../../../gn:default_deps",
"../../../gn:gtest_deps",
+ "../../process_stats:process_stats",
+ "../../tracing:unittests",
]
sources = [
"process_stats_data_source_unittest.cc",
diff --git a/src/traced/probes/process_stats_data_source.cc b/src/traced/probes/process_stats_data_source.cc
index 344d51f77..53e7dd343 100644
--- a/src/traced/probes/process_stats_data_source.cc
+++ b/src/traced/probes/process_stats_data_source.cc
@@ -45,17 +45,18 @@ void ProcessStatsDataSource::WriteAllProcesses() {
auto* process_tree = trace_packet->set_process_tree();
std::set<int32_t>* seen_pids = &seen_pids_;
- file_utils::ForEachPidInProcPath("/proc", [process_tree, 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;
+ file_utils::ForEachPidInProcPath("/proc",
+ [this, process_tree, 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, process_tree);
- seen_pids->insert(pid);
- });
+ WriteProcess(pid, process_tree);
+ seen_pids->insert(pid);
+ });
}
void ProcessStatsDataSource::OnPids(const std::vector<int32_t>& pids) {
@@ -77,10 +78,14 @@ void ProcessStatsDataSource::Flush() {
writer_->Flush();
}
-// static
+// To be overidden for testing.
+std::unique_ptr<ProcessInfo> ProcessStatsDataSource::ReadProcessInfo(int pid) {
+ return procfs_utils::ReadProcessInfo(pid);
+}
+
void ProcessStatsDataSource::WriteProcess(int32_t pid,
protos::pbzero::ProcessTree* tree) {
- std::unique_ptr<ProcessInfo> process = procfs_utils::ReadProcessInfo(pid);
+ std::unique_ptr<ProcessInfo> process = ReadProcessInfo(pid);
procfs_utils::ReadProcessThreads(process.get());
auto* process_writer = tree->add_processes();
process_writer->set_pid(process->pid);
diff --git a/src/traced/probes/process_stats_data_source.h b/src/traced/probes/process_stats_data_source.h
index 7a6426980..32d2057d5 100644
--- a/src/traced/probes/process_stats_data_source.h
+++ b/src/traced/probes/process_stats_data_source.h
@@ -26,6 +26,7 @@
#include "perfetto/tracing/core/basic_types.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/trace_writer.h"
+#include "src/process_stats/process_info.h"
namespace perfetto {
@@ -34,7 +35,7 @@ class ProcessStatsDataSource {
ProcessStatsDataSource(TracingSessionID,
std::unique_ptr<TraceWriter> writer,
const DataSourceConfig&);
- ~ProcessStatsDataSource();
+ virtual ~ProcessStatsDataSource();
TracingSessionID session_id() const { return session_id_; }
const DataSourceConfig& config() const { return config_; }
@@ -44,12 +45,15 @@ class ProcessStatsDataSource {
void OnPids(const std::vector<int32_t>& pids);
void Flush();
- private:
- static void WriteProcess(int32_t pid, protos::pbzero::ProcessTree*);
+ // Virtual for testing.
+ virtual std::unique_ptr<ProcessInfo> ReadProcessInfo(int pid);
+ private:
ProcessStatsDataSource(const ProcessStatsDataSource&) = delete;
ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete;
+ void WriteProcess(int32_t pid, protos::pbzero::ProcessTree*);
+
const TracingSessionID session_id_;
std::unique_ptr<TraceWriter> writer_;
const DataSourceConfig config_;
diff --git a/src/traced/probes/process_stats_data_source_unittest.cc b/src/traced/probes/process_stats_data_source_unittest.cc
index 2faff6e0c..1d4e040ba 100644
--- a/src/traced/probes/process_stats_data_source_unittest.cc
+++ b/src/traced/probes/process_stats_data_source_unittest.cc
@@ -15,14 +15,69 @@
*/
#include "src/traced/probes/process_stats_data_source.h"
+#include "perfetto/trace/trace_packet.pb.h"
+#include "perfetto/trace/trace_packet.pbzero.h"
+
+#include "src/process_stats/process_info.h"
+#include "src/tracing/core/trace_writer_for_testing.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+using ::testing::Invoke;
+
namespace perfetto {
namespace {
-// TODO(hjd): Add tests.
+class TestProcessStatsDataSource : public ProcessStatsDataSource {
+ public:
+ TestProcessStatsDataSource(TracingSessionID id,
+ std::unique_ptr<TraceWriter> writer,
+ const DataSourceConfig& config)
+ : ProcessStatsDataSource(id, std::move(writer), config) {}
+
+ MOCK_METHOD1(ReadProcessInfo, std::unique_ptr<ProcessInfo>(int pid));
+};
+
+class ProcessStatsDataSourceTest : public ::testing::Test {
+ protected:
+ ProcessStatsDataSourceTest() {}
+
+ TraceWriterForTesting* writer_raw_;
+
+ std::unique_ptr<TestProcessStatsDataSource> GetProcessStatsDataSource(
+ const DataSourceConfig& cfg) {
+ auto writer =
+ std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
+ writer_raw_ = writer.get();
+ return std::unique_ptr<TestProcessStatsDataSource>(
+ new TestProcessStatsDataSource(0, std::move(writer), cfg));
+ }
+
+ static std::unique_ptr<ProcessInfo> GetProcessInfo(int pid) {
+ ProcessInfo* process = new ProcessInfo();
+ process->pid = pid;
+ process->in_kernel = true; // So that it doesn't try to read threads.
+ process->ppid = 0;
+ process->cmdline.push_back("test_process");
+ return std::unique_ptr<ProcessInfo>(process);
+ }
+};
+
+TEST_F(ProcessStatsDataSourceTest, TestWriteOnDemand) {
+ DataSourceConfig config;
+ auto data_source = GetProcessStatsDataSource(config);
+ EXPECT_CALL(*data_source, ReadProcessInfo(42))
+ .WillRepeatedly(Invoke(GetProcessInfo));
+ data_source->OnPids({42});
+ std::unique_ptr<protos::TracePacket> packet = writer_raw_->ParseProto();
+ ASSERT_TRUE(packet->has_process_tree());
+ ASSERT_EQ(packet->process_tree().processes_size(), 1);
+ auto first_process = packet->process_tree().processes(0);
+ ASSERT_EQ(first_process.pid(), 42);
+ ASSERT_EQ(first_process.ppid(), 0);
+ ASSERT_EQ(first_process.cmdline(0), std::string("test_process"));
+}
} // namespace
} // namespace perfetto
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index 3a682e7a9..3c181ccad 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -128,6 +128,7 @@ source_set("unittests") {
"../../protos/perfetto/trace:zero",
"../base",
"../base:test_support",
+ "../ftrace_reader:test_support",
]
sources = [
"core/id_allocator_unittest.cc",
@@ -140,6 +141,8 @@ 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",
diff --git a/src/tracing/core/trace_writer_for_testing.cc b/src/tracing/core/trace_writer_for_testing.cc
new file mode 100644
index 000000000..1b7e5316e
--- /dev/null
+++ b/src/tracing/core/trace_writer_for_testing.cc
@@ -0,0 +1,70 @@
+/*
+ * 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/trace_writer_for_testing.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 {
+
+TraceWriterForTesting::TraceWriterForTesting()
+ : delegate_(static_cast<size_t>(base::kPageSize)), stream_(&delegate_) {
+ delegate_.set_writer(&stream_);
+ cur_packet_.reset(new protos::pbzero::TracePacket());
+ cur_packet_->Finalize(); // To avoid the DCHECK in NewTracePacket().
+}
+
+TraceWriterForTesting::~TraceWriterForTesting() {}
+
+void TraceWriterForTesting::Flush(std::function<void()> callback) {
+ // Flush() cannot be called in the middle of a TracePacket.
+ PERFETTO_CHECK(cur_packet_->is_finalized());
+
+ if (callback)
+ callback();
+}
+
+std::unique_ptr<protos::TracePacket> TraceWriterForTesting::ParseProto() {
+ PERFETTO_CHECK(cur_packet_->is_finalized());
+ size_t chunk_size_ = base::kPageSize;
+ auto packet = std::unique_ptr<protos::TracePacket>(new protos::TracePacket());
+ size_t msg_size =
+ delegate_.chunks().size() * chunk_size_ - stream_.bytes_available();
+ std::unique_ptr<uint8_t[]> buffer = delegate_.StitchChunks(msg_size);
+ if (!packet->ParseFromArray(buffer.get(), static_cast<int>(msg_size)))
+ return nullptr;
+ return packet;
+}
+
+TraceWriterForTesting::TracePacketHandle
+TraceWriterForTesting::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 TraceWriterForTesting::writer_id() const {
+ return 0;
+}
+
+} // namespace perfetto
diff --git a/src/tracing/core/trace_writer_for_testing.h b/src/tracing/core/trace_writer_for_testing.h
new file mode 100644
index 000000000..6937095ad
--- /dev/null
+++ b/src/tracing/core/trace_writer_for_testing.h
@@ -0,0 +1,58 @@
+/*
+ * 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_TRACE_WRITER_FOR_TESTING_H_
+#define SRC_TRACING_CORE_TRACE_WRITER_FOR_TESTING_H_
+
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/trace/trace_packet.pb.h"
+#include "perfetto/tracing/core/trace_writer.h"
+#include "src/ftrace_reader/test/scattered_stream_delegate_for_testing.h"
+
+namespace perfetto {
+
+// A specialization of TraceWriter for testing which writes into memory
+// allocated by the ScatteredStreamDelegateForTesting.
+// See //include/perfetto/tracing/core/trace_writer.h for docs.
+class TraceWriterForTesting : public TraceWriter {
+ public:
+ // TraceWriterForTesting(const ScatteredStreamDelegateForTesting& delegate);
+ TraceWriterForTesting();
+ ~TraceWriterForTesting() 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;
+
+ std::unique_ptr<protos::TracePacket> ParseProto();
+
+ WriterID writer_id() const override;
+
+ private:
+ TraceWriterForTesting(const TraceWriterForTesting&) = delete;
+ TraceWriterForTesting& operator=(const TraceWriterForTesting&) = delete;
+
+ ScatteredStreamDelegateForTesting 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_TRACE_WRITER_FOR_TESTING_H_