Bug 1486400 - add task dispatch/run delays for ChaosMode; r=jesup
authorNathan Froyd <froydnj@mozilla.com>
Wed, 19 Sep 2018 12:02:09 -0400
changeset 437302 1dd7a055bae0985e895946fa62b561feb8fbe78d
parent 437301 8e4824d6f1357859bc4a374433ab282d7741c28b
child 437303 80c1f51adc77306086ed3cc6e97da9eede4e379b
push id34675
push userbtara@mozilla.com
push dateWed, 19 Sep 2018 21:58:47 +0000
treeherdermozilla-central@9812141ec782 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1486400
milestone64.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 1486400 - add task dispatch/run delays for ChaosMode; r=jesup
mfbt/ChaosMode.h
xpcom/threads/ThreadDelay.cpp
xpcom/threads/ThreadDelay.h
xpcom/threads/ThreadEventTarget.cpp
xpcom/threads/moz.build
xpcom/threads/nsThread.cpp
xpcom/threads/nsThreadPool.cpp
--- a/mfbt/ChaosMode.h
+++ b/mfbt/ChaosMode.h
@@ -24,16 +24,20 @@ enum ChaosFeature {
   // Altering timer scheduling.
   TimerScheduling = 0x4,
   // Read and write less-than-requested amounts.
   IOAmounts = 0x8,
   // Iterate over hash tables in random order.
   HashTableIteration = 0x10,
   // Randomly refuse to use cached version of image (when allowed by spec).
   ImageCache = 0x20,
+  // Delay dispatching threads to encourage dispatched tasks to run.
+  TaskDispatching = 0x40,
+  // Delay task running to encourage sending threads to run.
+  TaskRunning = 0x80,
   Any = 0xffffffff,
 };
 
 namespace detail {
 extern MFBT_DATA Atomic<uint32_t,
                         SequentiallyConsistent,
                         recordreplay::Behavior::DontPreserve> gChaosModeCounter;
 extern MFBT_DATA ChaosFeature gChaosFeatures;
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/ThreadDelay.cpp
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Assertions.h"
+#include "mozilla/ChaosMode.h"
+
+#if defined(XP_WIN)
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+namespace mozilla {
+
+void
+DelayForChaosMode(ChaosFeature aFeature, const uint32_t aMicrosecondLimit)
+{
+  if (!ChaosMode::isActive(aFeature)) {
+    return;
+  }
+
+  MOZ_ASSERT(aMicrosecondLimit <= 1000);
+#if defined(XP_WIN)
+  // Windows doesn't support sleeping at less than millisecond resolution.
+  // We could spin here, or we could just sleep for one millisecond.
+  ::Sleep(1);
+#else
+  const uint32_t duration = ChaosMode::randomUint32LessThan(aMicrosecondLimit);
+  ::usleep(duration);
+#endif
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/ThreadDelay.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ChaosMode.h"
+
+namespace mozilla {
+
+// Sleep for a random number of microseconds less than aMicrosecondLimit
+// if aFeature is enabled.  On Windows, the sleep will always be 1 millisecond
+// due to platform limitations.
+void
+DelayForChaosMode(ChaosFeature aFeature, const uint32_t aMicrosecondLimit);
+
+} // namespace mozilla
--- a/xpcom/threads/ThreadEventTarget.cpp
+++ b/xpcom/threads/ThreadEventTarget.cpp
@@ -10,16 +10,17 @@
 #include "LeakRefPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "nsComponentManagerUtils.h"
 #include "nsITimer.h"
 #include "nsThreadManager.h"
 #include "nsThreadSyncDispatch.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMPrivate.h" // for gXPCOMThreadsShutDown
+#include "ThreadDelay.h"
 
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #include "TracedTaskCommon.h"
 using namespace mozilla::tasktracer;
 #endif
 
 using namespace mozilla;
@@ -169,16 +170,18 @@ ThreadEventTarget::Dispatch(already_AddR
     return NS_OK;
   }
 
   NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL ||
                aFlags == NS_DISPATCH_AT_END, "unexpected dispatch flags");
   if (!mSink->PutEvent(event.take(), EventPriority::Normal)) {
     return NS_ERROR_UNEXPECTED;
   }
+  // Delay to encourage the receiving task to run before we do work.
+  DelayForChaosMode(ChaosFeature::TaskDispatching, 1000);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ThreadEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aDelayMs)
 {
   NS_ENSURE_TRUE(!!aDelayMs, NS_ERROR_UNEXPECTED);
 
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -68,16 +68,17 @@ EXPORTS.mozilla += [
     'TaskDispatcher.h',
     'TaskQueue.h',
     'ThreadEventQueue.h',
     'ThrottledEventQueue.h',
 ]
 
 SOURCES += [
     'IdleTaskRunner.cpp',
+    'ThreadDelay.cpp',
 ]
 
 UNIFIED_SOURCES += [
     'AbstractThread.cpp',
     'BlockingResourceBase.cpp',
     'CooperativeThreadPool.cpp',
     'CPUUsageWatcher.cpp',
     'EventQueue.cpp',
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -41,16 +41,17 @@
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsThreadSyncDispatch.h"
 #include "nsServiceManagerUtils.h"
 #include "GeckoProfiler.h"
 #include "InputEventStatistics.h"
 #include "ThreadEventTarget.h"
+#include "ThreadDelay.h"
 
 #ifdef XP_LINUX
 #ifdef __GLIBC__
 #include <gnu/libc-version.h>
 #endif
 #include <sys/mman.h>
 #include <sys/time.h>
 #include <sys/resource.h>
@@ -1096,16 +1097,20 @@ nsThread::ProcessNextEvent(bool aMayWait
       activation.ref().SetEvent(event, priority);
     }
 
     *aResult = (event.get() != nullptr);
 
     if (event) {
       LOG(("THRD(%p) running [%p]\n", this, event.get()));
 
+      // Delay event processing to encourage whoever dispatched this event
+      // to run.
+      DelayForChaosMode(ChaosFeature::TaskRunning, 1000);
+
       if (IsMainThread()) {
         BackgroundHangMonitor().NotifyActivity();
       }
 
       bool schedulerLoggingEnabled = mozilla::StaticPrefs::dom_performance_enable_scheduler_timing();
       if (schedulerLoggingEnabled
           && mNestedEventLoopDepth > mCurrentEventLoopDepth
           && mCurrentPerformanceCounter) {
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCOMArray.h"
 #include "nsIClassInfoImpl.h"
+#include "ThreadDelay.h"
 #include "nsThreadPool.h"
 #include "nsThreadManager.h"
 #include "nsThread.h"
 #include "nsMemory.h"
 #include "nsAutoPtr.h"
 #include "prinrval.h"
 #include "mozilla/Logging.h"
 #include "mozilla/SystemGroup.h"
@@ -95,16 +96,21 @@ nsThreadPool::PutEvent(already_AddRefed<
       spawnThread = true;
     }
 
     mEvents.PutEvent(std::move(aEvent), EventPriority::Normal, lock);
     mEventsAvailable.Notify();
     stackSize = mStackSize;
   }
 
+  auto delay = MakeScopeExit([&]() {
+      // Delay to encourage the receiving task to run before we do work.
+      DelayForChaosMode(ChaosFeature::TaskDispatching, 1000);
+  });
+
   LOG(("THRD-P(%p) put [spawn=%d]\n", this, spawnThread));
   if (!spawnThread) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIThread> thread;
   nsresult rv = NS_NewNamedThread(mThreadNaming.GetNextThreadName(mName),
                                   getter_AddRefs(thread), nullptr, stackSize);
@@ -223,16 +229,21 @@ nsThreadPool::Run()
         }
       } else if (wasIdle) {
         wasIdle = false;
         --mIdleCount;
       }
     }
     if (event) {
       LOG(("THRD-P(%p) %s running [%p]\n", this, mName.BeginReading(), event.get()));
+
+      // Delay event processing to encourage whoever dispatched this event
+      // to run.
+      DelayForChaosMode(ChaosFeature::TaskRunning, 1000);
+
       event->Run();
     }
   } while (!exitThread);
 
   if (listener) {
     listener->OnThreadShuttingDown();
   }