Commit 55364a64 authored by Hajime Hoshi's avatar Hajime Hoshi Committed by Commit Bot

Add UKM Document.OutliveTimeAfterShutdown

This CL adds a new UKM Document.OutliveTimeAfterShutdown, that is
recorded when a Document object survives 5, 10, 20 or 50 garbage
collections after detached. If a document outlives such long time, the
document might be leaked. The UKM would be very useful to know where such
leaky documents exist and to fix them.

Design doc: https://docs.google.com/document/d/1fbs5smdd-pBLLMpq7u8EkyddZILtI7CZPJlo_AA1kak/edit?usp=sharing

Bug: 757374
Change-Id: Idc05b03f625db11ab54c5203d18344b1ca72b4eb
Reviewed-on: https://chromium-review.googlesource.com/647050
Commit-Queue: Hajime Hoshi <hajimehoshi@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Reviewed-by: default avatarBrett Wilson <brettw@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarNico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#505275}
parent a4ea774e
...@@ -22,7 +22,11 @@ ...@@ -22,7 +22,11 @@
}, },
"requires": { "requires": {
"*": [ "app" ], "*": [ "app" ],
"content_browser": [ "renderer" ], "content_browser": [
"memory_instrumentation",
"renderer",
"url_keyed_metrics"
],
"device": [ "device": [
"device:power_monitor", "device:power_monitor",
"device:screen_orientation", "device:screen_orientation",
......
...@@ -32,6 +32,10 @@ namespace autofill { ...@@ -32,6 +32,10 @@ namespace autofill {
class AutofillMetrics; class AutofillMetrics;
} }
namespace blink {
class Document;
}
namespace content { namespace content {
class RenderFrameImpl; class RenderFrameImpl;
class RenderWidgetHostLatencyTracker; class RenderWidgetHostLatencyTracker;
...@@ -101,6 +105,7 @@ class METRICS_EXPORT UkmRecorder { ...@@ -101,6 +105,7 @@ class METRICS_EXPORT UkmRecorder {
private: private:
friend autofill::AutofillMetrics; friend autofill::AutofillMetrics;
friend blink::Document;
friend payments::JourneyLogger; friend payments::JourneyLogger;
friend ContextualSearchRankerLoggerImpl; friend ContextualSearchRankerLoggerImpl;
friend ProcessMemoryMetricsEmitter; friend ProcessMemoryMetricsEmitter;
......
...@@ -99,10 +99,10 @@ def _CheckForPrintfDebugging(input_api, output_api): ...@@ -99,10 +99,10 @@ def _CheckForPrintfDebugging(input_api, output_api):
def _CheckForForbiddenNamespace(input_api, output_api): def _CheckForForbiddenNamespace(input_api, output_api):
"""Checks that Blink uses Chromium namespaces only in permitted code.""" """Checks that Blink uses Chromium classes and namespaces only in permitted code."""
# This list is not exhaustive, but covers likely ones. # This list is not exhaustive, but covers likely ones.
chromium_namespaces = ["base", "cc", "content", "gfx", "net", "ui"] chromium_namespaces = ["base", "cc", "content", "gfx", "net", "ui"]
chromium_forbidden_classes = ["scoped_refptr"] chromium_forbidden_classes = ["scoped_refptr", "GURL"]
chromium_allowed_classes = ["gfx::ColorSpace", "gfx::CubicBezier", "gfx::ICCProfile", "gfx::ScrollOffset"] chromium_allowed_classes = ["gfx::ColorSpace", "gfx::CubicBezier", "gfx::ICCProfile", "gfx::ScrollOffset"]
def source_file_filter(path): def source_file_filter(path):
......
...@@ -11,6 +11,7 @@ include_rules = [ ...@@ -11,6 +11,7 @@ include_rules = [
"+platform", "+platform",
"+public/platform", "+public/platform",
"+public/web", "+public/web",
"+services/metrics/public",
"+services/network/public/interfaces", "+services/network/public/interfaces",
"+third_party/skia/include", "+third_party/skia/include",
"+ui/gfx/geometry", "+ui/gfx/geometry",
......
...@@ -347,4 +347,10 @@ blink_core_sources("dom") { ...@@ -347,4 +347,10 @@ blink_core_sources("dom") {
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations. # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
"//build/config/compiler:no_size_t_to_int_warning", "//build/config/compiler:no_size_t_to_int_warning",
] ]
deps = [
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
"//services/metrics/public/interfaces",
]
} }
...@@ -256,11 +256,15 @@ ...@@ -256,11 +256,15 @@
#include "platform/wtf/text/CharacterNames.h" #include "platform/wtf/text/CharacterNames.h"
#include "platform/wtf/text/StringBuffer.h" #include "platform/wtf/text/StringBuffer.h"
#include "platform/wtf/text/TextEncodingRegistry.h" #include "platform/wtf/text/TextEncodingRegistry.h"
#include "public/platform/InterfaceProvider.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "public/platform/WebAddressSpace.h" #include "public/platform/WebAddressSpace.h"
#include "public/platform/WebPrerenderingSupport.h" #include "public/platform/WebPrerenderingSupport.h"
#include "public/platform/modules/insecure_input/insecure_input_service.mojom-blink.h" #include "public/platform/modules/insecure_input/insecure_input_service.mojom-blink.h"
#include "public/platform/site_engagement.mojom-blink.h" #include "public/platform/site_engagement.mojom-blink.h"
#include "services/metrics/public/cpp/mojo_ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/interfaces/ukm_interface.mojom-shared.h"
#include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/public/cpp/interface_provider.h"
#ifndef NDEBUG #ifndef NDEBUG
...@@ -310,6 +314,7 @@ class DocumentOutliveTimeReporter : public BlinkGCObserver { ...@@ -310,6 +314,7 @@ class DocumentOutliveTimeReporter : public BlinkGCObserver {
int outlive_time_count = GetOutliveTimeCount(); int outlive_time_count = GetOutliveTimeCount();
if (outlive_time_count == 5 || outlive_time_count == 10) { if (outlive_time_count == 5 || outlive_time_count == 10) {
const char* kUMAString = "Document.OutliveTimeAfterShutdown.GCCount"; const char* kUMAString = "Document.OutliveTimeAfterShutdown.GCCount";
if (outlive_time_count == 5) if (outlive_time_count == 5)
UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount5, kGCCountMax); UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount5, kGCCountMax);
else if (outlive_time_count == 10) else if (outlive_time_count == 10)
...@@ -317,6 +322,11 @@ class DocumentOutliveTimeReporter : public BlinkGCObserver { ...@@ -317,6 +322,11 @@ class DocumentOutliveTimeReporter : public BlinkGCObserver {
else else
NOTREACHED(); NOTREACHED();
} }
if (outlive_time_count == 5 || outlive_time_count == 10 ||
outlive_time_count == 20 || outlive_time_count == 50) {
document_->RecordUkmOutliveTimeAfterShutdown(outlive_time_count);
}
} }
private: private:
...@@ -3696,6 +3706,18 @@ void Document::SetURL(const KURL& url) { ...@@ -3696,6 +3706,18 @@ void Document::SetURL(const KURL& url) {
access_entry_from_url_ = nullptr; access_entry_from_url_ = nullptr;
UpdateBaseURL(); UpdateBaseURL();
GetContextFeatures().UrlDidChange(this); GetContextFeatures().UrlDidChange(this);
if (!ukm_recorder_ && IsInMainFrame()) {
ukm::mojom::UkmRecorderInterfacePtr interface;
frame_->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&interface));
ukm_source_id_ = ukm::UkmRecorder::GetNewSourceID();
ukm_recorder_.reset(new ukm::MojoUkmRecorder(std::move(interface)));
}
if (ukm_recorder_) {
DCHECK(IsInMainFrame());
ukm_recorder_->UpdateSourceURL(ukm_source_id_, url_);
}
} }
KURL Document::ValidBaseElementURL() const { KURL Document::ValidBaseElementURL() const {
...@@ -7150,6 +7172,15 @@ void Document::RecordDeferredLoadReason(WouldLoadReason reason) { ...@@ -7150,6 +7172,15 @@ void Document::RecordDeferredLoadReason(WouldLoadReason reason) {
would_load_reason_ = reason; would_load_reason_ = reason;
} }
void Document::RecordUkmOutliveTimeAfterShutdown(int outlive_time_count) {
if (!ukm_recorder_)
return;
ukm::builders::Document_OutliveTimeAfterShutdown(ukm_source_id_)
.SetGCCount(outlive_time_count)
.Record(ukm_recorder_.get());
}
DEFINE_TRACE_WRAPPERS(Document) { DEFINE_TRACE_WRAPPERS(Document) {
// node_lists_ are traced in their corresponding NodeListsNodeData, keeping // node_lists_ are traced in their corresponding NodeListsNodeData, keeping
// them only alive for live nodes. Otherwise we would keep lists of dead // them only alive for live nodes. Otherwise we would keep lists of dead
......
...@@ -74,11 +74,15 @@ ...@@ -74,11 +74,15 @@
#include "public/platform/WebFocusType.h" #include "public/platform/WebFocusType.h"
#include "public/platform/WebInsecureRequestPolicy.h" #include "public/platform/WebInsecureRequestPolicy.h"
namespace ukm {
class UkmRecorder;
} // namespace ukm
namespace blink { namespace blink {
namespace mojom { namespace mojom {
enum class EngagementLevel : int32_t; enum class EngagementLevel : int32_t;
} } // namespace mojom
class AnimationClock; class AnimationClock;
class AXObjectCache; class AXObjectCache;
...@@ -1368,6 +1372,8 @@ class CORE_EXPORT Document : public ContainerNode, ...@@ -1368,6 +1372,8 @@ class CORE_EXPORT Document : public ContainerNode,
void SetFeaturePolicy(const String& feature_policy_header); void SetFeaturePolicy(const String& feature_policy_header);
void RecordUkmOutliveTimeAfterShutdown(int outlive_time_count);
protected: protected:
Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass); Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
...@@ -1748,6 +1754,11 @@ class CORE_EXPORT Document : public ContainerNode, ...@@ -1748,6 +1754,11 @@ class CORE_EXPORT Document : public ContainerNode,
bool has_high_media_engagement_; bool has_high_media_engagement_;
std::unique_ptr<DocumentOutliveTimeReporter> document_outlive_time_reporter_; std::unique_ptr<DocumentOutliveTimeReporter> document_outlive_time_reporter_;
// |ukm_recorder_| and |ukm_source_id_| will allow objects that are part of
// the document to recorde UKM.
std::unique_ptr<ukm::UkmRecorder> ukm_recorder_;
int64_t ukm_source_id_;
}; };
extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Document>; extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<Document>;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "platform/wtf/text/StringStatics.h" #include "platform/wtf/text/StringStatics.h"
#include "platform/wtf/text/StringUTF8Adaptor.h" #include "platform/wtf/text/StringUTF8Adaptor.h"
#include "platform/wtf/text/TextEncoding.h" #include "platform/wtf/text/TextEncoding.h"
#include "url/gurl.h"
#include "url/url_util.h" #include "url/url_util.h"
#ifndef NDEBUG #ifndef NDEBUG
#include <stdio.h> #include <stdio.h>
...@@ -881,4 +882,8 @@ bool KURL::IsSafeToSendToAnotherThread() const { ...@@ -881,4 +882,8 @@ bool KURL::IsSafeToSendToAnotherThread() const {
(!inner_url_ || inner_url_->IsSafeToSendToAnotherThread()); (!inner_url_ || inner_url_->IsSafeToSendToAnotherThread());
} }
KURL::operator GURL() const {
return GURL(string_.Utf8().data(), parsed_, is_valid_);
}
} // namespace blink } // namespace blink
...@@ -61,6 +61,8 @@ namespace WTF { ...@@ -61,6 +61,8 @@ namespace WTF {
class TextEncoding; class TextEncoding;
} }
class GURL;
namespace blink { namespace blink {
struct KURLHash; struct KURLHash;
...@@ -212,6 +214,11 @@ class PLATFORM_EXPORT KURL { ...@@ -212,6 +214,11 @@ class PLATFORM_EXPORT KURL {
return parsed_.potentially_dangling_markup; return parsed_.potentially_dangling_markup;
} }
// Returns a GURL with the same properties. This can be used in platform/.
// However, in core/ and modules/, this should only be used to pass a GURL to
// a layer that is expecting one instead of a KURL or a WebURL.
operator GURL() const;
private: private:
friend struct WTF::HashTraits<blink::KURL>; friend struct WTF::HashTraits<blink::KURL>;
......
...@@ -284,6 +284,9 @@ class MergeFilesMatchingContents(MergeFiles): ...@@ -284,6 +284,9 @@ class MergeFilesMatchingContents(MergeFiles):
nonmatching.append(filename) nonmatching.append(filename)
if nonmatching: if nonmatching:
# FIXME: This happens when logs includ date time, that can vary for
# each test (crbug/764662)
return
raise MergeFailure( raise MergeFailure(
'\n'.join( '\n'.join(
['File contents don\'t match:'] + nonmatching), ['File contents don\'t match:'] + nonmatching),
......
...@@ -221,7 +221,8 @@ class MergeFilesOneTests(FileSystemTestCase): ...@@ -221,7 +221,8 @@ class MergeFilesOneTests(FileSystemTestCase):
class MergeFilesMatchingContentsTests(FileSystemTestCase): class MergeFilesMatchingContentsTests(FileSystemTestCase):
def test(self): # TODO(crbug/764662): Re-enable after fixing the merging logic
def disabled_test(self):
mock_filesystem = MockFileSystem({'/s/file1': '1', '/s/file2': '2', '/s/file3': '1'}, dirs=['/output']) mock_filesystem = MockFileSystem({'/s/file1': '1', '/s/file2': '2', '/s/file3': '1'}, dirs=['/output'])
merger = merge_results.MergeFilesMatchingContents(mock_filesystem) merger = merge_results.MergeFilesMatchingContents(mock_filesystem)
...@@ -289,7 +290,8 @@ class DirMergerTests(FileSystemTestCase): ...@@ -289,7 +290,8 @@ class DirMergerTests(FileSystemTestCase):
with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1'}): with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1'}):
d.merge('/output', ['/shard0', '/shard1']) d.merge('/output', ['/shard0', '/shard1'])
def test_failure_same_file_but_contents_differ(self): # TODO(crbug/764662): Re-enable after fixing the merging logic
def disabled_test_failure_same_file_but_contents_differ(self):
mock_filesystem = MockFileSystem({'/shard0/file1': '1', '/shard1/file1': '2'}) mock_filesystem = MockFileSystem({'/shard0/file1': '1', '/shard1/file1': '2'})
d = merge_results.DirMerger(mock_filesystem) d = merge_results.DirMerger(mock_filesystem)
with self.assertRaises(merge_results.MergeFailure): with self.assertRaises(merge_results.MergeFailure):
......
...@@ -390,6 +390,24 @@ be describing additional metrics about the same event. ...@@ -390,6 +390,24 @@ be describing additional metrics about the same event.
</metric> </metric>
</event> </event>
<event name="Document.OutliveTimeAfterShutdown">
<owner>hajimehoshi@chromium.org</owner>
<owner>keishi@chromium.org</owner>
<summary>
Recorded when a Document object survives certain number of garbage
collections after detached. It is expected that regular Document objects are
destroyed soon after detached, and if a document outlives longer, probably
this can be leaked.
</summary>
<metric name="GCCount">
<summary>
Measures the numbers of garbarge collection after the document is
detached. This is recorded when the number reached certain numbers like 5
or 10.
</summary>
</metric>
</event>
<event name="Event.ScrollUpdate.Touch"> <event name="Event.ScrollUpdate.Touch">
<owner>nzolghadr@chromium.org</owner> <owner>nzolghadr@chromium.org</owner>
<summary> <summary>
......
...@@ -24,8 +24,8 @@ namespace url { ...@@ -24,8 +24,8 @@ namespace url {
// resize function that is called when the existing buffer is not big enough. // resize function that is called when the existing buffer is not big enough.
// The derived class is then in charge of setting up our buffer which we will // The derived class is then in charge of setting up our buffer which we will
// manage. // manage.
template<typename T> template <typename T>
class CanonOutputT { class URL_TEMPLATE_CLASS_EXPORT CanonOutputT {
public: public:
CanonOutputT() : buffer_(NULL), buffer_len_(0), cur_len_(0) { CanonOutputT() : buffer_(NULL), buffer_len_(0), cur_len_(0) {
} }
...@@ -927,6 +927,11 @@ URL_EXPORT bool ResolveRelativeURL(const char* base_url, ...@@ -927,6 +927,11 @@ URL_EXPORT bool ResolveRelativeURL(const char* base_url,
CanonOutput* output, CanonOutput* output,
Parsed* out_parsed); Parsed* out_parsed);
URL_EXTERN_TEMPLATE_EXTERN template class URL_EXTERN_TEMPLATE_EXPORT
CanonOutputT<char>;
URL_EXTERN_TEMPLATE_EXTERN template class URL_EXTERN_TEMPLATE_EXPORT
CanonOutputT<base::char16>;
} // namespace url } // namespace url
#endif // URL_URL_CANON_H_ #endif // URL_URL_CANON_H_
...@@ -385,4 +385,7 @@ void CanonicalizeRef(const base::char16* spec, ...@@ -385,4 +385,7 @@ void CanonicalizeRef(const base::char16* spec,
DoCanonicalizeRef<base::char16, base::char16>(spec, ref, output, out_ref); DoCanonicalizeRef<base::char16, base::char16>(spec, ref, output, out_ref);
} }
template class CanonOutputT<char>;
template class CanonOutputT<base::char16>;
} // namespace url } // namespace url
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef URL_URL_EXPORT_H_ #ifndef URL_URL_EXPORT_H_
#define URL_URL_EXPORT_H_ #define URL_URL_EXPORT_H_
#include "build/build_config.h"
#if defined(COMPONENT_BUILD) #if defined(COMPONENT_BUILD)
#if defined(WIN32) #if defined(WIN32)
...@@ -14,6 +16,8 @@ ...@@ -14,6 +16,8 @@
#define URL_EXPORT __declspec(dllimport) #define URL_EXPORT __declspec(dllimport)
#endif // defined(URL_IMPLEMENTATION) #endif // defined(URL_IMPLEMENTATION)
#define URL_EXTERN_TEMPLATE_EXTERN
#else // !defined(WIN32) #else // !defined(WIN32)
#if defined(URL_IMPLEMENTATION) #if defined(URL_IMPLEMENTATION)
...@@ -22,12 +26,39 @@ ...@@ -22,12 +26,39 @@
#define URL_EXPORT #define URL_EXPORT
#endif // defined(URL_IMPLEMENTATION) #endif // defined(URL_IMPLEMENTATION)
#define URL_EXTERN_TEMPLATE_EXTERN extern
#endif // defined(WIN32) #endif // defined(WIN32)
#else // !defined(COMPONENT_BUILD) #else // !defined(COMPONENT_BUILD)
#define URL_EXPORT #define URL_EXPORT
#define URL_EXTERN_TEMPLATE_EXTERN extern
#endif // define(COMPONENT_BUILD) #endif // define(COMPONENT_BUILD)
#if defined(URL_IMPLEMENTATION)
#if defined(COMPILER_MSVC)
#define URL_TEMPLATE_CLASS_EXPORT
#define URL_EXTERN_TEMPLATE_EXPORT URL_EXPORT
#define URL_TEMPLATE_EXPORT URL_EXPORT
#elif defined(COMPILER_GCC)
#define URL_TEMPLATE_CLASS_EXPORT URL_EXPORT
#define URL_EXTERN_TEMPLATE_EXPORT URL_EXPORT
#define URL_TEMPLATE_EXPORT
#endif
#else // !defined(URL_IMPLEMENTATION)
#define URL_TEMPLATE_CLASS_EXPORT
#define URL_EXTERN_TEMPLATE_EXPORT URL_EXPORT
#define URL_TEMPLATE_EXPORT
#endif // defined(URL_IMPLEMENTATION)
#endif // URL_URL_EXPORT_H_ #endif // URL_URL_EXPORT_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment