Bug 1363700 - Add RCWN stats to about:networking r=michal draft
authorValentin Gosu <valentin.gosu@gmail.com>
Wed, 10 May 2017 19:23:54 +0200
changeset 575569 1a3762b5313f99e5718a0a50f6cc395d2a66b69c
parent 574065 1fda52a1f3b81cf1a821155998dca637bb64e3d9
child 627962 46bd8b6a0f1cac551908d216127091751a4545e1
push id58103
push uservalentin.gosu@gmail.com
push dateWed, 10 May 2017 17:34:15 +0000
reviewersmichal
bugs1363700
milestone55.0a1
Bug 1363700 - Add RCWN stats to about:networking r=michal MozReview-Commit-ID: GVt1omCfL6t
dom/webidl/NetDashboard.webidl
netwerk/base/Dashboard.cpp
netwerk/base/Dashboard.h
netwerk/base/nsIDashboard.idl
netwerk/base/nsIOService.cpp
netwerk/base/nsIOService.h
netwerk/protocol/http/nsHttpChannel.cpp
toolkit/content/aboutNetworking.js
toolkit/content/aboutNetworking.xhtml
toolkit/locales/en-US/chrome/global/aboutNetworking.dtd
--- a/dom/webidl/NetDashboard.webidl
+++ b/dom/webidl/NetDashboard.webidl
@@ -70,8 +70,14 @@ dictionary DNSLookupDict {
   sequence<DOMString> address;
   DOMString error = "";
   boolean answer = false;
 };
 
 dictionary ConnStatusDict {
   DOMString status = "";
 };
+
+dictionary RcwnStatus {
+  unsigned long totalNetworkRequests = 0;
+  unsigned long rcwnCacheWonCount = 0;
+  unsigned long rcwnNetWonCount = 0;
+};
--- a/netwerk/base/Dashboard.cpp
+++ b/netwerk/base/Dashboard.cpp
@@ -14,16 +14,17 @@
 #include "nsIInputStream.h"
 #include "nsISocketTransport.h"
 #include "nsIThread.h"
 #include "nsProxyRelease.h"
 #include "nsSocketTransportService2.h"
 #include "nsThreadUtils.h"
 #include "nsURLHelper.h"
 #include "mozilla/Logging.h"
+#include "nsIOService.h"
 
 using mozilla::AutoSafeJSContext;
 using mozilla::dom::Sequence;
 using mozilla::dom::ToJSValue;
 
 namespace mozilla {
 namespace net {
 
@@ -162,16 +163,38 @@ public:
     const char *mProtocol;
     uint32_t mTimeout;
 
     nsString mStatus;
 };
 
 NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback)
 
+
+class RcwnData
+    : public nsISupports
+{
+    virtual ~RcwnData()
+    {
+    }
+
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+
+    RcwnData()
+    {
+        mThread = nullptr;
+    }
+
+    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
+    nsIThread *mThread;
+};
+
+NS_IMPL_ISUPPORTS0(RcwnData)
+
 NS_IMETHODIMP
 ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
                                   int64_t aProgress, int64_t aProgressMax)
 {
     if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
         StopTimer();
     }
 
@@ -750,16 +773,49 @@ Dashboard::RequestDNSLookup(const nsACSt
     helper->mThread = NS_GetCurrentThread();
     OriginAttributes attrs;
     rv = mDnsService->AsyncResolveNative(aHost, 0, helper.get(),
                                          NS_GetCurrentThread(), attrs,
                                          getter_AddRefs(helper->mCancel));
     return rv;
 }
 
+NS_IMETHODIMP
+Dashboard::RequestRcwnStats(NetDashboardCallback *aCallback)
+{
+    RefPtr<RcwnData> rcwnData = new RcwnData();
+    rcwnData->mThread = NS_GetCurrentThread();
+    rcwnData->mCallback =
+        new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
+
+    return rcwnData->mThread->Dispatch(
+        NewRunnableMethod<RefPtr<RcwnData>>(this, &Dashboard::GetRcwnData, rcwnData),
+        NS_DISPATCH_NORMAL);
+}
+
+nsresult
+Dashboard::GetRcwnData(RcwnData *aData)
+{
+    AutoSafeJSContext cx;
+    mozilla::dom::RcwnStatus dict;
+
+    dict.mTotalNetworkRequests = gIOService->GetTotalRequestNumber();
+    dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber();
+    dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber();
+
+    JS::RootedValue val(cx);
+    if (!ToJSValue(cx, dict, &val)) {
+        return NS_ERROR_FAILURE;
+    }
+
+    aData->mCallback->OnDashboardDataAvailable(val);
+
+    return NS_OK;
+}
+
 void
 HttpConnInfo::SetHTTP1ProtocolVersion(uint8_t pv)
 {
     switch (pv) {
     case NS_HTTP_VERSION_0_9:
         protocolVersion.AssignLiteral(u"http/0.9");
         break;
     case NS_HTTP_VERSION_1_0:
--- a/netwerk/base/Dashboard.h
+++ b/netwerk/base/Dashboard.h
@@ -19,16 +19,17 @@ class nsIDNSService;
 namespace mozilla {
 namespace net {
 
 class SocketData;
 class HttpData;
 class DnsData;
 class WebSocketRequest;
 class ConnectionData;
+class RcwnData;
 
 class Dashboard final
     : public nsIDashboard
     , public nsIDashboardEventNotifier
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIDASHBOARD
@@ -90,16 +91,17 @@ private:
     nsresult GetDnsInfoDispatch(DnsData *);
     nsresult TestNewConnection(ConnectionData *);
 
     /* Helper methods that pass the JSON to the callback function. */
     nsresult GetSockets(SocketData *);
     nsresult GetHttpConnections(HttpData *);
     nsresult GetDNSCacheEntries(DnsData *);
     nsresult GetWebSocketConnections(WebSocketRequest *);
+    nsresult GetRcwnData(RcwnData *);
 
     nsCOMPtr<nsIDNSService> mDnsService;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // nsDashboard_h__
--- a/netwerk/base/nsIDashboard.idl
+++ b/netwerk/base/nsIDashboard.idl
@@ -45,10 +45,15 @@ interface nsIDashboard : nsISupports
 
     /* When true, the service will log websocket events */
     attribute boolean enableLogging;
 
     /* DNS resolver for host name
      * aHost: host name */
     void requestDNSLookup(in ACString aHost, in NetDashboardCallback cb);
 
+    /**
+     * Asyncly returns stats regarding the "Race Cache With Network" feature.
+     */
+    void requestRcwnStats(in NetDashboardCallback cb);
+
     AUTF8String getLogPath();
 };
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -183,16 +183,19 @@ nsIOService::nsIOService()
     , mOfflineMirrorsConnectivity(true)
     , mSettingOffline(false)
     , mSetOfflineValue(false)
     , mShutdown(false)
     , mHttpHandlerAlreadyShutingDown(false)
     , mNetworkLinkServiceInitialized(false)
     , mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY)
     , mNetworkNotifyChanged(true)
+    , mTotalRequests(0)
+    , mCacheWon(0)
+    , mNetWon(0)
     , mLastOfflineStateChange(PR_IntervalNow())
     , mLastConnectivityChange(PR_IntervalNow())
     , mLastNetworkLinkChange(PR_IntervalNow())
     , mNetTearingDownStarted(0)
 {
 }
 
 nsresult
--- a/netwerk/base/nsIOService.h
+++ b/netwerk/base/nsIOService.h
@@ -92,16 +92,25 @@ public:
     // As soon as nsIOService gets notification that it is shutdown it is going to
     // reset mHttpHandlerAlreadyShutingDown.
     void SetHttpHandlerAlreadyShutingDown();
 
     bool IsLinkUp();
 
     static bool IsInheritSecurityContextForDataURIEnabled();
 
+    // Used to count the total number of HTTP requests made
+    void IncrementRequestNumber() { mTotalRequests++; }
+    uint32_t GetTotalRequestNumber() { return mTotalRequests; }
+    // Used to keep "race cache with network" stats
+    void IncrementCacheWonRequestNumber() { mCacheWon++; }
+    uint32_t GetCacheWonRequestNumber() { return mCacheWon; }
+    void IncrementNetWonRequestNumber() { mNetWon++; }
+    uint32_t GetNetWonRequestNumber() { return mNetWon; }
+
     // Used to trigger a recheck of the captive portal status
     nsresult RecheckCaptivePortal();
 private:
     // These shouldn't be called directly:
     // - construct using GetInstance
     // - destroy using Release
     nsIOService();
     ~nsIOService();
@@ -173,16 +182,20 @@ private:
     nsCategoryCache<nsIChannelEventSink> mChannelEventSinks;
 
     nsTArray<int32_t>                    mRestrictedPortList;
 
     bool                                 mNetworkNotifyChanged;
 
     static bool                          sDataURIInheritSecurityContext;
 
+    uint32_t mTotalRequests;
+    uint32_t mCacheWon;
+    uint32_t mNetWon;
+
     // These timestamps are needed for collecting telemetry on PR_Connect,
     // PR_ConnectContinue and PR_Close blocking time.  If we spend very long
     // time in any of these functions we want to know if and what network
     // change has happened shortly before.
     mozilla::Atomic<PRIntervalTime> mLastOfflineStateChange;
     mozilla::Atomic<PRIntervalTime> mLastConnectivityChange;
     mozilla::Atomic<PRIntervalTime> mLastNetworkLinkChange;
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -7239,16 +7239,23 @@ nsHttpChannel::OnStopRequest(nsIRequest 
             nsresult rv = FinalizeCacheEntry();
             if (NS_FAILED(rv)) {
                 LOG(("FinalizeCacheEntry failed (%08x)",
                      static_cast<uint32_t>(rv)));
             }
         }
     }
 
+    gIOService->IncrementRequestNumber();
+    if (rcwnStatus == kRaceUsedCache) {
+        gIOService->IncrementCacheWonRequestNumber();
+    } else if (rcwnStatus == kRaceUsedNetwork) {
+        gIOService->IncrementNetWonRequestNumber();
+    }
+
     // Register entry to the Performance resource timing
     mozilla::dom::Performance* documentPerformance = GetPerformance();
     if (documentPerformance) {
         documentPerformance->AddEntry(this, this);
     }
 
     if (mListener) {
         LOG(("  calling OnStopRequest\n"));
--- a/toolkit/content/aboutNetworking.js
+++ b/toolkit/content/aboutNetworking.js
@@ -16,23 +16,25 @@ const gDashboard = Cc["@mozilla.org/netw
                      .getService(Ci.nsIDashboard);
 const gDirServ = Cc["@mozilla.org/file/directory_service;1"]
                    .getService(Ci.nsIDirectoryServiceProvider);
 
 const gRequestNetworkingData = {
   "http": gDashboard.requestHttpConnections,
   "sockets": gDashboard.requestSockets,
   "dns": gDashboard.requestDNSInfo,
-  "websockets": gDashboard.requestWebsocketConnections
+  "websockets": gDashboard.requestWebsocketConnections,
+  "rcwn": gDashboard.requestRcwnStats,
 };
 const gDashboardCallbacks = {
   "http": displayHttp,
   "sockets": displaySockets,
   "dns": displayDns,
-  "websockets": displayWebsockets
+  "websockets": displayWebsockets,
+  "rcwn": displayRcwnStats,
 };
 
 const REFRESH_INTERVAL_MS = 3000;
 
 function col(element) {
   let col = document.createElement("td");
   let content = document.createTextNode(element);
   col.appendChild(content);
@@ -119,16 +121,28 @@ function displayWebsockets(data) {
     row.appendChild(col(data.websockets[i].sentsize));
     row.appendChild(col(data.websockets[i].receivedsize));
     new_cont.appendChild(row);
   }
 
   parent.replaceChild(new_cont, cont);
 }
 
+function displayRcwnStats(data) {
+  let status = Services.prefs.getBoolPref("network.http.rcwn.enabled");
+  let cacheWon = data.rcwnCacheWonCount;
+  let netWon = data.rcwnNetWonCount;
+  let total = data.totalNetworkRequests;
+
+  document.getElementById("rcwn_status").innerText = status;
+  document.getElementById("total_req_count").innerText = total;
+  document.getElementById("rcwn_cache_won_count").innerText = cacheWon;
+  document.getElementById("rcwn_cache_net_count").innerText = netWon;
+}
+
 function requestAllNetworkingData() {
   for (let id in gRequestNetworkingData)
     requestNetworkingDataForTab(id);
 }
 
 function requestNetworkingDataForTab(id) {
   gRequestNetworkingData[id](gDashboardCallbacks[id]);
 }
--- a/toolkit/content/aboutNetworking.xhtml
+++ b/toolkit/content/aboutNetworking.xhtml
@@ -45,16 +45,19 @@
             </div>
             <hr></hr>
             <div class="category" value="dnslookuptool">
                 <span class="category-name">&aboutNetworking.dnsLookup;</span>
             </div>
             <div class="category" value="logging">
                 <span class="category-name">&aboutNetworking.logging;</span>
             </div>
+             <div class="category" value="rcwn">
+                <span class="category-name">&aboutNetworking.rcwn;</span>
+            </div>
         </div>
         <div class="main-content">
             <div class="header">
                 <div id="sectionTitle" class="header-name">
                     &aboutNetworking.HTTP;
                 </div>
                 <div id="refreshDiv" class="toggle-container-with-text">
                     <button id="refreshButton">&aboutNetworking.refresh;</button>
@@ -134,16 +137,37 @@
                       <tr>
                           <th>&aboutNetworking.dnsLookupTableColumn;</th>
                       </tr>
                   </thead>
                   <tbody id="dnslookuptool_content" />
               </table>
           </div>
 
+          <div id="rcwn" class="tab" hidden="true">
+              <table>
+                  <thead>
+                      <tr>
+                          <th>&aboutNetworking.rcwnStatus;</th>
+                          <th>&aboutNetworking.totalNetworkRequests;</th>
+                          <th>&aboutNetworking.rcwnCacheWonCount;</th>
+                          <th>&aboutNetworking.rcwnNetWonCount;</th>
+                      </tr>
+                  </thead>
+                  <tbody id="rcwn_content">
+                    <tr>
+                      <td id="rcwn_status"> </td>
+                      <td id="total_req_count"> </td>
+                      <td id="rcwn_cache_won_count"> </td>
+                      <td id="rcwn_cache_net_count"> </td>
+                    </tr>
+                  </tbody>
+              </table>
+          </div>
+
           <div id="logging" class="tab" hidden="true">
             <div>
               &aboutNetworking.logTutorial;
             </div>
             <br/>
             <div>
               <button id="start-logging-button"> &aboutNetworking.startLogging; </button>
               <button id="stop-logging-button"> &aboutNetworking.stopLogging; </button>
--- a/toolkit/locales/en-US/chrome/global/aboutNetworking.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutNetworking.dtd
@@ -36,8 +36,13 @@
 <!ENTITY aboutNetworking.setLogFile            "Set Log File">
 <!ENTITY aboutNetworking.setLogModules         "Set Log Modules">
 <!ENTITY aboutNetworking.startLogging          "Start Logging">
 <!ENTITY aboutNetworking.stopLogging           "Stop Logging">
 <!ENTITY aboutNetworking.dnsLookup             "DNS Lookup">
 <!ENTITY aboutNetworking.dnsLookupButton       "Resolve">
 <!ENTITY aboutNetworking.dnsDomain             "Domain">
 <!ENTITY aboutNetworking.dnsLookupTableColumn  "IPs">
+<!ENTITY aboutNetworking.rcwn                  "RCWN Stats">
+<!ENTITY aboutNetworking.rcwnStatus            "RCWN Status">
+<!ENTITY aboutNetworking.rcwnCacheWonCount     "Cache won count">
+<!ENTITY aboutNetworking.rcwnNetWonCount       "Net won count">
+<!ENTITY aboutNetworking.totalNetworkRequests  "Total network request count">