diff options
author | Isabelle Taylor <taylori@google.com> | 2018-04-12 07:29:40 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-04-12 07:29:40 -0700 |
commit | 90ba107f673996697fe76b640c7ecd686927ce1d (patch) | |
tree | a85d1d6f47d09eeb5f4b7f4b76dfe2ab2f467ee0 | |
parent | 9b180bff85e010b7a3eab8770e0bfd6fcc843350 (diff) | |
parent | c0af5300057eb4f9b04fe575e3648d20407b9855 (diff) | |
download | perfetto-90ba107f673996697fe76b640c7ecd686927ce1d.tar.gz |
Merge "ProcessStatsDataSource test"
am: c0af530005
Change-Id: I2bd6b4b0fe4e94cbe5389a8bf12a63cf94cb6c89
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | src/traced/probes/BUILD.gn | 2 | ||||
-rw-r--r-- | src/traced/probes/process_stats_data_source.cc | 29 | ||||
-rw-r--r-- | src/traced/probes/process_stats_data_source.h | 10 | ||||
-rw-r--r-- | src/traced/probes/process_stats_data_source_unittest.cc | 57 | ||||
-rw-r--r-- | src/tracing/BUILD.gn | 3 | ||||
-rw-r--r-- | src/tracing/core/trace_writer_for_testing.cc | 70 | ||||
-rw-r--r-- | src/tracing/core/trace_writer_for_testing.h | 58 |
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_ |