Bug 1162364 - Report telemetry on WMFMediaDataDecoder errors. r=cpearce, f=vladan, f=bsmedberg, a=sledru
authorKarl Tomlinson <karlt+@karlt.net>
Wed, 13 May 2015 17:54:31 +1200
changeset 274906 22e1e8e0eb6c3932f6b8b66689264517063c0cdb
parent 274905 580fbd9d7778a9233d30312827bb552c90cafbbc
child 274907 ed87acf8cc926a5caa037941d01c22caea5950a9
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sledru
bugs1162364
milestone40.0a2
Bug 1162364 - Report telemetry on WMFMediaDataDecoder errors. r=cpearce, f=vladan, f=bsmedberg, a=sledru
dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
dom/media/fmp4/wmf/WMFMediaDataDecoder.h
dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
toolkit/components/telemetry/Histograms.json
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp
@@ -3,16 +3,17 @@
 /* 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 "WMFMediaDataDecoder.h"
 #include "VideoUtils.h"
 #include "WMFUtils.h"
 #include "nsTArray.h"
+#include "mozilla/Telemetry.h"
 
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define LOG(...)
@@ -44,16 +45,49 @@ WMFMediaDataDecoder::Init()
   MOZ_ASSERT(!mIsShutDown);
 
   mDecoder = mMFTManager->Init();
   NS_ENSURE_TRUE(mDecoder, NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
+// A single telemetry sample is reported for each MediaDataDecoder object
+// that has detected error or produced output successfully.
+static void
+SendTelemetry(HRESULT hr)
+{
+  // Collapse the error codes into a range of 0-0xff that can be viewed in
+  // telemetry histograms.  For most MF_E_* errors, unique samples are used,
+  // retaining the least significant 7 or 8 bits.  Other error codes are
+  // bucketed.
+  uint32_t sample;
+  if (SUCCEEDED(hr)) {
+    sample = 0;
+  } else if (hr < 0xc00d36b0) {
+    sample = 1; // low bucket
+  } else if (hr < 0xc00d3700) {
+    sample = hr & 0xffU; // MF_E_*
+  } else if (hr <= 0xc00d3705) {
+    sample = 0x80 + (hr & 0xfU); // more MF_E_*
+  } else if (hr < 0xc00d6d60) {
+    sample = 2; // mid bucket
+  } else if (hr <= 0xc00d6d78) {
+    sample = hr & 0xffU; // MF_E_TRANSFORM_*
+  } else {
+    sample = 3; // high bucket
+  }
+
+  nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
+    [sample] {
+      Telemetry::Accumulate(Telemetry::MEDIA_WMF_DECODE_ERROR, sample);
+    });
+  NS_DispatchToMainThread(runnable);
+}
+
 nsresult
 WMFMediaDataDecoder::Shutdown()
 {
   MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown);
 
   if (mTaskQueue) {
     mTaskQueue->Dispatch(
       NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown));
@@ -65,16 +99,19 @@ WMFMediaDataDecoder::Shutdown()
 }
 
 void
 WMFMediaDataDecoder::ProcessShutdown()
 {
   if (mMFTManager) {
     mMFTManager->Shutdown();
     mMFTManager = nullptr;
+    if (!mRecordedError && mHasSuccessfulOutput) {
+      SendTelemetry(S_OK);
+    }
   }
   mDecoder = nullptr;
 }
 
 // Inserts data into the decoder's pipeline.
 nsresult
 WMFMediaDataDecoder::Input(MediaRawData* aSample)
 {
@@ -100,40 +137,49 @@ WMFMediaDataDecoder::ProcessDecode(Media
       return;
     }
   }
 
   HRESULT hr = mMFTManager->Input(aSample);
   if (FAILED(hr)) {
     NS_WARNING("MFTManager rejected sample");
     mCallback->Error();
+    if (!mRecordedError) {
+      SendTelemetry(hr);
+      mRecordedError = true;
+    }
     return;
   }
 
   mLastStreamOffset = aSample->mOffset;
 
   ProcessOutput();
 }
 
 void
 WMFMediaDataDecoder::ProcessOutput()
 {
   nsRefPtr<MediaData> output;
   HRESULT hr = S_OK;
   while (SUCCEEDED(hr = mMFTManager->Output(mLastStreamOffset, output)) &&
          output) {
+    mHasSuccessfulOutput = true;
     mCallback->Output(output);
   }
   if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
     if (mTaskQueue->IsEmpty()) {
       mCallback->InputExhausted();
     }
   } else if (FAILED(hr)) {
     NS_WARNING("WMFMediaDataDecoder failed to output data");
     mCallback->Error();
+    if (!mRecordedError) {
+      SendTelemetry(hr);
+      mRecordedError = true;
+    }
   }
 }
 
 void
 WMFMediaDataDecoder::ProcessFlush()
 {
   if (mDecoder) {
     mDecoder->Flush();
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -104,13 +104,17 @@ private:
   // For access to and waiting on mIsFlushing
   Monitor mMonitor;
   // Set on reader/decode thread calling Flush() to indicate that output is
   // not required and so input samples on mTaskQueue need not be processed.
   // Cleared on mTaskQueue.
   bool mIsFlushing;
 
   bool mIsShutDown;
+
+  // For telemetry
+  bool mHasSuccessfulOutput = false;
+  bool mRecordedError = false;
 };
 
 } // namespace mozilla
 
 #endif // WMFMediaDataDecoder_h_
--- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp
@@ -495,17 +495,17 @@ WMFVideoMFTManager::Output(int64_t aStre
       ++typeChangeCount;
       continue;
     }
     if (SUCCEEDED(hr)) {
       break;
     }
     // Else unexpected error, assert, and bail.
     NS_WARNING("WMFVideoMFTManager::Output() unexpected error");
-    return E_FAIL;
+    return hr;
   }
 
   nsRefPtr<VideoData> frame;
   if (mUseHwAccel) {
     hr = CreateD3DVideoFrame(sample, aStreamOffset, getter_AddRefs(frame));
   } else {
     hr = CreateBasicVideoFrame(sample, aStreamOffset, getter_AddRefs(frame));
   }
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5535,16 +5535,22 @@
   },
   "DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETHREAD_MS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "10000",
     "n_buckets": "1000",
     "description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip."
   },
+  "MEDIA_WMF_DECODE_ERROR": {
+    "expires_in_version": "50",
+    "kind": "enumerated",
+    "n_values": 256,
+    "description": "WMF media decoder error or success (0) codes."
+  },
   "VIDEO_CANPLAYTYPE_H264_CONSTRAINT_SET_FLAG": {
     "expires_in_version": "50",
     "kind": "enumerated",
     "n_values": 128,
     "description": "The H.264 constraint set flag as extracted from the codecs parameter passed to HTMLMediaElement.canPlayType, with the addition of 0 for unknown values."
   },
   "VIDEO_CANPLAYTYPE_H264_LEVEL": {
     "expires_in_version": "50",