Bug 781124 - Report CPU usage for hung flash processes. r=bsmedberg
authorGeorg Fritzsche <georg.fritzsche@googlemail.com>
Thu, 09 Aug 2012 12:36:30 +0200
changeset 102929 4c81cb568cb40a56f5466c38e83226c28436c825
parent 102928 6cfd16fe1cb3052056e9be8e99a44b70d1453bc9
child 102930 03dd9481be201b3283b0b840979d9e21015f3d94
push id23317
push userryanvm@gmail.com
push dateWed, 22 Aug 2012 02:05:02 +0000
treeherdermozilla-central@abc17059522b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs781124
milestone17.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 781124 - Report CPU usage for hung flash processes. r=bsmedberg
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -105,17 +105,17 @@ PluginModuleParent::PluginModuleParent(c
     : mSubprocess(new PluginProcessParent(aFilePath))
     , mShutdown(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(NULL)
     , mPlugin(NULL)
     , mTaskFactory(this)
 #ifdef XP_WIN
-    , mPluginCpuUsageOnHang(-1)
+    , mPluginCpuUsageOnHang()
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , mFlashProcess1(0)
     , mFlashProcess2(0)
 #endif
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
 
@@ -173,23 +173,31 @@ PluginModuleParent::WriteExtraDataForMin
     notes.Put(CS("PluginVersion"), CS(""));
 
     CrashReporterParent* crashReporter = CrashReporter();
     if (crashReporter) {
         const nsString& hangID = crashReporter->HangID();
         if (!hangID.IsEmpty()) {
             notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
 #ifdef XP_WIN
-            if (mPluginCpuUsageOnHang >= 0) {
+            if (mPluginCpuUsageOnHang.Length() > 0) {
+              notes.Put(CS("NumberOfProcessors"),
+                        nsPrintfCString("%d", PR_GetNumberOfProcessors()));
+
               nsCString cpuUsageStr;
-              cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang * 100) / 100);
+              cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
               notes.Put(CS("PluginCpuUsage"), cpuUsageStr);
 
-              notes.Put(CS("NumberOfProcessors"),
-                        nsPrintfCString("%d", PR_GetNumberOfProcessors()));
+#ifdef MOZ_CRASHREPORTER_INJECTOR
+              for (PRUint32 i=1; i<mPluginCpuUsageOnHang.Length(); ++i) {
+                nsCString tempStr;
+                tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100);
+                notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr);
+              }
+#endif
             }
 #endif
         }
     }
 }
 #endif  // MOZ_CRASHREPORTER
 
 int
@@ -224,51 +232,64 @@ PRUint64
 FileTimeToUTC(const FILETIME& ftime) 
 {
   ULARGE_INTEGER li;
   li.LowPart = ftime.dwLowDateTime;
   li.HighPart = ftime.dwHighDateTime;
   return li.QuadPart;
 }
 
+struct CpuUsageSamples
+{
+  PRUint64 sampleTimes[2];
+  PRUint64 cpuTimes[2];
+};
+
 bool 
-GetProcessCpuUsage(const base::ProcessHandle& processHandle, float& cpuUsage)
+GetProcessCpuUsage(const InfallibleTArray<base::ProcessHandle>& processHandles, InfallibleTArray<float>& cpuUsage)
 {
+  InfallibleTArray<CpuUsageSamples> samples(processHandles.Length());
   FILETIME creationTime, exitTime, kernelTime, userTime, currentTime;
   BOOL res;
 
-  ::GetSystemTimeAsFileTime(&currentTime);
-  res = ::GetProcessTimes(processHandle, &creationTime, &exitTime, &kernelTime, &userTime);
-  if (!res) {
-    NS_WARNING("failed to get process times");
-    return false;
+  for (PRUint32 i = 0; i < processHandles.Length(); ++i) {
+    ::GetSystemTimeAsFileTime(&currentTime);
+    res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
+    if (!res) {
+      NS_WARNING("failed to get process times");
+      return false;
+    }
+  
+    CpuUsageSamples s;
+    s.sampleTimes[0] = FileTimeToUTC(currentTime);
+    s.cpuTimes[0]    = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
+    samples.AppendElement(s);
   }
 
-  PRUint64 sampleTimes[2];
-  PRUint64 cpuTimes[2];
-  
-  sampleTimes[0] = FileTimeToUTC(currentTime);
-  cpuTimes[0]    = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);
-
   // we already hung for a while, a little bit longer won't matter
   ::Sleep(50);
 
-  ::GetSystemTimeAsFileTime(&currentTime);
-  res = ::GetProcessTimes(processHandle, &creationTime, &exitTime, &kernelTime, &userTime);
-  if (!res) {
-    NS_WARNING("failed to get process times");
-    return false;
-  }
+  const PRInt32 numberOfProcessors = PR_GetNumberOfProcessors();
 
-  sampleTimes[1] = FileTimeToUTC(currentTime);
-  cpuTimes[1]    = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);    
+  for (PRUint32 i = 0; i < processHandles.Length(); ++i) {
+    ::GetSystemTimeAsFileTime(&currentTime);
+    res = ::GetProcessTimes(processHandles[i], &creationTime, &exitTime, &kernelTime, &userTime);
+    if (!res) {
+      NS_WARNING("failed to get process times");
+      return false;
+    }
 
-  const PRUint64 deltaSampleTime = sampleTimes[1] - sampleTimes[0];
-  const PRUint64 deltaCpuTime    = cpuTimes[1]    - cpuTimes[0];
-  cpuUsage = 100.f * (float(deltaCpuTime) / deltaSampleTime) / PR_GetNumberOfProcessors();
+    samples[i].sampleTimes[1] = FileTimeToUTC(currentTime);
+    samples[i].cpuTimes[1]    = FileTimeToUTC(kernelTime) + FileTimeToUTC(userTime);    
+
+    const PRUint64 deltaSampleTime = samples[i].sampleTimes[1] - samples[i].sampleTimes[0];
+    const PRUint64 deltaCpuTime    = samples[i].cpuTimes[1]    - samples[i].cpuTimes[0];
+    const float usage = 100.f * (float(deltaCpuTime) / deltaSampleTime) / numberOfProcessors;
+    cpuUsage.AppendElement(usage);
+  }
 
   return true;
 }
 
 } // anonymous namespace
 #endif // #ifdef XP_WIN
 
 bool
@@ -285,19 +306,33 @@ PluginModuleParent::ShouldContinueFromRe
                  NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
                  NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
     } else {
         NS_WARNING("failed to capture paired minidumps from hang");
     }
 #endif
 
 #ifdef XP_WIN
-    float cpuUsage;
-    if (GetProcessCpuUsage(OtherProcess(), cpuUsage)) {
-      mPluginCpuUsageOnHang = cpuUsage;
+    // collect cpu usage for plugin processes
+
+    InfallibleTArray<base::ProcessHandle> processHandles;
+    base::ProcessHandle handle;
+
+    processHandles.AppendElement(OtherProcess());
+#ifdef MOZ_CRASHREPORTER_INJECTOR
+    if (mFlashProcess1 && base::OpenProcessHandle(mFlashProcess1, &handle)) {
+      processHandles.AppendElement(handle);
+    }
+    if (mFlashProcess2 && base::OpenProcessHandle(mFlashProcess2, &handle)) {
+      processHandles.AppendElement(handle);
+    }
+#endif
+
+    if (!GetProcessCpuUsage(processHandles, mPluginCpuUsageOnHang)) {
+      mPluginCpuUsageOnHang.Clear();
     }
 #endif
 
     // this must run before the error notification from the channel,
     // or not at all
     MessageLoop::current()->PostTask(
         FROM_HERE,
         mTaskFactory.NewRunnableMethod(
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -297,17 +297,17 @@ private:
     const NPNetscapeFuncs* mNPNIface;
     nsDataHashtable<nsPtrHashKey<void>, PluginIdentifierParent*> mIdentifiers;
     nsNPAPIPlugin* mPlugin;
     ScopedRunnableMethodFactory<PluginModuleParent> mTaskFactory;
     nsString mPluginDumpID;
     nsString mBrowserDumpID;
     nsString mHangID;
 #ifdef XP_WIN
-    float mPluginCpuUsageOnHang;
+    InfallibleTArray<float> mPluginCpuUsageOnHang;
 #endif
 
 #ifdef MOZ_X11
     // Dup of plugin's X socket, used to scope its resources to this
     // object instead of the plugin process's lifetime
     ScopedClose mPluginXSocketFdDup;
 #endif