Bug 1037184 - Extended the speculative connection overrider to track predictor preconnects. r=hurley
authorJeremy Poulin <jpoulin@cs.uml.edu>
Mon, 14 Jul 2014 11:30:18 -0700
changeset 216283 aca7944ee3df0768cb9bc82e77c31e37c2487193
parent 216282 31c23d75e53962d3b8f2ace38e65d72daf090498
child 216284 71bc8f4a5bb7364c91ffbee095e7a21d159e2623
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershurley
bugs1037184
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1037184 - Extended the speculative connection overrider to track predictor preconnects. r=hurley
netwerk/base/public/nsISpeculativeConnect.idl
netwerk/base/src/Predictor.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
toolkit/components/telemetry/Histograms.json
--- a/netwerk/base/public/nsISpeculativeConnect.idl
+++ b/netwerk/base/public/nsISpeculativeConnect.idl
@@ -30,17 +30,17 @@ interface nsISpeculativeConnect : nsISup
 
 };
 
 /**
  * This is used to override the default values for various values (documented
  * inline) to determine whether or not to actually make a speculative
  * connection.
  */
-[builtinclass, uuid(2b6d6fb6-ab28-4f4c-af84-bfdbb7866d72)]
+[builtinclass, uuid(a9cdd875-2ef8-4d53-95d6-e4e18f65e0db)]
 interface nsISpeculativeConnectionOverrider : nsISupports
 {
     /**
      * Used to determine the maximum number of unused speculative connections
      * we will have open for a host at any one time
      */
     [infallible] readonly attribute unsigned long parallelSpeculativeConnectLimit;
 
@@ -52,9 +52,15 @@ interface nsISpeculativeConnectionOverri
     [infallible] readonly attribute boolean ignorePossibleSpdyConnections;
 
     /**
      * Used to determine if we will ignore the existence of any currently idle
      * connections when we decide whether or not to make a speculative
      * connection.
      */
     [infallible] readonly attribute boolean ignoreIdle;
+
+    /*
+     * Used by the Predictor to gather telemetry data on speculative connection
+     * usage.
+     */
+    [infallible] readonly attribute boolean isFromPredictor;
 };
--- a/netwerk/base/src/Predictor.cpp
+++ b/netwerk/base/src/Predictor.cpp
@@ -383,16 +383,23 @@ Predictor::GetIgnorePossibleSpdyConnecti
 NS_IMETHODIMP
 Predictor::GetParallelSpeculativeConnectLimit(
     uint32_t *parallelSpeculativeConnectLimit)
 {
   *parallelSpeculativeConnectLimit = 6;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+Predictor::GetIsFromPredictor(bool *isFromPredictor)
+{
+  *isFromPredictor = true;
+  return NS_OK;
+}
+
 // Predictor::nsIInterfaceRequestor
 
 NS_IMETHODIMP
 Predictor::GetInterface(const nsIID &iid, void **result)
 {
   return QueryInterface(iid, result);
 }
 
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -354,16 +354,17 @@ public:
 
 public: // intentional!
     nsRefPtr<NullHttpTransaction> mTrans;
 
     bool mOverridesOK;
     uint32_t mParallelSpeculativeConnectLimit;
     bool mIgnoreIdle;
     bool mIgnorePossibleSpdyConnections;
+    bool mIsFromPredictor;
 
     // As above, added manually so we can use nsRefPtr without inheriting from
     // nsISupports
 protected:
     ThreadSafeAutoRefCnt mRefCnt;
     NS_DECL_OWNINGTHREAD
 };
 
@@ -402,16 +403,17 @@ nsHttpConnectionMgr::SpeculativeConnect(
         do_GetInterface(callbacks);
     if (overrider) {
         args->mOverridesOK = true;
         overrider->GetParallelSpeculativeConnectLimit(
             &args->mParallelSpeculativeConnectLimit);
         overrider->GetIgnoreIdle(&args->mIgnoreIdle);
         overrider->GetIgnorePossibleSpdyConnections(
             &args->mIgnorePossibleSpdyConnections);
+        overrider->GetIsFromPredictor(&args->mIsFromPredictor);
     }
 
     nsresult rv =
         PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
     if (NS_SUCCEEDED(rv))
         unused << args.forget();
     return rv;
 }
@@ -1396,16 +1398,21 @@ nsHttpConnectionMgr::MakeNewConnection(n
             // need to open a new connection here.
             LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s]\n"
                  "Found a speculative half open connection\n",
                  ent->mConnInfo->HashKey().get()));
             ent->mHalfOpens[i]->SetSpeculative(false);
             Telemetry::AutoCounter<Telemetry::HTTPCONNMGR_USED_SPECULATIVE_CONN> usedSpeculativeConn;
             ++usedSpeculativeConn;
 
+            if (ent->mHalfOpens[i]->IsFromPredictor()) {
+              Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_USED> totalPreconnectsUsed;
+              ++totalPreconnectsUsed;
+            }
+
             // return OK because we have essentially opened a new connection
             // by converting a speculative half-open to general use
             return NS_OK;
         }
     }
 
     // If this host is trying to negotiate a SPDY session right now,
     // don't create any new connections until the result of the
@@ -2056,25 +2063,32 @@ nsHttpConnectionMgr::RecvdConnect()
     mNumActiveConns--;
     ConditionallyStopTimeoutTick();
 }
 
 nsresult
 nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
                                      nsAHttpTransaction *trans,
                                      uint32_t caps,
-                                     bool speculative)
+                                     bool speculative,
+                                     bool isFromPredictor)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
     nsRefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans, caps);
     if (speculative) {
         sock->SetSpeculative(true);
         Telemetry::AutoCounter<Telemetry::HTTPCONNMGR_TOTAL_SPECULATIVE_CONN> totalSpeculativeConn;
         ++totalSpeculativeConn;
+
+        if (isFromPredictor) {
+          sock->SetIsFromPredictor(true);
+          Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_CREATED> totalPreconnectsCreated;
+          ++totalPreconnectsCreated;
+        }
     }
 
     nsresult rv = sock->SetupPrimaryStreams();
     NS_ENSURE_SUCCESS(rv, rv);
 
     ent->mHalfOpens.AppendElement(sock);
     mNumHalfOpenConns++;
     return NS_OK;
@@ -2780,29 +2794,31 @@ nsHttpConnectionMgr::OnMsgSpeculativeCon
     nsConnectionEntry *preferredEntry = GetSpdyPreferredEnt(ent);
     if (preferredEntry)
         ent = preferredEntry;
 
     uint32_t parallelSpeculativeConnectLimit =
         gHttpHandler->ParallelSpeculativeConnectLimit();
     bool ignorePossibleSpdyConnections = false;
     bool ignoreIdle = false;
+    bool isFromPredictor = false;
 
     if (args->mOverridesOK) {
         parallelSpeculativeConnectLimit = args->mParallelSpeculativeConnectLimit;
         ignorePossibleSpdyConnections = args->mIgnorePossibleSpdyConnections;
         ignoreIdle = args->mIgnoreIdle;
+        isFromPredictor = args->mIsFromPredictor;
     }
 
     if (mNumHalfOpenConns < parallelSpeculativeConnectLimit &&
         ((ignoreIdle && (ent->mIdleConns.Length() < parallelSpeculativeConnectLimit)) ||
          !ent->mIdleConns.Length()) &&
         !RestrictConnections(ent, ignorePossibleSpdyConnections) &&
         !AtActiveConnectionLimit(ent, args->mTrans->Caps())) {
-        CreateTransport(ent, args->mTrans, args->mTrans->Caps(), true);
+        CreateTransport(ent, args->mTrans, args->mTrans->Caps(), true, isFromPredictor);
     }
     else {
         LOG(("  Transport not created due to existing connection count\n"));
     }
 }
 
 bool
 nsHttpConnectionMgr::nsConnectionHandle::IsPersistent()
@@ -2841,16 +2857,17 @@ NS_IMPL_ISUPPORTS(nsHttpConnectionMgr::n
 nsHttpConnectionMgr::
 nsHalfOpenSocket::nsHalfOpenSocket(nsConnectionEntry *ent,
                                    nsAHttpTransaction *trans,
                                    uint32_t caps)
     : mEnt(ent)
     , mTransaction(trans)
     , mCaps(caps)
     , mSpeculative(false)
+    , mIsFromPredictor(false)
     , mHasConnected(false)
     , mPrimaryConnectedOK(false)
     , mBackupConnectedOK(false)
 {
     MOZ_ASSERT(ent && trans, "constructor with null arguments");
     LOG(("Creating nsHalfOpenSocket [this=%p trans=%p ent=%s key=%s]\n",
          this, trans, ent->mConnInfo->Host(), ent->mConnInfo->HashKey().get()));
 }
@@ -3711,16 +3728,21 @@ nsConnectionEntry::UnconnectedHalfOpens(
 
 void
 nsHttpConnectionMgr::
 nsConnectionEntry::RemoveHalfOpen(nsHalfOpenSocket *halfOpen)
 {
     if (halfOpen->IsSpeculative()) {
       Telemetry::AutoCounter<Telemetry::HTTPCONNMGR_UNUSED_SPECULATIVE_CONN> unusedSpeculativeConn;
       ++unusedSpeculativeConn;
+
+      if (halfOpen->IsFromPredictor()) {
+        Telemetry::AutoCounter<Telemetry::PREDICTOR_TOTAL_PRECONNECTS_UNUSED> totalPreconnectsUnused;
+        ++totalPreconnectsUnused;
+      }
     }
 
     // A failure to create the transport object at all
     // will result in it not being present in the halfopen table
     // so ignore failures of RemoveElement()
     mHalfOpens.RemoveElement(halfOpen);
     gHttpHandler->ConnMgr()->mNumHalfOpenConns--;
 
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -446,16 +446,19 @@ private:
         nsISocketTransport *SocketTransport() { return mSocketTransport; }
         nsISocketTransport *BackupTransport() { return mBackupTransport; }
 
         nsAHttpTransaction *Transaction() { return mTransaction; }
 
         bool IsSpeculative() { return mSpeculative; }
         void SetSpeculative(bool val) { mSpeculative = val; }
 
+        bool IsFromPredictor() { return mIsFromPredictor; }
+        void SetIsFromPredictor(bool val) { mIsFromPredictor = val; }
+
         bool HasConnected() { return mHasConnected; }
 
         void PrintDiagnostics(nsCString &log);
     private:
         nsConnectionEntry              *mEnt;
         nsRefPtr<nsAHttpTransaction>   mTransaction;
         nsCOMPtr<nsISocketTransport>   mSocketTransport;
         nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
@@ -466,16 +469,21 @@ private:
         // SpeculativeConnect(). It is cleared when a transaction would normally
         // start a new connection from scratch but instead finds this one in
         // the half open list and claims it for its own use. (which due to
         // the vagaries of scheduling from the pending queue might not actually
         // match up - but it prevents a speculative connection from opening
         // more connections that are needed.)
         bool                           mSpeculative;
 
+        // mIsFromPredictor is set if the socket originated from the network
+        // Predictor. It is used to gather telemetry data on used speculative
+        // connections from the predictor.
+        bool                           mIsFromPredictor;
+
         TimeStamp             mPrimarySynStarted;
         TimeStamp             mBackupSynStarted;
 
         // for syn retry
         nsCOMPtr<nsITimer>             mSynTimer;
         nsCOMPtr<nsISocketTransport>   mBackupTransport;
         nsCOMPtr<nsIAsyncOutputStream> mBackupStreamOut;
         nsCOMPtr<nsIAsyncInputStream>  mBackupStreamIn;
@@ -536,17 +544,17 @@ private:
                            nsAHttpTransaction *,
                            nsHttpPipeline **);
     bool     RestrictConnections(nsConnectionEntry *, bool = false);
     nsresult ProcessNewTransaction(nsHttpTransaction *);
     nsresult EnsureSocketThreadTarget();
     void     ClosePersistentConnections(nsConnectionEntry *ent);
     void     ReportProxyTelemetry(nsConnectionEntry *ent);
     nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
-                             uint32_t, bool);
+                             uint32_t, bool, bool = false);
     void     AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
     void     DecrementActiveConnCount(nsHttpConnection *);
     void     StartedConnect();
     void     RecvdConnect();
 
     nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *,
                                                   bool allowWildCard);
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2196,16 +2196,40 @@
   "PREDICTOR_TOTAL_PRECONNECTS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "1000 * 1000",
     "n_buckets": 50,
     "extended_statistics_ok": true,
     "description": "How many actual preconnects happen"
   },
+  "PREDICTOR_TOTAL_PRECONNECTS_CREATED": {
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": "1000 * 1000",
+    "n_buckets": 50,
+    "extended_statistics_ok": true,
+    "description": "How many preconnects actually created a speculative socket"
+  },
+  "PREDICTOR_TOTAL_PRECONNECTS_USED": {
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": "1000 * 1000",
+    "n_buckets": 50,
+    "extended_statistics_ok": true,
+    "description": "How many preconnects actually created a used speculative socket"
+  },
+  "PREDICTOR_TOTAL_PRECONNECTS_UNUSED": {
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": "1000 * 1000",
+    "n_buckets": 50,
+    "extended_statistics_ok": true,
+    "description": "How many preconnects needlessly created a speculative socket"
+  },
   "PREDICTOR_TOTAL_PRERESOLVES": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "1000 * 1000",
     "n_buckets": 50,
     "extended_statistics_ok": true,
     "description": "How many actual preresolves happen"
   },