Bug 793735 - Make StartupTimeline use TimeStamp instead of PRTime and adjust nsAppStartup to cope with it, r=nfroyd

This commit is contained in:
Gabriele Svelto 2013-03-28 11:50:16 +01:00
Родитель 871c2afe3b
Коммит 852d5ec03d
3 изменённых файлов: 79 добавлений и 196 удалений

Просмотреть файл

@ -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());
}

Просмотреть файл

@ -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];
};

Просмотреть файл

@ -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>
// windows.h can go to hell
// Prevent collisions with nsAppStartup::GetStartupInfo()
#undef GetStartupInfo
#elif defined(XP_UNIX)
#include <unistd.h>
#include <sys/syscall.h>
#endif
#if defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \
|| defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#if defined(__DragonFly__) || defined(__FreeBSD__)
#include <sys/user.h>
#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(&timestamp, &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<PRTime>(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<JSObject*> 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<StartupTimeline::Event>(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<JSObject*> 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) {