Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(559)

Unified Diff: content/browser/gpu/gpu_memory_test.cc

Issue 11667030: Add GPU memory usage contents browser test (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporate review feedback Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/common/gpu/gpu_memory_manager.cc » ('j') | content/test/data/gpu/mem_css3d.html » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/gpu/gpu_memory_test.cc
diff --git a/content/browser/gpu/gpu_memory_test.cc b/content/browser/gpu/gpu_memory_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7eecc3b3cdbcf9fd0531b273f55ce296e6b11f74
--- /dev/null
+++ b/content/browser/gpu/gpu_memory_test.cc
@@ -0,0 +1,317 @@
+// 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 {
+
+// Run the tests with a memory limit of 256MB, and give
+// and extra 16MB of wiggle-room for over-allocation.
piman 2013/01/08 00:04:17 nit: s/16/24/ given the value below
ccameron 2013/01/08 00:41:24 Done.
+const char* kMemoryLimitSwitch = "256";
+const size_t kMemoryLimit = 256;
+const size_t kSingleTabLimit = 128;
+const size_t kSingleTabMinimum = 64;
+const size_t kWiggleRoom = 24;
+
+// 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();
+ // Will break after OnVideoMemoryUsageStatsUpdate
piman 2013/01/08 00:04:17 nit: not sure what this comment means. Consider re
ccameron 2013/01/08 00:41:24 This was to say the Run() call will stop after the
+ 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) {
+ }
+ 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);
+ command_line->AppendSwitchASCII(switches::kForceGpuMemAvailableMb,
+ kMemoryLimitSwitch);
+ // 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,
+ };
+
+ 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;
+ default:
piman 2013/01/08 00:04:17 nit: just remove and have the compiler warn about
ccameron 2013/01/08 00:41:24 Done.
+ NOTREACHED();
+ 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\"", message);
+ }
+
+ size_t GetMemoryUsageMbytes() {
+ GpuMemoryBytesAllocatedObserver observer;
+ observer.GetBytesAllocated();
+ return observer.GetBytesAllocated()/1048576;
piman 2013/01/08 00:04:17 nit: spaces around /
ccameron 2013/01/08 00:41:24 Done.
+ }
+
+ void ExpectMemoryUsageGE(size_t mbytes_expected) {
+ // 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.
+
+ // The above is a big undertaking, so, instead, we wait for the condition
+ // to be satisfied, risking that we will give a false PASS if it happens
+ // to be being transiently satisfied.
+ WaitForMemoryStableInRange(mbytes_expected, static_cast<size_t>(-1));
piman 2013/01/08 00:04:17 nit: std::memory_limits<size_t>::max()
ccameron 2013/01/08 00:41:24 Done.
+ }
+
+ void ExpectMemoryUsageLE(size_t mbytes_expected) {
+ WaitForMemoryStableInRange(0, mbytes_expected);
+ }
+
+ content::Shell* CreateShell() {
+ // 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 = shells_.empty() ? shell() : CreateBrowser();
+ shells_.push_back(new_shell);
+ return new_shell;
+ }
+
+ bool AllowTestsToRun() const {
+ return allow_tests_to_run_;
+ }
+
+ private:
+ void WaitForMemoryStableInRange(size_t low, size_t high) {
+ // Wait until we get the same vaue in the expected interval 20 times in
piman 2013/01/08 00:04:17 typo: vaue->value
ccameron 2013/01/08 00:41:24 Done.
+ // a row. By waiting for the value to settle, we increase the chance that
+ // if we are in the process of plowing through the interval, we will
+ // not give a false pass.
+ // TODO: Implement the scheme discussed in ExpectMemoryUsageGE instead.
+ const size_t iterations_to_consider_stable = 20;
+ size_t same_value_observed_count = 0;
+ size_t mbytes_last_observed = 0;
+ while (same_value_observed_count < iterations_to_consider_stable) {
+ size_t mbytes_observed = GetMemoryUsageMbytes();
+ if (low <= mbytes_observed && mbytes_observed <= high) {
+ if (mbytes_observed != mbytes_last_observed)
+ same_value_observed_count = 0;
+ else
+ same_value_observed_count++;
+ mbytes_last_observed = mbytes_observed;
+ }
+ }
piman 2013/01/08 00:04:17 This can't return failure, it will just not return
ccameron 2013/01/08 00:41:24 Yes, the failure method is time-out. The comments
+ }
+
+ std::vector<content::Shell*> shells_;
+ FilePath gpu_test_dir_;
+ bool allow_tests_to_run_;
+};
+
+// When trying to load something that doesn't fit into our total GPU memory
+// limit, we shouldn't exceed that limit.
+IN_PROC_BROWSER_TEST_F(GpuMemoryTest, SingleWindowDoesNotExceedLimit) {
+ if (!AllowTestsToRun())
+ return;
+
+ content::Shell* shell1 = CreateShell();
+ LoadPage(shell1, PAGE_CSS3D, kMemoryLimit);
+ // Make sure that the CSS3D page triggers allocation of at least 64MB,
+ // otherwise the test doesn't test anything.
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ // Make sure that we stay below the memory limit.
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+}
+
+// This should remain true if we load the same big page in three windows.
+IN_PROC_BROWSER_TEST_F(GpuMemoryTest, MultipleWindowsDoNotExceedLimit) {
+ if (!AllowTestsToRun())
+ return;
+
+ // Load three instances of a heavy page in visible windows.
+ content::Shell* shell1 = CreateShell();
+ LoadPage(shell1, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+ content::Shell* shell2 = CreateShell();
+ LoadPage(shell2, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kMemoryLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+ content::Shell* shell3 = CreateShell();
+ LoadPage(shell3, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kMemoryLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+}
+
+// This should remain true if we load the same big page in multiple tabs.
+IN_PROC_BROWSER_TEST_F(GpuMemoryTest, MultipleTabsDoNotExceedLimit) {
+ if (!AllowTestsToRun())
+ return;
+
+ content::Shell* shell1 = CreateShell();
+ // Load and then background two tabs, then load a foregrounded tab.
+ LoadPage(shell1, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ shell1->web_contents()->WasHidden();
+ ExpectMemoryUsageLE(0u);
+
+ content::Shell* shell2 = CreateShell();
+ LoadPage(shell2, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ shell2->web_contents()->WasHidden();
+ ExpectMemoryUsageLE(0u);
+
+ content::Shell* shell3 = CreateShell();
+ LoadPage(shell3, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+}
+
+// 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
+IN_PROC_BROWSER_TEST_F(GpuMemoryTest, WebGLMakesCompositorUseLessMemory) {
+ if (!AllowTestsToRun())
+ return;
+
+ content::Shell* shell1 = CreateShell();
+ LoadPage(shell1, PAGE_WEBGL, kMemoryLimit - kSingleTabMinimum);
+ // Make sure that the WEBGL page triggers allocation of at least what
+ // WebGL allocated, otherwise the test doesn't test anything.
+ ExpectMemoryUsageGE(kMemoryLimit - kSingleTabMinimum);
+ // Background that tab, and load heavy content in a new foreground tab.
+ shell1->web_contents()->WasHidden();
+ content::Shell* shell2 = CreateShell();
+ LoadPage(shell2, PAGE_CSS3D, kMemoryLimit);
+ // Make sure we are still under the limit, but that we get close
+ ExpectMemoryUsageGE(kMemoryLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+}
+
+// Load a big CSS page, then open a new window with WebGL, and make
+// sure that the compositor gave up some of its resources.
+IN_PROC_BROWSER_TEST_F(GpuMemoryTest, CompositorUsesLessWhenWebGLIsOpened) {
+ if (!AllowTestsToRun())
+ return;
+
+ // Open the CSS page.
+ content::Shell* shell1 = CreateShell();
+ LoadPage(shell1, PAGE_CSS3D, kMemoryLimit);
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+
+ // Open the WebGL page.
+ content::Shell* shell2 = CreateShell();
+ LoadPage(shell2, PAGE_WEBGL, kMemoryLimit - kSingleTabMinimum);
+ // Make sure we are still under the limit, but that we get close
+ ExpectMemoryUsageGE(kMemoryLimit - kWiggleRoom);
+ ExpectMemoryUsageLE(kMemoryLimit + kWiggleRoom);
+}
+
+// Make sure that we don't waste memory on backgrounded tabs that can't
+// be rendered fully.
+IN_PROC_BROWSER_TEST_F(GpuMemoryTest, BackgroundingBigTabsDropsTheirMemory) {
+ if (!AllowTestsToRun())
+ return;
+
+ content::Shell* shell = CreateShell();
+ LoadPage(shell, PAGE_CSS3D, kMemoryLimit);
+ // Make sure that the CSS3D page triggers allocation of at least 64MB,
+ // otherwise the test doesn't test anything.
+ ExpectMemoryUsageGE(kSingleTabLimit - kWiggleRoom);
+ // Background the tab. Because it is too big to be kept in memory,
+ // its allocation should drop to zero.
+ shell->web_contents()->WasHidden();
+ ExpectMemoryUsageLE(0u);
+}
+
+} // namespace
« no previous file with comments | « no previous file | content/common/gpu/gpu_memory_manager.cc » ('j') | content/test/data/gpu/mem_css3d.html » ('J')

Powered by Google App Engine
This is Rietveld 408576698