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 @@
},
"requires": {
"*": [ "app" ],
"content_browser": [ "renderer" ],
"content_browser": [
"memory_instrumentation",
"renderer",
"url_keyed_metrics"
],
"device": [
"device:power_monitor",
"device:screen_orientation",
......
......@@ -32,6 +32,10 @@ namespace autofill {
class AutofillMetrics;
}
namespace blink {
class Document;
}
namespace content {
class RenderFrameImpl;
class RenderWidgetHostLatencyTracker;
......@@ -101,6 +105,7 @@ class METRICS_EXPORT UkmRecorder {
private:
friend autofill::AutofillMetrics;
friend blink::Document;
friend payments::JourneyLogger;
friend ContextualSearchRankerLoggerImpl;
friend ProcessMemoryMetricsEmitter;
......
......@@ -99,10 +99,10 @@ def _CheckForPrintfDebugging(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.
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"]
def source_file_filter(path):
......
......@@ -11,6 +11,7 @@ include_rules = [
"+platform",
"+public/platform",
"+public/web",
"+services/metrics/public",
"+services/network/public/interfaces",
"+third_party/skia/include",
"+ui/gfx/geometry",
......
......@@ -347,4 +347,10 @@ blink_core_sources("dom") {
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
"//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 @@
#include "platform/wtf/text/CharacterNames.h"
#include "platform/wtf/text/StringBuffer.h"
#include "platform/wtf/text/TextEncodingRegistry.h"
#include "public/platform/InterfaceProvider.h"
#include "public/platform/Platform.h"
#include "public/platform/WebAddressSpace.h"
#include "public/platform/WebPrerenderingSupport.h"
#include "public/platform/modules/insecure_input/insecure_input_service.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"
#ifndef NDEBUG
......@@ -310,6 +314,7 @@ class DocumentOutliveTimeReporter : public BlinkGCObserver {
int outlive_time_count = GetOutliveTimeCount();
if (outlive_time_count == 5 || outlive_time_count == 10) {
const char* kUMAString = "Document.OutliveTimeAfterShutdown.GCCount";
if (outlive_time_count == 5)
UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount5, kGCCountMax);
else if (outlive_time_count == 10)
......@@ -317,6 +322,11 @@ class DocumentOutliveTimeReporter : public BlinkGCObserver {
else
NOTREACHED();
}
if (outlive_time_count == 5 || outlive_time_count == 10 ||
outlive_time_count == 20 || outlive_time_count == 50) {
document_->RecordUkmOutliveTimeAfterShutdown(outlive_time_count);
}
}
private:
......@@ -3696,6 +3706,18 @@ void Document::SetURL(const KURL& url) {
access_entry_from_url_ = nullptr;
UpdateBaseURL();
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 {
......@@ -7150,6 +7172,15 @@ void Document::RecordDeferredLoadReason(WouldLoadReason 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) {
// node_lists_ are traced in their corresponding NodeListsNodeData, keeping
// them only alive for live nodes. Otherwise we would keep lists of dead
......
......@@ -74,11 +74,15 @@
#include "public/platform/WebFocusType.h"
#include "public/platform/WebInsecureRequestPolicy.h"
namespace ukm {
class UkmRecorder;
} // namespace ukm
namespace blink {
namespace mojom {
enum class EngagementLevel : int32_t;
}
} // namespace mojom
class AnimationClock;
class AXObjectCache;
......@@ -1368,6 +1372,8 @@ class CORE_EXPORT Document : public ContainerNode,
void SetFeaturePolicy(const String& feature_policy_header);
void RecordUkmOutliveTimeAfterShutdown(int outlive_time_count);
protected:
Document(const DocumentInit&, DocumentClassFlags = kDefaultDocumentClass);
......@@ -1748,6 +1754,11 @@ class CORE_EXPORT Document : public ContainerNode,
bool has_high_media_engagement_;
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>;
......
......@@ -37,6 +37,7 @@
#include "platform/wtf/text/StringStatics.h"
#include "platform/wtf/text/StringUTF8Adaptor.h"
#include "platform/wtf/text/TextEncoding.h"
#include "url/gurl.h"
#include "url/url_util.h"
#ifndef NDEBUG
#include <stdio.h>
......@@ -881,4 +882,8 @@ bool KURL::IsSafeToSendToAnotherThread() const {
(!inner_url_ || inner_url_->IsSafeToSendToAnotherThread());
}
KURL::operator GURL() const {
return GURL(string_.Utf8().data(), parsed_, is_valid_);
}
} // namespace blink
......@@ -61,6 +61,8 @@ namespace WTF {
class TextEncoding;
}
class GURL;
namespace blink {
struct KURLHash;
......@@ -212,6 +214,11 @@ class PLATFORM_EXPORT KURL {
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:
friend struct WTF::HashTraits<blink::KURL>;
......
......@@ -284,6 +284,9 @@ class MergeFilesMatchingContents(MergeFiles):
nonmatching.append(filename)
if nonmatching:
# FIXME: This happens when logs includ date time, that can vary for
# each test (crbug/764662)
return
raise MergeFailure(
'\n'.join(
['File contents don\'t match:'] + nonmatching),
......
......@@ -221,7 +221,8 @@ class MergeFilesOneTests(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'])
merger = merge_results.MergeFilesMatchingContents(mock_filesystem)
......@@ -289,7 +290,8 @@ class DirMergerTests(FileSystemTestCase):
with self.assertFilesAdded(mock_filesystem, {'/output/file1': '1'}):
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'})
d = merge_results.DirMerger(mock_filesystem)
with self.assertRaises(merge_results.MergeFailure):
......
......@@ -390,6 +390,24 @@ be describing additional metrics about the same event.
</metric>
</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">
<owner>nzolghadr@chromium.org</owner>
<summary>
......
......@@ -24,8 +24,8 @@ namespace url {
// 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
// manage.
template<typename T>
class CanonOutputT {
template <typename T>
class URL_TEMPLATE_CLASS_EXPORT CanonOutputT {
public:
CanonOutputT() : buffer_(NULL), buffer_len_(0), cur_len_(0) {
}
......@@ -927,6 +927,11 @@ URL_EXPORT bool ResolveRelativeURL(const char* base_url,
CanonOutput* output,
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
#endif // URL_URL_CANON_H_
......@@ -385,4 +385,7 @@ void CanonicalizeRef(const base::char16* spec,
DoCanonicalizeRef<base::char16, base::char16>(spec, ref, output, out_ref);
}
template class CanonOutputT<char>;
template class CanonOutputT<base::char16>;
} // namespace url
......@@ -5,6 +5,8 @@
#ifndef URL_URL_EXPORT_H_
#define URL_URL_EXPORT_H_
#include "build/build_config.h"
#if defined(COMPONENT_BUILD)
#if defined(WIN32)
......@@ -14,6 +16,8 @@
#define URL_EXPORT __declspec(dllimport)
#endif // defined(URL_IMPLEMENTATION)
#define URL_EXTERN_TEMPLATE_EXTERN
#else // !defined(WIN32)
#if defined(URL_IMPLEMENTATION)
......@@ -22,12 +26,39 @@
#define URL_EXPORT
#endif // defined(URL_IMPLEMENTATION)
#define URL_EXTERN_TEMPLATE_EXTERN extern
#endif // defined(WIN32)
#else // !defined(COMPONENT_BUILD)
#define URL_EXPORT
#define URL_EXTERN_TEMPLATE_EXTERN extern
#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_
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