Send accumulated GPU process telemetry to the UI process. (bug 1304494 part 3, r=gfritzsche)
authorDavid Anderson <danderson@mozilla.com>
Sun, 30 Oct 2016 22:35:57 -0700
changeset 320268 ebb6abdb33b9
parent 320267 0129ae28198b
child 320269 9a76e10e5450
push id20754
push usercbook@mozilla.com
push date2016-10-31 15:58 +0000
treeherderfx-team@b1b66b1780c2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgfritzsche
bugs1304494
milestone52.0a1
Send accumulated GPU process telemetry to the UI process. (bug 1304494 part 3, r=gfritzsche)
gfx/ipc/GPUChild.cpp
gfx/ipc/GPUChild.h
gfx/ipc/GPUProcessManager.h
gfx/ipc/PGPU.ipdl
toolkit/components/telemetry/TelemetryHistogram.cpp
--- a/gfx/ipc/GPUChild.cpp
+++ b/gfx/ipc/GPUChild.cpp
@@ -132,16 +132,30 @@ GPUChild::RecvNotifyUiObservers(const ns
   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
   MOZ_ASSERT(obsSvc);
   if (obsSvc) {
     obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr);
   }
   return true;
 }
 
+bool
+GPUChild::RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations)
+{
+  Telemetry::AccumulateChild(GeckoProcessType_GPU, aAccumulations);
+  return true;
+}
+
+bool
+GPUChild::RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations)
+{
+  Telemetry::AccumulateChildKeyed(GeckoProcessType_GPU, aAccumulations);
+  return true;
+}
+
 void
 GPUChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (aWhy == AbnormalShutdown) {
 #ifdef MOZ_CRASHREPORTER
     if (mCrashReporter) {
       mCrashReporter->GenerateCrashReport(OtherPid());
       mCrashReporter = nullptr;
--- a/gfx/ipc/GPUChild.h
+++ b/gfx/ipc/GPUChild.h
@@ -33,16 +33,18 @@ public:
 
   // gfxVarReceiver overrides.
   void OnVarChanged(const GfxVarUpdate& aVar) override;
 
   // PGPUChild overrides.
   bool RecvInitComplete(const GPUDeviceData& aData) override;
   bool RecvReportCheckerboard(const uint32_t& aSeverity, const nsCString& aLog) override;
   bool RecvInitCrashReporter(Shmem&& shmem) override;
+  bool RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations) override;
+  bool RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
   void ActorDestroy(ActorDestroyReason aWhy) override;
   bool RecvGraphicsError(const nsCString& aError) override;
   bool RecvNotifyUiObservers(const nsCString& aTopic) override;
 
   static void Destroy(UniquePtr<GPUChild>&& aChild);
 
 private:
   GPUProcessHost* mHost;
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -132,16 +132,21 @@ public:
   // true if the message was sent, false if not.
   bool NotifyGpuObservers(const char* aTopic);
 
   // Returns access to the PGPU protocol if a GPU process is present.
   GPUChild* GetGPUChild() {
     return mGPUChild;
   }
 
+  // Returns whether or not a GPU process was ever launched.
+  bool AttemptedGPUProcess() const {
+    return mNumProcessAttempts > 0;
+  }
+
 private:
   // Called from our xpcom-shutdown observer.
   void OnXPCOMShutdown();
 
   bool CreateContentCompositorBridge(base::ProcessId aOtherProcess,
                                      ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint);
   bool CreateContentImageBridge(base::ProcessId aOtherProcess,
                                 ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -9,16 +9,18 @@ include protocol PImageBridge;
 include protocol PVRManager;
 include protocol PVsyncBridge;
 include protocol PVideoDecoderManager;
 
 using base::ProcessId from "base/process.h";
 using mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using mozilla::CSSToLayoutDeviceScale from "Units.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
+using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
+using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
 
 namespace mozilla {
 namespace gfx {
 
 union GfxPrefValue {
   bool;
   int32_t;
   uint32_t;
@@ -83,12 +85,16 @@ child:
   // Graphics errors, analogous to PContent::GraphicsError
   async GraphicsError(nsCString aError);
 
   async InitCrashReporter(Shmem shmem);
 
   // Have a message be broadcasted to the UI process by the UI process
   // observer service.
   async NotifyUiObservers(nsCString aTopic);
+
+  // Messages for reporting telemetry to the UI process.
+  async AccumulateChildHistogram(Accumulation[] accumulations);
+  async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
 };
 
 } // namespace gfx
 } // namespace mozilla
--- a/toolkit/components/telemetry/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/TelemetryHistogram.cpp
@@ -11,16 +11,18 @@
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsBaseHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsITelemetry.h"
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/gfx/GPUParent.h"
+#include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/StartupTimeline.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Unused.h"
 
 #include "TelemetryCommon.h"
 #include "TelemetryHistogram.h"
@@ -95,16 +97,17 @@ using mozilla::Telemetry::KeyedAccumulat
 ////////////////////////////////////////////////////////////////////////
 //
 // PRIVATE TYPES
 
 #define EXPIRED_ID "__expired__"
 #define SUBSESSION_HISTOGRAM_PREFIX "sub#"
 #define KEYED_HISTOGRAM_NAME_SEPARATOR "#"
 #define CONTENT_HISTOGRAM_SUFFIX "#content"
+#define GPU_HISTOGRAM_SUFFIX "#gpu"
 
 namespace {
 
 using mozilla::Telemetry::Common::AutoHashtable;
 using mozilla::Telemetry::Common::IsExpiredVersion;
 using mozilla::Telemetry::Common::CanRecordDataset;
 using mozilla::Telemetry::Common::IsInDataset;
 
@@ -448,34 +451,32 @@ internal_HistogramGet(const char *name, 
 // Read the process type from the given histogram name. The process type, if
 // one exists, is embedded in a suffix.
 GeckoProcessType
 GetProcessFromName(const nsACString& aString)
 {
   if (StringEndsWith(aString, NS_LITERAL_CSTRING(CONTENT_HISTOGRAM_SUFFIX))) {
     return GeckoProcessType_Content;
   }
+  if (StringEndsWith(aString, NS_LITERAL_CSTRING(GPU_HISTOGRAM_SUFFIX))) {
+    return GeckoProcessType_GPU;
+  }
   return GeckoProcessType_Default;
 }
 
-GeckoProcessType
-GetProcessFromName(const std::string& aString)
-{
-  nsDependentCString string(aString.c_str(), aString.length());
-  return GetProcessFromName(string);
-}
-
 const char*
 SuffixForProcessType(GeckoProcessType aProcessType)
 {
   switch (aProcessType) {
     case GeckoProcessType_Default:
       return nullptr;
     case GeckoProcessType_Content:
       return CONTENT_HISTOGRAM_SUFFIX;
+    case GeckoProcessType_GPU:
+      return GPU_HISTOGRAM_SUFFIX;
     default:
       MOZ_ASSERT_UNREACHABLE("unknown process type");
       return nullptr;
   }
 }
 
 CharPtrEntryType*
 internal_GetHistogramMapEntry(const char* aName)
@@ -507,26 +508,30 @@ internal_GetHistogramEnumId(const char *
 }
 
 // O(1) histogram lookup by numeric id
 nsresult
 internal_GetHistogramByEnumId(mozilla::Telemetry::ID id, Histogram **ret, GeckoProcessType aProcessType)
 {
   static Histogram* knownHistograms[mozilla::Telemetry::HistogramCount] = {0};
   static Histogram* knownContentHistograms[mozilla::Telemetry::HistogramCount] = {0};
+  static Histogram* knownGPUHistograms[mozilla::Telemetry::HistogramCount] = {0};
 
   Histogram** knownList = nullptr;
 
   switch (aProcessType) {
   case GeckoProcessType_Default:
     knownList = knownHistograms;
     break;
   case GeckoProcessType_Content:
     knownList = knownContentHistograms;
     break;
+  case GeckoProcessType_GPU:
+    knownList = knownGPUHistograms;
+    break;
   default:
     MOZ_ASSERT_UNREACHABLE("unknown process type");
     return NS_ERROR_FAILURE;
   }
 
   Histogram* h = knownList[id];
   if (h) {
     *ret = h;
@@ -634,39 +639,50 @@ internal_CloneHistogram(const nsACString
     return nullptr;
   }
 
   return internal_CloneHistogram(newName, existingId, *existing);
 }
 
 #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
 
+GeckoProcessType
+GetProcessFromName(const std::string& aString)
+{
+  nsDependentCString string(aString.c_str(), aString.length());
+  return GetProcessFromName(string);
+}
+
 Histogram*
 internal_GetSubsessionHistogram(Histogram& existing)
 {
   mozilla::Telemetry::ID id;
   nsresult rv
     = internal_GetHistogramEnumId(existing.histogram_name().c_str(), &id);
   if (NS_FAILED(rv) || gHistograms[id].keyed) {
     return nullptr;
   }
 
   static Histogram* subsession[mozilla::Telemetry::HistogramCount] = {};
   static Histogram* subsessionContent[mozilla::Telemetry::HistogramCount] = {};
+  static Histogram* subsessionGPU[mozilla::Telemetry::HistogramCount] = {};
 
   Histogram** cache = nullptr;
 
   GeckoProcessType process = GetProcessFromName(existing.histogram_name());
   switch (process) {
   case GeckoProcessType_Default:
     cache = subsession;
     break;
   case GeckoProcessType_Content:
     cache = subsessionContent;
     break;
+  case GeckoProcessType_GPU:
+    cache = subsessionGPU;
+    break;
   default:
     MOZ_ASSERT_UNREACHABLE("unknown process type");
     return nullptr;
   }
 
   if (Histogram* cached = cache[id]) {
     return cached;
   }
@@ -2079,16 +2095,23 @@ void TelemetryHistogram::InitializeGloba
       // We must create registered child keyed histograms as well or else the
       // same code in TelemetrySession.jsm that fails without parent keyed
       // histograms will fail without child keyed histograms.
       nsCString contentId(id);
       contentId.AppendLiteral(CONTENT_HISTOGRAM_SUFFIX);
       gKeyedHistograms.Put(contentId,
                            new KeyedHistogram(id, expiration, h.histogramType,
                                               h.min, h.max, h.bucketCount, h.dataset));
+
+
+      nsCString gpuId(id);
+      gpuId.AppendLiteral(GPU_HISTOGRAM_SUFFIX);
+      gKeyedHistograms.Put(gpuId,
+                           new KeyedHistogram(id, expiration, h.histogramType,
+                                              h.min, h.max, h.bucketCount, h.dataset));
     }
   }
 
   // Some Telemetry histograms depend on the value of C++ constants and hardcode
   // their values in Histograms.json.
   // We add static asserts here for those values to match so that future changes
   // don't go unnoticed.
   // TODO: Compare explicitly with gHistograms[<histogram id>].bucketCount here
@@ -2376,16 +2399,23 @@ TelemetryHistogram::CreateHistogramSnaps
                                              bool clearSubsession)
 {
   // Runs without protection from |gTelemetryHistogramMutex|
   JS::Rooted<JSObject*> root_obj(cx, JS_NewPlainObject(cx));
   if (!root_obj)
     return NS_ERROR_FAILURE;
   ret.setObject(*root_obj);
 
+  // Include the GPU process in histogram snapshots only if we actually tried
+  // to launch a process for it.
+  bool includeGPUProcess = false;
+  if (auto gpm = mozilla::gfx::GPUProcessManager::Get()) {
+    includeGPUProcess = gpm->AttemptedGPUProcess();
+  }
+
   // Ensure that all the HISTOGRAM_FLAG & HISTOGRAM_COUNT histograms have
   // been created, so that their values are snapshotted.
   for (size_t i = 0; i < mozilla::Telemetry::HistogramCount; ++i) {
     if (gHistograms[i].keyed) {
       continue;
     }
     const uint32_t type = gHistograms[i].histogramType;
     if (type == nsITelemetry::HISTOGRAM_FLAG ||
@@ -2394,16 +2424,21 @@ TelemetryHistogram::CreateHistogramSnaps
       mozilla::DebugOnly<nsresult> rv;
       mozilla::Telemetry::ID id = mozilla::Telemetry::ID(i);
 
       rv = internal_GetHistogramByEnumId(id, &h, GeckoProcessType_Default);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
 
       rv = internal_GetHistogramByEnumId(id, &h, GeckoProcessType_Content);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+      if (includeGPUProcess) {
+        rv = internal_GetHistogramByEnumId(id, &h, GeckoProcessType_GPU);
+        MOZ_ASSERT(NS_SUCCEEDED(rv));
+      }
     }
   }
 
   StatisticsRecorder::Histograms hs;
   StatisticsRecorder::GetHistograms(&hs);
 
   // We identify corrupt histograms first, rather than interspersing it
   // in the loop below, to ensure that our corruption statistics don't
@@ -2682,23 +2717,42 @@ TelemetryHistogram::IPCTimerFired(nsITim
     if (gAccumulations) {
       accumulationsToSend.SwapElements(*gAccumulations);
     }
     if (gKeyedAccumulations) {
       keyedAccumulationsToSend.SwapElements(*gKeyedAccumulations);
     }
   }
 
-  mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton();
-  mozilla::Unused << NS_WARN_IF(!contentChild);
-  if (contentChild) {
-    if (accumulationsToSend.Length()) {
-      mozilla::Unused <<
-        NS_WARN_IF(!contentChild->SendAccumulateChildHistogram(accumulationsToSend));
+  switch (XRE_GetProcessType()) {
+    case GeckoProcessType_Content: {
+      mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton();
+      mozilla::Unused << NS_WARN_IF(!contentChild);
+      if (contentChild) {
+        if (accumulationsToSend.Length()) {
+          mozilla::Unused <<
+            NS_WARN_IF(!contentChild->SendAccumulateChildHistogram(accumulationsToSend));
+        }
+        if (keyedAccumulationsToSend.Length()) {
+          mozilla::Unused <<
+            NS_WARN_IF(!contentChild->SendAccumulateChildKeyedHistogram(keyedAccumulationsToSend));
+        }
+      }
+      break;
     }
-    if (keyedAccumulationsToSend.Length()) {
-      mozilla::Unused <<
-        NS_WARN_IF(!contentChild->SendAccumulateChildKeyedHistogram(keyedAccumulationsToSend));
+    case GeckoProcessType_GPU: {
+      if (mozilla::gfx::GPUParent* gpu = mozilla::gfx::GPUParent::GetSingleton()) {
+        if (accumulationsToSend.Length()) {
+          mozilla::Unused << gpu->SendAccumulateChildHistogram(accumulationsToSend);
+        }
+        if (keyedAccumulationsToSend.Length()) {
+          mozilla::Unused << gpu->SendAccumulateChildKeyedHistogram(keyedAccumulationsToSend);
+        }
+      }
+      break;
     }
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unsupported process type");
+      break;
   }
 
   gIPCTimerArmed = false;
 }