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
|
// Copyright (c) 2012 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/callback.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "content/shell/shell.h"
#include "content/test/content_browser_test.h"
#include "content/test/content_browser_test_utils.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "net/base/net_util.h"
namespace {
// Observer to report GPU memory usage when requested.
class GpuMemoryBytesAllocatedObserver
: public content::GpuDataManagerObserver {
public:
GpuMemoryBytesAllocatedObserver()
: bytes_allocated_(0) {
}
virtual ~GpuMemoryBytesAllocatedObserver() {
}
virtual void OnGpuInfoUpdate() OVERRIDE {}
virtual void OnVideoMemoryUsageStatsUpdate(
const content::GPUVideoMemoryUsageStats& video_memory_usage_stats)
OVERRIDE {
bytes_allocated_ = video_memory_usage_stats.bytes_allocated;
message_loop_runner_->Quit();
}
size_t GetBytesAllocated() {
message_loop_runner_ = new content::MessageLoopRunner;
content::GpuDataManager::GetInstance()->AddObserver(this);
content::GpuDataManager::GetInstance()->
RequestVideoMemoryUsageStatsUpdate();
message_loop_runner_->Run();
content::GpuDataManager::GetInstance()->RemoveObserver(this);
message_loop_runner_ = NULL;
return bytes_allocated_;
}
private:
size_t bytes_allocated_;
scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
};
class GpuMemoryTest : public content::ContentBrowserTest {
public:
GpuMemoryTest()
: allow_tests_to_run_(false),
has_used_first_shell_(false) {
}
virtual ~GpuMemoryTest() {
}
virtual void SetUpInProcessBrowserTestFixture() {
FilePath test_dir;
ASSERT_TRUE(PathService::Get(content::DIR_TEST_DATA, &test_dir));
gpu_test_dir_ = test_dir.AppendASCII("gpu");
}
virtual void SetUpCommandLine(CommandLine* command_line) {
command_line->AppendSwitch(switches::kEnableLogging);
command_line->AppendSwitch(switches::kForceCompositingMode);
// TODO: Use switches::kForceGpuMemAvailableMb to fix the memory limit
// (this is failing some bots (probably because of differing meanings of
// GPU_EXPORT)
// Only run this on GPU bots for now. These tests should work with
// any GPU process, but may be slow.
if (command_line->HasSwitch(switches::kUseGpuInTests)) {
allow_tests_to_run_ = true;
}
// Don't enable these tests on Android just yet (they use lots of memory and
// may not be stable).
#if defined(OS_ANDROID)
allow_tests_to_run_ = false;
#endif
}
enum PageType {
PAGE_CSS3D,
PAGE_WEBGL,
};
// Load a page and consume a specified amount of GPU memory.
void LoadPage(content::Shell* shell_to_load,
PageType page_type,
size_t mb_to_use) {
FilePath url;
switch (page_type) {
case PAGE_CSS3D:
url = gpu_test_dir_.AppendASCII("mem_css3d.html");
break;
case PAGE_WEBGL:
url = gpu_test_dir_.AppendASCII("mem_webgl.html");
break;
}
content::NavigateToURL(shell_to_load, net::FilePathToFileURL(url));
std::ostringstream js_call;
js_call << "useGpuMemory(";
js_call << mb_to_use;
js_call << ");";
content::DOMMessageQueue message_queue;
std::string message;
ASSERT_TRUE(content::ExecuteScript(
shell_to_load->web_contents(), js_call.str()));
ASSERT_TRUE(message_queue.WaitForMessage(&message));
EXPECT_EQ("\"DONE_USE_GPU_MEMORY\"", message);
}
// Create a new tab.
content::Shell* CreateNewTab() {
// The ContentBrowserTest will create one shell by default, use that one
// first so that we don't confuse the memory manager into thinking there
// are more windows than there are.
content::Shell* new_shell =
has_used_first_shell_ ? CreateBrowser() : shell();
has_used_first_shell_ = true;
visible_shells_.insert(new_shell);
return new_shell;
}
void SetTabBackgrounded(content::Shell* shell_to_background) {
ASSERT_TRUE(
visible_shells_.find(shell_to_background) != visible_shells_.end());
visible_shells_.erase(shell_to_background);
shell_to_background->web_contents()->WasHidden();
}
size_t GetMemoryUsageMbytes() {
// TODO: This should wait until all effects of memory management complete.
// We will need to wait until all
// 1. pending commits from the main thread to the impl thread in the
// compositor complete (for visible compositors).
// 2. allocations that the renderer's impl thread will make due to the
// compositor and WebGL are completed.
// 3. pending GpuMemoryManager::Manage() calls to manage are made.
// 4. renderers' OnMemoryAllocationChanged callbacks in response to
// manager are made.
// Each step in this sequence can cause trigger the next (as a 1-2-3-4-1
// cycle), so we will need to pump this cycle until it stabilizes.
GpuMemoryBytesAllocatedObserver observer;
observer.GetBytesAllocated();
return observer.GetBytesAllocated() / 1048576;
}
bool AllowTestsToRun() const {
return allow_tests_to_run_;
}
private:
bool allow_tests_to_run_;
std::set<content::Shell*> visible_shells_;
bool has_used_first_shell_;
FilePath gpu_test_dir_;
};
} // namespace
|