Bug 815709 - Shutdown time is read in the main thread. r=ehsan.
authorRafael Ávila de Espíndola <respindola@mozilla.org>
Thu, 13 Dec 2012 12:06:27 -0500
changeset 115941 2e34b7c8a339ae3e092e918bd6e16e6ea7eb9bb0
parent 115940 1868793fca42237be3ce0dbdd4f496f21e571b45
child 115942 2aae75e86935f2bec86fef0826c095600620b905
push id24034
push useremorley@mozilla.com
push dateFri, 14 Dec 2012 15:28:57 +0000
treeherdermozilla-central@50d8f411d305 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs815709
milestone20.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 815709 - Shutdown time is read in the main thread. r=ehsan. Move code to Telemetry.cpp and s/NULL/nullptr/.
toolkit/components/startup/StartupTimeline.h
toolkit/components/startup/nsAppStartup.cpp
toolkit/components/startup/nsAppStartup.h
toolkit/components/startup/public/nsIAppStartup.idl
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/TelemetryPing.js
toolkit/components/telemetry/nsITelemetry.idl
--- a/toolkit/components/startup/StartupTimeline.h
+++ b/toolkit/components/startup/StartupTimeline.h
@@ -35,16 +35,17 @@ NS_VISIBILITY_DEFAULT __attribute__((wea
 } /* extern "C" */
 #else
 
 #endif
 
 namespace mozilla {
 
 void RecordShutdownEndTimeStamp();
+void RecordShutdownStartTimeStamp();
 
 class StartupTimeline {
 public:
   enum Event {
     #define mozilla_StartupTimeline_Event(ev, z) ev,
     #include "StartupTimeline.h"
     #undef mozilla_StartupTimeline_Event
     MAX_EVENT_ID
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -158,19 +158,17 @@ public:
 nsAppStartup::nsAppStartup() :
   mConsiderQuitStopper(0),
   mRunning(false),
   mShuttingDown(false),
   mAttemptingQuit(false),
   mRestart(false),
   mInterrupted(false),
   mIsSafeModeNecessary(false),
-  mStartupCrashTrackingEnded(false),
-  mCachedShutdownTime(false),
-  mLastShutdownTime(0)
+  mStartupCrashTrackingEnded(false)
 { }
 
 
 nsresult
 nsAppStartup::Init()
 {
   nsresult rv;
 
@@ -291,110 +289,34 @@ nsAppStartup::Run(void)
     nsresult rv = mAppShell->Run();
     if (NS_FAILED(rv))
       return rv;
   }
 
   return mRestart ? NS_SUCCESS_RESTART_APP : NS_OK;
 }
 
-static TimeStamp gRecordedShutdownStartTime;
-static bool gAlreadyFreedShutdownTimeFileName = false;
-static char *gRecordedShutdownTimeFileName = NULL;
 
-static char *
-GetShutdownTimeFileName()
-{
-  if (gAlreadyFreedShutdownTimeFileName) {
-    return NULL;
-  }
-
-  if (!gRecordedShutdownTimeFileName) {
-    nsCOMPtr<nsIFile> mozFile;
-    NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
-    if (!mozFile)
-      return NULL;
-
-    mozFile->AppendNative(NS_LITERAL_CSTRING("Telemetry.ShutdownTime.txt"));
-    nsAutoCString nativePath;
-    nsresult rv = mozFile->GetNativePath(nativePath);
-    if (!NS_SUCCEEDED(rv))
-      return NULL;
-
-    gRecordedShutdownTimeFileName = PL_strdup(nativePath.get());
-  }
-
-  return gRecordedShutdownTimeFileName;
-}
-
-static void
-RecordShutdownStartTimeStamp() {
-  if (!Telemetry::CanRecord())
-    return;
-
-  gRecordedShutdownStartTime = TimeStamp::Now();
-
-  GetShutdownTimeFileName();
-}
-
-namespace mozilla {
-void
-RecordShutdownEndTimeStamp() {
-  if (!gRecordedShutdownTimeFileName || gAlreadyFreedShutdownTimeFileName)
-    return;
-
-  nsCString name(gRecordedShutdownTimeFileName);
-  PL_strfree(gRecordedShutdownTimeFileName);
-  gRecordedShutdownTimeFileName = NULL;
-  gAlreadyFreedShutdownTimeFileName = true;
-
-  nsCString tmpName = name;
-  tmpName += ".tmp";
-  FILE *f = fopen(tmpName.get(), "w");
-  if (!f)
-    return;
-  // On a normal release build this should be called just before
-  // calling _exit, but on a debug build or when the user forces a full
-  // shutdown this is called as late as possible, so we have to
-  // white list this write as write poisoning will be enabled.
-  int fd = fileno(f);
-  MozillaRegisterDebugFD(fd);
-
-  TimeStamp now = TimeStamp::Now();
-  MOZ_ASSERT(now >= gRecordedShutdownStartTime);
-  TimeDuration diff = now - gRecordedShutdownStartTime;
-  uint32_t diff2 = diff.ToMilliseconds();
-  int written = fprintf(f, "%d\n", diff2);
-  MozillaUnRegisterDebugFILE(f);
-  int rv = fclose(f);
-  if (written < 0 || rv != 0) {
-    PR_Delete(tmpName.get());
-    return;
-  }
-  PR_Delete(name.get());
-  PR_Rename(tmpName.get(), name.get());
-}
-}
 
 NS_IMETHODIMP
 nsAppStartup::Quit(uint32_t aMode)
 {
   uint32_t ferocity = (aMode & 0xF);
 
   // Quit the application. We will asynchronously call the appshell's
   // Exit() method via nsAppExitEvent to allow one last pass
   // through any events in the queue. This guarantees a tidy cleanup.
   nsresult rv = NS_OK;
   bool postedExitEvent = false;
 
   if (mShuttingDown)
     return NS_OK;
 
   SAMPLE_MARKER("Shutdown start");
-  RecordShutdownStartTimeStamp();
+  mozilla::RecordShutdownStartTimeStamp();
 
   // If we're considering quitting, we will only do so if:
   if (ferocity == eConsiderQuit) {
     if (mConsiderQuitStopper == 0) {
       // there are no windows...
       ferocity = eAttemptQuit;
     }
 #ifdef XP_MACOSX
@@ -583,57 +505,16 @@ nsAppStartup::ExitLastWindowClosingSurvi
   --mConsiderQuitStopper;
 
   if (mRunning)
     Quit(eConsiderQuit);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsAppStartup::GetLastShutdownDuration(uint32_t *aResult)
-{
-  // We make this check so that GetShutdownTimeFileName() doesn't get
-  // called; calling that function without telemetry enabled violates
-  // assumptions that the write-the-shutdown-timestamp machinery makes.
-  if (!Telemetry::CanRecord()) {
-    *aResult = 0;
-    return NS_OK;
-  }
-
-  if (!mCachedShutdownTime) {
-    const char *filename = GetShutdownTimeFileName();
-
-    if (!filename) {
-      *aResult = 0;
-      return NS_OK;
-    }
-
-    FILE *f = fopen(filename, "r");
-    if (!f) {
-      *aResult = 0;
-      return NS_OK;
-    }
-
-    int shutdownTime;
-    int r = fscanf(f, "%d\n", &shutdownTime);
-    fclose(f);
-    if (r != 1) {
-      *aResult = 0;
-      return NS_OK;
-    }
-
-    mLastShutdownTime = shutdownTime;
-    mCachedShutdownTime = true;
-  }
-
-  *aResult = mLastShutdownTime;
-  return NS_OK;
-}
-
 //
 // nsAppStartup->nsIAppStartup2
 //
 
 NS_IMETHODIMP
 nsAppStartup::GetShuttingDown(bool *aResult)
 {
   *aResult = mShuttingDown;
--- a/toolkit/components/startup/nsAppStartup.h
+++ b/toolkit/components/startup/nsAppStartup.h
@@ -56,18 +56,16 @@ private:
   int32_t      mConsiderQuitStopper; // if > 0, Quit(eConsiderQuit) fails
   bool mRunning;        // Have we started the main event loop?
   bool mShuttingDown;   // Quit method reentrancy check
   bool mAttemptingQuit; // Quit(eAttemptQuit) still trying
   bool mRestart;        // Quit(eRestart)
   bool mInterrupted;    // Was startup interrupted by an interactive prompt?
   bool mIsSafeModeNecessary;       // Whether safe mode is necessary
   bool mStartupCrashTrackingEnded; // Whether startup crash tracking has already ended
-  bool mCachedShutdownTime;
-  uint32_t mLastShutdownTime;
 
 #if defined(XP_WIN)
   //Interaction with OS-provided profiling probes
   typedef mozilla::probes::ProbeManager ProbeManager;
   typedef mozilla::probes::Probe        Probe;
   nsRefPtr<ProbeManager> mProbesManager;
   nsRefPtr<Probe> mPlacesInitCompleteProbe;
   nsRefPtr<Probe> mSessionWindowRestoredProbe;
--- a/toolkit/components/startup/public/nsIAppStartup.idl
+++ b/toolkit/components/startup/public/nsIAppStartup.idl
@@ -2,17 +2,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 "nsISupports.idl"
 
 interface nsICmdLineService;
 
-[scriptable, uuid(5016bc45-54d9-4f97-935c-df4cef4b999f)]
+[scriptable, uuid(2b51b67f-6f05-4145-b37e-7369bbc92b19)]
 interface nsIAppStartup : nsISupports
 {
     /**
      * Create the hidden window.
      */
     void createHiddenWindow();
 
     /**
@@ -38,22 +38,16 @@ interface nsIAppStartup : nsISupports
      * closed but we don't want to take this as a signal to quit the
      * app. Bracket the code where the last window could close with
      * these.
      */
     void enterLastWindowClosingSurvivalArea();
     void exitLastWindowClosingSurvivalArea();
 
     /**
-     * The amount of time, in milliseconds, that the last session took
-     * to shutdown.  Reads as 0 to indicate failure.
-     */
-    readonly attribute uint32_t lastShutdownDuration;
-
-    /**
      * Startup Crash Detection
      *
      * Keeps track of application startup begining and success using flags to
      * determine whether the application is crashing on startup.
      * When the number of crashes crosses the acceptable threshold, safe mode
      * or other repair procedures are performed.
      */
 
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -19,22 +19,25 @@
 #include "nsIFile.h"
 #include "nsIMemoryReporter.h"
 #include "Telemetry.h" 
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "nsBaseHashtable.h"
 #include "nsXULAppAPI.h"
 #include "nsThreadUtils.h"
+#include "plstr.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "mozilla/ProcessedStack.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
+#include "mozilla/mozPoisonWrite.h"
 
 namespace {
 
 using namespace base;
 using namespace mozilla;
 
 template<class EntryType>
 class AutoHashtable : public nsTHashtable<EntryType>
@@ -308,16 +311,19 @@ private:
   AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
   // This gets marked immutable in debug builds, so we can't use
   // AutoHashtable here.
   nsTHashtable<nsCStringHashKey> mTrackedDBs;
   Mutex mHashMutex;
   HangReports mHangReports;
   Mutex mHangReportsMutex;
   nsIMemoryReporter *mMemoryReporter;
+
+  bool mCachedShutdownTime;
+  uint32_t mLastShutdownTime;
 };
 
 TelemetryImpl*  TelemetryImpl::sTelemetry = NULL;
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(TelemetryMallocSizeOf, "telemetry")
 
 size_t
 TelemetryImpl::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf)
@@ -675,21 +681,93 @@ WrapAndReturnHistogram(Histogram *h, JSC
         && JS_DefineFunction(cx, obj, "clear", JSHistogram_Clear, 0, 0))) {
     return NS_ERROR_FAILURE;
   }
   *ret = OBJECT_TO_JSVAL(obj);
   JS_SetPrivate(obj, h);
   return NS_OK;
 }
 
+static TimeStamp gRecordedShutdownStartTime;
+static bool gAlreadyFreedShutdownTimeFileName = false;
+static char *gRecordedShutdownTimeFileName = nullptr;
+
+static char *
+GetShutdownTimeFileName()
+{
+  if (gAlreadyFreedShutdownTimeFileName) {
+    return nullptr;
+  }
+
+  if (!gRecordedShutdownTimeFileName) {
+    nsCOMPtr<nsIFile> mozFile;
+    NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
+    if (!mozFile)
+      return nullptr;
+
+    mozFile->AppendNative(NS_LITERAL_CSTRING("Telemetry.ShutdownTime.txt"));
+    nsAutoCString nativePath;
+    nsresult rv = mozFile->GetNativePath(nativePath);
+    if (!NS_SUCCEEDED(rv))
+      return nullptr;
+
+    gRecordedShutdownTimeFileName = PL_strdup(nativePath.get());
+  }
+
+  return gRecordedShutdownTimeFileName;
+}
+
+NS_IMETHODIMP
+TelemetryImpl::GetLastShutdownDuration(uint32_t *aResult)
+{
+  // We make this check so that GetShutdownTimeFileName() doesn't get
+  // called; calling that function without telemetry enabled violates
+  // assumptions that the write-the-shutdown-timestamp machinery makes.
+  if (!Telemetry::CanRecord()) {
+    *aResult = 0;
+    return NS_OK;
+  }
+
+  if (!mCachedShutdownTime) {
+    const char *filename = GetShutdownTimeFileName();
+
+    if (!filename) {
+      *aResult = 0;
+      return NS_OK;
+    }
+
+    FILE *f = fopen(filename, "r");
+    if (!f) {
+      *aResult = 0;
+      return NS_OK;
+    }
+
+    int shutdownTime;
+    int r = fscanf(f, "%d\n", &shutdownTime);
+    fclose(f);
+    if (r != 1) {
+      *aResult = 0;
+      return NS_OK;
+    }
+
+    mLastShutdownTime = shutdownTime;
+    mCachedShutdownTime = true;
+  }
+
+  *aResult = mLastShutdownTime;
+  return NS_OK;
+}
+
 TelemetryImpl::TelemetryImpl():
 mHistogramMap(Telemetry::HistogramCount),
 mCanRecord(XRE_GetProcessType() == GeckoProcessType_Default),
 mHashMutex("Telemetry::mHashMutex"),
-mHangReportsMutex("Telemetry::mHangReportsMutex")
+mHangReportsMutex("Telemetry::mHangReportsMutex"),
+mCachedShutdownTime(false),
+mLastShutdownTime(0)
 {
   // A whitelist to prevent Telemetry reporting on Addon & Thunderbird DBs
   const char *trackedDBs[] = {
     "addons.sqlite", "content-prefs.sqlite",
     "cookies.sqlite", "downloads.sqlite", "extensions.sqlite",
     "formhistory.sqlite", "index.sqlite", "permissions.sqlite", "places.sqlite",
     "search.sqlite", "signons.sqlite", "urlclassifier3.sqlite",
     "webappsstore.sqlite"
@@ -1668,16 +1746,63 @@ const Module kTelemetryModule = {
   NULL,
   NULL,
   TelemetryImpl::ShutdownTelemetry
 };
 
 } // anonymous namespace
 
 namespace mozilla {
+void
+RecordShutdownStartTimeStamp() {
+  if (!Telemetry::CanRecord())
+    return;
+
+  gRecordedShutdownStartTime = TimeStamp::Now();
+
+  GetShutdownTimeFileName();
+}
+
+void
+RecordShutdownEndTimeStamp() {
+  if (!gRecordedShutdownTimeFileName || gAlreadyFreedShutdownTimeFileName)
+    return;
+
+  nsCString name(gRecordedShutdownTimeFileName);
+  PL_strfree(gRecordedShutdownTimeFileName);
+  gRecordedShutdownTimeFileName = nullptr;
+  gAlreadyFreedShutdownTimeFileName = true;
+
+  nsCString tmpName = name;
+  tmpName += ".tmp";
+  FILE *f = fopen(tmpName.get(), "w");
+  if (!f)
+    return;
+  // On a normal release build this should be called just before
+  // calling _exit, but on a debug build or when the user forces a full
+  // shutdown this is called as late as possible, so we have to
+  // white list this write as write poisoning will be enabled.
+  int fd = fileno(f);
+  MozillaRegisterDebugFD(fd);
+
+  TimeStamp now = TimeStamp::Now();
+  MOZ_ASSERT(now >= gRecordedShutdownStartTime);
+  TimeDuration diff = now - gRecordedShutdownStartTime;
+  uint32_t diff2 = diff.ToMilliseconds();
+  int written = fprintf(f, "%d\n", diff2);
+  MozillaUnRegisterDebugFILE(f);
+  int rv = fclose(f);
+  if (written < 0 || rv != 0) {
+    PR_Delete(tmpName.get());
+    return;
+  }
+  PR_Delete(name.get());
+  PR_Rename(tmpName.get(), name.get());
+}
+
 namespace Telemetry {
 
 void
 Accumulate(ID aHistogram, uint32_t aSample)
 {
   if (!TelemetryImpl::CanRecord()) {
     return;
   }
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -142,17 +142,17 @@ function getSimpleMeasurements() {
   let isDebuggerAttached = debugService.isDebuggerAttached;
   gWasDebuggerAttached = gWasDebuggerAttached || isDebuggerAttached;
   ret.debuggerAttached = new Number(gWasDebuggerAttached);
 
   ret.js = Cc["@mozilla.org/js/xpc/XPConnect;1"]
            .getService(Ci.nsIJSEngineTelemetryStats)
            .telemetryValue;
 
-  let shutdownDuration = Services.startup.lastShutdownDuration;
+  let shutdownDuration = Telemetry.lastShutdownDuration;
   if (shutdownDuration)
     ret.shutdownDuration = shutdownDuration;
 
   return ret;
 }
 
 /**
  * Read current process I/O counters.
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 "nsISupports.idl"
 #include "nsIFile.idl"
 
-[scriptable, uuid(de54f594-4c20-4968-a27a-83b38ff952b9)]
+[scriptable, uuid(420ebbd5-efe3-42f2-8a13-f695e0fdcca0)]
 interface nsITelemetry : nsISupports
 {
   /**
    * Histogram types:
    * HISTOGRAM_EXPONENTIAL - buckets increase exponentially
    * HISTOGRAM_LINEAR - buckets increase linearly
    * HISTOGRAM_BOOLEAN - For storing 0/1 values
    * HISTOGRAM_FLAG - For storing a single value; its count is always == 1.
@@ -31,16 +31,22 @@ interface nsITelemetry : nsISupports
    *   counts - array representing contents of the buckets in the histogram
    *   ranges -  an array with calculated bucket sizes
    *   sum - sum of the bucket contents
    *   static - true for histograms defined in TelemetryHistograms.h, false for ones defined with newHistogram
    */
   [implicit_jscontext]
   readonly attribute jsval histogramSnapshots;
 
+  /**
+   * The amount of time, in milliseconds, that the last session took
+   * to shutdown.  Reads as 0 to indicate failure.
+   */
+  readonly attribute uint32_t lastShutdownDuration;
+
   /*
    * An object containing information about slow SQL statements.
    *
    * {
    *   mainThread: { "sqlString1": [<hit count>, <total time>], "sqlString2": [...], ... },
    *   otherThreads: { "sqlString3": [<hit count>, <total time>], "sqlString4": [...], ... }
    * }
    *