Bug 1393399 P2 - keep the GPU process crash time and send back to MFR; draft
authorKaku Kuo <kaku@mozilla.com>
Thu, 31 Aug 2017 17:21:28 +0800
changeset 657859 66b90044a9efe8f05d2729c550f6eb2753a60941
parent 657858 ef1aeda098d9e205081303f3d7ec0c067a4dcf93
child 657860 49f4c2f7de4bd619ce03ff3e64be8892c5f37b50
push id77648
push userbmo:kaku@mozilla.com
push dateSat, 02 Sep 2017 06:37:18 +0000
bugs1393399
milestone57.0a1
Bug 1393399 P2 - keep the GPU process crash time and send back to MFR; We keep the GPU crash time and send back to MFR through MediaResult. We cannot save the information in VideoDecoderChild as a static member because we are going to read it in MFR's task queue and the data was written in VideoDecoderManager's thread. This is going to be racing. MozReview-Commit-ID: FXqOgelWY6e
dom/media/MediaResult.h
dom/media/ipc/VideoDecoderChild.cpp
dom/media/ipc/VideoDecoderChild.h
--- a/dom/media/MediaResult.h
+++ b/dom/media/MediaResult.h
@@ -4,16 +4,17 @@
  * 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/. */
 
 #ifndef MediaResult_h_
 #define MediaResult_h_
 
 #include "nsString.h" // Required before 'mozilla/ErrorNames.h'!?
 #include "mozilla/ErrorNames.h"
+#include "mozilla/TimeStamp.h"
 #include "nsError.h"
 #include "nsPrintfCString.h"
 
 // MediaResult can be used interchangeably with nsresult.
 // It allows to store extra information such as where the error occurred.
 // While nsresult is typically passed by value; due to its potential size, using
 // MediaResult const references is recommended.
 namespace mozilla {
@@ -57,19 +58,23 @@ public:
     GetErrorName(mCode, static_cast<nsACString&>(name));
     return nsPrintfCString("%s (0x%08" PRIx32 ")%s%s",
                            name.get(),
                            static_cast<uint32_t>(mCode),
                            mMessage.IsEmpty() ? "" : " - ",
                            mMessage.get());
   }
 
+  void SetGPUCrashTimeStamp(const TimeStamp& aTime) { mGPUCrashTimeStamp = aTime; }
+  const TimeStamp& GPUCrashTimeStamp() const { return mGPUCrashTimeStamp; }
+
 private:
   nsresult mCode;
   nsCString mMessage;
+  TimeStamp mGPUCrashTimeStamp; // Used in bug 1393399 for temporary telemetry usage.
 };
 
 #ifdef _MSC_VER
 #define RESULT_DETAIL(arg, ...) nsPrintfCString("%s: " arg, __FUNCSIG__, ##__VA_ARGS__)
 #else
 #define RESULT_DETAIL(arg, ...) nsPrintfCString("%s: " arg, __PRETTY_FUNCTION__, ##__VA_ARGS__)
 #endif
 
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -135,35 +135,36 @@ VideoDecoderChild::RecvFlushComplete()
   mFlushPromise.ResolveIfExists(true, __func__);
   return IPC_OK();
 }
 
 void
 VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (aWhy == AbnormalShutdown) {
+    // GPU process crashed, record the time and send back to MFR for telemetry.
+    mGPUCrashTime = TimeStamp::Now();
+
     // Defer reporting an error until we've recreated the manager so that
     // it'll be safe for MediaFormatReader to recreate decoders
     RefPtr<VideoDecoderChild> ref = this;
     GetManager()->RunWhenRecreated(
       NS_NewRunnableFunction("dom::VideoDecoderChild::ActorDestroy", [=]() {
+        MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+        error.SetGPUCrashTimeStamp(ref->mGPUCrashTime);
         if (ref->mInitialized) {
           mDecodedData.Clear();
-          mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
-                                        __func__);
-          mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
-                                       __func__);
-          mFlushPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
-                                       __func__);
+          mDecodePromise.RejectIfExists(error, __func__);
+          mDrainPromise.RejectIfExists(error, __func__);
+          mFlushPromise.RejectIfExists(error, __func__);
           // Make sure the next request will be rejected accordingly if ever
           // called.
           mNeedNewDecoder = true;
         } else {
-          ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
-                                           __func__);
+          ref->mInitPromise.RejectIfExists(error, __func__);
         }
       }));
   }
   mCanSend = false;
 
 #ifdef XP_WIN
   ReportUnblacklistingTelemetry(aWhy == AbnormalShutdown,
                                 mBlacklistedD3D11Driver,
@@ -240,18 +241,19 @@ VideoDecoderChild::Init()
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 VideoDecoderChild::Decode(MediaRawData* aSample)
 {
   AssertOnManagerThread();
 
   if (mNeedNewDecoder) {
-    return MediaDataDecoder::DecodePromise::CreateAndReject(
-      NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+    MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+    error.SetGPUCrashTimeStamp(mGPUCrashTime);
+    return MediaDataDecoder::DecodePromise::CreateAndReject(error, __func__);
   }
   if (!mCanSend) {
     // We're here if the IPC channel has died but we're still waiting for the
     // RunWhenRecreated task to complete. The decode promise will be rejected
     // when that task is run.
     return mDecodePromise.Ensure(__func__);
   }
 
@@ -279,32 +281,34 @@ VideoDecoderChild::Decode(MediaRawData* 
 
 RefPtr<MediaDataDecoder::FlushPromise>
 VideoDecoderChild::Flush()
 {
   AssertOnManagerThread();
   mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   if (mNeedNewDecoder) {
-    return MediaDataDecoder::FlushPromise::CreateAndReject(
-      NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+    MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+    error.SetGPUCrashTimeStamp(mGPUCrashTime);
+    return MediaDataDecoder::FlushPromise::CreateAndReject(error, __func__);
   }
   if (mCanSend) {
     SendFlush();
   }
   return mFlushPromise.Ensure(__func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 VideoDecoderChild::Drain()
 {
   AssertOnManagerThread();
   if (mNeedNewDecoder) {
-    return MediaDataDecoder::DecodePromise::CreateAndReject(
-      NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
+    MediaResult error(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER);
+    error.SetGPUCrashTimeStamp(mGPUCrashTime);
+    return MediaDataDecoder::DecodePromise::CreateAndReject(error, __func__);
   }
   if (mCanSend) {
     SendDrain();
   }
   return mDrainPromise.Ensure(__func__);
 }
 
 void
--- a/dom/media/ipc/VideoDecoderChild.h
+++ b/dom/media/ipc/VideoDecoderChild.h
@@ -77,14 +77,15 @@ private:
 
   // Set to true if the actor got destroyed and we haven't yet notified the
   // caller.
   bool mNeedNewDecoder;
   MediaDataDecoder::DecodedData mDecodedData;
 
   nsCString mBlacklistedD3D11Driver;
   nsCString mBlacklistedD3D9Driver;
+  TimeStamp mGPUCrashTime;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // include_dom_ipc_VideoDecoderChild_h