Title: [218841] trunk
Revision
218841
Author
[email protected]
Date
2017-06-27 14:10:24 -0700 (Tue, 27 Jun 2017)

Log Message

Resource Load Statistics: Add telemetry
https://bugs.webkit.org/show_bug.cgi?id=173499
<rdar://problem/32826094>

Reviewed by Brent Fulgham.

Source/WebCore:

Test: http/tests/loading/resourceLoadStatistics/telemetry-generation.html

* loader/ResourceLoadObserver.cpp:
(WebCore::ResourceLoadObserver::fireTelemetryHandler):
    Test infrastructure.
* loader/ResourceLoadObserver.h:
* loader/ResourceLoadStatisticsStore.cpp:
(WebCore::ResourceLoadStatisticsStore::setFireTelemetryCallback):
(WebCore::ResourceLoadStatisticsStore::fireTelemetryHandler):
    Test infrastructure.
(WebCore::ResourceLoadStatisticsStore::sortedPrevalentResourceTelemetry):
    Convenience function for telemetry.
* loader/ResourceLoadStatisticsStore.h:
    Added struct WebCore::PrevalentResourceTelemetry.
* page/DiagnosticLoggingKeys.cpp:
(WebCore::DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey):
    Added.
* page/DiagnosticLoggingKeys.h:

Source/WebKit2:

* PlatformGTK.cmake:
    Added UIProcess/WebResourceLoadStatisticsTelemetry.cpp
* PlatformMac.cmake:
    Added UIProcess/WebResourceLoadStatisticsTelemetry.cpp
* PlatformWPE.cmake:
    Added UIProcess/WebResourceLoadStatisticsTelemetry.cpp
* UIProcess/API/C/WKResourceLoadStatisticsManager.cpp:
(WKResourceLoadStatisticsManagerFireTelemetryHandler):
(WKResourceLoadStatisticsManagerSetNotifyPagesWhenTelemetryWasCaptured):
    Test infrastructure.
* UIProcess/API/C/WKResourceLoadStatisticsManager.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::notifyPageStatisticsTelemetryFinished):
    Test infrastructure.
* UIProcess/WebProcessProxy.h:
* UIProcess/WebResourceLoadStatisticsManager.cpp:
(WebKit::WebResourceLoadStatisticsManager::fireTelemetryHandler):
(WebKit::WebResourceLoadStatisticsManager::setNotifyPagesWhenTelemetryWasCaptured):
(WebKit::WebResourceLoadStatisticsManager::resetToConsistentState):
    Test infrastructure.
* UIProcess/WebResourceLoadStatisticsManager.h:
* UIProcess/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::WebResourceLoadStatisticsStore):
    Configures a timer for telemetry capture. Fires 5 seconds after launch
    and then every 24 hours.
(WebKit::WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned):
    Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
(WebKit::WebResourceLoadStatisticsStore::removeDataRecords):
    Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
(WebKit::WebResourceLoadStatisticsStore::processStatisticsAndDataRecords):
    Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
(WebKit::WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver):
    Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
(WebKit::WebResourceLoadStatisticsStore::grandfatherExistingWebsiteData):
    Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
(WebKit::WebResourceLoadStatisticsStore::telemetryTimerFired):
     Calls WebResourceLoadStatisticsTelemetry::calculateAndSubmit().
* UIProcess/WebResourceLoadStatisticsStore.h:
* UIProcess/WebResourceLoadStatisticsTelemetry.cpp: Added.
(WebKit::numberOfResourcesWithUserInteraction):
(WebKit::median):
(WebKit::nonEphemeralWebPageProxy):
(WebKit::submitTopList):
(WebKit::submitTopLists):
(WebKit::notifyPages):
(WebKit::WebResourceLoadStatisticsTelemetry::calculateAndSubmit):
(WebKit::WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured):
* UIProcess/WebResourceLoadStatisticsTelemetry.h: Added.
* WebKit2.xcodeproj/project.pbxproj:

Tools:

Adds three new testRunner functions:
- installStatisticsDidRunTelemetryCallback()
- statisticsFireTelemetryHandler()
- setStatisticsNotifyPagesWhenTelemetryWasCaptured()

* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
(WTR::InjectedBundle::didReceiveMessageToPage):
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::installStatisticsDidRunTelemetryCallback):
(WTR::TestRunner::statisticsDidRunTelemetryCallback):
(WTR::TestRunner::statisticsFireTelemetryHandler):
(WTR::TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::resetStateToConsistentValues):
(WTR::TestController::statisticsFireTelemetryHandler):
(WTR::TestController::setStatisticsNotifyPagesWhenTelemetryWasCaptured):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):

LayoutTests:

* http/tests/loading/resourceLoadStatistics/telemetry-generation-expected.txt: Added.
* http/tests/loading/resourceLoadStatistics/telemetry-generation.html: Added.
* platform/wk2/TestExpectations:
    Enabled here since ResourceLoadStatistics is WK2-only.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (218840 => 218841)


--- trunk/LayoutTests/ChangeLog	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/LayoutTests/ChangeLog	2017-06-27 21:10:24 UTC (rev 218841)
@@ -1,3 +1,16 @@
+2017-06-27  John Wilander  <[email protected]>
+
+        Resource Load Statistics: Add telemetry
+        https://bugs.webkit.org/show_bug.cgi?id=173499
+        <rdar://problem/32826094>
+
+        Reviewed by Brent Fulgham.
+
+        * http/tests/loading/resourceLoadStatistics/telemetry-generation-expected.txt: Added.
+        * http/tests/loading/resourceLoadStatistics/telemetry-generation.html: Added.
+        * platform/wk2/TestExpectations:
+            Enabled here since ResourceLoadStatistics is WK2-only.
+
 2017-06-27  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: Crash generating object preview for ArrayIterator

Added: trunk/LayoutTests/http/tests/loading/resourceLoadStatistics/telemetry-generation-expected.txt (0 => 218841)


--- trunk/LayoutTests/http/tests/loading/resourceLoadStatistics/telemetry-generation-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/resourceLoadStatistics/telemetry-generation-expected.txt	2017-06-27 21:10:24 UTC (rev 218841)
@@ -0,0 +1,23 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: Test for Telemetry Generation
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+Tests that telemetry for prevalent resources is calculated correctly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Hosts classified as prevalent resources.
+PASS testResult.totalPrevalentResources is 0
+PASS testResult.totalPrevalentResourcesWithUserInteraction is 0
+PASS testResult.top3SubframeUnderTopFrameOrigins is 0
+PASS Hosts classified as prevalent resources.
+PASS testResult.totalPrevalentResources is 4
+PASS testResult.totalPrevalentResourcesWithUserInteraction is 1
+PASS testResult.top3SubframeUnderTopFrameOrigins is 4
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/loading/resourceLoadStatistics/telemetry-generation.html (0 => 218841)


--- trunk/LayoutTests/http/tests/loading/resourceLoadStatistics/telemetry-generation.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/loading/resourceLoadStatistics/telemetry-generation.html	2017-06-27 21:10:24 UTC (rev 218841)
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Test for Telemetry Generation</title>
+    <script src=""
+</head>
+<body>
+<script>
+    description("Tests that telemetry for prevalent resources is calculated correctly.");
+    jsTestIsAsync = true;
+
+    const topFrameUrl1 = "http://127.0.0.1:8000/temp";
+    const topFrameUrl2 = "http://127.0.0.2:8000/temp";
+    const topFrameUrl3 = "http://127.0.0.3:8000/temp";
+    const topFrameUrl4 = "http://127.0.0.4:8000/temp";
+    const prevalentResourceUrl1 = "http://127.0.1.1:8000/temp";
+    const prevalentResourceUrl2 = "http://127.0.1.2:8000/temp";
+    const prevalentResourceUrl3 = "http://127.0.1.3:8000/temp";
+    const prevalentResourceUrl4 = "http://127.0.1.4:8000/temp";
+
+    function checkInsufficientClassificationAndContinue() {
+        if (!testRunner.isStatisticsPrevalentResource(prevalentResourceUrl1)) {
+            testFailed("Host 1 did not get classified as prevalent resource.");
+            finishJSTest();
+        } else if (!testRunner.isStatisticsPrevalentResource(prevalentResourceUrl2)) {
+            testFailed("Host 2 did not get classified as prevalent resource.");
+            finishJSTest();
+        } else {
+            testPassed("Hosts classified as prevalent resources.");
+            runTelemetryAndContinue();
+        }
+    }
+
+    function checkSufficientClassificationAndContinue() {
+        if (!testRunner.isStatisticsPrevalentResource(prevalentResourceUrl1)) {
+            testFailed("Host 1 did not get classified as prevalent resource.");
+            finishJSTest();
+        } else if (!testRunner.isStatisticsPrevalentResource(prevalentResourceUrl2)) {
+            testFailed("Host 2 did not get classified as prevalent resource.");
+            finishJSTest();
+        } else if (!testRunner.isStatisticsPrevalentResource(prevalentResourceUrl3)) {
+            testFailed("Host 3 did not get classified as prevalent resource.");
+            finishJSTest();
+        } else if (!testRunner.isStatisticsPrevalentResource(prevalentResourceUrl4)) {
+            testFailed("Host 4 did not get classified as prevalent resource.");
+            finishJSTest();
+        } else {
+            testPassed("Hosts classified as prevalent resources.");
+            runTelemetryAndContinue();
+        }
+    }
+
+    function makeUrlPrevalent(prevalentResourceUrl) {
+        testRunner.setStatisticsSubframeUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl1);
+        testRunner.setStatisticsSubframeUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl2);
+        testRunner.setStatisticsSubframeUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl3);
+        testRunner.setStatisticsSubframeUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl4);
+
+        testRunner.setStatisticsSubresourceUniqueRedirectTo(prevalentResourceUrl, topFrameUrl1);
+        testRunner.setStatisticsSubresourceUniqueRedirectTo(prevalentResourceUrl, topFrameUrl2);
+        testRunner.setStatisticsSubresourceUniqueRedirectTo(prevalentResourceUrl, topFrameUrl3);
+        testRunner.setStatisticsSubresourceUniqueRedirectTo(prevalentResourceUrl, topFrameUrl4);
+
+        testRunner.setStatisticsSubresourceUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl1);
+        testRunner.setStatisticsSubresourceUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl2);
+        testRunner.setStatisticsSubresourceUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl3);
+        testRunner.setStatisticsSubresourceUnderTopFrameOrigin(prevalentResourceUrl, topFrameUrl4);
+    }
+
+    function setUpInsufficientStatisticsAndContinue() {
+        makeUrlPrevalent(prevalentResourceUrl1);
+        makeUrlPrevalent(prevalentResourceUrl2);
+
+        testRunner.installStatisticsDidScanDataRecordsCallback(checkInsufficientClassificationAndContinue);
+        testRunner.installStatisticsDidRunTelemetryCallback(checkInsufficientTelemetry);
+        testRunner.statisticsFireDataModificationHandler();
+    }
+
+    function setUpSufficientStatisticsAndContinue() {
+        makeUrlPrevalent(prevalentResourceUrl3);
+        makeUrlPrevalent(prevalentResourceUrl4);
+
+        testRunner.setStatisticsHasHadUserInteraction(prevalentResourceUrl4, true);
+
+        testRunner.installStatisticsDidScanDataRecordsCallback(checkSufficientClassificationAndContinue);
+        testRunner.installStatisticsDidRunTelemetryCallback(checkSufficientTelemetry);
+        testRunner.statisticsFireDataModificationHandler();
+    }
+
+    function runTelemetryAndContinue() {
+        testRunner.statisticsFireTelemetryHandler();
+    }
+
+    var testResult;
+    function checkInsufficientTelemetry(result) {
+        testResult = result;
+        shouldBe("testResult.totalPrevalentResources", "0");
+        shouldBe("testResult.totalPrevalentResourcesWithUserInteraction", "0");
+        shouldBe("testResult.top3SubframeUnderTopFrameOrigins", "0");
+        setUpSufficientStatisticsAndContinue();
+    }
+
+    function checkSufficientTelemetry(result) {
+        testResult = result;
+        shouldBe("testResult.totalPrevalentResources", "4");
+        shouldBe("testResult.totalPrevalentResourcesWithUserInteraction", "1");
+        shouldBe("testResult.top3SubframeUnderTopFrameOrigins", "4");
+        finishJSTest();
+    }
+
+    if (window.testRunner) {
+        testRunner.setStatisticsNotifyPagesWhenDataRecordsWereScanned(true);
+        testRunner.setStatisticsNotifyPagesWhenTelemetryWasCaptured(true);
+        setUpInsufficientStatisticsAndContinue();
+    }
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/LayoutTests/platform/wk2/TestExpectations (218840 => 218841)


--- trunk/LayoutTests/platform/wk2/TestExpectations	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/LayoutTests/platform/wk2/TestExpectations	2017-06-27 21:10:24 UTC (rev 218841)
@@ -705,6 +705,7 @@
 http/tests/loading/resourceLoadStatistics/classify-as-prevalent-based-on-subresource-unique-redirects-to.html [ Pass ]
 http/tests/loading/resourceLoadStatistics/clear-in-memory-and-persistent-store.html [ Pass ]
 webkit.org/b/172452 http/tests/loading/resourceLoadStatistics/grandfathering.html [ Pass Failure Timeout ]
+http/tests/loading/resourceLoadStatistics/telemetry-generation.html [ Pass ]
 
 ### END OF (5) Progressions, expected successes that are expected failures in WebKit1.
 ########################################

Modified: trunk/Source/WebCore/ChangeLog (218840 => 218841)


--- trunk/Source/WebCore/ChangeLog	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/ChangeLog	2017-06-27 21:10:24 UTC (rev 218841)
@@ -1,3 +1,30 @@
+2017-06-27  John Wilander  <[email protected]>
+
+        Resource Load Statistics: Add telemetry
+        https://bugs.webkit.org/show_bug.cgi?id=173499
+        <rdar://problem/32826094>
+
+        Reviewed by Brent Fulgham.
+
+        Test: http/tests/loading/resourceLoadStatistics/telemetry-generation.html
+
+        * loader/ResourceLoadObserver.cpp:
+        (WebCore::ResourceLoadObserver::fireTelemetryHandler):
+            Test infrastructure.
+        * loader/ResourceLoadObserver.h:
+        * loader/ResourceLoadStatisticsStore.cpp:
+        (WebCore::ResourceLoadStatisticsStore::setFireTelemetryCallback):
+        (WebCore::ResourceLoadStatisticsStore::fireTelemetryHandler):
+            Test infrastructure.
+        (WebCore::ResourceLoadStatisticsStore::sortedPrevalentResourceTelemetry):
+            Convenience function for telemetry.
+        * loader/ResourceLoadStatisticsStore.h:
+            Added struct WebCore::PrevalentResourceTelemetry.
+        * page/DiagnosticLoggingKeys.cpp:
+        (WebCore::DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey):
+            Added.
+        * page/DiagnosticLoggingKeys.h:
+
 2017-06-27  Ting-Wei Lan  <[email protected]>
 
         Add missing includes to fix compilation error on FreeBSD

Modified: trunk/Source/WebCore/loader/ResourceLoadObserver.cpp (218840 => 218841)


--- trunk/Source/WebCore/loader/ResourceLoadObserver.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/loader/ResourceLoadObserver.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -584,6 +584,13 @@
     });
 }
 
+void ResourceLoadObserver::fireTelemetryHandler()
+{
+    // Helper function used by testing system. Should only be called from the main thread.
+    ASSERT(isMainThread());
+    m_store->fireTelemetryHandler();
+}
+    
 String ResourceLoadObserver::primaryDomain(const URL& url)
 {
     return primaryDomain(url.host());

Modified: trunk/Source/WebCore/loader/ResourceLoadObserver.h (218840 => 218841)


--- trunk/Source/WebCore/loader/ResourceLoadObserver.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/loader/ResourceLoadObserver.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -78,6 +78,7 @@
     WEBCORE_EXPORT void fireDataModificationHandler();
     WEBCORE_EXPORT void fireShouldPartitionCookiesHandler();
     WEBCORE_EXPORT void fireShouldPartitionCookiesHandler(const Vector<String>& domainsToRemove, const Vector<String>& domainsToAdd, bool clearFirst);
+    WEBCORE_EXPORT void fireTelemetryHandler();
 
     WEBCORE_EXPORT void setStatisticsStore(Ref<ResourceLoadStatisticsStore>&&);
     WEBCORE_EXPORT void setStatisticsQueue(Ref<WTF::WorkQueue>&&);

Modified: trunk/Source/WebCore/loader/ResourceLoadStatisticsStore.cpp (218840 => 218841)


--- trunk/Source/WebCore/loader/ResourceLoadStatisticsStore.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/loader/ResourceLoadStatisticsStore.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -223,6 +223,11 @@
     m_grandfatherExistingWebsiteDataHandler = WTFMove(handler);
 }
 
+void ResourceLoadStatisticsStore::setFireTelemetryCallback(WTF::Function<void()>&& handler)
+{
+    m_fireTelemetryHandler = WTFMove(handler);
+}
+    
 void ResourceLoadStatisticsStore::fireDataModificationHandler()
 {
     ASSERT(!isMainThread());
@@ -232,6 +237,13 @@
     });
 }
 
+void ResourceLoadStatisticsStore::fireTelemetryHandler()
+{
+    ASSERT(isMainThread());
+    if (m_fireTelemetryHandler)
+        m_fireTelemetryHandler();
+}
+    
 static inline bool shouldPartitionCookies(const ResourceLoadStatistics& statistic)
 {
     return statistic.isPrevalentResource
@@ -361,7 +373,38 @@
 
     return prevalentResources;
 }
+    
+Vector<PrevalentResourceTelemetry> ResourceLoadStatisticsStore::sortedPrevalentResourceTelemetry() const
+{
+    auto locker = holdLock(m_statisticsLock);
+    Vector<PrevalentResourceTelemetry> sorted;
+    
+    for (auto& statistic : m_resourceStatisticsMap.values()) {
+        if (statistic.isPrevalentResource) {
+            unsigned daysSinceUserInteraction = statistic.mostRecentUserInteraction <= 0 ? 0 :
+                std::floor((currentTime() - statistic.mostRecentUserInteraction) / secondsPerDay);
+            sorted.append(PrevalentResourceTelemetry(
+                statistic.dataRecordsRemoved,
+                statistic.hadUserInteraction,
+                daysSinceUserInteraction,
+                statistic.subframeUnderTopFrameOrigins.size(),
+                statistic.subresourceUnderTopFrameOrigins.size(),
+                statistic.subresourceUniqueRedirectsTo.size()
+            ));
+        }
+    }
+    
+    if (sorted.size() < minimumPrevalentResourcesForTelemetry)
+        return Vector<PrevalentResourceTelemetry>();
 
+    std::sort(sorted.begin(), sorted.end(), [](const PrevalentResourceTelemetry& a, const PrevalentResourceTelemetry& b) {
+        return a.subframeUnderTopFrameOrigins + a.subresourceUnderTopFrameOrigins + a.subresourceUniqueRedirectsTo >
+        b.subframeUnderTopFrameOrigins + b.subresourceUnderTopFrameOrigins + b.subresourceUniqueRedirectsTo;
+    });
+    
+    return sorted;
+}
+
 void ResourceLoadStatisticsStore::updateStatisticsForRemovedDataRecords(const HashSet<String>& prevalentResourceDomains)
 {
     auto locker = holdLock(m_statisticsLock);

Modified: trunk/Source/WebCore/loader/ResourceLoadStatisticsStore.h (218840 => 218841)


--- trunk/Source/WebCore/loader/ResourceLoadStatisticsStore.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/loader/ResourceLoadStatisticsStore.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -36,6 +36,25 @@
 class KeyedEncoder;
 class URL;
 
+static const auto minimumPrevalentResourcesForTelemetry = 3;
+    
+struct PrevalentResourceTelemetry {
+    unsigned numberOfTimesDataRecordsRemoved;
+    bool hasHadUserInteraction;
+    unsigned daysSinceUserInteraction;
+    unsigned subframeUnderTopFrameOrigins;
+    unsigned subresourceUnderTopFrameOrigins;
+    unsigned subresourceUniqueRedirectsTo;
+    PrevalentResourceTelemetry()
+        : numberOfTimesDataRecordsRemoved(0), hasHadUserInteraction(0), daysSinceUserInteraction(0), subframeUnderTopFrameOrigins(0), subresourceUnderTopFrameOrigins(0), subresourceUniqueRedirectsTo(0)
+    {
+    }
+    PrevalentResourceTelemetry(unsigned recordsRemoved, bool userInteraction, unsigned daysSince, unsigned subframe, unsigned subresource, unsigned uniqueRedirects)
+        : numberOfTimesDataRecordsRemoved(recordsRemoved), hasHadUserInteraction(userInteraction), daysSinceUserInteraction(daysSince), subframeUnderTopFrameOrigins(subframe), subresourceUnderTopFrameOrigins(subresource), subresourceUniqueRedirectsTo(uniqueRedirects)
+    {
+    }
+};
+    
 struct ResourceLoadStatistics;
 
 class ResourceLoadStatisticsStore : public ThreadSafeRefCounted<ResourceLoadStatisticsStore> {
@@ -64,8 +83,10 @@
     WEBCORE_EXPORT void setShouldPartitionCookiesCallback(WTF::Function<void(const Vector<String>& domainsToRemove, const Vector<String>& domainsToAdd, bool clearFirst)>&&);
     WEBCORE_EXPORT void setWritePersistentStoreCallback(WTF::Function<void()>&&);
     WEBCORE_EXPORT void setGrandfatherExistingWebsiteDataCallback(WTF::Function<void()>&&);
+    WEBCORE_EXPORT void setFireTelemetryCallback(WTF::Function<void()>&& handler);
 
     void fireDataModificationHandler();
+    void fireTelemetryHandler();
     void setTimeToLiveUserInteraction(double seconds);
     void setTimeToLiveCookiePartitionFree(double seconds);
     void setMinimumTimeBetweeenDataRecordsRemoval(double seconds);
@@ -77,6 +98,7 @@
 
     WEBCORE_EXPORT bool hasHadRecentUserInteraction(ResourceLoadStatistics&) const;
     WEBCORE_EXPORT Vector<String> topPrivatelyControlledDomainsToRemoveWebsiteDataFor();
+    WEBCORE_EXPORT Vector<PrevalentResourceTelemetry> sortedPrevalentResourceTelemetry() const;
     WEBCORE_EXPORT void updateStatisticsForRemovedDataRecords(const HashSet<String>& prevalentResourceDomains);
 
     WEBCORE_EXPORT void handleFreshStartWithEmptyOrNoStore(HashSet<String>&& topPrivatelyControlledDomainsToGrandfather);
@@ -95,6 +117,7 @@
     WTF::Function<void(const Vector<String>&, const Vector<String>&, bool clearFirst)> m_shouldPartitionCookiesForDomainsHandler;
     WTF::Function<void()> m_writePersistentStoreHandler;
     WTF::Function<void()> m_grandfatherExistingWebsiteDataHandler;
+    WTF::Function<void()> m_fireTelemetryHandler;
 
     double m_endOfGrandfatheringTimestamp { 0 };
     double m_lastTimeDataRecordsWereRemoved { 0 };

Modified: trunk/Source/WebCore/page/DiagnosticLoggingKeys.cpp (218840 => 218841)


--- trunk/Source/WebCore/page/DiagnosticLoggingKeys.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/page/DiagnosticLoggingKeys.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -767,5 +767,10 @@
     return ASCIILiteral("over70");
 }
 
+String DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey()
+{
+    return ASCIILiteral("resourceLoadStatisticsTelemetry");
+}
+    
 } // namespace WebCore
 

Modified: trunk/Source/WebCore/page/DiagnosticLoggingKeys.h (218840 => 218841)


--- trunk/Source/WebCore/page/DiagnosticLoggingKeys.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebCore/page/DiagnosticLoggingKeys.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -171,6 +171,8 @@
     WEBCORE_EXPORT static String memoryUsageToDiagnosticLoggingKey(uint64_t memoryUsage);
     WEBCORE_EXPORT static String foregroundCPUUsageToDiagnosticLoggingKey(double cpuUsage);
     WEBCORE_EXPORT static String backgroundCPUUsageToDiagnosticLoggingKey(double cpuUsage);
+    
+    WEBCORE_EXPORT static String resourceLoadStatisticsTelemetryKey();
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebKit2/ChangeLog (218840 => 218841)


--- trunk/Source/WebKit2/ChangeLog	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/ChangeLog	2017-06-27 21:10:24 UTC (rev 218841)
@@ -1,3 +1,61 @@
+2017-06-27  John Wilander  <[email protected]>
+
+        Resource Load Statistics: Add telemetry
+        https://bugs.webkit.org/show_bug.cgi?id=173499
+        <rdar://problem/32826094>
+
+        Reviewed by Brent Fulgham.
+
+        * PlatformGTK.cmake:
+            Added UIProcess/WebResourceLoadStatisticsTelemetry.cpp
+        * PlatformMac.cmake:
+            Added UIProcess/WebResourceLoadStatisticsTelemetry.cpp
+        * PlatformWPE.cmake:
+            Added UIProcess/WebResourceLoadStatisticsTelemetry.cpp
+        * UIProcess/API/C/WKResourceLoadStatisticsManager.cpp:
+        (WKResourceLoadStatisticsManagerFireTelemetryHandler):
+        (WKResourceLoadStatisticsManagerSetNotifyPagesWhenTelemetryWasCaptured):
+            Test infrastructure.
+        * UIProcess/API/C/WKResourceLoadStatisticsManager.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::notifyPageStatisticsTelemetryFinished):
+            Test infrastructure.
+        * UIProcess/WebProcessProxy.h:
+        * UIProcess/WebResourceLoadStatisticsManager.cpp:
+        (WebKit::WebResourceLoadStatisticsManager::fireTelemetryHandler):
+        (WebKit::WebResourceLoadStatisticsManager::setNotifyPagesWhenTelemetryWasCaptured):
+        (WebKit::WebResourceLoadStatisticsManager::resetToConsistentState):
+            Test infrastructure.
+        * UIProcess/WebResourceLoadStatisticsManager.h:
+        * UIProcess/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::WebResourceLoadStatisticsStore):
+            Configures a timer for telemetry capture. Fires 5 seconds after launch
+            and then every 24 hours.
+        (WebKit::WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned):
+            Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
+        (WebKit::WebResourceLoadStatisticsStore::removeDataRecords):
+            Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
+        (WebKit::WebResourceLoadStatisticsStore::processStatisticsAndDataRecords):
+            Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
+        (WebKit::WebResourceLoadStatisticsStore::registerSharedResourceLoadObserver):
+            Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
+        (WebKit::WebResourceLoadStatisticsStore::grandfatherExistingWebsiteData):
+            Variable renamed notifyPages -> notifyPagesWhenDataRecordsWereScanned.
+        (WebKit::WebResourceLoadStatisticsStore::telemetryTimerFired):
+             Calls WebResourceLoadStatisticsTelemetry::calculateAndSubmit().
+        * UIProcess/WebResourceLoadStatisticsStore.h:
+        * UIProcess/WebResourceLoadStatisticsTelemetry.cpp: Added.
+        (WebKit::numberOfResourcesWithUserInteraction):
+        (WebKit::median):
+        (WebKit::nonEphemeralWebPageProxy):
+        (WebKit::submitTopList):
+        (WebKit::submitTopLists):
+        (WebKit::notifyPages):
+        (WebKit::WebResourceLoadStatisticsTelemetry::calculateAndSubmit):
+        (WebKit::WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured):
+        * UIProcess/WebResourceLoadStatisticsTelemetry.h: Added.
+        * WebKit2.xcodeproj/project.pbxproj:
+
 2017-06-27  Ting-Wei Lan  <[email protected]>
 
         Add missing includes to fix compilation error on FreeBSD

Modified: trunk/Source/WebKit2/PlatformGTK.cmake (218840 => 218841)


--- trunk/Source/WebKit2/PlatformGTK.cmake	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/PlatformGTK.cmake	2017-06-27 21:10:24 UTC (rev 218841)
@@ -109,6 +109,7 @@
     UIProcess/LegacySessionStateCodingNone.cpp
     UIProcess/WebResourceLoadStatisticsManager.cpp
     UIProcess/WebResourceLoadStatisticsStore.cpp
+    UIProcess/WebResourceLoadStatisticsTelemetry.cpp
     UIProcess/WebTextChecker.cpp
     UIProcess/WebTextCheckerClient.cpp
 

Modified: trunk/Source/WebKit2/PlatformMac.cmake (218840 => 218841)


--- trunk/Source/WebKit2/PlatformMac.cmake	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/PlatformMac.cmake	2017-06-27 21:10:24 UTC (rev 218841)
@@ -167,6 +167,7 @@
     UIProcess/WebContextMenuListenerProxy.cpp
     UIProcess/WebResourceLoadStatisticsManager.cpp
     UIProcess/WebResourceLoadStatisticsStore.cpp
+    UIProcess/WebResourceLoadStatisticsTelemetry.cpp
 
     UIProcess/Automation/WebAutomationSession.cpp
 

Modified: trunk/Source/WebKit2/PlatformWPE.cmake (218840 => 218841)


--- trunk/Source/WebKit2/PlatformWPE.cmake	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/PlatformWPE.cmake	2017-06-27 21:10:24 UTC (rev 218841)
@@ -127,6 +127,7 @@
     UIProcess/LegacySessionStateCodingNone.cpp
     UIProcess/WebResourceLoadStatisticsManager.cpp
     UIProcess/WebResourceLoadStatisticsStore.cpp
+    UIProcess/WebResourceLoadStatisticsTelemetry.cpp
 
     UIProcess/API/C/WKGrammarDetail.cpp
     UIProcess/API/C/WKResourceLoadStatisticsManager.cpp

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.cpp (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -116,6 +116,11 @@
     WebResourceLoadStatisticsManager::fireShouldPartitionCookiesHandlerForOneDomain(toWTFString(hostName), value);
 }
 
+void WKResourceLoadStatisticsManagerFireTelemetryHandler()
+{
+    WebResourceLoadStatisticsManager::fireTelemetryHandler();
+}
+
 void WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WebResourceLoadStatisticsManager::setNotifyPagesWhenDataRecordsWereScanned(value);
@@ -126,6 +131,11 @@
     WebResourceLoadStatisticsManager::setShouldClassifyResourcesBeforeDataRecordsRemoval(value);
 }
 
+void WKResourceLoadStatisticsManagerSetNotifyPagesWhenTelemetryWasCaptured(bool value)
+{
+    WebResourceLoadStatisticsManager::setNotifyPagesWhenTelemetryWasCaptured(value);
+}
+
 void WKResourceLoadStatisticsManagerClearInMemoryAndPersistentStore()
 {
     WebResourceLoadStatisticsManager::clearInMemoryAndPersistentStore();

Modified: trunk/Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.h (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/API/C/WKResourceLoadStatisticsManager.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -49,8 +49,10 @@
     WK_EXPORT void WKResourceLoadStatisticsManagerFireDataModificationHandler();
     WK_EXPORT void WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandler();
     WK_EXPORT void WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandlerForOneDomain(WKStringRef hostName, bool value);
+    WK_EXPORT void WKResourceLoadStatisticsManagerFireTelemetryHandler();
     WK_EXPORT void WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(bool value);
     WK_EXPORT void WKResourceLoadStatisticsManagerSetShouldClassifyResourcesBeforeDataRecordsRemoval(bool value);
+    WK_EXPORT void WKResourceLoadStatisticsManagerSetNotifyPagesWhenTelemetryWasCaptured(bool value);
     WK_EXPORT void WKResourceLoadStatisticsManagerClearInMemoryAndPersistentStore();
     WK_EXPORT void WKResourceLoadStatisticsManagerClearInMemoryAndPersistentStoreModifiedSinceHours(unsigned);
     WK_EXPORT void WKResourceLoadStatisticsManagerResetToConsistentState();

Modified: trunk/Source/WebKit2/UIProcess/WebProcessProxy.cpp (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebProcessProxy.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/WebProcessProxy.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -338,6 +338,12 @@
         page.value->postMessageToInjectedBundle("WebsiteDataScanForTopPrivatelyControlledDomainsFinished", nullptr);
 }
     
+void WebProcessProxy::notifyPageStatisticsTelemetryFinished(API::Object* messageBody)
+{
+    for (auto& page : globalPageMap())
+        page.value->postMessageToInjectedBundle("ResourceLoadStatisticsTelemetryFinished", messageBody);
+}
+    
 Ref<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, Ref<API::PageConfiguration>&& pageConfiguration)
 {
     uint64_t pageID = generatePageID();

Modified: trunk/Source/WebKit2/UIProcess/WebProcessProxy.h (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebProcessProxy.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/WebProcessProxy.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -144,6 +144,7 @@
     static void deleteWebsiteDataForTopPrivatelyControlledDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType>, Vector<String>&& topPrivatelyControlledDomains, bool shouldNotifyPages, Function<void (const HashSet<String>&)>&& completionHandler);
     static void topPrivatelyControlledDomainsWithWebsiteData(OptionSet<WebsiteDataType> dataTypes, bool shouldNotifyPage, Function<void(HashSet<String>&&)>&& completionHandler);
     static void notifyPageStatisticsAndDataRecordsProcessed();
+    static void notifyPageStatisticsTelemetryFinished(API::Object* messageBody);
 
     void enableSuddenTermination();
     void disableSuddenTermination();

Modified: trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.cpp (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -124,11 +124,21 @@
         WebCore::ResourceLoadObserver::sharedObserver().fireShouldPartitionCookiesHandler({hostName}, { }, false);
 }
 
+void WebResourceLoadStatisticsManager::fireTelemetryHandler()
+{
+    WebCore::ResourceLoadObserver::sharedObserver().fireTelemetryHandler();
+}
+    
 void WebResourceLoadStatisticsManager::setNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned(value);
 }
 
+void WebResourceLoadStatisticsManager::setNotifyPagesWhenTelemetryWasCaptured(bool value)
+{
+    WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured(value);
+}
+    
 void WebResourceLoadStatisticsManager::setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
 {
     WebResourceLoadStatisticsStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(value);
@@ -151,6 +161,7 @@
     WebCore::ResourceLoadObserver::sharedObserver().setMinimumTimeBetweeenDataRecordsRemoval(60);
     WebCore::ResourceLoadObserver::sharedObserver().setGrandfatheringTime(3600);
     WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned(false);
+    WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured(false);
     WebResourceLoadStatisticsStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(true);
     WebCore::ResourceLoadObserver::sharedObserver().clearInMemoryStore();
 }

Modified: trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.h (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsManager.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -55,7 +55,9 @@
     static void fireDataModificationHandler();
     static void fireShouldPartitionCookiesHandler();
     static void fireShouldPartitionCookiesHandlerForOneDomain(const String& hostName, bool value);
+    static void fireTelemetryHandler();
     static void setNotifyPagesWhenDataRecordsWereScanned(bool);
+    static void setNotifyPagesWhenTelemetryWasCaptured(bool value);
     static void setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value);
     static void clearInMemoryAndPersistentStore();
     static void clearInMemoryAndPersistentStoreModifiedSinceHours(unsigned);

Modified: trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.cpp (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -40,6 +40,7 @@
 #include <wtf/MainThread.h>
 #include <wtf/MathExtras.h>
 #include <wtf/RunLoop.h>
+#include <wtf/Seconds.h>
 #include <wtf/threads/BinarySemaphore.h>
 
 using namespace WebCore;
@@ -47,7 +48,7 @@
 namespace WebKit {
 
 static OptionSet<WebKit::WebsiteDataType> dataTypesToRemove;
-static auto notifyPages = false;
+static auto notifyPagesWhenDataRecordsWereScanned = false;
 static auto shouldClassifyResourcesBeforeDataRecordsRemoval = true;
 
 Ref<WebResourceLoadStatisticsStore> WebResourceLoadStatisticsStore::create(const String& resourceLoadStatisticsDirectory)
@@ -59,7 +60,11 @@
     : m_resourceLoadStatisticsStore(ResourceLoadStatisticsStore::create())
     , m_statisticsQueue(WorkQueue::create("WebResourceLoadStatisticsStore Process Data Queue"))
     , m_statisticsStoragePath(resourceLoadStatisticsDirectory)
+    , m_telemetryOneShotTimer(RunLoop::main(), this, &WebResourceLoadStatisticsStore::telemetryTimerFired)
+    , m_telemetryRepeatedTimer(RunLoop::main(), this, &WebResourceLoadStatisticsStore::telemetryTimerFired)
 {
+    m_telemetryOneShotTimer.startOneShot(5_s);
+    m_telemetryRepeatedTimer.startRepeating(24_h);
 }
 
 WebResourceLoadStatisticsStore::~WebResourceLoadStatisticsStore()
@@ -68,7 +73,7 @@
 
 void WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned(bool always)
 {
-    notifyPages = always;
+    notifyPagesWhenDataRecordsWereScanned = always;
 }
 
 void WebResourceLoadStatisticsStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
@@ -119,7 +124,7 @@
 
     // Switch to the main thread to get the default website data store
     RunLoop::main().dispatch([prevalentResourceDomains = CrossThreadCopier<Vector<String>>::copy(prevalentResourceDomains), this, protectedThis = makeRef(*this)] () mutable {
-        WebProcessProxy::deleteWebsiteDataForTopPrivatelyControlledDomainsInAllPersistentDataStores(dataTypesToRemove, WTFMove(prevalentResourceDomains), notifyPages, [this, protectedThis = WTFMove(protectedThis)](const HashSet<String>& domainsWithDeletedWebsiteData) mutable {
+        WebProcessProxy::deleteWebsiteDataForTopPrivatelyControlledDomainsInAllPersistentDataStores(dataTypesToRemove, WTFMove(prevalentResourceDomains), notifyPagesWhenDataRecordsWereScanned, [this, protectedThis = WTFMove(protectedThis)](const HashSet<String>& domainsWithDeletedWebsiteData) mutable {
             // But always touch the ResourceLoadStatistics store on the worker queue.
             m_statisticsQueue->dispatch([protectedThis = WTFMove(protectedThis), topDomains = CrossThreadCopier<HashSet<String>>::copy(domainsWithDeletedWebsiteData)] () mutable {
                 protectedThis->coreStore().updateStatisticsForRemovedDataRecords(topDomains);
@@ -140,7 +145,7 @@
         }
         removeDataRecords();
         
-        if (notifyPages) {
+        if (notifyPagesWhenDataRecordsWereScanned) {
             RunLoop::main().dispatch([] () mutable {
                 WebProcessProxy::notifyPageStatisticsAndDataRecordsProcessed();
             });
@@ -193,6 +198,10 @@
     m_resourceLoadStatisticsStore->setGrandfatherExistingWebsiteDataCallback([this, protectedThis = makeRef(*this)]() {
         grandfatherExistingWebsiteData();
     });
+    m_resourceLoadStatisticsStore->setFireTelemetryCallback([this, protectedThis = makeRef(*this)]() {
+        // This cancels the one shot timer and is only intended for testing purposes.
+        m_telemetryOneShotTimer.startOneShot(100_ms);
+    });
 #if PLATFORM(COCOA)
     WebResourceLoadStatisticsManager::registerUserDefaultsIfNeeded();
 #endif
@@ -215,7 +224,7 @@
     
     // Switch to the main thread to get the default website data store
     RunLoop::main().dispatch([this, protectedThis = makeRef(*this)] () mutable {
-        WebProcessProxy::topPrivatelyControlledDomainsWithWebsiteData(dataTypesToRemove, notifyPages, [this, protectedThis = WTFMove(protectedThis)] (HashSet<String>&& topPrivatelyControlledDomainsWithWebsiteData) mutable {
+        WebProcessProxy::topPrivatelyControlledDomainsWithWebsiteData(dataTypesToRemove, notifyPagesWhenDataRecordsWereScanned, [this, protectedThis = WTFMove(protectedThis)] (HashSet<String>&& topPrivatelyControlledDomainsWithWebsiteData) mutable {
             // But always touch the ResourceLoadStatistics store on the worker queue
             m_statisticsQueue->dispatch([protectedThis = WTFMove(protectedThis), topDomains = CrossThreadCopier<HashSet<String>>::copy(topPrivatelyControlledDomainsWithWebsiteData)] () mutable {
                 protectedThis->coreStore().handleFreshStartWithEmptyOrNoStore(WTFMove(topDomains));
@@ -330,4 +339,14 @@
     return KeyedDecoder::decoder(reinterpret_cast<const uint8_t*>(rawData->data()), rawData->size());
 }
 
+void WebResourceLoadStatisticsStore::telemetryTimerFired()
+{
+    ASSERT(RunLoop::isMain());
+    
+    m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this)] {
+        auto locker = holdLock(coreStore().statisticsLock());
+        WebResourceLoadStatisticsTelemetry::calculateAndSubmit(coreStore());
+    });
+}
+    
 } // namespace WebKit

Modified: trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.h (218840 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsStore.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -28,8 +28,10 @@
 #include "APIObject.h"
 #include "Connection.h"
 #include "ResourceLoadStatisticsClassifier.h"
+#include "WebResourceLoadStatisticsTelemetry.h"
 #include "WebsiteDataRecord.h"
 #include <WebCore/ResourceLoadStatisticsStore.h>
+#include <wtf/RunLoop.h>
 #include <wtf/Vector.h>
 #include <wtf/text/WTFString.h>
 
@@ -95,6 +97,8 @@
     void writeEncoderToDisk(WebCore::KeyedEncoder&, const String& label) const;
     std::unique_ptr<WebCore::KeyedDecoder> createDecoderFromDisk(const String& label) const;
     void platformExcludeFromBackup() const;
+    
+    void telemetryTimerFired();
 
     Ref<WebCore::ResourceLoadStatisticsStore> m_resourceLoadStatisticsStore;
 #if HAVE(CORE_PREDICTION)
@@ -105,6 +109,8 @@
     Ref<WTF::WorkQueue> m_statisticsQueue;
     String m_statisticsStoragePath;
     bool m_resourceLoadStatisticsEnabled { false };
+    RunLoop::Timer<WebResourceLoadStatisticsStore> m_telemetryOneShotTimer;
+    RunLoop::Timer<WebResourceLoadStatisticsStore> m_telemetryRepeatedTimer;
 };
 
 } // namespace WebKit

Added: trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsTelemetry.cpp (0 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsTelemetry.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsTelemetry.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebResourceLoadStatisticsTelemetry.h"
+
+#include "WebProcessPool.h"
+#include "WebProcessProxy.h"
+#include <WebCore/DiagnosticLoggingKeys.h>
+#include <WebCore/ResourceLoadStatistics.h>
+#include <WebCore/ResourceLoadStatisticsStore.h>
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RunLoop.h>
+#include <wtf/text/StringBuilder.h>
+
+using namespace WebCore;
+
+namespace WebKit {
+    
+static auto notifyPagesWhenTelemetryWasCaptured = false;
+    
+static unsigned numberOfResourcesWithUserInteraction(const Vector<PrevalentResourceTelemetry>& resources, size_t begin, size_t end)
+{
+    if (resources.isEmpty() || resources.size() < begin + 1 || resources.size() < end + 1)
+        return 0;
+    
+    unsigned result = 0;
+    for (size_t i = begin; i < end; ++i) {
+        if (resources[i].hasHadUserInteraction)
+            ++result;
+    }
+    
+    return result;
+}
+    
+static unsigned median(const Vector<unsigned>& v)
+{
+    if (v.isEmpty())
+        return 0;
+    if (v.size() == 1)
+        return v[0];
+    
+    auto size = v.size();
+    auto middle = size / 2;
+    if (size % 2)
+        return v[middle];
+    return (v[middle - 1] + v[middle]) / 2;
+}
+    
+static unsigned median(const Vector<PrevalentResourceTelemetry>& v, unsigned begin, unsigned end, const WTF::Function<unsigned(const PrevalentResourceTelemetry& telemetry)>& statisticGetter)
+{
+    if (v.isEmpty() || v.size() < begin + 1 || v.size() < end + 1)
+        return 0;
+    
+    Vector<unsigned> part;
+    part.reserveInitialCapacity(end - begin + 1);
+    for (unsigned i = begin; i <= end; ++i)
+        part.uncheckedAppend(statisticGetter(v[i]));
+    
+    return median(part);
+}
+    
+static WebPageProxy* nonEphemeralWebPageProxy()
+{
+    auto processPools = WebProcessPool::allProcessPools();
+    if (processPools.isEmpty())
+        return nullptr;
+    
+    auto processPool = processPools[0];
+    if (!processPool)
+        return nullptr;
+    
+    for (auto& webProcess : processPool->processes()) {
+        for (auto& page : webProcess->pages()) {
+            if (page->sessionID().isEphemeral())
+                continue;
+            return page;
+        }
+    }
+    return nullptr;
+}
+    
+static void submitTopList(unsigned numberOfResourcesFromTheTop, const Vector<PrevalentResourceTelemetry>& sortedPrevalentResources, const Vector<PrevalentResourceTelemetry>& sortedPrevalentResourcesWithoutUserInteraction, WebPageProxy& webPageProxy)
+{
+    WTF::Function<unsigned(const PrevalentResourceTelemetry& telemetry)> subframeUnderTopFrameOriginsGetter = [] (const PrevalentResourceTelemetry& t) {
+        return t.subframeUnderTopFrameOrigins;
+    };
+    WTF::Function<unsigned(const PrevalentResourceTelemetry& telemetry)> subresourceUnderTopFrameOriginsGetter = [] (const PrevalentResourceTelemetry& t) {
+        return t.subresourceUnderTopFrameOrigins;
+    };
+    WTF::Function<unsigned(const PrevalentResourceTelemetry& telemetry)> subresourceUniqueRedirectsToGetter = [] (const PrevalentResourceTelemetry& t) {
+        return t.subresourceUniqueRedirectsTo;
+    };
+    WTF::Function<unsigned(const PrevalentResourceTelemetry& telemetry)> numberOfTimesDataRecordsRemovedGetter = [] (const PrevalentResourceTelemetry& t) {
+        return t.numberOfTimesDataRecordsRemoved;
+    };
+    
+    unsigned topPrevalentResourcesWithUserInteraction = numberOfResourcesWithUserInteraction(sortedPrevalentResources, 0, numberOfResourcesFromTheTop - 1);
+    unsigned topSubframeUnderTopFrameOrigins = median(sortedPrevalentResourcesWithoutUserInteraction, 0, numberOfResourcesFromTheTop - 1, subframeUnderTopFrameOriginsGetter);
+    unsigned topSubresourceUnderTopFrameOrigins = median(sortedPrevalentResourcesWithoutUserInteraction, 0, numberOfResourcesFromTheTop - 1, subresourceUnderTopFrameOriginsGetter);
+    unsigned topSubresourceUniqueRedirectsTo = median(sortedPrevalentResourcesWithoutUserInteraction, 0, numberOfResourcesFromTheTop - 1, subresourceUniqueRedirectsToGetter);
+    unsigned topNumberOfTimesDataRecordsRemoved = median(sortedPrevalentResourcesWithoutUserInteraction, 0, numberOfResourcesFromTheTop - 1, numberOfTimesDataRecordsRemovedGetter);
+    
+    StringBuilder preambleBuilder;
+    preambleBuilder.appendLiteral("top");
+    preambleBuilder.appendNumber(numberOfResourcesFromTheTop);
+    String descriptionPreamble = preambleBuilder.toString();
+    
+    webPageProxy.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), descriptionPreamble + "PrevalentResourcesWithUserInteraction",
+        topPrevalentResourcesWithUserInteraction, 0, ShouldSample::No);
+    webPageProxy.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), descriptionPreamble + "SubframeUnderTopFrameOrigins",
+        topSubframeUnderTopFrameOrigins, 0, ShouldSample::No);
+    webPageProxy.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), descriptionPreamble + "SubresourceUnderTopFrameOrigins",
+        topSubresourceUnderTopFrameOrigins, 0, ShouldSample::No);
+    webPageProxy.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), descriptionPreamble + "SubresourceUniqueRedirectsTo",
+        topSubresourceUniqueRedirectsTo, 0, ShouldSample::No);
+    webPageProxy.logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), descriptionPreamble + "NumberOfTimesDataRecordsRemoved",
+        topNumberOfTimesDataRecordsRemoved, 0, ShouldSample::No);
+}
+    
+static void submitTopLists(const Vector<PrevalentResourceTelemetry>& sortedPrevalentResources, const Vector<PrevalentResourceTelemetry>& sortedPrevalentResourcesWithoutUserInteraction, WebPageProxy& webPageProxy)
+{
+    submitTopList(1, sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, webPageProxy);
+    
+    if (sortedPrevalentResourcesWithoutUserInteraction.size() < 3)
+        return;
+    submitTopList(3, sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, webPageProxy);
+    
+    if (sortedPrevalentResourcesWithoutUserInteraction.size() < 10)
+        return;
+    submitTopList(10, sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, webPageProxy);
+    
+    if (sortedPrevalentResourcesWithoutUserInteraction.size() < 50)
+        return;
+    submitTopList(50, sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, webPageProxy);
+    
+    if (sortedPrevalentResourcesWithoutUserInteraction.size() < 100)
+        return;
+    submitTopList(100, sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, webPageProxy);
+}
+    
+// This function is for testing purposes.
+void static notifyPages(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
+{
+    RunLoop::main().dispatch([totalPrevalentResources, totalPrevalentResourcesWithUserInteraction, top3SubframeUnderTopFrameOrigins] {
+        API::Dictionary::MapType messageBody;
+        messageBody.set(ASCIILiteral("TotalPrevalentResources"), API::UInt64::create(totalPrevalentResources));
+        messageBody.set(ASCIILiteral("TotalPrevalentResourcesWithUserInteraction"), API::UInt64::create(totalPrevalentResourcesWithUserInteraction));
+        messageBody.set(ASCIILiteral("Top3SubframeUnderTopFrameOrigins"), API::UInt64::create(top3SubframeUnderTopFrameOrigins));
+        WebProcessProxy::notifyPageStatisticsTelemetryFinished(API::Dictionary::create(messageBody).ptr());
+    });
+}
+    
+// This function is for testing purposes.
+void static notifyPages(const Vector<PrevalentResourceTelemetry>& sortedPrevalentResources, const Vector<PrevalentResourceTelemetry>& sortedPrevalentResourcesWithoutUserInteraction, unsigned totalNumberOfPrevalentResourcesWithUserInteraction)
+{
+    WTF::Function<unsigned(const PrevalentResourceTelemetry& telemetry)> subframeUnderTopFrameOriginsGetter = [] (const PrevalentResourceTelemetry& t) {
+        return t.subframeUnderTopFrameOrigins;
+    };
+    
+    notifyPages(sortedPrevalentResources.size(), totalNumberOfPrevalentResourcesWithUserInteraction, median(sortedPrevalentResourcesWithoutUserInteraction, 0, 2, subframeUnderTopFrameOriginsGetter));
+}
+    
+void WebResourceLoadStatisticsTelemetry::calculateAndSubmit(const ResourceLoadStatisticsStore& resourceLoadStatisticsStore)
+{
+    ASSERT(!RunLoop::isMain());
+    
+    auto sortedPrevalentResources = resourceLoadStatisticsStore.sortedPrevalentResourceTelemetry();
+    if (sortedPrevalentResources.size() < minimumPrevalentResourcesForTelemetry) {
+        notifyPages(0, 0, 0);
+        return;
+    }
+    
+    Vector<PrevalentResourceTelemetry> sortedPrevalentResourcesWithoutUserInteraction;
+    sortedPrevalentResourcesWithoutUserInteraction.reserveInitialCapacity(sortedPrevalentResources.size());
+    Vector<unsigned> prevalentResourcesDaysSinceUserInteraction;
+    
+    for (auto& prevalentResource : sortedPrevalentResources) {
+        if (prevalentResource.hasHadUserInteraction)
+            prevalentResourcesDaysSinceUserInteraction.append(prevalentResource.daysSinceUserInteraction);
+        else
+            sortedPrevalentResourcesWithoutUserInteraction.uncheckedAppend(prevalentResource);
+    }
+    
+    auto webPageProxy = nonEphemeralWebPageProxy();
+    if (!webPageProxy) {
+        notifyPages(0, 0, 0);
+        return;
+    }
+    
+    webPageProxy->logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), ASCIILiteral("totalNumberOfPrevalentResources"), sortedPrevalentResources.size(), 0, ShouldSample::No);
+    webPageProxy->logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), ASCIILiteral("totalNumberOfPrevalentResourcesWithUserInteraction"), prevalentResourcesDaysSinceUserInteraction.size(), 0, ShouldSample::No);
+    
+    if (prevalentResourcesDaysSinceUserInteraction.size() > 0)
+        webPageProxy->logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), ASCIILiteral("topPrevalentResourceWithUserInteractionDaysSinceUserInteraction"), prevalentResourcesDaysSinceUserInteraction[0], 0, ShouldSample::No);
+    if (prevalentResourcesDaysSinceUserInteraction.size() > 1)
+        webPageProxy->logDiagnosticMessageWithValue(DiagnosticLoggingKeys::resourceLoadStatisticsTelemetryKey(), ASCIILiteral("medianPrevalentResourcesWithUserInteractionDaysSinceUserInteraction"), median(prevalentResourcesDaysSinceUserInteraction), 0, ShouldSample::No);
+    
+    submitTopLists(sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, *webPageProxy);
+    
+    if (notifyPagesWhenTelemetryWasCaptured)
+        notifyPages(sortedPrevalentResources, sortedPrevalentResourcesWithoutUserInteraction, prevalentResourcesDaysSinceUserInteraction.size());
+}
+    
+void WebResourceLoadStatisticsTelemetry::setNotifyPagesWhenTelemetryWasCaptured(bool always)
+{
+    notifyPagesWhenTelemetryWasCaptured = always;
+}
+    
+}

Added: trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsTelemetry.h (0 => 218841)


--- trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsTelemetry.h	                        (rev 0)
+++ trunk/Source/WebKit2/UIProcess/WebResourceLoadStatisticsTelemetry.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class ResourceLoadStatisticsStore;
+}
+
+namespace WebKit {
+    
+namespace WebResourceLoadStatisticsTelemetry {
+    
+void calculateAndSubmit(const WebCore::ResourceLoadStatisticsStore&);
+void setNotifyPagesWhenTelemetryWasCaptured(bool);
+    
+};
+    
+}

Modified: trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj (218840 => 218841)


--- trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj	2017-06-27 21:10:24 UTC (rev 218841)
@@ -1189,6 +1189,8 @@
 		6501BD1A12F1243400E9F248 /* WKBundleInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65B86F1712F11D7B00B7DD8A /* WKBundleInspector.cpp */; };
 		659C551E130006410025C0C2 /* InjectedBundlePageResourceLoadClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6546A82913000164000CEB1C /* InjectedBundlePageResourceLoadClient.cpp */; };
 		65B86F1E12F11DE300B7DD8A /* WKBundleInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B86F1812F11D7B00B7DD8A /* WKBundleInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		6B821DDC1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B821DDA1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.h */; };
+		6B821DDD1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6B821DDB1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.cpp */; };
 		6BBBAD381EC3E57800AD0A2A /* WebResourceLoadStatisticsManagerCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 6BBBAD371EC3E56300AD0A2A /* WebResourceLoadStatisticsManagerCocoa.mm */; };
 		6BE9699C1E43B3FF008B7483 /* WKResourceLoadStatisticsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BE9699B1E43B3FF008B7483 /* WKResourceLoadStatisticsManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6BE9699E1E43B41D008B7483 /* WKResourceLoadStatisticsManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BE9699D1E43B41D008B7483 /* WKResourceLoadStatisticsManager.cpp */; };
@@ -3478,6 +3480,8 @@
 		6546A82A13000164000CEB1C /* InjectedBundlePageResourceLoadClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundlePageResourceLoadClient.h; sourceTree = "<group>"; };
 		65B86F1712F11D7B00B7DD8A /* WKBundleInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKBundleInspector.cpp; sourceTree = "<group>"; };
 		65B86F1812F11D7B00B7DD8A /* WKBundleInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBundleInspector.h; sourceTree = "<group>"; };
+		6B821DDA1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebResourceLoadStatisticsTelemetry.h; sourceTree = "<group>"; };
+		6B821DDB1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebResourceLoadStatisticsTelemetry.cpp; sourceTree = "<group>"; };
 		6BBBAD371EC3E56300AD0A2A /* WebResourceLoadStatisticsManagerCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebResourceLoadStatisticsManagerCocoa.mm; sourceTree = "<group>"; };
 		6BE9699B1E43B3FF008B7483 /* WKResourceLoadStatisticsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKResourceLoadStatisticsManager.h; sourceTree = "<group>"; };
 		6BE9699D1E43B41D008B7483 /* WKResourceLoadStatisticsManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKResourceLoadStatisticsManager.cpp; sourceTree = "<group>"; };
@@ -6860,6 +6864,8 @@
 				7A9CD8C01C77984900D9F6C7 /* WebResourceLoadStatisticsStore.cpp */,
 				7A9CD8C11C77984900D9F6C7 /* WebResourceLoadStatisticsStore.h */,
 				7A9CD8C21C779AD600D9F6C7 /* WebResourceLoadStatisticsStore.messages.in */,
+				6B821DDA1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.h */,
+				6B821DDB1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.cpp */,
 				51D124241E6D3CC3002B2820 /* WebURLSchemeHandler.cpp */,
 				51D124251E6D3CC3002B2820 /* WebURLSchemeHandler.h */,
 				51E8B68D1E712873001B7132 /* WebURLSchemeTask.cpp */,
@@ -8246,6 +8252,7 @@
 				2DABA7761A82B42100EF0F1A /* APIHistoryClient.h in Headers */,
 				93A88B461BC8829300ABA5C2 /* APIHitTestResult.h in Headers */,
 				377512311DF0DEE2008A351C /* APIInjectedBundleEditorClient.h in Headers */,
+				6B821DDC1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.h in Headers */,
 				3769079E18F340A2001DFF04 /* APIInjectedBundleFormClient.h in Headers */,
 				3769079A18F31CB2001DFF04 /* APIInjectedBundlePageUIClient.h in Headers */,
 				7CE4D2071A46776100C7F152 /* APILegacyContextHistoryClient.h in Headers */,
@@ -9877,6 +9884,7 @@
 				515E772B184008B90007203F /* DatabaseProcessCreationParameters.cpp in Sources */,
 				E115C714190F89E400ECC516 /* DatabaseProcessIOS.mm in Sources */,
 				51E35202180F5D1E00E53BE9 /* DatabaseProcessMac.mm in Sources */,
+				6B821DDD1EEF05DD00D7AF4A /* WebResourceLoadStatisticsTelemetry.cpp in Sources */,
 				512A9760180E031D0039A149 /* DatabaseProcessMessageReceiver.cpp in Sources */,
 				517DD5BE180DA7D30081660B /* DatabaseProcessProxy.cpp in Sources */,
 				512A9769180E09B80039A149 /* DatabaseProcessProxyMessageReceiver.cpp in Sources */,

Modified: trunk/Tools/ChangeLog (218840 => 218841)


--- trunk/Tools/ChangeLog	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/ChangeLog	2017-06-27 21:10:24 UTC (rev 218841)
@@ -1,3 +1,33 @@
+2017-06-27  John Wilander  <[email protected]>
+
+        Resource Load Statistics: Add telemetry
+        https://bugs.webkit.org/show_bug.cgi?id=173499
+        <rdar://problem/32826094>
+
+        Reviewed by Brent Fulgham.
+
+        Adds three new testRunner functions:
+        - installStatisticsDidRunTelemetryCallback()
+        - statisticsFireTelemetryHandler()
+        - setStatisticsNotifyPagesWhenTelemetryWasCaptured()
+
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+        (WTR::InjectedBundle::didReceiveMessageToPage):
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::installStatisticsDidRunTelemetryCallback):
+        (WTR::TestRunner::statisticsDidRunTelemetryCallback):
+        (WTR::TestRunner::statisticsFireTelemetryHandler):
+        (WTR::TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::resetStateToConsistentValues):
+        (WTR::TestController::statisticsFireTelemetryHandler):
+        (WTR::TestController::setStatisticsNotifyPagesWhenTelemetryWasCaptured):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+
 2017-06-27  Ting-Wei Lan  <[email protected]>
 
         Add missing includes to fix compilation error on FreeBSD

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl	2017-06-27 21:10:24 UTC (rev 218841)
@@ -253,6 +253,7 @@
     // Resource Load Statistics
     void installStatisticsDidModifyDataRecordsCallback(object callback);
     void installStatisticsDidScanDataRecordsCallback(object callback);
+    void installStatisticsDidRunTelemetryCallback(object callback);
     void setStatisticsPrevalentResource(DOMString hostName, boolean value);
     boolean isStatisticsPrevalentResource(DOMString hostName);
     void setStatisticsHasHadUserInteraction(DOMString hostName, boolean value);
@@ -267,8 +268,10 @@
     void statisticsFireDataModificationHandler();
     void statisticsFireShouldPartitionCookiesHandler();
     void statisticsFireShouldPartitionCookiesHandlerForOneDomain(DOMString hostName, boolean value);
+    void statisticsFireTelemetryHandler();
     void setStatisticsNotifyPagesWhenDataRecordsWereScanned(boolean value);
     void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(boolean value);
+    void setStatisticsNotifyPagesWhenTelemetryWasCaptured(boolean value);
     void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds);
     void setStatisticsGrandfatheringTime(double seconds);
     void statisticsClearInMemoryAndPersistentStore();

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -281,6 +281,17 @@
         return;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "ResourceLoadStatisticsTelemetryFinished")) {
+        WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
+        
+        unsigned totalPrevalentResources = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, WKStringCreateWithUTF8CString("TotalPrevalentResources"))));
+        unsigned totalPrevalentResourcesWithUserInteraction = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, WKStringCreateWithUTF8CString("TotalPrevalentResourcesWithUserInteraction"))));
+        unsigned top3SubframeUnderTopFrameOrigins = (unsigned)WKUInt64GetValue(static_cast<WKUInt64Ref>(WKDictionaryGetItemForKey(messageBodyDictionary, WKStringCreateWithUTF8CString("Top3SubframeUnderTopFrameOrigins"))));
+        
+        m_testRunner->statisticsDidRunTelemetryCallback(totalPrevalentResources, totalPrevalentResourcesWithUserInteraction, top3SubframeUnderTopFrameOrigins);
+        return;
+    }
+    
     WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error"));
     WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown"));
     WKBundlePagePostMessage(page, errorMessageName.get(), errorMessageBody.get());

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -636,6 +636,7 @@
     DidRemoveSwipeSnapshotCallbackID,
     StatisticsDidModifyDataRecordsCallbackID,
     StatisticsDidScanDataRecordsCallbackID,
+    StatisticsDidRunTelemetryCallbackID,
     DidRemoveAllSessionCredentialsCallbackID,
     FirstUIScriptCallbackID = 100
 };
@@ -1389,6 +1390,30 @@
     callTestRunnerCallback(StatisticsDidScanDataRecordsCallbackID);
 }
 
+void TestRunner::installStatisticsDidRunTelemetryCallback(JSValueRef callback)
+{
+    cacheTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, callback);
+}
+    
+void TestRunner::statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins)
+{
+    WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
+    JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+    
+    StringBuilder stringBuilder;
+    stringBuilder.appendLiteral("{ \"totalPrevalentResources\" : ");
+    stringBuilder.appendNumber(totalPrevalentResources);
+    stringBuilder.appendLiteral(", \"totalPrevalentResourcesWithUserInteraction\" : ");
+    stringBuilder.appendNumber(totalPrevalentResourcesWithUserInteraction);
+    stringBuilder.appendLiteral(", \"top3SubframeUnderTopFrameOrigins\" : ");
+    stringBuilder.appendNumber(top3SubframeUnderTopFrameOrigins);
+    stringBuilder.appendLiteral(" }");
+    
+    JSValueRef result = JSValueMakeFromJSONString(context, JSStringCreateWithUTF8CString(stringBuilder.toString().utf8().data()));
+    
+    callTestRunnerCallback(StatisticsDidRunTelemetryCallbackID, 1, &result);
+}
+    
 void TestRunner::statisticsFireDataModificationHandler()
 {
     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireDataModificationHandler"));
@@ -1426,6 +1451,12 @@
     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
 }
 
+void TestRunner::statisticsFireTelemetryHandler()
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsFireTelemetryHandler"));
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), 0, nullptr);
+}
+    
 void TestRunner::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenDataRecordsWereScanned"));
@@ -1440,6 +1471,14 @@
     WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
     WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
 }
+    
+void TestRunner::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
+{
+    WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("StatisticsNotifyPagesWhenTelemetryWasCaptured"));
+    WKRetainPtr<WKBooleanRef> messageBody(AdoptWK, WKBooleanCreate(value));
+    WKBundlePostSynchronousMessage(InjectedBundle::singleton().bundle(), messageName.get(), messageBody.get(), nullptr);
+    WKResourceLoadStatisticsManagerSetNotifyPagesWhenTelemetryWasCaptured(value);
+}
 
 void TestRunner::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
 {

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -349,11 +349,14 @@
     // Resource Load Statistics
     void installStatisticsDidModifyDataRecordsCallback(JSValueRef callback);
     void installStatisticsDidScanDataRecordsCallback(JSValueRef callback);
+    void installStatisticsDidRunTelemetryCallback(JSValueRef callback);
     void statisticsDidModifyDataRecordsCallback();
     void statisticsDidScanDataRecordsCallback();
+    void statisticsDidRunTelemetryCallback(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins);
     void statisticsFireDataModificationHandler();
     void statisticsFireShouldPartitionCookiesHandler();
     void statisticsFireShouldPartitionCookiesHandlerForOneDomain(JSStringRef hostName, bool value);
+    void statisticsFireTelemetryHandler();
     void setStatisticsPrevalentResource(JSStringRef hostName, bool value);
     bool isStatisticsPrevalentResource(JSStringRef hostName);
     void setStatisticsHasHadUserInteraction(JSStringRef hostName, bool value);
@@ -367,6 +370,7 @@
     void setStatisticsTimeToLiveCookiePartitionFree(double seconds);
     void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool);
     void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
+    void setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value);
     void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double);
     void setStatisticsGrandfatheringTime(double seconds);
     void statisticsClearInMemoryAndPersistentStore();

Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/TestController.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -836,6 +836,8 @@
     setIgnoresViewportScaleLimits(options.ignoresViewportScaleLimits);
 
     m_openPanelFileURLs = nullptr;
+    
+    statisticsResetToConsistentState();
 
     WKPageLoadURL(m_mainWebView->page(), blankURL());
     runUntil(m_doneResetting, m_currentInvocation->shortTimeout());
@@ -2274,6 +2276,11 @@
     WKResourceLoadStatisticsManagerFireShouldPartitionCookiesHandlerForOneDomain(hostName, value);
 }
 
+void TestController::statisticsFireTelemetryHandler()
+{
+    WKResourceLoadStatisticsManagerFireTelemetryHandler();
+}
+    
 void TestController::setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool value)
 {
     WKResourceLoadStatisticsManagerSetNotifyPagesWhenDataRecordsWereScanned(value);
@@ -2284,6 +2291,11 @@
     WKResourceLoadStatisticsManagerSetShouldClassifyResourcesBeforeDataRecordsRemoval(value);
 }
 
+void TestController::setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value)
+{
+    WKResourceLoadStatisticsManagerSetNotifyPagesWhenTelemetryWasCaptured(value);
+}
+    
 void TestController::setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double seconds)
 {
     WKResourceLoadStatisticsManagerSetMinimumTimeBetweeenDataRecordsRemoval(seconds);

Modified: trunk/Tools/WebKitTestRunner/TestController.h (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/TestController.h	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/TestController.h	2017-06-27 21:10:24 UTC (rev 218841)
@@ -164,8 +164,10 @@
     void statisticsFireDataModificationHandler();
     void statisticsFireShouldPartitionCookiesHandler();
     void statisticsFireShouldPartitionCookiesHandlerForOneDomain(WKStringRef hostName, bool value);
+    void statisticsFireTelemetryHandler();
     void setStatisticsNotifyPagesWhenDataRecordsWereScanned(bool);
     void setStatisticsShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
+    void setStatisticsNotifyPagesWhenTelemetryWasCaptured(bool value);
     void setStatisticsMinimumTimeBetweeenDataRecordsRemoval(double);
     void setStatisticsGrandfatheringTime(double seconds);
     void statisticsClearInMemoryAndPersistentStore();

Modified: trunk/Tools/WebKitTestRunner/TestInvocation.cpp (218840 => 218841)


--- trunk/Tools/WebKitTestRunner/TestInvocation.cpp	2017-06-27 21:06:04 UTC (rev 218840)
+++ trunk/Tools/WebKitTestRunner/TestInvocation.cpp	2017-06-27 21:10:24 UTC (rev 218841)
@@ -1061,6 +1061,11 @@
         return nullptr;
     }
     
+    if (WKStringIsEqualToUTF8CString(messageName, "StatisticsFireTelemetryHandler")) {
+        TestController::singleton().statisticsFireTelemetryHandler();
+        return nullptr;
+    }
+    
     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsNotifyPagesWhenDataRecordsWereScanned")) {
         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
@@ -1068,6 +1073,13 @@
         return nullptr;
     }
 
+    if (WKStringIsEqualToUTF8CString(messageName, "StatisticsNotifyPagesWhenTelemetryWasCaptured")) {
+        ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
+        WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
+        TestController::singleton().setStatisticsNotifyPagesWhenTelemetryWasCaptured(WKBooleanGetValue(value));
+        return nullptr;
+    }
+    
     if (WKStringIsEqualToUTF8CString(messageName, "StatisticsShouldClassifyResourcesBeforeDataRecordsRemoval")) {
         ASSERT(WKGetTypeID(messageBody) == WKBooleanGetTypeID());
         WKBooleanRef value = static_cast<WKBooleanRef>(messageBody);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to