From 852d5ec03da703e173c2b0e9378b0da1397ba5ea Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Thu, 28 Mar 2013 11:50:16 +0100 Subject: [PATCH] Bug 793735 - Make StartupTimeline use TimeStamp instead of PRTime and adjust nsAppStartup to cope with it, r=nfroyd --- .../components/startup/StartupTimeline.cpp | 8 +- toolkit/components/startup/StartupTimeline.h | 12 +- toolkit/components/startup/nsAppStartup.cpp | 255 +++++------------- 3 files changed, 79 insertions(+), 196 deletions(-) diff --git a/toolkit/components/startup/StartupTimeline.cpp b/toolkit/components/startup/StartupTimeline.cpp index a21d6b2453a3..31911f74498b 100644 --- a/toolkit/components/startup/StartupTimeline.cpp +++ b/toolkit/components/startup/StartupTimeline.cpp @@ -7,7 +7,7 @@ namespace mozilla { -PRTime StartupTimeline::sStartupTimeline[StartupTimeline::MAX_EVENT_ID]; +TimeStamp StartupTimeline::sStartupTimeline[StartupTimeline::MAX_EVENT_ID]; const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID] = { #define mozilla_StartupTimeline_Event(ev, desc) desc, #include "StartupTimeline.h" @@ -23,6 +23,8 @@ const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID] void XRE_StartupTimelineRecord(int aEvent, PRTime aWhen) { - mozilla::StartupTimeline::Record((mozilla::StartupTimeline::Event) aEvent, aWhen); + /* FIXME: This effectively becomes a no-op until we fix all the users to + * provide proper timestamps */ + mozilla::StartupTimeline::Record((mozilla::StartupTimeline::Event) aEvent, + mozilla::TimeStamp()); } - diff --git a/toolkit/components/startup/StartupTimeline.h b/toolkit/components/startup/StartupTimeline.h index 848c10255249..2c38592ffb3f 100644 --- a/toolkit/components/startup/StartupTimeline.h +++ b/toolkit/components/startup/StartupTimeline.h @@ -21,7 +21,7 @@ mozilla_StartupTimeline_Event(FIRST_LOAD_URI, "firstLoadURI") #ifndef mozilla_StartupTimeline #define mozilla_StartupTimeline -#include "prtime.h" +#include "mozilla/TimeStamp.h" #include "nscore.h" #include "GeckoProfiler.h" @@ -51,7 +51,7 @@ public: MAX_EVENT_ID }; - static PRTime Get(Event ev) { + static TimeStamp Get(Event ev) { return sStartupTimeline[ev]; } @@ -61,10 +61,10 @@ public: static void Record(Event ev) { PROFILER_MARKER(Describe(ev)); - Record(ev, PR_Now()); + Record(ev, TimeStamp::Now()); } - static void Record(Event ev, PRTime when) { + static void Record(Event ev, TimeStamp when) { sStartupTimeline[ev] = when; #ifdef MOZ_LINKER if (__moz_linker_stats) @@ -78,11 +78,11 @@ public: } static bool HasRecord(Event ev) { - return sStartupTimeline[ev]; + return !sStartupTimeline[ev].IsNull(); } private: - static NS_EXTERNAL_VIS_(PRTime) sStartupTimeline[MAX_EVENT_ID]; + static NS_EXTERNAL_VIS_(TimeStamp) sStartupTimeline[MAX_EVENT_ID]; static NS_EXTERNAL_VIS_(const char *) sStartupTimelineDesc[MAX_EVENT_ID]; }; diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp index a8858ed5c09d..e74f7ec420b8 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -28,7 +28,6 @@ #include "GeckoProfiler.h" #include "prprf.h" -#include "nsCRT.h" #include "nsIInterfaceRequestorUtils.h" #include "nsWidgetsCID.h" #include "nsAppShellCID.h" @@ -41,49 +40,13 @@ #include "mozilla/mozPoisonWrite.h" #if defined(XP_WIN) -#include -// windows.h can go to hell +// Prevent collisions with nsAppStartup::GetStartupInfo() #undef GetStartupInfo -#elif defined(XP_UNIX) -#include -#include -#endif - -#if defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) -#include -#include -#endif - -#if defined(__DragonFly__) || defined(__FreeBSD__) -#include #endif #include "mozilla/Telemetry.h" #include "mozilla/StartupTimeline.h" -#if defined(__NetBSD__) -#undef KERN_PROC -#define KERN_PROC KERN_PROC2 -#define KINFO_PROC struct kinfo_proc2 -#else -#define KINFO_PROC struct kinfo_proc -#endif - -#if defined(XP_MACOSX) -#define KP_START_SEC kp_proc.p_un.__p_starttime.tv_sec -#define KP_START_USEC kp_proc.p_un.__p_starttime.tv_usec -#elif defined(__DragonFly__) -#define KP_START_SEC kp_start.tv_sec -#define KP_START_USEC kp_start.tv_usec -#elif defined(__FreeBSD__) -#define KP_START_SEC ki_start.tv_sec -#define KP_START_USEC ki_start.tv_usec -#else -#define KP_START_SEC p_ustart_sec -#define KP_START_USEC p_ustart_usec -#endif - static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); #define kPrefLastSuccess "toolkit.startup.last_success" @@ -151,6 +114,23 @@ public: } }; +/** + * Computes an approximation of the absolute time represented by @a stamp + * which is comparable to those obtained via PR_Now(). If the current absolute + * time varies a lot (e.g. DST adjustments) since the first call then the + * resulting times may be inconsistent. + * + * @param stamp The timestamp to be converted + * @returns The converted timestamp + */ +uint64_t ComputeAbsoluteTimestamp(PRTime prnow, TimeStamp now, TimeStamp stamp) +{ + static PRTime sAbsoluteNow = PR_Now(); + static TimeStamp sMonotonicNow = TimeStamp::Now(); + + return sAbsoluteNow - (sMonotonicNow - stamp).ToMicroseconds(); +} + // // nsAppStartup // @@ -383,8 +363,9 @@ nsAppStartup::Quit(uint32_t aMode) } if (mRestart) { - // Firefox-restarts reuse the process. Process start-time isn't a useful indicator of startup time - PR_SetEnv(PR_smprintf("MOZ_APP_RESTART=%lld", (int64_t) PR_Now() / PR_USEC_PER_MSEC)); + /* Firefox-restarts reuse the process so regular process start-time isn't + a useful indicator of startup time anymore. */ + TimeStamp::RecordProcessRestart(); } obsService = mozilla::services::GetObserverService(); @@ -666,160 +647,53 @@ nsAppStartup::Observe(nsISupports *aSubject, return NS_OK; } -#if defined(LINUX) || defined(ANDROID) -static uint64_t -JiffiesSinceBoot(const char *file) -{ - char stat[512]; - FILE *f = fopen(file, "r"); - if (!f) - return 0; - int n = fread(&stat, 1, sizeof(stat) - 1, f); - fclose(f); - if (n <= 0) - return 0; - stat[n] = 0; - - long long unsigned starttime = 0; // instead of uint64_t to keep GCC quiet - - char *s = strrchr(stat, ')'); - if (!s) - return 0; - int ret = sscanf(s + 2, - "%*c %*d %*d %*d %*d %*d %*u %*u %*u %*u " - "%*u %*u %*u %*u %*u %*d %*d %*d %*d %llu", - &starttime); - if (ret != 1 || !starttime) - return 0; - return starttime; -} - -static void -ThreadedCalculateProcessCreationTimestamp(void *aClosure) -{ - PR_SetCurrentThreadName("Startup Timer"); - - PRTime now = PR_Now(); - long hz = sysconf(_SC_CLK_TCK); - if (!hz) - return; - - char thread_stat[40]; - sprintf(thread_stat, "/proc/self/task/%d/stat", (pid_t) syscall(__NR_gettid)); - - uint64_t thread_jiffies = JiffiesSinceBoot(thread_stat); - uint64_t self_jiffies = JiffiesSinceBoot("/proc/self/stat"); - - if (!thread_jiffies || !self_jiffies) - return; - - PRTime interval = (thread_jiffies - self_jiffies) * PR_USEC_PER_SEC / hz; - StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, now - interval); -} - -static PRTime -CalculateProcessCreationTimestamp() -{ - PRThread *thread = PR_CreateThread(PR_USER_THREAD, - ThreadedCalculateProcessCreationTimestamp, - NULL, - PR_PRIORITY_NORMAL, - PR_LOCAL_THREAD, - PR_JOINABLE_THREAD, - 0); - - PR_JoinThread(thread); - return StartupTimeline::Get(StartupTimeline::PROCESS_CREATION); -} -#elif defined(XP_WIN) -static PRTime -CalculateProcessCreationTimestamp() -{ - FILETIME start, foo, bar, baz; - bool success = GetProcessTimes(GetCurrentProcess(), &start, &foo, &bar, &baz); - if (!success) - return 0; - // copied from NSPR _PR_FileTimeToPRTime - uint64_t timestamp = 0; - CopyMemory(×tamp, &start, sizeof(PRTime)); -#ifdef __GNUC__ - timestamp = (timestamp - 116444736000000000LL) / 10LL; -#else - timestamp = (timestamp - 116444736000000000i64) / 10i64; -#endif - return timestamp; -} -#elif defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \ - || defined(__NetBSD__) || defined(__OpenBSD__) -static PRTime -CalculateProcessCreationTimestamp() -{ - int mib[] = { - CTL_KERN, - KERN_PROC, - KERN_PROC_PID, - getpid(), -#if defined(__NetBSD__) || defined(__OpenBSD__) - sizeof(KINFO_PROC), - 1, -#endif - }; - u_int miblen = sizeof(mib) / sizeof(mib[0]); - - KINFO_PROC proc; - size_t buffer_size = sizeof(proc); - if (sysctl(mib, miblen, &proc, &buffer_size, NULL, 0)) - return 0; - - PRTime starttime = static_cast(proc.KP_START_SEC) * PR_USEC_PER_SEC; - starttime += proc.KP_START_USEC; - return starttime; -} -#else -static PRTime -CalculateProcessCreationTimestamp() -{ - return 0; -} -#endif - NS_IMETHODIMP nsAppStartup::GetStartupInfo(JSContext* aCx, JS::Value* aRetval) { JS::Rooted obj(aCx, JS_NewObject(aCx, NULL, NULL, NULL)); *aRetval = OBJECT_TO_JSVAL(obj); - PRTime ProcessCreationTimestamp = StartupTimeline::Get(StartupTimeline::PROCESS_CREATION); + TimeStamp procTime = StartupTimeline::Get(StartupTimeline::PROCESS_CREATION); + TimeStamp now = TimeStamp::Now(); + PRTime absNow = PR_Now(); - if (!ProcessCreationTimestamp) { - PRTime MainTimestamp = StartupTimeline::Get(StartupTimeline::MAIN); - char *moz_app_restart = PR_GetEnv("MOZ_APP_RESTART"); - if (moz_app_restart) { - ProcessCreationTimestamp = nsCRT::atoll(moz_app_restart) * PR_USEC_PER_MSEC; - } else { - ProcessCreationTimestamp = CalculateProcessCreationTimestamp(); + if (procTime.IsNull()) { + bool error = false; + + procTime = TimeStamp::ProcessCreation(error); + + if (error) { + Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, + StartupTimeline::PROCESS_CREATION); } - // Bug 670008 & 689256: Avoid obviously invalid process creation times - if ((PR_Now() <= ProcessCreationTimestamp) || - (MainTimestamp && (ProcessCreationTimestamp > MainTimestamp))) - { - ProcessCreationTimestamp = MainTimestamp ? MainTimestamp : -1; - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, StartupTimeline::PROCESS_CREATION); - } - StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, ProcessCreationTimestamp); + + StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, procTime); } - for (int i = StartupTimeline::PROCESS_CREATION; i < StartupTimeline::MAX_EVENT_ID; ++i) { + for (int i = StartupTimeline::PROCESS_CREATION; + i < StartupTimeline::MAX_EVENT_ID; + ++i) + { StartupTimeline::Event ev = static_cast(i); - if (StartupTimeline::Get(ev) > 0) { - // always define main to aid with bug 689256 - if ((ev != StartupTimeline::MAIN) && - (StartupTimeline::Get(ev) < StartupTimeline::Get(StartupTimeline::PROCESS_CREATION))) { - Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, i); - StartupTimeline::Record(ev, -1); + TimeStamp stamp = StartupTimeline::Get(ev); + + if (stamp.IsNull() && (ev == StartupTimeline::MAIN)) { + // Always define main to aid with bug 689256. + stamp = procTime; + MOZ_ASSERT(!stamp.IsNull()); + Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, + StartupTimeline::MAIN); + } + + if (!stamp.IsNull()) { + if (stamp >= procTime) { + PRTime prStamp = ComputeAbsoluteTimestamp(absNow, now, stamp) + / PR_USEC_PER_MSEC; + JS::Rooted date(aCx, JS_NewDateObjectMsec(aCx, prStamp)); + JS_DefineProperty(aCx, obj, StartupTimeline::Describe(ev), + OBJECT_TO_JSVAL(date), NULL, NULL, JSPROP_ENUMERATE); } else { - JSObject *date = JS_NewDateObjectMsec(aCx, StartupTimeline::Get(ev) / PR_USEC_PER_MSEC); - JS_DefineProperty(aCx, obj, StartupTimeline::Describe(ev), OBJECT_TO_JSVAL(date), NULL, NULL, JSPROP_ENUMERATE); + Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, ev); } } } @@ -967,14 +841,21 @@ nsAppStartup::TrackStartupCrashEnd() // Use the timestamp of XRE_main as an approximation for the lock file timestamp. // See MAX_STARTUP_BUFFER for the buffer time period. + TimeStamp mainTime = StartupTimeline::Get(StartupTimeline::MAIN); + TimeStamp now = TimeStamp::Now(); + PRTime prNow = PR_Now(); nsresult rv; - PRTime mainTime = StartupTimeline::Get(StartupTimeline::MAIN); - if (mainTime <= 0) { + + if (mainTime.IsNull()) { NS_WARNING("Could not get StartupTimeline::MAIN time."); } else { - int32_t lockFileTime = (int32_t)(mainTime / PR_USEC_PER_SEC); - rv = Preferences::SetInt(kPrefLastSuccess, lockFileTime); - if (NS_FAILED(rv)) NS_WARNING("Could not set startup crash detection pref."); + uint64_t lockFileTime = ComputeAbsoluteTimestamp(prNow, now, mainTime); + + rv = Preferences::SetInt(kPrefLastSuccess, + (int32_t)(lockFileTime / PR_USEC_PER_SEC)); + + if (NS_FAILED(rv)) + NS_WARNING("Could not set startup crash detection pref."); } if (inSafeMode && mIsSafeModeNecessary) {