1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "testing/gmock/include/gmock/gmock.h"
using base::trace_event::MemoryDumpArgs;
using base::trace_event::MemoryDumpManager;
using base::trace_event::MemoryDumpType;
using base::trace_event::ProcessMemoryDump;
using testing::_;
using testing::Return;
namespace content {
// A mock dump provider, used to check that dump requests actually end up
// creating memory dumps.
class MockDumpProvider : public base::trace_event::MemoryDumpProvider {
public:
MOCK_METHOD2(OnMemoryDump, bool(const MemoryDumpArgs& args,
ProcessMemoryDump* pmd));
};
class MemoryTracingTest : public ContentBrowserTest {
public:
void DoRequestGlobalDump(const base::trace_event::MemoryDumpCallback& cb) {
MemoryDumpArgs dump_args = { MemoryDumpArgs::LevelOfDetail::HIGH };
MemoryDumpManager::GetInstance()->RequestGlobalDump(
MemoryDumpType::EXPLICITLY_TRIGGERED, dump_args, cb);
}
// Used as callback argument for MemoryDumpManager::RequestGlobalDump():
void OnGlobalMemoryDumpDone(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
base::Closure closure,
uint64 dump_guid,
bool success) {
// Make sure we run the RunLoop closure on the same thread that originated
// the run loop (which is the IN_PROC_BROWSER_TEST_F main thread).
if (!task_runner->RunsTasksOnCurrentThread()) {
task_runner->PostTask(
FROM_HERE, base::Bind(&MemoryTracingTest::OnGlobalMemoryDumpDone,
base::Unretained(this), task_runner, closure,
dump_guid, success));
return;
}
++callback_call_count_;
last_callback_dump_guid_ = dump_guid;
last_callback_success_ = success;
closure.Run();
}
protected:
void SetUp() override {
callback_call_count_ = 0;
last_callback_dump_guid_ = 0;
last_callback_success_ = false;
// TODO(primiano): This should be done via TraceConfig.
// See https://goo.gl/5Hj3o0.
MemoryDumpManager::GetInstance()->DisablePeriodicDumpsForTesting();
mock_dump_provider_.reset(new MockDumpProvider());
MemoryDumpManager::GetInstance()->RegisterDumpProvider(
mock_dump_provider_.get());
ContentBrowserTest::SetUp();
}
void TearDown() override {
MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
mock_dump_provider_.get());
mock_dump_provider_.reset();
ContentBrowserTest::TearDown();
}
void EnableMemoryTracing() {
base::RunLoop run_loop;
std::string category_filter = MemoryDumpManager::kTraceCategory;
base::trace_event::TraceConfig trace_config(category_filter, "");
bool success = TracingController::GetInstance()->EnableRecording(
trace_config, run_loop.QuitClosure());
EXPECT_TRUE(success);
run_loop.Run();
}
void DisableTracing() {
bool success = TracingController::GetInstance()->DisableRecording(NULL);
EXPECT_TRUE(success);
base::RunLoop().RunUntilIdle();
}
void RequestGlobalDumpAndWait(bool from_renderer_thread) {
base::RunLoop run_loop;
base::trace_event::MemoryDumpCallback callback = base::Bind(
&MemoryTracingTest::OnGlobalMemoryDumpDone, base::Unretained(this),
base::ThreadTaskRunnerHandle::Get(), run_loop.QuitClosure());
if (from_renderer_thread) {
PostTaskToInProcessRendererAndWait(
base::Bind(&MemoryTracingTest::DoRequestGlobalDump,
base::Unretained(this), callback));
} else {
DoRequestGlobalDump(callback);
}
run_loop.Run();
}
void Navigate(Shell* shell) {
NavigateToURL(shell, GetTestUrl("", "title.html"));
}
base::Closure on_memory_dump_complete_closure_;
scoped_ptr<MockDumpProvider> mock_dump_provider_;
uint32 callback_call_count_;
uint64 last_callback_dump_guid_;
bool last_callback_success_;
};
// Ignore SingleProcessMemoryTracingTests for Google Chrome builds because
// single-process is not supported on those builds.
#if !defined(GOOGLE_CHROME_BUILD)
class SingleProcessMemoryTracingTest : public MemoryTracingTest {
public:
SingleProcessMemoryTracingTest() {}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kSingleProcess);
}
};
// Checks that a memory dump initiated from a the main browser thread ends up in
// a single dump even in single process mode.
IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest,
BrowserInitiatedSingleDump) {
Navigate(shell());
EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_)).WillOnce(Return(true));
EnableMemoryTracing();
RequestGlobalDumpAndWait(false /* from_renderer_thread */);
EXPECT_EQ(1u, callback_call_count_);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
DisableTracing();
}
// Checks that a memory dump initiated from a renderer thread ends up in a
// single dump even in single process mode.
IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest,
RendererInitiatedSingleDump) {
Navigate(shell());
EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_)).WillOnce(Return(true));
EnableMemoryTracing();
RequestGlobalDumpAndWait(true /* from_renderer_thread */);
EXPECT_EQ(1u, callback_call_count_);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
DisableTracing();
}
IN_PROC_BROWSER_TEST_F(SingleProcessMemoryTracingTest, ManyInterleavedDumps) {
Navigate(shell());
EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_))
.Times(4)
.WillRepeatedly(Return(true));
EnableMemoryTracing();
RequestGlobalDumpAndWait(true /* from_renderer_thread */);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
RequestGlobalDumpAndWait(false /* from_renderer_thread */);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
RequestGlobalDumpAndWait(false /* from_renderer_thread */);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
RequestGlobalDumpAndWait(true /* from_renderer_thread */);
EXPECT_EQ(4u, callback_call_count_);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
DisableTracing();
}
#endif // !defined(GOOGLE_CHROME_BUILD)
// Checks that a memory dump initiated from a the main browser thread ends up in
// a successful dump.
IN_PROC_BROWSER_TEST_F(MemoryTracingTest, BrowserInitiatedDump) {
Navigate(shell());
EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_,_)).WillOnce(Return(true));
EnableMemoryTracing();
RequestGlobalDumpAndWait(false /* from_renderer_thread */);
EXPECT_EQ(1u, callback_call_count_);
EXPECT_NE(0u, last_callback_dump_guid_);
EXPECT_TRUE(last_callback_success_);
DisableTracing();
}
} // namespace content
|