OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "chrome/browser/metrics/process_memory_metrics_emitter.h" | 5 #include "chrome/browser/metrics/process_memory_metrics_emitter.h" |
6 | 6 |
| 7 #include "base/memory/ref_counted.h" |
7 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/test/histogram_tester.h" |
| 10 #include "base/test/trace_event_analyzer.h" |
| 11 #include "base/trace_event/memory_dump_manager.h" |
| 12 #include "base/trace_event/trace_config_memory_test_util.h" |
8 #include "chrome/test/base/in_process_browser_test.h" | 13 #include "chrome/test/base/in_process_browser_test.h" |
| 14 #include "chrome/test/base/tracing.h" |
| 15 #include "chrome/test/base/ui_test_utils.h" |
9 #include "content/public/test/test_utils.h" | 16 #include "content/public/test/test_utils.h" |
| 17 #include "url/gurl.h" |
10 | 18 |
11 namespace { | 19 namespace { |
12 | 20 |
| 21 using base::trace_event::MemoryDumpType; |
| 22 |
| 23 void RequestGlobalDumpCallback(base::Closure quit_closure, |
| 24 uint64_t, |
| 25 bool success) { |
| 26 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure); |
| 27 ASSERT_TRUE(success); |
| 28 } |
| 29 |
| 30 void OnStartTracingDoneCallback( |
| 31 base::trace_event::MemoryDumpLevelOfDetail explicit_dump_type, |
| 32 base::Closure quit_closure) { |
| 33 base::trace_event::MemoryDumpManager::GetInstance()->RequestGlobalDump( |
| 34 MemoryDumpType::EXPLICITLY_TRIGGERED, explicit_dump_type, |
| 35 Bind(&RequestGlobalDumpCallback, quit_closure)); |
| 36 } |
| 37 |
13 class ProcessMemoryMetricsEmitterFake : public ProcessMemoryMetricsEmitter { | 38 class ProcessMemoryMetricsEmitterFake : public ProcessMemoryMetricsEmitter { |
14 public: | 39 public: |
15 ProcessMemoryMetricsEmitterFake() {} | 40 explicit ProcessMemoryMetricsEmitterFake(base::RunLoop* run_loop) |
| 41 : run_loop_(run_loop) {} |
16 | 42 |
17 private: | 43 private: |
18 ~ProcessMemoryMetricsEmitterFake() override {} | 44 ~ProcessMemoryMetricsEmitterFake() override {} |
19 | 45 |
20 void ReceivedMemoryDump( | 46 void ReceivedMemoryDump( |
21 uint64_t dump_guid, | 47 uint64_t dump_guid, |
22 bool success, | 48 bool success, |
23 memory_instrumentation::mojom::GlobalMemoryDumpPtr ptr) override { | 49 memory_instrumentation::mojom::GlobalMemoryDumpPtr ptr) override { |
24 EXPECT_TRUE(success); | 50 EXPECT_TRUE(success); |
25 base::MessageLoop::current()->QuitWhenIdle(); | 51 ProcessMemoryMetricsEmitter::ReceivedMemoryDump(dump_guid, success, |
| 52 std::move(ptr)); |
| 53 if (run_loop_) |
| 54 run_loop_->Quit(); |
26 } | 55 } |
27 | 56 |
| 57 base::RunLoop* run_loop_; |
| 58 |
28 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterFake); | 59 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterFake); |
29 }; | 60 }; |
30 | 61 |
| 62 void CheckMemoryMetric(const std::string& name, |
| 63 const base::HistogramTester& histogram_tester, |
| 64 int count, |
| 65 bool check_minimum) { |
| 66 std::unique_ptr<base::HistogramSamples> samples( |
| 67 histogram_tester.GetHistogramSamplesSinceCreation(name)); |
| 68 ASSERT_TRUE(samples); |
| 69 |
| 70 bool count_matches = samples->TotalCount() == count; |
| 71 // The exact number of renderers present at the time the metrics are emitted |
| 72 // is not deterministic. Sometimes there are 2 renderers instead of 1. |
| 73 if (name.find("Renderer") != std::string::npos) { |
| 74 count_matches = |
| 75 samples->TotalCount() >= count && samples->TotalCount() <= 2 * count; |
| 76 } |
| 77 |
| 78 EXPECT_TRUE(count_matches); |
| 79 if (check_minimum) |
| 80 EXPECT_GT(samples->sum(), 0u) << name; |
| 81 |
| 82 // As a sanity check, no memory stat should exceed 1 GB. |
| 83 int64_t maximum_expected_size = 1ll << 30; |
| 84 EXPECT_LT(samples->sum(), maximum_expected_size) << name; |
| 85 } |
| 86 |
| 87 void CheckAllMemoryMetrics(const base::HistogramTester& histogram_tester, |
| 88 int count) { |
| 89 #if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_LINUX) || \ |
| 90 defined(OS_ANDROID) |
| 91 bool private_footprint_implemented = true; |
| 92 #else |
| 93 bool private_footprint_implemented = false; |
| 94 #endif |
| 95 |
| 96 CheckMemoryMetric("Memory.Experimental.Browser2.Malloc", histogram_tester, |
| 97 count, true); |
| 98 CheckMemoryMetric("Memory.Experimental.Browser2.Resident", histogram_tester, |
| 99 count, true); |
| 100 CheckMemoryMetric("Memory.Experimental.Browser2.PrivateMemoryFootprint", |
| 101 histogram_tester, count, private_footprint_implemented); |
| 102 CheckMemoryMetric("Memory.Experimental.Renderer2.Malloc", histogram_tester, |
| 103 count, true); |
| 104 CheckMemoryMetric("Memory.Experimental.Renderer2.Resident", histogram_tester, |
| 105 count, true); |
| 106 CheckMemoryMetric("Memory.Experimental.Renderer2.BlinkGC", histogram_tester, |
| 107 count, false); |
| 108 CheckMemoryMetric("Memory.Experimental.Renderer2.PartitionAlloc", |
| 109 histogram_tester, count, false); |
| 110 CheckMemoryMetric("Memory.Experimental.Renderer2.V8", histogram_tester, count, |
| 111 true); |
| 112 CheckMemoryMetric("Memory.Experimental.Renderer2.PrivateMemoryFootprint", |
| 113 histogram_tester, count, private_footprint_implemented); |
| 114 } |
| 115 |
31 } // namespace | 116 } // namespace |
32 | 117 |
33 class ProcessMemoryMetricsEmitterTest : public InProcessBrowserTest { | 118 class ProcessMemoryMetricsEmitterTest : public InProcessBrowserTest { |
34 public: | 119 public: |
35 ProcessMemoryMetricsEmitterTest() {} | 120 ProcessMemoryMetricsEmitterTest() {} |
36 ~ProcessMemoryMetricsEmitterTest() override {} | 121 ~ProcessMemoryMetricsEmitterTest() override {} |
37 | 122 |
38 private: | 123 private: |
39 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterTest); | 124 DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMetricsEmitterTest); |
40 }; | 125 }; |
41 | 126 |
42 IN_PROC_BROWSER_TEST_F(ProcessMemoryMetricsEmitterTest, FetchAndEmitMetrics) { | 127 #if defined(ADDRESS_SANITIZER) |
| 128 #define MAYBE_FetchAndEmitMetrics DISABLED_FetchAndEmitMetrics |
| 129 #else |
| 130 #define MAYBE_FetchAndEmitMetrics FetchAndEmitMetrics |
| 131 #endif |
| 132 IN_PROC_BROWSER_TEST_F(ProcessMemoryMetricsEmitterTest, |
| 133 MAYBE_FetchAndEmitMetrics) { |
| 134 GURL url1("about:blank"); |
| 135 ui_test_utils::NavigateToURLWithDisposition( |
| 136 browser(), url1, WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| 137 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
| 138 |
| 139 base::HistogramTester histogram_tester; |
| 140 base::RunLoop run_loop; |
| 141 |
43 // Intentionally let emitter leave scope to check that it correctly keeps | 142 // Intentionally let emitter leave scope to check that it correctly keeps |
44 // itself alive. | 143 // itself alive. |
45 { | 144 { |
46 scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter( | 145 scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter( |
47 new ProcessMemoryMetricsEmitterFake); | 146 new ProcessMemoryMetricsEmitterFake(&run_loop)); |
48 emitter->FetchAndEmitProcessMemoryMetrics(); | 147 emitter->FetchAndEmitProcessMemoryMetrics(); |
49 } | 148 } |
50 | 149 |
51 content::RunMessageLoop(); | 150 run_loop.Run(); |
| 151 |
| 152 CheckAllMemoryMetrics(histogram_tester, 1); |
52 } | 153 } |
| 154 |
| 155 #if defined(ADDRESS_SANITIZER) |
| 156 #define MAYBE_FetchDuringTrace DISABLED_FetchDuringTrace |
| 157 #else |
| 158 #define MAYBE_FetchDuringTrace FetchDuringTrace |
| 159 #endif |
| 160 IN_PROC_BROWSER_TEST_F(ProcessMemoryMetricsEmitterTest, |
| 161 MAYBE_FetchDuringTrace) { |
| 162 GURL url1("about:blank"); |
| 163 ui_test_utils::NavigateToURLWithDisposition( |
| 164 browser(), url1, WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| 165 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
| 166 |
| 167 base::HistogramTester histogram_tester; |
| 168 |
| 169 { |
| 170 base::RunLoop run_loop; |
| 171 |
| 172 base::trace_event::TraceConfig trace_config( |
| 173 base::trace_event::TraceConfigMemoryTestUtil:: |
| 174 GetTraceConfig_EmptyTriggers()); |
| 175 ASSERT_TRUE(tracing::BeginTracingWithTraceConfig( |
| 176 trace_config, Bind(&OnStartTracingDoneCallback, |
| 177 base::trace_event::MemoryDumpLevelOfDetail::DETAILED, |
| 178 run_loop.QuitClosure()))); |
| 179 run_loop.Run(); |
| 180 } |
| 181 |
| 182 { |
| 183 base::RunLoop run_loop; |
| 184 scoped_refptr<ProcessMemoryMetricsEmitterFake> emitter( |
| 185 new ProcessMemoryMetricsEmitterFake(&run_loop)); |
| 186 emitter->FetchAndEmitProcessMemoryMetrics(); |
| 187 |
| 188 run_loop.Run(); |
| 189 } |
| 190 |
| 191 std::string json_events; |
| 192 ASSERT_TRUE(tracing::EndTracing(&json_events)); |
| 193 |
| 194 trace_analyzer::TraceEventVector events; |
| 195 std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer( |
| 196 trace_analyzer::TraceAnalyzer::Create(json_events)); |
| 197 analyzer->FindEvents( |
| 198 trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP), |
| 199 &events); |
| 200 |
| 201 ASSERT_GT(events.size(), 1u); |
| 202 ASSERT_TRUE(trace_analyzer::CountMatches( |
| 203 events, trace_analyzer::Query::EventNameIs(MemoryDumpTypeToString( |
| 204 MemoryDumpType::EXPLICITLY_TRIGGERED)))); |
| 205 |
| 206 CheckAllMemoryMetrics(histogram_tester, 1); |
| 207 } |
| 208 |
| 209 #if defined(ADDRESS_SANITIZER) |
| 210 #define MAYBE_FetchThreeTimes DISABLED_FetchThreeTimes |
| 211 #else |
| 212 #define MAYBE_FetchThreeTimes FetchThreeTimes |
| 213 #endif |
| 214 IN_PROC_BROWSER_TEST_F(ProcessMemoryMetricsEmitterTest, MAYBE_FetchThreeTimes) { |
| 215 GURL url1("about:blank"); |
| 216 ui_test_utils::NavigateToURLWithDisposition( |
| 217 browser(), url1, WindowOpenDisposition::NEW_FOREGROUND_TAB, |
| 218 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); |
| 219 |
| 220 base::HistogramTester histogram_tester; |
| 221 base::RunLoop run_loop; |
| 222 |
| 223 int count = 3; |
| 224 for (int i = 0; i < count; ++i) { |
| 225 // Only the last emitter should stop the run loop. |
| 226 auto emitter = base::MakeShared<ProcessMemoryMetricsEmitterFake>( |
| 227 (i == count - 1) ? &run_loop : nullptr); |
| 228 emitter->FetchAndEmitProcessMemoryMetrics(); |
| 229 } |
| 230 |
| 231 run_loop.Run(); |
| 232 |
| 233 CheckAllMemoryMetrics(histogram_tester, count); |
| 234 } |
OLD | NEW |