Bug 852250 - When restarting recompute the process startup timestamp instead of using the timestamp stored it in MOZ_APP_RESTART during the shutdown procedure. r=froydnj, a=bajaj
authorGabriele Svelto <gsvelto@mozilla.com>
Thu, 01 Aug 2013 11:22:36 +0200
changeset 148259 84137b5de476cd85673e4d6b47d5a9ec6ebb7ea2
parent 148258 a73c5aef86cf889327bd5546764b131292db022f
child 148260 0afce5e84e3108ad1a21b7f16bc736a4c83ded8b
push id2717
push userryanvm@gmail.com
push dateFri, 09 Aug 2013 18:46:52 +0000
treeherdermozilla-beta@502d43258e80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj, bajaj
bugs852250
milestone24.0
Bug 852250 - When restarting recompute the process startup timestamp instead of using the timestamp stored it in MOZ_APP_RESTART during the shutdown procedure. r=froydnj, a=bajaj
xpcom/ds/TimeStamp.cpp
xpcom/ds/TimeStamp.h
xpcom/ds/TimeStamp_darwin.cpp
xpcom/ds/TimeStamp_posix.cpp
xpcom/ds/TimeStamp_windows.cpp
xpcom/ds/moz.build
new file mode 100644
--- /dev/null
+++ b/xpcom/ds/TimeStamp.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+/*
+ * Implementation of the OS-independent methods of the TimeStamp class
+ */
+
+#include "mozilla/TimeStamp.h"
+#include "prenv.h"
+
+namespace mozilla {
+
+TimeStamp TimeStamp::sFirstTimeStamp;
+TimeStamp TimeStamp::sProcessCreation;
+
+TimeStamp
+TimeStamp::ProcessCreation(bool& aIsInconsistent)
+{
+  aIsInconsistent = false;
+
+  if (sProcessCreation.IsNull()) {
+    char *mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
+    TimeStamp ts;
+
+    /* When calling PR_SetEnv() with an empty value the existing variable may
+     * be unset or set to the empty string depending on the underlying platform
+     * thus we have to check if the variable is present and not empty. */
+    if (mozAppRestart && (strcmp(mozAppRestart, "") != 0)) {
+      /* Firefox was restarted, use the first time-stamp we've taken as the new
+       * process startup time and unset MOZ_APP_RESTART. */
+      ts = sFirstTimeStamp;
+      PR_SetEnv("MOZ_APP_RESTART=");
+    } else {
+      TimeStamp now = Now();
+      uint64_t uptime = ComputeProcessUptime();
+
+      ts = now - TimeDuration::FromMicroseconds(uptime);
+
+      if ((ts > sFirstTimeStamp) || (uptime == 0)) {
+        /* If the process creation timestamp was inconsistent replace it with
+         * the first one instead and notify that a telemetry error was
+         * detected. */
+        aIsInconsistent = true;
+        ts = sFirstTimeStamp;
+      }
+    }
+
+    sProcessCreation = ts;
+  }
+
+  return sProcessCreation;
+}
+
+void
+TimeStamp::RecordProcessRestart()
+{
+  PR_SetEnv("MOZ_APP_RESTART=1");
+  sProcessCreation = TimeStamp();
+}
+
+} // namespace mozilla
--- a/xpcom/ds/TimeStamp.h
+++ b/xpcom/ds/TimeStamp.h
@@ -335,16 +335,26 @@ private:
   friend struct IPC::ParamTraits<mozilla::TimeStamp>;
   friend void StartupTimelineRecordExternal(int, uint64_t);
 
   TimeStamp(TimeStampValue aValue) : mValue(aValue) {}
 
   static TimeStamp Now(bool aHighResolution);
 
   /**
+   * Computes the uptime of the current process in microseconds. The result
+   * is platform-dependent and needs to be checked against existing timestamps
+   * for consistency.
+   *
+   * @returns The number of microseconds since the calling process was started
+   *          or 0 if an error was encountered while computing the uptime
+   */
+  static uint64_t ComputeProcessUptime();
+
+  /**
    * When built with PRIntervalTime, a value of 0 means this instance
    * is "null". Otherwise, the low 32 bits represent a PRIntervalTime,
    * and the high 32 bits represent a counter of the number of
    * rollovers of PRIntervalTime that we've seen. This counter starts
    * at 1 to avoid a real time colliding with the "null" value.
    * 
    * PR_INTERVAL_MAX is set at 100,000 ticks per second. So the minimum
    * time to wrap around is about 2^64/100000 seconds, i.e. about
--- a/xpcom/ds/TimeStamp_darwin.cpp
+++ b/xpcom/ds/TimeStamp_darwin.cpp
@@ -19,17 +19,16 @@
 #include <mach/mach_time.h>
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/sysctl.h>
 #include <time.h>
 
 #include "mozilla/TimeStamp.h"
 #include "nsCRT.h"
-#include "prenv.h"
 #include "prprf.h"
 
 // Estimate of the smallest duration of time we can measure.
 static uint64_t sResolution;
 static uint64_t sResolutionSigDigs;
 
 static const uint64_t kNsPerMs   =    1000000;
 static const uint64_t kUsPerSec  =    1000000;
@@ -78,19 +77,16 @@ ClockResolutionNs()
     minres = 1 * kNsPerMs;
   }
 
   return minres;
 }
 
 namespace mozilla {
 
-TimeStamp TimeStamp::sFirstTimeStamp;
-TimeStamp TimeStamp::sProcessCreation;
-
 double
 TimeDuration::ToSeconds() const
 {
   NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early");
   return (mValue * sNsPerTick) / kNsPerSecd;
 }
 
 double
@@ -171,18 +167,18 @@ TimeStamp
 TimeStamp::Now(bool aHighResolution)
 {
   return TimeStamp(ClockTime());
 }
 
 // Computes and returns the process uptime in microseconds.
 // Returns 0 if an error was encountered.
 
-static uint64_t
-ComputeProcessUptime()
+uint64_t
+TimeStamp::ComputeProcessUptime()
 {
   struct timeval tv;
   int rv = gettimeofday(&tv, NULL);
 
   if (rv == -1) {
     return 0;
   }
 
@@ -207,47 +203,9 @@ ComputeProcessUptime()
   uint64_t now = (tv.tv_sec * kUsPerSec) + tv.tv_usec;
 
   if (startTime > now)
     return 0;
 
   return now - startTime;
 }
 
-TimeStamp
-TimeStamp::ProcessCreation(bool& aIsInconsistent)
-{
-  aIsInconsistent = false;
-
-  if (sProcessCreation.IsNull()) {
-    char *mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
-    TimeStamp ts;
-
-    if (mozAppRestart) {
-      ts = TimeStamp(nsCRT::atoll(mozAppRestart));
-    } else {
-      TimeStamp now = TimeStamp::Now();
-      uint64_t uptime = ComputeProcessUptime();
-
-      ts = now - TimeDuration::FromMicroseconds(uptime);
-
-      if ((ts > sFirstTimeStamp) || (uptime == 0)) {
-        // If the process creation timestamp was inconsistent replace it with the
-        // first one instead and notify that a telemetry error was detected.
-        aIsInconsistent = true;
-        ts = sFirstTimeStamp;
-      }
-    }
-
-    sProcessCreation = ts;
-  }
-
-  return sProcessCreation;
-}
-
-void
-TimeStamp::RecordProcessRestart()
-{
-  PR_SetEnv(PR_smprintf("MOZ_APP_RESTART=%lld", ClockTime()));
-  sProcessCreation = TimeStamp();
-}
-
-}
+} // namespace mozilla
--- a/xpcom/ds/TimeStamp_posix.cpp
+++ b/xpcom/ds/TimeStamp_posix.cpp
@@ -43,17 +43,16 @@
 #define KP_START_USEC ki_start.tv_usec
 #else
 #define KP_START_SEC p_ustart_sec
 #define KP_START_USEC p_ustart_usec
 #endif
 
 #include "mozilla/TimeStamp.h"
 #include "nsCRT.h"
-#include "prenv.h"
 #include "prprf.h"
 #include "prthread.h"
 
 // Estimate of the smallest duration of time we can measure.
 static uint64_t sResolution;
 static uint64_t sResolutionSigDigs;
 
 static const uint16_t kNsPerUs   =       1000;
@@ -127,19 +126,16 @@ ClockResolutionNs()
     minres = 1 * kNsPerMs;
   }
 
   return minres;
 }
 
 namespace mozilla {
 
-TimeStamp TimeStamp::sFirstTimeStamp;
-TimeStamp TimeStamp::sProcessCreation;
-
 double
 TimeDuration::ToSeconds() const
 {
   return double(mValue) / kNsPerSecd;
 }
 
 double
 TimeDuration::ToSecondsSigDigits() const
@@ -278,44 +274,44 @@ ComputeProcessUptimeThread(void *aTime)
   uint64_t selfJiffies = JiffiesSinceBoot("/proc/self/stat");
 
   if (!threadJiffies || !selfJiffies)
     return;
 
   *uptime = ((threadJiffies - selfJiffies) * kNsPerSec) / hz;
 }
 
-// Computes and returns the process uptime in ns on Linux & its derivatives.
+// Computes and returns the process uptime in us on Linux & its derivatives.
 // Returns 0 if an error was encountered.
 
-static uint64_t
-ComputeProcessUptime()
+uint64_t
+TimeStamp::ComputeProcessUptime()
 {
   uint64_t uptime = 0;
   PRThread *thread = PR_CreateThread(PR_USER_THREAD,
                                      ComputeProcessUptimeThread,
                                      &uptime,
                                      PR_PRIORITY_NORMAL,
                                      PR_LOCAL_THREAD,
                                      PR_JOINABLE_THREAD,
                                      0);
 
   PR_JoinThread(thread);
 
-  return uptime;
+  return uptime / kNsPerUs;
 }
 
 #elif defined(__DragonFly__) || defined(__FreeBSD__) \
       || defined(__NetBSD__) || defined(__OpenBSD__)
 
-// Computes and returns the process uptime in ns on various BSD flavors.
+// Computes and returns the process uptime in us on various BSD flavors.
 // Returns 0 if an error was encountered.
 
-static uint64_t
-ComputeProcessUptime()
+uint64_t
+TimeStamp::ComputeProcessUptime()
 {
   struct timespec ts;
   int rv = clock_gettime(CLOCK_REALTIME, &ts);
 
   if (rv == -1) {
     return 0;
   }
 
@@ -340,60 +336,22 @@ ComputeProcessUptime()
 
   uint64_t startTime = ((uint64_t)proc.KP_START_SEC * kNsPerSec)
     + (proc.KP_START_USEC * kNsPerUs);
   uint64_t now = ((uint64_t)ts.tv_sec * kNsPerSec) + ts.tv_nsec;
 
   if (startTime > now)
     return 0;
 
-  return (now - startTime);
+  return (now - startTime) / kNsPerUs;
 }
 
 #else
 
-static uint64_t
-ComputeProcessUptime()
+uint64_t
+TimeStamp::ComputeProcessUptime()
 {
   return 0;
 }
 
 #endif
 
-TimeStamp
-TimeStamp::ProcessCreation(bool& aIsInconsistent)
-{
-  aIsInconsistent = false;
-
-  if (sProcessCreation.IsNull()) {
-    char *mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
-    TimeStamp ts;
-
-    if (mozAppRestart) {
-      ts = TimeStamp(nsCRT::atoll(mozAppRestart));
-    } else {
-      TimeStamp now = TimeStamp::Now();
-      uint64_t uptime = ComputeProcessUptime();
-
-      ts = now - TimeDuration::FromMicroseconds(uptime / 1000);
-
-      if ((ts > sFirstTimeStamp) || (uptime == 0)) {
-        // If the process creation timestamp was inconsistent replace it with the
-        // first one instead and notify that a telemetry error was detected.
-        aIsInconsistent = true;
-        ts = sFirstTimeStamp;
-      }
-    }
-
-    sProcessCreation = ts;
-  }
-
-  return sProcessCreation;
-}
-
-void
-TimeStamp::RecordProcessRestart()
-{
-  PR_SetEnv(PR_smprintf("MOZ_APP_RESTART=%lld", ClockTimeNs()));
-  sProcessCreation = TimeStamp();
-}
-
-}
+} // namespace mozilla
--- a/xpcom/ds/TimeStamp_windows.cpp
+++ b/xpcom/ds/TimeStamp_windows.cpp
@@ -13,17 +13,16 @@
 
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/TimeStamp.h"
 #include <windows.h>
 
 #include "nsCRT.h"
 #include "prlog.h"
-#include "prenv.h"
 #include "prprf.h"
 #include <stdio.h>
 
 #include <intrin.h>
 
 #if defined(PR_LOGGING)
 // Log module for mozilla::TimeStamp for Windows logging...
 //
@@ -178,19 +177,16 @@ static ULONGLONG sFaultIntoleranceCheckp
 static DWORD sLastGTCResult = 0;
 
 // Higher part of the 64-bit value of MozGetTickCount64,
 // incremented atomically.
 static DWORD sLastGTCRollover = 0;
 
 namespace mozilla {
 
-TimeStamp TimeStamp::sFirstTimeStamp;
-TimeStamp TimeStamp::sProcessCreation;
-
 typedef ULONGLONG (WINAPI* GetTickCount64_t)();
 static GetTickCount64_t sGetTickCount64 = nullptr;
 
 // ----------------------------------------------------------------------------
 // Critical Section helper class
 // ----------------------------------------------------------------------------
 
 class AutoCriticalSection
@@ -557,21 +553,21 @@ TimeStamp::Now(bool aHighResolution)
   bool useQPC = (aHighResolution && sUseQPC);
 
   // Both values are in [mt] units.
   ULONGLONG QPC = useQPC ? PerformanceCounter() : uint64_t(0);
   ULONGLONG GTC = ms2mt(sGetTickCount64());
   return TimeStamp(TimeStampValue(GTC, QPC, useQPC));
 }
 
-// Computes and returns the current process uptime in microseconds.
-// Returns 0 if an error was encountered while computing the uptime.
+// Computes and returns the process uptime in microseconds.
+// Returns 0 if an error was encountered.
 
-static uint64_t
-ComputeProcessUptime()
+uint64_t
+TimeStamp::ComputeProcessUptime()
 {
   SYSTEMTIME nowSys;
   GetSystemTime(&nowSys);
 
   FILETIME now;
   bool success = SystemTimeToFileTime(&nowSys, &now);
 
   if (!success)
@@ -590,46 +586,9 @@ ComputeProcessUptime()
   ULARGE_INTEGER nowUsec = {
     now.dwLowDateTime,
     now.dwHighDateTime
   };
 
   return (nowUsec.QuadPart - startUsec.QuadPart) / 10ULL;
 }
 
-TimeStamp
-TimeStamp::ProcessCreation(bool& aIsInconsistent)
-{
-  aIsInconsistent = false;
-
-  if (sProcessCreation.IsNull()) {
-    char *mozAppRestart = PR_GetEnv("MOZ_APP_RESTART");
-    TimeStamp ts;
-
-    if (mozAppRestart) {
-      ts = TimeStamp(TimeStampValue(nsCRT::atoll(mozAppRestart), 0, false));
-    } else {
-      TimeStamp now = TimeStamp::Now();
-      uint64_t uptime = ComputeProcessUptime();
-      ts = now - TimeDuration::FromMicroseconds(static_cast<double>(uptime));
-
-      if ((ts > sFirstTimeStamp) || (uptime == 0)) {
-        // If the process creation timestamp was inconsistent replace it with the
-        // first one instead and notify that a telemetry error was detected.
-        aIsInconsistent = true;
-        ts = sFirstTimeStamp;
-      }
-    }
-
-    sProcessCreation = ts;
-  }
-
-  return sProcessCreation;
-}
-
-void
-TimeStamp::RecordProcessRestart()
-{
-  PR_SetEnv(PR_smprintf("MOZ_APP_RESTART=%lld", ms2mt(sGetTickCount64())));
-  sProcessCreation = TimeStamp();
-}
-
 } // namespace mozilla
--- a/xpcom/ds/moz.build
+++ b/xpcom/ds/moz.build
@@ -90,16 +90,17 @@ CPP_SOURCES += [
     'nsProperties.cpp',
     'nsStaticNameTable.cpp',
     'nsStringEnumerator.cpp',
     'nsSupportsArray.cpp',
     'nsSupportsArrayEnumerator.cpp',
     'nsSupportsPrimitives.cpp',
     'nsUnicharBuffer.cpp',
     'nsVariant.cpp',
+    'TimeStamp.cpp',
 ]
 
 if CONFIG['HAVE_CLOCK_MONOTONIC']:
     CPP_SOURCES += [
         'TimeStamp_posix.cpp',
     ]
 elif CONFIG['OS_ARCH'] == 'Darwin':
     CPP_SOURCES += [