Bug 1323100 - Register most of the remaining threadfunc threads with the profiler. r=froydnj
☠☠ backed out by dbe5b7ff43b6 ☠ ☠
authorMarkus Stange <mstange@themasta.com>
Thu, 29 Dec 2016 22:32:52 +0100
changeset 327583 d6d25e8bd001ff063ab7063d3bfb06356b0cd350
parent 327582 1b0855bb0c387415b4c619b7aa9562442ba14615
child 327584 84fb749698abd1b1c73e2f0a48dce6a3b60aa5e0
push id35526
push usermstange@themasta.com
push dateFri, 30 Dec 2016 00:24:47 +0000
treeherderautoland@84fb749698ab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1323100
milestone53.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 1323100 - Register most of the remaining threadfunc threads with the profiler. r=froydnj As far as I can tell, this covers all the remaining threads which we start using PR_CreateThread, except the ones that are created inside NSPR or NSS. This adds a AutoProfilerRegister stack class for easy registering and unregistering. There are a few places where we still call profiler_register_thread() and profiler_unregister_thread() manually, either because registration happens conditionally, or because there is a variable that gets put on the stack before the AutoProfilerRegister (e.g. a dynamically generated thread name). AutoProfilerRegister needs to be the first object on the stack because it uses its own `this` pointer as the stack top address. MozReview-Commit-ID: 3vwhS55Yzt
dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
dom/storage/DOMStorageDBThread.cpp
js/xpconnect/src/XPCJSContext.cpp
netwerk/cache2/CacheIOThread.cpp
netwerk/dns/nsHostResolver.cpp
security/manager/ssl/nsKeygenThread.cpp
security/manager/ssl/nsProtectedAuthThread.cpp
security/manager/ssl/nsSmartCardMonitor.cpp
startupcache/StartupCache.cpp
toolkit/components/terminator/nsTerminator.cpp
toolkit/xre/EventTracer.cpp
tools/profiler/public/GeckoProfiler.h
tools/profiler/public/GeckoProfilerImpl.h
xpcom/build/MainThreadIOLogger.cpp
xpcom/threads/BackgroundHangMonitor.cpp
xpcom/threads/HangMonitor.cpp
xpcom/threads/nsProcessCommon.cpp
--- a/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
+++ b/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
@@ -23,16 +23,17 @@
  * 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 "HRTFDatabaseLoader.h"
 #include "HRTFDatabase.h"
+#include "GeckoProfiler.h"
 
 using namespace mozilla;
 
 namespace WebCore {
 
 // Singleton
 nsTHashtable<HRTFDatabaseLoader::LoaderByRateEntry>*
     HRTFDatabaseLoader::s_loaderMap = nullptr;
@@ -146,16 +147,17 @@ void HRTFDatabaseLoader::MainThreadRelea
         // on this (main) thread.
         delete this;
     }
 }
 
 // Asynchronously load the database in this thread.
 static void databaseLoaderEntry(void* threadData)
 {
+    AutoProfilerRegister registerThread("HRTFDatabaseLdr");
     PR_SetCurrentThreadName("HRTFDatabaseLdr");
 
     HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData);
     MOZ_ASSERT(loader);
     loader->load();
 }
 
 void HRTFDatabaseLoader::load()
--- a/dom/storage/DOMStorageDBThread.cpp
+++ b/dom/storage/DOMStorageDBThread.cpp
@@ -22,16 +22,17 @@
 #include "mozIStorageValueArray.h"
 #include "mozIStorageFunction.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsIObserverService.h"
 #include "nsVariant.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/Services.h"
 #include "mozilla/Tokenizer.h"
+#include "GeckoProfiler.h"
 
 // How long we collect write oprerations
 // before they are flushed to the database
 // In milliseconds.
 #define FLUSHING_INTERVAL_MS 5000
 
 // Write Ahead Log's maximum size is 512KB
 #define MAX_WAL_SIZE_BYTES 512 * 1024
@@ -332,16 +333,17 @@ DOMStorageDBThread::SetDefaultPriority()
   if (--mPriorityCounter <= 0) {
     PR_SetThreadPriority(mThread, PR_PRIORITY_LOW);
   }
 }
 
 void
 DOMStorageDBThread::ThreadFunc(void* aArg)
 {
+  AutoProfilerRegister registerThread("localStorage DB");
   PR_SetCurrentThreadName("localStorage DB");
   mozilla::IOInterposer::RegisterCurrentThread();
 
   DOMStorageDBThread* thread = static_cast<DOMStorageDBThread*>(aArg);
   thread->ThreadFunc();
   mozilla::IOInterposer::UnregisterCurrentThread();
 }
 
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -1161,16 +1161,17 @@ AutoLockWatchdog::AutoLockWatchdog(Watch
 AutoLockWatchdog::~AutoLockWatchdog()
 {
     PR_Unlock(mWatchdog->GetLock());
 }
 
 static void
 WatchdogMain(void* arg)
 {
+    mozilla::AutoProfilerRegister registerThread("JS Watchdog");
     PR_SetCurrentThreadName("JS Watchdog");
 
     Watchdog* self = static_cast<Watchdog*>(arg);
     WatchdogManager* manager = self->Manager();
 
     // Lock lasts until we return
     AutoLockWatchdog lock(self);
 
--- a/netwerk/cache2/CacheIOThread.cpp
+++ b/netwerk/cache2/CacheIOThread.cpp
@@ -5,16 +5,17 @@
 #include "CacheIOThread.h"
 #include "CacheFileIOManager.h"
 
 #include "nsIRunnable.h"
 #include "nsISupportsImpl.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "mozilla/IOInterposer.h"
+#include "GeckoProfiler.h"
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #include "TracedTaskCommon.h"
@@ -432,16 +433,17 @@ already_AddRefed<nsIEventTarget> CacheIO
   }
 
   return target.forget();
 }
 
 // static
 void CacheIOThread::ThreadFunc(void* aClosure)
 {
+  AutoProfilerRegister registerThread("Cache2 I/O");
   PR_SetCurrentThreadName("Cache2 I/O");
   mozilla::IOInterposer::RegisterCurrentThread();
   CacheIOThread* thread = static_cast<CacheIOThread*>(aClosure);
   thread->ThreadFunc();
   mozilla::IOInterposer::UnregisterCurrentThread();
 }
 
 void CacheIOThread::ThreadFunc()
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -24,16 +24,17 @@
 #include "prerror.h"
 #include "prtime.h"
 #include "mozilla/Logging.h"
 #include "PLDHashTable.h"
 #include "plstr.h"
 #include "nsURLHelper.h"
 #include "nsThreadUtils.h"
 #include "GetAddrInfo.h"
+#include "GeckoProfiler.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
@@ -1430,22 +1431,25 @@ nsHostResolver::SizeOfIncludingThis(Mall
     //   |mDB| is measured.
 
     return n;
 }
 
 void
 nsHostResolver::ThreadFunc(void *arg)
 {
+    char stackTop;
+
     LOG(("DNS lookup thread - starting execution.\n"));
 
     static nsThreadPoolNaming naming;
     nsCString name = naming.GetNextThreadName("DNS Resolver");
 
     PR_SetCurrentThreadName(name.BeginReading());
+    profiler_register_thread(name.BeginReading(), &stackTop);
 
 #if defined(RES_RETRY_ON_FAILURE)
     nsResState rs;
 #endif
     nsHostResolver *resolver = (nsHostResolver *)arg;
     nsHostRecord *rec  = nullptr;
     AddrInfo *ai = nullptr;
 
@@ -1506,16 +1510,18 @@ nsHostResolver::ThreadFunc(void *arg)
                  LOG_HOST(rec->host, rec->netInterface)));
         } else {
             rec = nullptr;
         }
     }
     resolver->mThreadCount--;
     NS_RELEASE(resolver);
     LOG(("DNS lookup thread - queue empty, thread finished.\n"));
+
+    profiler_unregister_thread();
 }
 
 nsresult
 nsHostResolver::Create(uint32_t maxCacheEntries,
                        uint32_t defaultCacheEntryLifetime,
                        uint32_t defaultGracePeriod,
                        nsHostResolver **result)
 {
--- a/security/manager/ssl/nsKeygenThread.cpp
+++ b/security/manager/ssl/nsKeygenThread.cpp
@@ -7,16 +7,17 @@
 #include "pk11func.h"
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
 #include "nsKeygenThread.h"
 #include "nsIObserver.h"
 #include "nsNSSShutDown.h"
 #include "PSMRunnable.h"
 #include "mozilla/DebugOnly.h"
+#include "GeckoProfiler.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 NS_IMPL_ISUPPORTS(nsKeygenThread, nsIKeygenThread)
 
 
 nsKeygenThread::nsKeygenThread()
@@ -109,16 +110,17 @@ nsresult nsKeygenThread::ConsumeResult(
       rv = NS_ERROR_FAILURE;
     }
   
   return rv;
 }
 
 static void nsKeygenThreadRunner(void *arg)
 {
+  AutoProfilerRegister registerThread("Keygen");
   PR_SetCurrentThreadName("Keygen");
   nsKeygenThread *self = static_cast<nsKeygenThread *>(arg);
   self->Run();
 }
 
 nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
 {
   if (!NS_IsMainThread()) {
--- a/security/manager/ssl/nsProtectedAuthThread.cpp
+++ b/security/manager/ssl/nsProtectedAuthThread.cpp
@@ -6,24 +6,26 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "PSMRunnable.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsPKCS11Slot.h"
 #include "nsProtectedAuthThread.h"
+#include "GeckoProfiler.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 NS_IMPL_ISUPPORTS(nsProtectedAuthThread, nsIProtectedAuthThread)
 
 static void nsProtectedAuthThreadRunner(void *arg)
 {
+    AutoProfilerRegister registerThread("Protected Auth");
     PR_SetCurrentThreadName("Protected Auth");
 
     nsProtectedAuthThread *self = static_cast<nsProtectedAuthThread *>(arg);
     self->Run();
 }
 
 nsProtectedAuthThread::nsProtectedAuthThread()
 : mMutex("nsProtectedAuthThread.mMutex")
--- a/security/manager/ssl/nsSmartCardMonitor.cpp
+++ b/security/manager/ssl/nsSmartCardMonitor.cpp
@@ -5,16 +5,17 @@
 #include "nsSmartCardMonitor.h"
 
 #include "ScopedNSSTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/Unused.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
+#include "GeckoProfiler.h"
 #include "nspr.h"
 #include "pk11func.h"
 
 using namespace mozilla;
 
 //
 // The SmartCard monitoring thread should start up for each module we load
 // that has removable tokens. This code calls an NSS function which waits
@@ -385,12 +386,13 @@ void SmartCardMonitoringThread::Execute(
 const SECMODModule* SmartCardMonitoringThread::GetModule()
 {
   return mModule;
 }
 
 // C-like calling sequence to glue into PR_CreateThread.
 void SmartCardMonitoringThread::LaunchExecute(void* arg)
 {
+  AutoProfilerRegister registerThread("SmartCard");
   PR_SetCurrentThreadName("SmartCard");
 
   ((SmartCardMonitoringThread*)arg)->Execute();
 }
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -31,16 +31,17 @@
 #include "nsWeakReference.h"
 #include "nsZipArchive.h"
 #include "mozilla/Omnijar.h"
 #include "prenv.h"
 #include "mozilla/Telemetry.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsIProtocolHandler.h"
+#include "GeckoProfiler.h"
 
 #ifdef IS_BIG_ENDIAN
 #define SC_ENDIAN "big"
 #else
 #define SC_ENDIAN "little"
 #endif
 
 #if PR_BYTES_PER_WORD == 4
@@ -498,16 +499,17 @@ StartupCache::WaitOnWriteThread()
 
   PR_JoinThread(mWriteThread);
   mWriteThread = nullptr;
 }
 
 void
 StartupCache::ThreadedWrite(void *aClosure)
 {
+  AutoProfilerRegister registerThread("StartupCache");
   PR_SetCurrentThreadName("StartupCache");
   mozilla::IOInterposer::RegisterCurrentThread();
   /*
    * It is safe to use the pointer passed in aClosure to reference the
    * StartupCache object because the thread's lifetime is tightly coupled to
    * the lifetime of the StartupCache object; this thread is joined in the
    * StartupCache destructor, guaranteeing that this function runs if and only
    * if the StartupCache object is valid.
--- a/toolkit/components/terminator/nsTerminator.cpp
+++ b/toolkit/components/terminator/nsTerminator.cpp
@@ -27,16 +27,17 @@
 #include "nsDirectoryServiceUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #endif
+#include "GeckoProfiler.h"
 
 #if defined(XP_WIN)
 #include <windows.h>
 #else
 #include <unistd.h>
 #endif
 
 #include "mozilla/ArrayUtils.h"
@@ -119,16 +120,17 @@ struct Options {
 };
 
 /**
  * Entry point for the watchdog thread
  */
 void
 RunWatchdog(void* arg)
 {
+  AutoProfilerRegister registerThread("Shutdown Hang Terminator");
   PR_SetCurrentThreadName("Shutdown Hang Terminator");
 
   // Let's copy and deallocate options, that's one less leak to worry
   // about.
   UniquePtr<Options> options((Options*)arg);
   uint32_t crashAfterTicks = options->crashAfterTicks;
   options = nullptr;
 
@@ -209,16 +211,17 @@ public:
 // The data written by the writer thread will be read by another
 // module upon the next restart and fed to Telemetry.
 //
 Atomic<nsCString*> gWriteData(nullptr);
 PRMonitor* gWriteReady = nullptr;
 
 void RunWriter(void* arg)
 {
+  AutoProfilerRegister registerThread("Shutdown Statistics Writer");
   PR_SetCurrentThreadName("Shutdown Statistics Writer");
 
   MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(arg);
   // Shutdown will generally complete before we have a chance to
   // deallocate. This is not a leak.
 
   // Setup destinationPath and tmpFilePath
 
--- a/toolkit/xre/EventTracer.cpp
+++ b/toolkit/xre/EventTracer.cpp
@@ -117,16 +117,17 @@ class EventLoopLagDispatcher : public Ru
  * it will not send another event until the previous response is received.
  *
  * The output defaults to stdout, but can be redirected to a file by
  * settting the environment variable MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT
  * to the name of a file to use.
  */
 void TracerThread(void *arg)
 {
+  AutoProfilerRegister registerThread("Event Tracer");
   PR_SetCurrentThreadName("Event Tracer");
 
   TracerStartClosure* threadArgs = static_cast<TracerStartClosure*>(arg);
 
   // These are the defaults. They can be overridden by environment vars.
   // This should be set to the maximum latency we'd like to allow
   // for responsiveness.
   int32_t thresholdInterval = threadArgs->mThresholdInterval;
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -243,16 +243,24 @@ static inline void profiler_js_operation
 static inline double profiler_time() { return 0; }
 static inline double profiler_time(const mozilla::TimeStamp& aTime) { return 0; }
 
 static inline bool profiler_in_privacy_mode() { return false; }
 
 static inline void profiler_log(const char *str) {}
 static inline void profiler_log(const char *fmt, va_list args) {}
 
+class AutoProfilerRegister final MOZ_STACK_CLASS
+{
+  AutoProfilerRegister(const char* aName) {}
+private:
+  AutoProfilerRegister(const AutoProfilerRegister&) = delete;
+  AutoProfilerRegister& operator=(const AutoProfilerRegister&) = delete;
+};
+
 #else
 
 #include "GeckoProfilerImpl.h"
 
 #endif
 
 class MOZ_RAII GeckoProfilerInitRAII {
 public:
--- a/tools/profiler/public/GeckoProfilerImpl.h
+++ b/tools/profiler/public/GeckoProfilerImpl.h
@@ -456,16 +456,36 @@ public:
   ~SamplerStackFramePrintfRAII() {
     mozilla_sampler_call_exit(mHandle);
   }
 private:
   char mDest[SAMPLER_MAX_STRING];
   void* mHandle;
 };
 
+/**
+ * Convenience class to register and unregister a thread with the profiler.
+ * Needs to be the first object on the stack of the thread.
+ */
+class MOZ_STACK_CLASS AutoProfilerRegister final
+{
+public:
+  explicit AutoProfilerRegister(const char* aName)
+  {
+    profiler_register_thread(aName, this);
+  }
+  ~AutoProfilerRegister()
+  {
+    profiler_unregister_thread();
+  }
+private:
+  AutoProfilerRegister(const AutoProfilerRegister&) = delete;
+  AutoProfilerRegister& operator=(const AutoProfilerRegister&) = delete;
+};
+
 } // namespace mozilla
 
 inline PseudoStack* mozilla_get_pseudo_stack(void)
 {
   if (!stack_key_initialized)
     return nullptr;
   return tlsPseudoStack.get();
 }
--- a/xpcom/build/MainThreadIOLogger.cpp
+++ b/xpcom/build/MainThreadIOLogger.cpp
@@ -109,16 +109,17 @@ MainThreadIOLoggerImpl::Init()
     return false;
   }
   return true;
 }
 
 /* static */ void
 MainThreadIOLoggerImpl::sIOThreadFunc(void* aArg)
 {
+  AutoProfilerRegister registerThread("MainThreadIOLogger");
   PR_SetCurrentThreadName("MainThreadIOLogger");
   MainThreadIOLoggerImpl* obj = static_cast<MainThreadIOLoggerImpl*>(aArg);
   obj->IOThreadFunc();
 }
 
 void
 MainThreadIOLoggerImpl::IOThreadFunc()
 {
--- a/xpcom/threads/BackgroundHangMonitor.cpp
+++ b/xpcom/threads/BackgroundHangMonitor.cpp
@@ -17,16 +17,17 @@
 
 #include "prinrval.h"
 #include "prthread.h"
 #include "ThreadStackHelper.h"
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
 #include "mozilla/Services.h"
 #include "nsXULAppAPI.h"
+#include "GeckoProfiler.h"
 
 #include <algorithm>
 
 // Activate BHR only for one every BHR_BETA_MOD users.
 // This is now 100% of Beta population for the Beta 45/46 e10s A/B trials
 // It can be scaled back again in the future
 #define BHR_BETA_MOD 1;
 
@@ -49,16 +50,17 @@ namespace mozilla {
  * manages all instances of BackgroundHangThread.
  */
 class BackgroundHangManager : public nsIObserver
 {
 private:
   // Background hang monitor thread function
   static void MonitorThread(void* aData)
   {
+    AutoProfilerRegister registerThread("BgHangMonitor");
     PR_SetCurrentThreadName("BgHangManager");
 
     /* We do not hold a reference to BackgroundHangManager here
        because the monitor thread only exists as long as the
        BackgroundHangManager instance exists. We stop the monitor
        thread in the BackgroundHangManager destructor, and we can
        only get to the destructor if we don't hold a reference here. */
     static_cast<BackgroundHangManager*>(aData)->RunMonitorThread();
--- a/xpcom/threads/HangMonitor.cpp
+++ b/xpcom/threads/HangMonitor.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/UniquePtr.h"
 #include "nsReadableUtils.h"
 #include "mozilla/StackWalk.h"
 #ifdef _WIN64
 #include "mozilla/StackWalk_windows.h"
 #endif
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
+#include "GeckoProfiler.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
@@ -204,16 +205,17 @@ GetChromeHangReport(Telemetry::Processed
   }
 }
 
 #endif
 
 void
 ThreadMain(void*)
 {
+  AutoProfilerRegister registerThread("Hang Monitor");
   PR_SetCurrentThreadName("Hang Monitor");
 
   MonitorAutoLock lock(*gMonitor);
 
   // In order to avoid issues with the hang monitor incorrectly triggering
   // during a general system stop such as sleeping, the monitor thread must
   // run twice to trigger hang protection.
   PRIntervalTime lastTimestamp = 0;
--- a/xpcom/threads/nsProcessCommon.cpp
+++ b/xpcom/threads/nsProcessCommon.cpp
@@ -20,16 +20,17 @@
 #include "nsProcess.h"
 #include "prio.h"
 #include "prenv.h"
 #include "nsCRT.h"
 #include "nsThreadUtils.h"
 #include "nsIObserverService.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Services.h"
+#include "GeckoProfiler.h"
 
 #include <stdlib.h>
 
 #if defined(PROCESSMODEL_WINAPI)
 #include "prmem.h"
 #include "nsString.h"
 #include "nsLiteralString.h"
 #include "nsReadableUtils.h"
@@ -230,20 +231,23 @@ assembleCmdLine(char* const* aArgv, wcha
   PR_Free(cmdLine);
   return 0;
 }
 #endif
 
 void
 nsProcess::Monitor(void* aArg)
 {
+  char stackBaseGuess;
+
   RefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(aArg));
 
   if (!process->mBlocking) {
     PR_SetCurrentThreadName("RunProcess");
+    profiler_register_thread("RunProcess", &stackBaseGuess);
   }
 
 #if defined(PROCESSMODEL_WINAPI)
   DWORD dwRetVal;
   unsigned long exitCode = -1;
 
   dwRetVal = WaitForSingleObject(process->mProcess, INFINITE);
   if (dwRetVal != WAIT_FAILED) {
@@ -299,16 +303,20 @@ nsProcess::Monitor(void* aArg)
 
   // If we ran a background thread for the monitor then notify on the main
   // thread
   if (NS_IsMainThread()) {
     process->ProcessComplete();
   } else {
     NS_DispatchToMainThread(NewRunnableMethod(process, &nsProcess::ProcessComplete));
   }
+
+  if (!process->mBlocking) {
+    profiler_unregister_thread();
+  }
 }
 
 void
 nsProcess::ProcessComplete()
 {
   if (mThread) {
     nsCOMPtr<nsIObserverService> os =
       mozilla::services::GetObserverService();