diff options
author | hajimehoshi@chromium.org <hajimehoshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-27 10:10:13 +0000 |
---|---|---|
committer | hajimehoshi@chromium.org <hajimehoshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-27 10:10:13 +0000 |
commit | 4562cf71dc6b216455843eccf0676dcff6e61013 (patch) | |
tree | fb506074edd017ed9ddbac999c923997147f9f1f /content | |
parent | 86aa0ae6229e258746fc53df7e3436bb874f9ee6 (diff) | |
download | chromium_src-4562cf71dc6b216455843eccf0676dcff6e61013.zip chromium_src-4562cf71dc6b216455843eccf0676dcff6e61013.tar.gz chromium_src-4562cf71dc6b216455843eccf0676dcff6e61013.tar.bz2 |
Leak detection at content_shell
At the layout test, about:blank is loaded before and after one test. We're adding a method to count objects (https://codereview.chromium.org/132913003/) and using this at about:blank, and comparing the numbers of objects at about:blank, we can detect a leak.
https://docs.google.com/a/chromium.org/document/d/1sFAsZxeISKnbGdXoLZlB2tDZ8pvO102ePFQx6TX4X14/edit#
BUG=332630
Review URL: https://codereview.chromium.org/132243006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247209 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/content_shell.gypi | 3 | ||||
-rw-r--r-- | content/shell/browser/shell_browser_main.cc | 82 | ||||
-rw-r--r-- | content/shell/browser/shell_content_browser_client.cc | 3 | ||||
-rw-r--r-- | content/shell/browser/webkit_test_controller.cc | 31 | ||||
-rw-r--r-- | content/shell/browser/webkit_test_controller.h | 2 | ||||
-rw-r--r-- | content/shell/common/leak_detection_result.h | 18 | ||||
-rw-r--r-- | content/shell/common/shell_messages.h | 12 | ||||
-rw-r--r-- | content/shell/common/shell_switches.cc | 4 | ||||
-rw-r--r-- | content/shell/common/shell_switches.h | 1 | ||||
-rw-r--r-- | content/shell/renderer/leak_detector.cc | 39 | ||||
-rw-r--r-- | content/shell/renderer/leak_detector.h | 41 | ||||
-rw-r--r-- | content/shell/renderer/webkit_test_runner.cc | 24 | ||||
-rw-r--r-- | content/shell/renderer/webkit_test_runner.h | 8 |
13 files changed, 234 insertions, 34 deletions
diff --git a/content/content_shell.gypi b/content/content_shell.gypi index f300629..d3373ad 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi @@ -146,6 +146,7 @@ 'shell/browser/shell_web_contents_view_delegate_win.cc', 'shell/browser/webkit_test_controller.cc', 'shell/browser/webkit_test_controller.h', + 'shell/common/leak_detection_result.h', 'shell/common/shell_content_client.cc', 'shell/common/shell_content_client.h', 'shell/common/shell_messages.cc', @@ -162,6 +163,8 @@ 'shell/geolocation/shell_access_token_store.h', 'shell/renderer/gc_controller.cc', 'shell/renderer/gc_controller.h', + 'shell/renderer/leak_detector.cc', + 'shell/renderer/leak_detector.h', 'shell/renderer/shell_content_renderer_client.cc', 'shell/renderer/shell_content_renderer_client.h', 'shell/renderer/shell_render_frame_observer.cc', diff --git a/content/shell/browser/shell_browser_main.cc b/content/shell/browser/shell_browser_main.cc index ca2cd82..7b17cd4 100644 --- a/content/shell/browser/shell_browser_main.cc +++ b/content/shell/browser/shell_browser_main.cc @@ -17,6 +17,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_main_runner.h" +#include "content/public/common/url_constants.h" #include "content/shell/browser/shell.h" #include "content/shell/browser/webkit_test_controller.h" #include "content/shell/common/shell_switches.h" @@ -106,6 +107,46 @@ bool GetNextTest(const CommandLine::StringVector& args, return true; } +bool RunOneTest(const std::string& test_string, + bool* ran_at_least_once, + const scoped_ptr<content::BrowserMainRunner>& main_runner) { + if (test_string.empty()) + return true; + if (test_string == "QUIT") + return false; + + bool enable_pixel_dumps; + std::string pixel_hash; + base::FilePath cwd; + GURL test_url = GetURLForLayoutTest( + test_string, &cwd, &enable_pixel_dumps, &pixel_hash); + if (!content::WebKitTestController::Get()->PrepareForLayoutTest( + test_url, cwd, enable_pixel_dumps, pixel_hash)) { + return false; + } + + *ran_at_least_once = true; +#if defined(OS_ANDROID) + // The message loop on Android is provided by the system, and does not + // offer a blocking Run() method. For layout tests, use a nested loop + // together with a base::RunLoop so it can block until a QuitClosure. + base::RunLoop run_loop; + run_loop.Run(); +#else + main_runner->Run(); +#endif + + if (!content::WebKitTestController::Get()->ResetAfterLayoutTest()) + return false; + +#if defined(OS_ANDROID) + // There will be left-over tasks in the queue for Android because the + // main window is being destroyed. Run them before starting the next test. + base::MessageLoop::current()->RunUntilIdle(); +#endif + return true; +} + } // namespace // Main routine for running as the Browser process. @@ -163,41 +204,16 @@ int ShellBrowserMain( std::cout << "#READY\n"; std::cout.flush(); - while (GetNextTest(args, &command_line_position, &test_string)) { - if (test_string.empty()) - continue; - if (test_string == "QUIT") - break; - - bool enable_pixel_dumps; - std::string pixel_hash; - base::FilePath cwd; - GURL test_url = GetURLForLayoutTest( - test_string, &cwd, &enable_pixel_dumps, &pixel_hash); - if (!content::WebKitTestController::Get()->PrepareForLayoutTest( - test_url, cwd, enable_pixel_dumps, pixel_hash)) { - break; - } + // To detect leaks, the numbers of objects are counted at about:blank before + // loading a page and after loading a page. The first content should be + // about:blank when the leak detection is enabled. + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLeakDetection)) + RunOneTest(content::kAboutBlankURL, &ran_at_least_once, main_runner); - ran_at_least_once = true; -#if defined(OS_ANDROID) - // The message loop on Android is provided by the system, and does not - // offer a blocking Run() method. For layout tests, use a nested loop - // together with a base::RunLoop so it can block until a QuitClosure. - base::RunLoop run_loop; - run_loop.Run(); -#else - main_runner->Run(); -#endif - - if (!content::WebKitTestController::Get()->ResetAfterLayoutTest()) + while (GetNextTest(args, &command_line_position, &test_string)) { + if (!RunOneTest(test_string, &ran_at_least_once, main_runner)) break; - -#if defined(OS_ANDROID) - // There will be left-over tasks in the queue for Android because the - // main window is being destroyed. Run them before starting the next test. - base::MessageLoop::current()->RunUntilIdle(); -#endif } if (!ran_at_least_once) { base::MessageLoop::current()->PostTask(FROM_HERE, diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index 53eb7f7..6b51c49 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc @@ -212,6 +212,9 @@ void ShellContentBrowserClient::AppendExtraCommandLineSwitches( CommandLine::ForCurrentProcess()->GetSwitchValuePath( switches::kCrashDumpsDir)); } + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLeakDetection)) + command_line->AppendSwitch(switches::kEnableLeakDetection); } void ShellContentBrowserClient::OverrideWebkitPrefs( diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc index 106540e..9a3b92b 100644 --- a/content/shell/browser/webkit_test_controller.cc +++ b/content/shell/browser/webkit_test_controller.cc @@ -26,6 +26,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" #include "content/public/common/content_switches.h" +#include "content/public/common/url_constants.h" #include "content/shell/browser/shell.h" #include "content/shell/browser/shell_browser_context.h" #include "content/shell/browser/shell_content_browser_client.h" @@ -378,6 +379,7 @@ bool WebKitTestController::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows, OnCloseRemainingWindows) IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone) + IPC_MESSAGE_HANDLER(ShellViewHostMsg_LeakDetectionDone, OnLeakDetectionDone) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -652,8 +654,37 @@ void WebKitTestController::OnCloseRemainingWindows() { } void WebKitTestController::OnResetDone() { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableLeakDetection)) { + if (main_window_ && main_window_->web_contents()) { + RenderViewHost* render_view_host = + main_window_->web_contents()->GetRenderViewHost(); + render_view_host->Send( + new ShellViewMsg_TryLeakDetection(render_view_host->GetRoutingID())); + } + return; + } + base::MessageLoop::current()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } +void WebKitTestController::OnLeakDetectionDone( + const LeakDetectionResult& result) { + if (!result.leaked) { + base::MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::QuitClosure()); + return; + } + + printer_->AddErrorMessage("#LEAK"); + printer_->AddErrorMessage( + base::StringPrintf(" Number of live documents: %d", + result.number_of_live_documents)); + printer_->AddErrorMessage( + base::StringPrintf(" Number of live nodes: %d", + result.number_of_live_nodes)); + DiscardMainWindow(); +} + } // namespace content diff --git a/content/shell/browser/webkit_test_controller.h b/content/shell/browser/webkit_test_controller.h index a23841d..865e395 100644 --- a/content/shell/browser/webkit_test_controller.h +++ b/content/shell/browser/webkit_test_controller.h @@ -16,6 +16,7 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_observer.h" +#include "content/shell/common/leak_detection_result.h" #include "ui/gfx/size.h" #include "webkit/common/webpreferences.h" @@ -173,6 +174,7 @@ class WebKitTestController : public base::NonThreadSafe, void OnCaptureSessionHistory(); void OnCloseRemainingWindows(); void OnResetDone(); + void OnLeakDetectionDone(const content::LeakDetectionResult& result); scoped_ptr<WebKitTestResultPrinter> printer_; diff --git a/content/shell/common/leak_detection_result.h b/content/shell/common/leak_detection_result.h new file mode 100644 index 0000000..7afcfd3 --- /dev/null +++ b/content/shell/common/leak_detection_result.h @@ -0,0 +1,18 @@ +// Copyright 2014 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. + +#ifndef CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_ +#define CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_ + +namespace content { + +struct LeakDetectionResult { + bool leaked; + unsigned number_of_live_documents; + unsigned number_of_live_nodes; +}; + +} // namespace content + +#endif // CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_ diff --git a/content/shell/common/shell_messages.h b/content/shell/common/shell_messages.h index 253baf4..62fc8f9 100644 --- a/content/shell/common/shell_messages.h +++ b/content/shell/common/shell_messages.h @@ -8,6 +8,7 @@ #include "content/public/common/common_param_traits.h" #include "content/public/common/page_state.h" +#include "content/shell/common/leak_detection_result.h" #include "content/shell/common/shell_test_configuration.h" #include "ipc/ipc_message_macros.h" #include "ipc/ipc_platform_file.h" @@ -50,6 +51,8 @@ IPC_MESSAGE_ROUTED3( std::vector<std::vector<content::PageState> > /* session_histories */, std::vector<unsigned> /* current_entry_indexes */) +IPC_MESSAGE_ROUTED0(ShellViewMsg_TryLeakDetection) + // Send a text dump of the WebContents to the render host. IPC_MESSAGE_ROUTED1(ShellViewHostMsg_TextDump, std::string /* dump */) @@ -99,3 +102,12 @@ IPC_MESSAGE_ROUTED1(ShellViewHostMsg_SetDeviceScaleFactor, float /* factor */) IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CaptureSessionHistory) IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CloseRemainingWindows) + +IPC_STRUCT_TRAITS_BEGIN(content::LeakDetectionResult) +IPC_STRUCT_TRAITS_MEMBER(leaked) +IPC_STRUCT_TRAITS_MEMBER(number_of_live_documents) +IPC_STRUCT_TRAITS_MEMBER(number_of_live_nodes) +IPC_STRUCT_TRAITS_END() + +IPC_MESSAGE_ROUTED1(ShellViewHostMsg_LeakDetectionDone, + content::LeakDetectionResult /* result */) diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc index dcd66a5..3e6b31f 100644 --- a/content/shell/common/shell_switches.cc +++ b/content/shell/common/shell_switches.cc @@ -27,6 +27,10 @@ const char kDumpRenderTree[] = "dump-render-tree"; // Enable accelerated 2D canvas. const char kEnableAccelerated2DCanvas[] = "enable-accelerated-2d-canvas"; +// Enables the leak detection of loading webpages. This allows us to check +// whether or not reloading a webpage releases web-related objects correctly. +const char kEnableLeakDetection[] = "enable-leak-detection"; + // Encode binary layout test results (images, audio) using base64. const char kEncodeBinary[] = "encode-binary"; diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h index 72797f8..094eabf 100644 --- a/content/shell/common/shell_switches.h +++ b/content/shell/common/shell_switches.h @@ -16,6 +16,7 @@ extern const char kContentShellDataPath[]; extern const char kCrashDumpsDir[]; extern const char kDumpRenderTree[]; extern const char kEnableAccelerated2DCanvas[]; +extern const char kEnableLeakDetection[]; extern const char kEncodeBinary[]; extern const char kExposeInternalsForTesting[]; extern const char kStableReleaseMode[]; diff --git a/content/shell/renderer/leak_detector.cc b/content/shell/renderer/leak_detector.cc new file mode 100644 index 0000000..2af12be --- /dev/null +++ b/content/shell/renderer/leak_detector.cc @@ -0,0 +1,39 @@ +// Copyright 2014 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 "content/shell/renderer/leak_detector.h" + +#include "base/logging.h" +#include "third_party/WebKit/public/web/WebLeakDetector.h" + +using blink::WebLeakDetector; + +namespace content { + +LeakDetector::LeakDetector() + : previous_number_of_live_documents_(0), + previous_number_of_live_nodes_(0) { +} + +LeakDetectionResult LeakDetector::TryLeakDetection(blink::WebFrame* frame) { + LeakDetectionResult result; + result.number_of_live_documents = 0; + result.number_of_live_nodes = 0; + + WebLeakDetector::collectGarbargeAndGetDOMCounts( + frame, &result.number_of_live_documents, &result.number_of_live_nodes); + + result.leaked = + previous_number_of_live_documents_ > 0 && + previous_number_of_live_nodes_ > 0 && + (previous_number_of_live_documents_ < result.number_of_live_documents || + previous_number_of_live_nodes_ < result.number_of_live_nodes); + + previous_number_of_live_documents_ = result.number_of_live_documents; + previous_number_of_live_nodes_ = result.number_of_live_nodes; + + return result; +} + +} // namespace content diff --git a/content/shell/renderer/leak_detector.h b/content/shell/renderer/leak_detector.h new file mode 100644 index 0000000..e9935c2 --- /dev/null +++ b/content/shell/renderer/leak_detector.h @@ -0,0 +1,41 @@ +// Copyright 2014 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. + +#ifndef CONTENT_SHELL_RENDERER_LEAK_DETECTOR_H_ +#define CONTENT_SHELL_RENDERER_LEAK_DETECTOR_H_ + +#include "base/basictypes.h" +#include "content/shell/common/leak_detection_result.h" + +namespace blink { +class WebFrame; +} + +namespace content { + +// LeakDetector counts DOM objects and compare them between two pages. +class LeakDetector { + public: + LeakDetector(); + + // Counts DOM objects, compare the previous status and returns the result of + // leak detection. It is assumed that this method is always called when a + // specific page, like about:blank is loaded to compare the previous + // circumstance of DOM objects. If the number of objects increses, there + // should be a leak. + LeakDetectionResult TryLeakDetection(blink::WebFrame* frame); + + private: + // The number of the live documents last time. + unsigned previous_number_of_live_documents_; + + // The number of the live nodes last time. + unsigned previous_number_of_live_nodes_; + + DISALLOW_COPY_AND_ASSIGN(LeakDetector); +}; + +} // namespace content + +#endif // CONTENT_SHELL_RENDERER_LEAK_DETECTOR_H_ diff --git a/content/shell/renderer/webkit_test_runner.cc b/content/shell/renderer/webkit_test_runner.cc index 09804e7..0484667 100644 --- a/content/shell/renderer/webkit_test_runner.cc +++ b/content/shell/renderer/webkit_test_runner.cc @@ -27,8 +27,10 @@ #include "content/public/renderer/render_view_visitor.h" #include "content/public/test/layouttest_support.h" #include "content/shell/common/shell_messages.h" +#include "content/shell/common/shell_switches.h" #include "content/shell/common/webkit_test_helpers.h" #include "content/shell/renderer/gc_controller.h" +#include "content/shell/renderer/leak_detector.h" #include "content/shell/renderer/shell_render_process_observer.h" #include "content/shell/renderer/test_runner/WebTask.h" #include "content/shell/renderer/test_runner/WebTestInterfaces.h" @@ -56,6 +58,7 @@ #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebHistoryItem.h" #include "third_party/WebKit/public/web/WebKit.h" +#include "third_party/WebKit/public/web/WebLeakDetector.h" #include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebTestingSupport.h" #include "third_party/WebKit/public/web/WebView.h" @@ -208,7 +211,9 @@ WebKitTestRunner::WebKitTestRunner(RenderView* render_view) proxy_(NULL), focused_view_(NULL), is_main_window_(false), - focus_on_next_commit_(false) { + focus_on_next_commit_(false), + leak_detector_(new LeakDetector()) +{ UseMockMediaStreams(render_view); } @@ -562,6 +567,7 @@ bool WebKitTestRunner::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ShellViewMsg_SessionHistory, OnSessionHistory) IPC_MESSAGE_HANDLER(ShellViewMsg_Reset, OnReset) IPC_MESSAGE_HANDLER(ShellViewMsg_NotifyDone, OnNotifyDone) + IPC_MESSAGE_HANDLER(ShellViewMsg_TryLeakDetection, OnTryLeakDetection) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -707,4 +713,20 @@ void WebKitTestRunner::OnNotifyDone() { WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();"))); } +void WebKitTestRunner::OnTryLeakDetection() { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&WebKitTestRunner::TryLeakDetection, base::Unretained(this))); +} + +void WebKitTestRunner::TryLeakDetection() { + WebFrame* main_frame = render_view()->GetWebView()->mainFrame(); + DCHECK_EQ(GURL(kAboutBlankURL), GURL(main_frame->document().url())); + DCHECK(!main_frame->isLoading()); + + LeakDetectionResult result = leak_detector_->TryLeakDetection( + render_view()->GetWebView()->mainFrame()); + Send(new ShellViewHostMsg_LeakDetectionDone(routing_id(), result)); +} + } // namespace content diff --git a/content/shell/renderer/webkit_test_runner.h b/content/shell/renderer/webkit_test_runner.h index 6399e7a..b6f9b02 100644 --- a/content/shell/renderer/webkit_test_runner.h +++ b/content/shell/renderer/webkit_test_runner.h @@ -31,6 +31,8 @@ class WebTestProxyBase; namespace content { +class LeakDetector; + // This is the renderer side of the webkit test runner. class WebKitTestRunner : public RenderViewObserver, public RenderViewObserverTracker<WebKitTestRunner>, @@ -119,11 +121,14 @@ class WebKitTestRunner : public RenderViewObserver, const std::vector<unsigned>& current_entry_indexes); void OnReset(); void OnNotifyDone(); + void OnTryLeakDetection(); // After finishing the test, retrieves the audio, text, and pixel dumps from // the TestRunner library and sends them to the browser process. void CaptureDump(); + void TryLeakDetection(); + ::WebTestRunner::WebTestProxyBase* proxy_; RenderView* focused_view_; @@ -140,6 +145,9 @@ class WebKitTestRunner : public RenderViewObserver, bool focus_on_next_commit_; + scoped_ptr<LeakDetector> leak_detector_; + bool needs_leak_detector_; + DISALLOW_COPY_AND_ASSIGN(WebKitTestRunner); }; |