Bug 1131557 - Serve multiple xpcom events in one poll iteration. r=mcmanus
☠☠ backed out by 7f4925153bd9 ☠ ☠
authorDragana Damjanovic <dd.mozilla@gmail.com>
Wed, 18 Feb 2015 06:35:00 -0500
changeset 229620 4ef497dc6f9b7fd560ac6f167c1c8d483d07fb3f
parent 229619 f47810257e9852f65a2fbe27bfd825306c15bb12
child 229621 b1cc2dd3e35c8c8e074ac15e3e618520dc07edbc
push id55749
push userryanvm@gmail.com
push dateWed, 18 Feb 2015 14:44:52 +0000
treeherdermozilla-inbound@4ef497dc6f9b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1131557
milestone38.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 1131557 - Serve multiple xpcom events in one poll iteration. r=mcmanus
modules/libpref/init/all.js
netwerk/base/nsSocketTransportService2.cpp
netwerk/base/nsSocketTransportService2.h
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1354,16 +1354,22 @@ pref("network.http.enforce-framing.http1
 
 // default values for FTP
 // in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
 // Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
 // per Section 4.7 "Low-Latency Data Service Class".
 pref("network.ftp.data.qos", 0);
 pref("network.ftp.control.qos", 0);
 
+// If this pref is false only one xpcom event will be served per poll
+// iteration. This is the original behavior.
+// If it is true multiple events will be served.
+pref("network.sts.serve_multiple_events_per_poll_iteration", true);
+// The max time to spend on xpcom events between two polls in ms.
+pref("network.sts.max_time_for_events_between_two_polls", 100);
 // </http>
 
 // 2147483647 == PR_INT32_MAX == ~2 GB
 pref("network.websocket.max-message-size", 2147483647);
 
 // Should we automatically follow http 3xx redirects during handshake
 pref("network.websocket.auto-follow-http-redirects", false);
 
--- a/netwerk/base/nsSocketTransportService2.cpp
+++ b/netwerk/base/nsSocketTransportService2.cpp
@@ -35,16 +35,18 @@ PRThread                 *gSocketThread 
 #define SEND_BUFFER_PREF "network.tcp.sendbuffer"
 #define KEEPALIVE_ENABLED_PREF "network.tcp.keepalive.enabled"
 #define KEEPALIVE_IDLE_TIME_PREF "network.tcp.keepalive.idle_time"
 #define KEEPALIVE_RETRY_INTERVAL_PREF "network.tcp.keepalive.retry_interval"
 #define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
 #define SOCKET_LIMIT_TARGET 550U
 #define SOCKET_LIMIT_MIN     50U
 #define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds"
+#define SERVE_MULTIPLE_EVENTS_PREF "network.sts.serve_multiple_events_per_poll_iteration"
+#define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
 
 uint32_t nsSocketTransportService::gMaxCount;
 PRCallOnceType nsSocketTransportService::gMaxCountInitOnce;
 
 //-----------------------------------------------------------------------------
 // ctor/dtor (called on the main/UI thread by the service manager)
 
 nsSocketTransportService::nsSocketTransportService()
@@ -62,16 +64,19 @@ nsSocketTransportService::nsSocketTransp
     , mIdleCount(0)
     , mSentBytesCount(0)
     , mReceivedBytesCount(0)
     , mSendBufferSize(0)
     , mKeepaliveIdleTimeS(600)
     , mKeepaliveRetryIntervalS(1)
     , mKeepaliveProbeCount(kDefaultTCPKeepCount)
     , mKeepaliveEnabledPref(false)
+    , mServeMultipleEventsPerPollIter(true)
+    , mServingPendingQueue(false)
+    , mMaxTimePerPollIter(100)
     , mProbedMaxCount(false)
 {
 #if defined(PR_LOGGING)
     gSocketTransportLog = PR_NewLogModule("nsSocketTransport");
 #endif
 
     NS_ASSERTION(NS_IsMainThread(), "wrong thread");
 
@@ -476,16 +481,18 @@ nsSocketTransportService::Init()
 
     nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (tmpPrefService) {
         tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, false);
         tmpPrefService->AddObserver(KEEPALIVE_ENABLED_PREF, this, false);
         tmpPrefService->AddObserver(KEEPALIVE_IDLE_TIME_PREF, this, false);
         tmpPrefService->AddObserver(KEEPALIVE_RETRY_INTERVAL_PREF, this, false);
         tmpPrefService->AddObserver(KEEPALIVE_PROBE_COUNT_PREF, this, false);
+        tmpPrefService->AddObserver(SERVE_MULTIPLE_EVENTS_PREF, this, false);
+        tmpPrefService->AddObserver(MAX_TIME_BETWEEN_TWO_POLLS, this, false);
     }
     UpdatePrefs();
 
     nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
     if (obsSvc) {
         obsSvc->AddObserver(this, "profile-initial-state", false);
         obsSvc->AddObserver(this, "last-pb-context-exited", false);
     }
@@ -681,16 +688,22 @@ nsSocketTransportService::OnProcessNextE
 NS_IMETHODIMP
 nsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal* thread,
                                                 uint32_t depth,
                                                 bool eventWasProcessed)
 {
     return NS_OK;
 }
 
+void
+nsSocketTransportService::MarkTheLastElementOfPendingQueue()
+{
+    mServingPendingQueue = false;
+}
+
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 NS_IMETHODIMP
 nsSocketTransportService::Run()
 {
     PR_SetCurrentThreadName("Socket Thread");
@@ -725,25 +738,49 @@ nsSocketTransportService::Run()
     for (;;) {
         bool pendingEvents = false;
         thread->HasPendingEvents(&pendingEvents);
 
         do {
             // If there are pending events for this thread then
             // DoPollIteration() should service the network without blocking.
             DoPollIteration(!pendingEvents);
-            
+
             // If nothing was pending before the poll, it might be now
-            if (!pendingEvents)
+            if (!pendingEvents) {
                 thread->HasPendingEvents(&pendingEvents);
+            }
 
             if (pendingEvents) {
-                NS_ProcessNextEvent(thread);
-                pendingEvents = false;
-                thread->HasPendingEvents(&pendingEvents);
+                if (mServeMultipleEventsPerPollIter) {
+                    if (!mServingPendingQueue) {
+                        nsresult rv = Dispatch(NS_NewRunnableMethod(this,
+                            &nsSocketTransportService::MarkTheLastElementOfPendingQueue),
+                            nsIEventTarget::DISPATCH_NORMAL);
+                        if (NS_FAILED(rv)) {
+                            NS_WARNING("Could not dispatch a new event on the "
+                                       "socket thread.");
+                        } else {
+                            mServingPendingQueue = true;
+                        }
+                    }
+                    TimeStamp eventQueueStart = TimeStamp::NowLoRes();
+                    do {
+                        NS_ProcessNextEvent(thread);
+                        pendingEvents = false;
+                        thread->HasPendingEvents(&pendingEvents);
+                    } while (pendingEvents && mServingPendingQueue &&
+                             ((TimeStamp::NowLoRes() -
+                               eventQueueStart).ToMilliseconds() <
+                              mMaxTimePerPollIter));
+                } else {
+                    NS_ProcessNextEvent(thread);
+                    pendingEvents = false;
+                    thread->HasPendingEvents(&pendingEvents);
+                }
             }
         } while (pendingEvents);
 
         bool goingOffline = false;
         // now that our event queue is empty, check to see if we should exit
         {
             MutexAutoLock lock(mLock);
             if (mShuttingDown)
@@ -977,16 +1014,30 @@ nsSocketTransportService::UpdatePrefs()
                                            1, kMaxTCPKeepCount);
         bool keepaliveEnabled = false;
         rv = tmpPrefService->GetBoolPref(KEEPALIVE_ENABLED_PREF,
                                          &keepaliveEnabled);
         if (NS_SUCCEEDED(rv) && keepaliveEnabled != mKeepaliveEnabledPref) {
             mKeepaliveEnabledPref = keepaliveEnabled;
             OnKeepaliveEnabledPrefChange();
         }
+
+        bool serveMultiplePref = false;
+        rv = tmpPrefService->GetBoolPref(SERVE_MULTIPLE_EVENTS_PREF,
+                                         &serveMultiplePref);
+        if (NS_SUCCEEDED(rv)) {
+            mServeMultipleEventsPerPollIter = serveMultiplePref;
+        }
+
+        int32_t maxTimePref;
+        rv = tmpPrefService->GetIntPref(MAX_TIME_BETWEEN_TWO_POLLS,
+                                        &maxTimePref);
+        if (NS_SUCCEEDED(rv) && maxTimePref >= 0) {
+            mMaxTimePerPollIter = maxTimePref;
+        }
     }
     
     return NS_OK;
 }
 
 void
 nsSocketTransportService::OnKeepaliveEnabledPrefChange()
 {
--- a/netwerk/base/nsSocketTransportService2.h
+++ b/netwerk/base/nsSocketTransportService2.h
@@ -12,16 +12,17 @@
 #include "nsEventQueue.h"
 #include "nsCOMPtr.h"
 #include "prinrval.h"
 #include "prlog.h"
 #include "prinit.h"
 #include "nsIObserver.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/net/DashboardTypes.h"
+#include "mozilla/Atomics.h"
 
 class nsASocketHandler;
 struct PRPollDesc;
 
 //-----------------------------------------------------------------------------
 
 #if defined(PR_LOGGING)
 //
@@ -212,30 +213,36 @@ private:
     int32_t     mKeepaliveIdleTimeS;
     // Number of seconds between retries should keepalive pings fail.
     int32_t     mKeepaliveRetryIntervalS;
     // Number of keepalive probes to send.
     int32_t     mKeepaliveProbeCount;
     // True if TCP keepalive is enabled globally.
     bool        mKeepaliveEnabledPref;
 
+    bool                   mServeMultipleEventsPerPollIter;
+    mozilla::Atomic<bool>  mServingPendingQueue;
+    int32_t                mMaxTimePerPollIter;
+
     void OnKeepaliveEnabledPrefChange();
     void NotifyKeepaliveEnabledPrefChange(SocketContext *sock);
 
     // Socket thread only for dynamically adjusting max socket size
 #if defined(XP_WIN)
     void ProbeMaxCount();
 #endif
     bool mProbedMaxCount;
 
     void AnalyzeConnection(nsTArray<mozilla::net::SocketInfo> *data,
                            SocketContext *context, bool aActive);
 
     void ClosePrivateConnections();
     void DetachSocketWithGuard(bool aGuardLocals,
                                SocketContext *socketList,
                                int32_t index);
+
+    void MarkTheLastElementOfPendingQueue();
 };
 
 extern nsSocketTransportService *gSocketTransportService;
 extern PRThread                 *gSocketThread;
 
 #endif // !nsSocketTransportService_h__