Bug 1267904 - Add telemetry for WorkerMainThreadRunnable, r=khuey
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 03 May 2016 09:09:47 +0200
changeset 320288 08f3c7a9f5a8204488c263a24e582012bc5a8da1
parent 320287 3996d3dd01ad7621cd0aa6e411ce716856cc2641
child 320289 1da0860325328fa27135f3d849be916d481c306d
push id9671
push userraliiev@mozilla.com
push dateMon, 06 Jun 2016 20:27:52 +0000
treeherdermozilla-aurora@cea65ca3d0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey
bugs1267904
milestone49.0a1
Bug 1267904 - Add telemetry for WorkerMainThreadRunnable, r=khuey
dom/base/WebSocket.cpp
dom/broadcastchannel/BroadcastChannel.cpp
dom/canvas/ImageBitmap.cpp
dom/fetch/Fetch.cpp
dom/fetch/Request.cpp
dom/notification/Notification.cpp
dom/workers/ServiceWorkerRegistration.cpp
dom/workers/URL.cpp
dom/workers/WorkerNavigator.cpp
dom/workers/WorkerRunnable.cpp
dom/workers/WorkerRunnable.h
gfx/thebes/gfxUtils.cpp
toolkit/components/telemetry/Histograms.json
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -282,17 +282,18 @@ namespace {
 class PrintErrorOnConsoleRunnable final : public WorkerMainThreadRunnable
 {
 public:
   PrintErrorOnConsoleRunnable(WebSocketImpl* aImpl,
                               const char* aBundleURI,
                               const char16_t* aError,
                               const char16_t** aFormatStrings,
                               uint32_t aFormatStringsLen)
-    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
+    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate,
+                               NS_LITERAL_CSTRING("WebSocket :: print error on console"))
     , mImpl(aImpl)
     , mBundleURI(aBundleURI)
     , mError(aError)
     , mFormatStrings(aFormatStrings)
     , mFormatStringsLen(aFormatStringsLen)
   { }
 
   bool MainThreadRun() override
@@ -567,17 +568,18 @@ WebSocketImpl::FailConnection(uint16_t a
 }
 
 namespace {
 
 class DisconnectInternalRunnable final : public WorkerMainThreadRunnable
 {
 public:
   explicit DisconnectInternalRunnable(WebSocketImpl* aImpl)
-    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate)
+    : WorkerMainThreadRunnable(aImpl->mWorkerPrivate,
+                               NS_LITERAL_CSTRING("WebSocket :: disconnect"))
     , mImpl(aImpl)
   { }
 
   bool MainThreadRun() override
   {
     mImpl->DisconnectInternal();
     return true;
   }
@@ -985,18 +987,19 @@ public:
 
 private:
   JSContext* mCx;
 };
 
 class WebSocketMainThreadRunnable : public WorkerMainThreadRunnable
 {
 public:
-  WebSocketMainThreadRunnable(WorkerPrivate* aWorkerPrivate)
-    : WorkerMainThreadRunnable(aWorkerPrivate)
+  WebSocketMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
+                              const nsACString& aTelemetryKey)
+    : WorkerMainThreadRunnable(aWorkerPrivate, aTelemetryKey)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool MainThreadRun() override
   {
     AssertIsOnMainThread();
@@ -1024,17 +1027,18 @@ protected:
 class InitRunnable final : public WebSocketMainThreadRunnable
 {
 public:
   InitRunnable(WebSocketImpl* aImpl, const nsAString& aURL,
                nsTArray<nsString>& aProtocolArray,
                const nsACString& aScriptFile, uint32_t aScriptLine,
                uint32_t aScriptColumn,
                ErrorResult& aRv, bool* aConnectionFailed)
-    : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate)
+    : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate,
+                                  NS_LITERAL_CSTRING("WebSocket :: init"))
     , mImpl(aImpl)
     , mURL(aURL)
     , mProtocolArray(aProtocolArray)
     , mScriptFile(aScriptFile)
     , mScriptLine(aScriptLine)
     , mScriptColumn(aScriptColumn)
     , mRv(aRv)
     , mConnectionFailed(aConnectionFailed)
@@ -1093,17 +1097,18 @@ protected:
   ErrorResult& mRv;
   bool* mConnectionFailed;
 };
 
 class AsyncOpenRunnable final : public WebSocketMainThreadRunnable
 {
 public:
   AsyncOpenRunnable(WebSocketImpl* aImpl, ErrorResult& aRv)
-    : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate)
+    : WebSocketMainThreadRunnable(aImpl->mWorkerPrivate,
+                                  NS_LITERAL_CSTRING("WebSocket :: AsyncOpen"))
     , mImpl(aImpl)
     , mRv(aRv)
   {
     MOZ_ASSERT(mWorkerPrivate);
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
 protected:
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -68,17 +68,18 @@ GetPrincipalFromWorkerPrivate(WorkerPriv
 }
 
 class InitializeRunnable final : public WorkerMainThreadRunnable
 {
 public:
   InitializeRunnable(WorkerPrivate* aWorkerPrivate, nsACString& aOrigin,
                      PrincipalInfo& aPrincipalInfo, bool& aPrivateBrowsing,
                      ErrorResult& aRv)
-    : WorkerMainThreadRunnable(aWorkerPrivate)
+    : WorkerMainThreadRunnable(aWorkerPrivate,
+                               NS_LITERAL_CSTRING("BroadcastChannel :: Initialize"))
     , mWorkerPrivate(GetCurrentThreadWorkerPrivate())
     , mOrigin(aOrigin)
     , mPrincipalInfo(aPrincipalInfo)
     , mPrivateBrowsing(aPrivateBrowsing)
     , mRv(aRv)
   {
     MOZ_ASSERT(mWorkerPrivate);
   }
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -264,17 +264,18 @@ class CreateImageFromRawDataInMainThread
 public:
   CreateImageFromRawDataInMainThreadSyncTask(uint8_t* aBuffer,
                                              uint32_t aBufferLength,
                                              uint32_t aStride,
                                              gfx::SurfaceFormat aFormat,
                                              const gfx::IntSize& aSize,
                                              const Maybe<IntRect>& aCropRect,
                                              layers::Image** aImage)
-  : WorkerMainThreadRunnable(GetCurrentThreadWorkerPrivate())
+  : WorkerMainThreadRunnable(GetCurrentThreadWorkerPrivate(),
+                               NS_LITERAL_CSTRING("ImageBitmap :: Create Image from Raw Data"))
   , mImage(aImage)
   , mBuffer(aBuffer)
   , mBufferLength(aBufferLength)
   , mStride(aStride)
   , mFormat(aFormat)
   , mSize(aSize)
   , mCropRect(aCropRect)
   {
@@ -1145,17 +1146,18 @@ class CreateImageBitmapFromBlobWorkerTas
   // This is a synchronous task.
   class DecodeBlobInMainThreadSyncTask final : public WorkerMainThreadRunnable
   {
   public:
     DecodeBlobInMainThreadSyncTask(WorkerPrivate* aWorkerPrivate,
                                    Blob& aBlob,
                                    Maybe<IntRect>& aCropRect,
                                    layers::Image** aImage)
-    : WorkerMainThreadRunnable(aWorkerPrivate)
+    : WorkerMainThreadRunnable(aWorkerPrivate,
+                               NS_LITERAL_CSTRING("ImageBitmap :: Create Image from Blob"))
     , mBlob(aBlob)
     , mCropRect(aCropRect)
     , mImage(aImage)
     {
     }
 
     bool MainThreadRun() override
     {
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -713,17 +713,18 @@ public:
 };
 
 template <class Derived>
 class CancelPumpRunnable final : public WorkerMainThreadRunnable
 {
   FetchBody<Derived>* mBody;
 public:
   explicit CancelPumpRunnable(FetchBody<Derived>* aBody)
-    : WorkerMainThreadRunnable(aBody->mWorkerPrivate)
+    : WorkerMainThreadRunnable(aBody->mWorkerPrivate,
+                               NS_LITERAL_CSTRING("Fetch :: Cancel Pump"))
     , mBody(aBody)
   { }
 
   bool
   MainThreadRun() override
   {
     mBody->CancelPump();
     return true;
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -226,17 +226,18 @@ GetRequestURLFromWorker(const GlobalObje
 }
 
 class ReferrerSameOriginChecker final : public workers::WorkerMainThreadRunnable
 {
 public:
   ReferrerSameOriginChecker(workers::WorkerPrivate* aWorkerPrivate,
                             const nsAString& aReferrerURL,
                             nsresult& aResult)
-    : workers::WorkerMainThreadRunnable(aWorkerPrivate),
+    : workers::WorkerMainThreadRunnable(aWorkerPrivate,
+                                        NS_LITERAL_CSTRING("Fetch :: Referrer same origin check")),
       mReferrerURL(aReferrerURL),
       mResult(aResult)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool
   MainThreadRun() override
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -284,17 +284,18 @@ public:
 };
 
 class GetPermissionRunnable final : public WorkerMainThreadRunnable
 {
   NotificationPermission mPermission;
 
 public:
   explicit GetPermissionRunnable(WorkerPrivate* aWorker)
-    : WorkerMainThreadRunnable(aWorker)
+    : WorkerMainThreadRunnable(aWorker,
+                               NS_LITERAL_CSTRING("Notification :: Get Permission"))
     , mPermission(NotificationPermission::Denied)
   { }
 
   bool
   MainThreadRun() override
   {
     ErrorResult result;
     mPermission =
@@ -2443,17 +2444,18 @@ NotificationFeature::NotificationFeature
 class CloseNotificationRunnable final
   : public WorkerMainThreadRunnable
 {
   Notification* mNotification;
   bool mHadObserver;
 
   public:
   explicit CloseNotificationRunnable(Notification* aNotification)
-    : WorkerMainThreadRunnable(aNotification->mWorkerPrivate)
+    : WorkerMainThreadRunnable(aNotification->mWorkerPrivate,
+                               NS_LITERAL_CSTRING("Notification :: Close Notification"))
     , mNotification(aNotification)
     , mHadObserver(false)
   {}
 
   bool
   MainThreadRun() override
   {
     if (mNotification->mObserver) {
@@ -2550,17 +2552,18 @@ Notification::UnregisterFeature()
  */
 class CheckLoadRunnable final : public WorkerMainThreadRunnable
 {
   nsresult mRv;
   nsCString mScope;
 
 public:
   explicit CheckLoadRunnable(WorkerPrivate* aWorker, const nsACString& aScope)
-    : WorkerMainThreadRunnable(aWorker)
+    : WorkerMainThreadRunnable(aWorker,
+                               NS_LITERAL_CSTRING("Notification :: Check Load"))
     , mRv(NS_ERROR_DOM_SECURITY_ERR)
     , mScope(aScope)
   { }
 
   bool
   MainThreadRun() override
   {
     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -1074,17 +1074,18 @@ public:
 };
 
 class SyncStopListeningRunnable final : public WorkerMainThreadRunnable
 {
   RefPtr<WorkerListener> mListener;
 public:
   SyncStopListeningRunnable(WorkerPrivate* aWorkerPrivate,
                             WorkerListener* aListener)
-    : WorkerMainThreadRunnable(aWorkerPrivate)
+    : WorkerMainThreadRunnable(aWorkerPrivate,
+                               NS_LITERAL_CSTRING("ServiceWorkerRegistration :: StopListening"))
     , mListener(aListener)
   {}
 
   bool
   MainThreadRun() override
   {
     mListener->StopListeningForEvents();
     return true;
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -72,17 +72,18 @@ class CreateURLRunnable : public WorkerM
 private:
   BlobImpl* mBlobImpl;
   nsAString& mURL;
 
 public:
   CreateURLRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl,
                     const mozilla::dom::objectURLOptions& aOptions,
                     nsAString& aURL)
-  : WorkerMainThreadRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate,
+                             NS_LITERAL_CSTRING("URL :: CreateURL"))
   , mBlobImpl(aBlobImpl)
   , mURL(aURL)
   {
     MOZ_ASSERT(aBlobImpl);
 
     DebugOnly<bool> isMutable;
     MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
     MOZ_ASSERT(!isMutable);
@@ -163,17 +164,18 @@ public:
 class RevokeURLRunnable : public WorkerMainThreadRunnable
 {
 private:
   const nsString mURL;
 
 public:
   RevokeURLRunnable(WorkerPrivate* aWorkerPrivate,
                     const nsAString& aURL)
-  : WorkerMainThreadRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate,
+                             NS_LITERAL_CSTRING("URL :: RevokeURL"))
   , mURL(aURL)
   {}
 
   bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
@@ -224,32 +226,34 @@ private:
   mozilla::ErrorResult& mRv;
 
   RefPtr<URLProxy> mRetval;
 
 public:
   ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
                       const nsAString& aURL, const Optional<nsAString>& aBase,
                       mozilla::ErrorResult& aRv)
-  : WorkerMainThreadRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate,
+                             NS_LITERAL_CSTRING("URL :: Constructor"))
   , mURL(aURL)
   , mRv(aRv)
   {
     if (aBase.WasPassed()) {
       mBase = aBase.Value();
     } else {
       mBase.SetIsVoid(true);
     }
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   ConstructorRunnable(WorkerPrivate* aWorkerPrivate,
                       const nsAString& aURL, URLProxy* aBaseProxy,
                       mozilla::ErrorResult& aRv)
-  : WorkerMainThreadRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate,
+                             NS_LITERAL_CSTRING("URL :: Constructor with BaseURL"))
   , mURL(aURL)
   , mBaseProxy(aBaseProxy)
   , mRv(aRv)
   {
     mBase.SetIsVoid(true);
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
@@ -321,17 +325,20 @@ public:
     GetterPathname,
     GetterSearch,
     GetterHash,
   };
 
   GetterRunnable(WorkerPrivate* aWorkerPrivate,
                  GetterType aType, nsAString& aValue,
                  URLProxy* aURLProxy)
-  : WorkerMainThreadRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate,
+                             // We can have telemetry keys for each getter when
+                             // needed.
+                             NS_LITERAL_CSTRING("URL :: getter"))
   , mValue(aValue)
   , mType(aType)
   , mURLProxy(aURLProxy)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   bool
@@ -409,17 +416,20 @@ public:
     SetterPathname,
     SetterSearch,
     SetterHash,
   };
 
   SetterRunnable(WorkerPrivate* aWorkerPrivate,
                  SetterType aType, const nsAString& aValue,
                  URLProxy* aURLProxy)
-  : WorkerMainThreadRunnable(aWorkerPrivate)
+  : WorkerMainThreadRunnable(aWorkerPrivate,
+                             // We can have telemetry keys for each setter when
+                             // needed.
+                             NS_LITERAL_CSTRING("URL :: setter"))
   , mValue(aValue)
   , mType(aType)
   , mURLProxy(aURLProxy)
   , mFailed(false)
   {
     mWorkerPrivate->AssertIsOnWorkerThread();
   }
 
--- a/dom/workers/WorkerNavigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -104,17 +104,18 @@ WorkerNavigator::GetPlatform(nsString& a
 namespace {
 
 class GetUserAgentRunnable final : public WorkerMainThreadRunnable
 {
   nsString& mUA;
 
 public:
   GetUserAgentRunnable(WorkerPrivate* aWorkerPrivate, nsString& aUA)
-    : WorkerMainThreadRunnable(aWorkerPrivate)
+    : WorkerMainThreadRunnable(aWorkerPrivate,
+                               NS_LITERAL_CSTRING("UserAgent getter"))
     , mUA(aUA)
   {
     MOZ_ASSERT(aWorkerPrivate);
     aWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   virtual bool MainThreadRun() override
   {
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -10,16 +10,17 @@
 #include "nsIEventTarget.h"
 #include "nsIGlobalObject.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/Telemetry.h"
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 #include "WorkerPrivate.h"
 #include "WorkerScope.h"
 
 USING_WORKERS_NAMESPACE
@@ -567,40 +568,48 @@ void
 MainThreadWorkerControlRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
                                               bool aDispatchResult)
 {
   AssertIsOnMainThread();
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable)
 
-WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate)
+WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
+                                                   const nsACString& aTelemetryKey)
 : mWorkerPrivate(aWorkerPrivate)
+, mTelemetryKey(aTelemetryKey)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 }
 
 void
 WorkerMainThreadRunnable::Dispatch(ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
+  TimeStamp startTime = TimeStamp::NowLoRes();
+
   AutoSyncLoopHolder syncLoop(mWorkerPrivate);
 
   mSyncLoopTarget = syncLoop.EventTarget();
   RefPtr<WorkerMainThreadRunnable> runnable(this);
 
   DebugOnly<nsresult> rv =
     NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL);
   MOZ_ASSERT(NS_SUCCEEDED(rv),
              "Should only fail after xpcom-shutdown-threads and we're gone by then");
 
   if (!syncLoop.Run()) {
     aRv.ThrowUncatchableException();
   }
+
+  Telemetry::Accumulate(Telemetry::SYNC_WORKER_OPERATION, mTelemetryKey,
+                        static_cast<uint32_t>((TimeStamp::NowLoRes() - startTime)
+                                                .ToMilliseconds()));
 }
 
 NS_IMETHODIMP
 WorkerMainThreadRunnable::Run()
 {
   AssertIsOnMainThread();
 
   bool runResult = MainThreadRun();
@@ -610,16 +619,24 @@ WorkerMainThreadRunnable::Run()
                                        mSyncLoopTarget.forget(),
                                        runResult);
 
   MOZ_ALWAYS_TRUE(response->Dispatch());
 
   return NS_OK;
 }
 
+WorkerCheckAPIExposureOnMainThreadRunnable::WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate):
+  WorkerMainThreadRunnable(aWorkerPrivate,
+                           NS_LITERAL_CSTRING("WorkerCheckAPIExposureOnMainThread"))
+{}
+
+WorkerCheckAPIExposureOnMainThreadRunnable::~WorkerCheckAPIExposureOnMainThreadRunnable()
+{}
+
 bool
 WorkerCheckAPIExposureOnMainThreadRunnable::Dispatch()
 {
   ErrorResult rv;
   WorkerMainThreadRunnable::Dispatch(rv);
   bool ok = !rv.Failed();
   rv.SuppressException();
   return ok;
--- a/dom/workers/WorkerRunnable.h
+++ b/dom/workers/WorkerRunnable.h
@@ -424,18 +424,20 @@ protected:
 // dispatch the tasks from the worker thread to the main thread.
 //
 // Note that the derived class must override MainThreadRun.
 class WorkerMainThreadRunnable : public Runnable
 {
 protected:
   WorkerPrivate* mWorkerPrivate;
   nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
+  const nsCString mTelemetryKey;
 
-  explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate);
+  explicit WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
+                                    const nsACString& aTelemetryKey);
   ~WorkerMainThreadRunnable() {}
 
   virtual bool MainThreadRun() = 0;
 
 public:
   // Dispatch the runnable to the main thread.  If dispatch to main thread
   // fails, or if the worker is shut down while dispatching, an error will be
   // reported on aRv.  In that case the error MUST be propagated out to script.
@@ -447,23 +449,24 @@ private:
 
 // Class for checking API exposure.  This totally violates the "MUST" in the
 // comments on WorkerMainThreadRunnable::Dispatch, because API exposure checks
 // can't throw.  Maybe we should change it so they _could_ throw.  But for now
 // we are bad people and should be ashamed of ourselves.  Let's hope none of
 // them happen while a worker is shutting down.
 //
 // Do NOT copy what this class is doing elsewhere.  Just don't.
-class WorkerCheckAPIExposureOnMainThreadRunnable : public WorkerMainThreadRunnable
+class WorkerCheckAPIExposureOnMainThreadRunnable
+  : public WorkerMainThreadRunnable
 {
 public:
-  explicit WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate):
-    WorkerMainThreadRunnable(aWorkerPrivate)
-  {}
-  ~WorkerCheckAPIExposureOnMainThreadRunnable() {}
+  explicit
+  WorkerCheckAPIExposureOnMainThreadRunnable(WorkerPrivate* aWorkerPrivate);
+  virtual
+  ~WorkerCheckAPIExposureOnMainThreadRunnable();
 
   // Returns whether the dispatch succeeded.  If this returns false, the API
   // should not be exposed.
   bool Dispatch();
 };
 
 END_WORKERS_NAMESPACE
 
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1496,17 +1496,18 @@ gfxUtils::GetInputStream(gfx::DataSource
 class GetFeatureStatusRunnable final : public dom::workers::WorkerMainThreadRunnable
 {
 public:
     GetFeatureStatusRunnable(dom::workers::WorkerPrivate* workerPrivate,
                              const nsCOMPtr<nsIGfxInfo>& gfxInfo,
                              int32_t feature,
                              nsACString& failureId,
                              int32_t* status)
-      : WorkerMainThreadRunnable(workerPrivate)
+      : WorkerMainThreadRunnable(workerPrivate,
+                                 NS_LITERAL_CSTRING("GFX :: GetFeatureStatus"))
       , mGfxInfo(gfxInfo)
       , mFeature(feature)
       , mStatus(status)
       , mFailureId(failureId)
       , mNSResult(NS_OK)
     {
     }
 
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -10595,10 +10595,20 @@
     "description": "Measures the size of message manager messages by message name"
   },
   "SANDBOX_BROKER_INITIALIZED": {
     "alert_emails": ["bowen@mozilla.com"],
     "bug_numbers": [1256992],
     "expires_in_version": "55",
     "kind": "boolean",
     "description": "Result of call to SandboxBroker::Initialize"
+  },
+  "SYNC_WORKER_OPERATION": {
+    "alert_emails": ["amarchesini@mozilla.com", "khuey@mozilla.com" ],
+    "bug_numbers": [1267904],
+    "expires_in_version": "never",
+    "kind": "exponential",
+    "high": 5000,
+    "n_buckets": 20,
+    "keyed": true,
+    "description": "Tracking how long a Worker thread is blocked when a sync operation is executed on the main-thread."
   }
 }