Chromium Code Reviews| Index: chrome/test/gpu/gpu_memory_test.cc |
| diff --git a/chrome/test/gpu/gpu_memory_test.cc b/chrome/test/gpu/gpu_memory_test.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1718c861b46f799680de0c776df4f49645a05a15 |
| --- /dev/null |
| +++ b/chrome/test/gpu/gpu_memory_test.cc |
| @@ -0,0 +1,230 @@ |
| +// 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/basictypes.h" |
| +#include "base/command_line.h" |
| +#include "base/file_util.h" |
| +#include "base/json/json_reader.h" |
| +#include "base/json/json_writer.h" |
| +#include "chrome/browser/net/url_fixer_upper.h" |
| +#include "chrome/common/chrome_switches.h" |
| +#include "chrome/test/automation/automation_proxy.h" |
| +#include "chrome/test/automation/browser_proxy.h" |
| +#include "chrome/test/automation/tab_proxy.h" |
| +#include "chrome/test/automation/window_proxy.h" |
| +#include "chrome/test/base/ui_test_utils.h" |
| +#include "chrome/test/ui/ui_test.h" |
| +#include "googleurl/src/gurl.h" |
| +#include "gpu/command_buffer/service/gpu_switches.h" |
|
ccameron
2013/01/03 19:07:56
Is this a layering violation -- should the switch
|
| +#include "net/base/net_util.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace { |
| + |
| +// Run the tests with a memory limit of 256MB, and give |
| +// and extra 32MB of wiggle-room for over-allocation. |
| +const char *kMemoryLimitSwitch = "256"; |
| +const size_t kMemoryLimit = 256 + 32; |
| + |
| +class GpuMemoryTest : public UITest { |
|
Zhenyao Mo
2013/01/03 20:27:07
Does this truly needs to be a UI test? Will conte
ccameron
2013/01/04 21:52:35
Yes, this should have been content browser tests.
|
| + public: |
| + GpuMemoryTest() : window_count_(1) { |
| + show_window_ = true; |
| + dom_automation_enabled_ = true; |
| + } |
| + |
| + ~GpuMemoryTest() { |
| + } |
| + |
| + virtual void SetUp() { |
| + launch_arguments_.AppendSwitch(switches::kEnableLogging); |
| + launch_arguments_.AppendSwitch(switches::kForceCompositingMode); |
| + launch_arguments_.AppendSwitchASCII(switches::kForceGpuMemAvailableMb, |
| + kMemoryLimitSwitch); |
| + UITest::SetUp(); |
| + } |
| + |
| + enum PageType { |
| + PAGE_SIMPLE, |
| + PAGE_CSS3D, |
| + PAGE_WEBGL, |
| + }; |
| + |
| + GURL GetPageGURL(PageType page_type) { |
| + const FilePath kDataPath(FILE_PATH_LITERAL("gpu")); |
| + const FilePath kCurrentDir(FilePath::kCurrentDirectory); |
|
Zhenyao Mo
2013/01/03 20:27:07
kCurrentDir is never used.
ccameron
2013/01/04 21:52:35
Removed (from the new test).
|
| + FilePath page_path; |
| + switch (page_type) { |
| + case PAGE_SIMPLE: |
| + page_path = ui_test_utils::GetTestFilePath( |
| + kDataPath, |
| + FilePath(FILE_PATH_LITERAL("mem_simple.html"))); |
| + break; |
| + case PAGE_CSS3D: |
| + page_path = ui_test_utils::GetTestFilePath( |
| + kDataPath, |
| + FilePath(FILE_PATH_LITERAL("mem_css3d.html"))); |
| + break; |
| + case PAGE_WEBGL: |
| + page_path = ui_test_utils::GetTestFilePath( |
| + kDataPath, |
| + FilePath(FILE_PATH_LITERAL("mem_webgl.html"))); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + return net::FilePathToFileURL(page_path); |
| + } |
| + |
| + BrowserProxy* GetCurrentWindow() { |
| + return automation()->GetBrowserWindow(window_count_ - 1); |
| + } |
| + |
| + size_t MemoryUsageMbytes() { |
| + std::string request, response, error; |
|
ccameron
2013/01/03 19:07:56
I use JSON to get the memory values. There is not
Zhenyao Mo
2013/01/03 20:27:07
I don't see any problem doing it, but I am not an
ccameron
2013/01/04 21:52:35
Changing to browser test removes this.
|
| + DictionaryValue request_dict; |
| + request_dict.SetString("command", "GetGpuMemoryUsage"); |
| + base::JSONWriter::Write(&request_dict, &request); |
| + |
| + bool result = GetCurrentWindow()->SendJSONRequest( |
| + request, -1, &response); |
| + EXPECT_TRUE(result); |
| + |
| + scoped_ptr<Value> values(base::JSONReader::ReadAndReturnError( |
| + response, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error)); |
| + EXPECT_TRUE(error.empty()); |
| + EXPECT_EQ(values->GetType(), Value::TYPE_DICTIONARY); |
| + |
| + DictionaryValue* values_dict = static_cast<DictionaryValue*>(values.get()); |
| + int mbytes_allocated = 0; |
| + result = values_dict->GetInteger("gpu_memory_mbytes_allocated", |
| + &mbytes_allocated); |
| + EXPECT_TRUE(result); |
| + |
| + return static_cast<size_t>(mbytes_allocated); |
| + } |
| + |
| + void NewTab() { |
| + scoped_refptr<BrowserProxy> window(GetCurrentWindow()); |
| + ASSERT_TRUE(window.get()); |
| + scoped_refptr<TabProxy> tab(window->GetActiveTab()); |
| + EXPECT_TRUE(window->AppendTab(GetPageGURL(PAGE_SIMPLE))); |
| + tab = window->GetActiveTab(); |
| + ASSERT_TRUE(tab.get()); |
| + } |
| + |
| + void NewWindow() { |
| + int actual_window_count = -1;; |
| + scoped_refptr<BrowserProxy> window(GetCurrentWindow()); |
| + ASSERT_TRUE(window.get()); |
| + EXPECT_TRUE(automation()->GetBrowserWindowCount(&actual_window_count)); |
| + EXPECT_EQ(actual_window_count, window_count_); |
| + window_count_ += 1; |
| + EXPECT_TRUE(automation()->OpenNewBrowserWindow(Browser::TYPE_TABBED, |
| + true)); |
| + EXPECT_TRUE(automation()->WaitForWindowCountToBecome( |
| + window_count_)); |
| + EXPECT_TRUE(automation()->GetBrowserWindowCount(&actual_window_count)); |
| + EXPECT_EQ(actual_window_count, window_count_); |
| + window = GetCurrentWindow(); |
| + |
| + // A new window will not load a url if requested too soon. The window |
| + // stays on the new tab page instead. |
| + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); |
|
vangelis
2013/01/03 20:26:14
Sleep() seems like a potential source of flakiness
ccameron
2013/01/04 21:52:35
This will be a lot of work, but I've wrapped my he
|
| + |
| + ASSERT_TRUE(window.get()); |
| + scoped_refptr<TabProxy> tab(window->GetActiveTab()); |
| + ASSERT_TRUE(tab.get()); |
| + } |
| + |
| + // Load a page of 3D CSS or WebGL (or a plain page), and make the page |
| + // allocate |mb_to_use| MB of GPU memory. |
| + void ReloadCurrentTab(PageType page_type, size_t mb_to_use) { |
| + scoped_refptr<BrowserProxy> window(GetCurrentWindow()); |
| + ASSERT_TRUE(window.get()); |
| + scoped_refptr<TabProxy> tab(window->GetActiveTab()); |
| + ASSERT_TRUE(tab.get()); |
| + |
| + EXPECT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, |
| + tab->NavigateToURL(GetPageGURL(page_type))); |
| + |
| + // Execute the JS command to allocate memory (either via CSS or WebGL). |
| + std::wostringstream js_call; |
| + js_call << "useGpuMemory("; |
| + js_call << mb_to_use; |
| + js_call << ");"; |
| + bool result = false; |
| + EXPECT_TRUE( |
| + tab->ExecuteAndExtractBool(L"", js_call.str(), &result)); |
| + EXPECT_TRUE(result); |
| + |
| + // Give up to a full 2 seconds for the page to load -- the WebGL |
| + // and 3D CSS pages can be very slow. |
| + base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(2000)); |
|
ccameron
2013/01/03 19:07:56
Given how big the pages are (256MB for some), wait
Zhenyao Mo
2013/01/03 20:27:07
I truly think this is bad practice. It wastes tim
|
| + } |
| + |
| + private: |
| + int window_count_; |
| +}; |
| + |
| +// These tests will need to be verified on Android before being enabled. |
| +#if !defined(OS_ANDROID) |
| + |
| +// When trying to load something that doesn't fit into our total GPU memory |
| +// limit, we shouldn't exceed that limit. |
| +TEST_F(GpuMemoryTest, Simple) { |
|
ccameron
2013/01/03 19:07:56
These tests will explode if the GPU process is dis
Zhenyao Mo
2013/01/03 20:27:07
You can use trace events to make sure GPU process
|
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + EXPECT_LT(MemoryUsageMbytes(), kMemoryLimit); |
| +} |
| + |
| +// This should remain true if we load the same big page in three windows. |
| +TEST_F(GpuMemoryTest, MultiWindow) { |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + NewWindow(); |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + NewWindow(); |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + EXPECT_LT(MemoryUsageMbytes(), kMemoryLimit); |
| +} |
| + |
| +// This should remain true if we load the same big page in multiple tabs. |
| +TEST_F(GpuMemoryTest, MultiTab) { |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + NewTab(); |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + NewTab(); |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + EXPECT_LT(MemoryUsageMbytes(), kMemoryLimit); |
| +} |
| + |
| +// Load a page with heavy WebGL, then background it, and make sure that |
| +// the WebGL page's allocation causes the CSS page to use less memory |
| +TEST_F(GpuMemoryTest, WebGL) { |
| + ReloadCurrentTab(PAGE_WEBGL, 192u); |
| + NewTab(); |
| + ReloadCurrentTab(PAGE_SIMPLE, 1u); |
| + // Make sure that we're still using <192 MB (cause we shouldn't have |
| + // torched the WebGL, which uses at least that much). |
| + EXPECT_GE(MemoryUsageMbytes(), 192u); |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + EXPECT_LT(MemoryUsageMbytes(), kMemoryLimit); |
| +} |
| + |
| +// Make sure that we don't waste memory on backgrounded tabs that can't |
| +// be rendered fully. |
| +TEST_F(GpuMemoryTest, Background) { |
| + ReloadCurrentTab(PAGE_CSS3D, 256u); |
| + // Make sure that the CSS page is using at least 64MB |
| + EXPECT_GE(MemoryUsageMbytes(), 64u); |
| + NewTab(); |
| + ReloadCurrentTab(PAGE_SIMPLE, 1u); |
| + // Assume that the simple page will use <32 MB, and make |
| + // sure that nothing remains from the hard page. |
| + EXPECT_LT(MemoryUsageMbytes(), 32u); |
| +} |
| + |
| +#endif // !defined(OS_ANDROID) |
| + |
| +} // namespace |