Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/trace_event/memory_dump_manager.h" | 5 #include "base/trace_event/memory_dump_manager.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind_helpers.h" | 9 #include "base/bind_helpers.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
| 13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
| 14 #include "base/synchronization/waitable_event.h" | 14 #include "base/synchronization/waitable_event.h" |
| 15 #include "base/test/test_io_thread.h" | 15 #include "base/test/test_io_thread.h" |
| 16 #include "base/test/trace_event_analyzer.h" | 16 #include "base/test/trace_event_analyzer.h" |
| 17 #include "base/thread_task_runner_handle.h" | 17 #include "base/thread_task_runner_handle.h" |
| 18 #include "base/threading/platform_thread.h" | |
| 18 #include "base/threading/thread.h" | 19 #include "base/threading/thread.h" |
| 19 #include "base/trace_event/memory_dump_provider.h" | 20 #include "base/trace_event/memory_dump_provider.h" |
| 20 #include "base/trace_event/process_memory_dump.h" | 21 #include "base/trace_event/process_memory_dump.h" |
| 21 #include "base/trace_event/trace_buffer.h" | 22 #include "base/trace_event/trace_buffer.h" |
| 22 #include "base/trace_event/trace_config_memory_test_util.h" | 23 #include "base/trace_event/trace_config_memory_test_util.h" |
| 23 #include "testing/gmock/include/gmock/gmock.h" | 24 #include "testing/gmock/include/gmock/gmock.h" |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 25 | 26 |
| 26 using testing::_; | 27 using testing::_; |
| 27 using testing::AnyNumber; | 28 using testing::AnyNumber; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 84 const MemoryDumpCallback& callback)); | 85 const MemoryDumpCallback& callback)); |
| 85 | 86 |
| 86 uint64 GetTracingProcessId() const override { | 87 uint64 GetTracingProcessId() const override { |
| 87 NOTREACHED(); | 88 NOTREACHED(); |
| 88 return MemoryDumpManager::kInvalidTracingProcessId; | 89 return MemoryDumpManager::kInvalidTracingProcessId; |
| 89 } | 90 } |
| 90 }; | 91 }; |
| 91 | 92 |
| 92 class MockMemoryDumpProvider : public MemoryDumpProvider { | 93 class MockMemoryDumpProvider : public MemoryDumpProvider { |
| 93 public: | 94 public: |
| 95 MOCK_METHOD0(Destructor, void()); | |
| 94 MOCK_METHOD2(OnMemoryDump, | 96 MOCK_METHOD2(OnMemoryDump, |
| 95 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); | 97 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); |
| 98 | |
| 99 MockMemoryDumpProvider() : enable_mock_destructor(false) {} | |
| 100 ~MockMemoryDumpProvider() override { | |
| 101 if (enable_mock_destructor) | |
| 102 Destructor(); | |
| 103 } | |
| 104 | |
| 105 bool enable_mock_destructor; | |
| 96 }; | 106 }; |
| 97 | 107 |
| 98 class MemoryDumpManagerTest : public testing::Test { | 108 class MemoryDumpManagerTest : public testing::Test { |
| 99 public: | 109 public: |
| 100 MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {} | 110 MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {} |
| 101 | 111 |
| 102 void SetUp() override { | 112 void SetUp() override { |
| 103 last_callback_success_ = false; | 113 last_callback_success_ = false; |
| 104 message_loop_.reset(new MessageLoop()); | 114 message_loop_.reset(new MessageLoop()); |
| 105 mdm_.reset(new MemoryDumpManager()); | 115 mdm_.reset(new MemoryDumpManager()); |
| (...skipping 762 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 868 | 878 |
| 869 ASSERT_EQ(3u, events.size()); | 879 ASSERT_EQ(3u, events.size()); |
| 870 ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123))); | 880 ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123))); |
| 871 ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456))); | 881 ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456))); |
| 872 ASSERT_EQ(1u, trace_analyzer::CountMatches( | 882 ASSERT_EQ(1u, trace_analyzer::CountMatches( |
| 873 events, Query::EventPidIs(GetCurrentProcId()))); | 883 events, Query::EventPidIs(GetCurrentProcId()))); |
| 874 ASSERT_EQ(events[0]->id, events[1]->id); | 884 ASSERT_EQ(events[0]->id, events[1]->id); |
| 875 ASSERT_EQ(events[0]->id, events[2]->id); | 885 ASSERT_EQ(events[0]->id, events[2]->id); |
| 876 } | 886 } |
| 877 | 887 |
| 888 // Tests the basics of the UnregisterAndDeleteDumpProviderAsync(): the | |
| 889 // unregistration should actually delete the providers and not leak them. | |
| 890 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderAsync) { | |
| 891 InitializeMemoryDumpManager(false /* is_coordinator */); | |
| 892 static const int kNumProviders = 3; | |
| 893 int dtor_count = 0; | |
| 894 std::vector<scoped_ptr<MemoryDumpProvider>> mdps; | |
| 895 for (int i = 0; i < kNumProviders; ++i) { | |
| 896 scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); | |
| 897 mdp->enable_mock_destructor = true; | |
| 898 EXPECT_CALL(*mdp, Destructor()) | |
| 899 .WillOnce(Invoke([&dtor_count]() -> void { dtor_count++; })); | |
|
Ruud van Asseldonk
2015/12/29 11:32:46
The |-> void| part can be omitted.
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Did I already say this week that I hate C++11 lam
| |
| 900 RegisterDumpProvider(mdp.get()); | |
| 901 mdps.push_back(std::move(mdp)); | |
| 902 } | |
| 903 | |
| 904 while (!mdps.empty()) { | |
| 905 mdm_->UnregisterAndDeleteDumpProviderAsync(std::move(mdps.back())); | |
|
Ruud van Asseldonk
2015/12/29 11:32:46
So actually deletion is happening synchronously he
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Ok, Ok. I see what you mean. I renamed the method
| |
| 906 mdps.pop_back(); | |
| 907 } | |
| 908 | |
| 909 ASSERT_EQ(kNumProviders, dtor_count); | |
| 910 } | |
| 911 | |
| 912 // This test checks against races when unregistering an unbound dump provider | |
| 913 // from another thread while dumping. It register one MDP and when | |
|
ssid
2015/12/22 16:14:56
s/register/registers/
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Done.
| |
| 914 // OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderAsync() | |
| 915 // from another thread. The OnMemoryDump() and the dtor call are expected to | |
| 916 // happen on the same thread (the MemoryDumpManager utility thread). | |
| 917 TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderAsyncDuringDump) { | |
| 918 InitializeMemoryDumpManager(false /* is_coordinator */); | |
| 919 scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider); | |
| 920 mdp->enable_mock_destructor = true; | |
| 921 RegisterDumpProvider(mdp.get()); | |
| 922 | |
| 923 base::PlatformThreadRef thread_ref; | |
| 924 auto self_unregister_from_another_thread = [&mdp, &thread_ref]( | |
| 925 const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { | |
| 926 thread_ref = PlatformThread::CurrentRef(); | |
| 927 TestIOThread thread_for_unregistration(TestIOThread::kAutoStart); | |
| 928 thread_for_unregistration.PostTaskAndWait( | |
| 929 FROM_HERE, | |
| 930 base::Bind( | |
| 931 &MemoryDumpManager::UnregisterAndDeleteDumpProviderAsync, | |
| 932 base::Unretained(MemoryDumpManager::GetInstance()), | |
| 933 base::Passed(scoped_ptr<MemoryDumpProvider>(std::move(mdp))))); | |
|
Ruud van Asseldonk
2015/12/29 11:32:46
Why is the extra |scoped_ptr| temporary required?
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
I know but this is for upcasting from scoped_ptr<M
Ruud van Asseldonk
2016/01/04 15:43:01
Ah, I see.
| |
| 934 thread_for_unregistration.Stop(); | |
| 935 return true; | |
| 936 }; | |
| 937 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) | |
| 938 .Times(1) | |
| 939 .WillOnce(Invoke(self_unregister_from_another_thread)); | |
| 940 EXPECT_CALL(*mdp, Destructor()) | |
| 941 .Times(1) | |
| 942 .WillOnce(Invoke([&thread_ref]() -> void { | |
|
Ruud van Asseldonk
2015/12/29 11:32:46
The |-> void| part can be omitted.
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
Done.
| |
| 943 EXPECT_EQ(thread_ref, PlatformThread::CurrentRef()); | |
| 944 })); | |
| 945 | |
| 946 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); | |
| 947 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2); | |
| 948 for (int i = 0; i < 2; ++i) { | |
| 949 RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, | |
| 950 MemoryDumpLevelOfDetail::DETAILED); | |
| 951 } | |
| 952 DisableTracing(); | |
| 953 | |
| 954 // Ownership of |mdp| should have been transferred to the MemoryDumpManager at | |
| 955 // the time UnregisterAndDeleteDumpProviderAsync() was called. | |
| 956 ASSERT_FALSE(mdp); | |
|
Ruud van Asseldonk
2015/12/29 11:32:46
I would say |ASSERT_NE(nullptr, mdp.get())|, |mdp|
Primiano Tucci (use gerrit)
2016/01/04 14:44:38
I think you are right. What I am really doing here
| |
| 957 } | |
| 958 | |
| 878 } // namespace trace_event | 959 } // namespace trace_event |
| 879 } // namespace base | 960 } // namespace base |
| OLD | NEW |