зеркало из https://github.com/mozilla/gecko-dev.git
Bug 793735 - Make StartupTimeline use TimeStamp instead of PRTime and adjust nsAppStartup to cope with it, r=nfroyd
This commit is contained in:
Родитель
871c2afe3b
Коммит
852d5ec03d
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
PRTime StartupTimeline::sStartupTimeline[StartupTimeline::MAX_EVENT_ID];
|
TimeStamp StartupTimeline::sStartupTimeline[StartupTimeline::MAX_EVENT_ID];
|
||||||
const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID] = {
|
const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID] = {
|
||||||
#define mozilla_StartupTimeline_Event(ev, desc) desc,
|
#define mozilla_StartupTimeline_Event(ev, desc) desc,
|
||||||
#include "StartupTimeline.h"
|
#include "StartupTimeline.h"
|
||||||
|
@ -23,6 +23,8 @@ const char *StartupTimeline::sStartupTimelineDesc[StartupTimeline::MAX_EVENT_ID]
|
||||||
void
|
void
|
||||||
XRE_StartupTimelineRecord(int aEvent, PRTime aWhen)
|
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
|
#ifndef mozilla_StartupTimeline
|
||||||
#define mozilla_StartupTimeline
|
#define mozilla_StartupTimeline
|
||||||
|
|
||||||
#include "prtime.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public:
|
||||||
MAX_EVENT_ID
|
MAX_EVENT_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
static PRTime Get(Event ev) {
|
static TimeStamp Get(Event ev) {
|
||||||
return sStartupTimeline[ev];
|
return sStartupTimeline[ev];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,10 +61,10 @@ public:
|
||||||
|
|
||||||
static void Record(Event ev) {
|
static void Record(Event ev) {
|
||||||
PROFILER_MARKER(Describe(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;
|
sStartupTimeline[ev] = when;
|
||||||
#ifdef MOZ_LINKER
|
#ifdef MOZ_LINKER
|
||||||
if (__moz_linker_stats)
|
if (__moz_linker_stats)
|
||||||
|
@ -78,11 +78,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HasRecord(Event ev) {
|
static bool HasRecord(Event ev) {
|
||||||
return sStartupTimeline[ev];
|
return !sStartupTimeline[ev].IsNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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];
|
static NS_EXTERNAL_VIS_(const char *) sStartupTimelineDesc[MAX_EVENT_ID];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
|
|
||||||
#include "prprf.h"
|
#include "prprf.h"
|
||||||
#include "nsCRT.h"
|
|
||||||
#include "nsIInterfaceRequestorUtils.h"
|
#include "nsIInterfaceRequestorUtils.h"
|
||||||
#include "nsWidgetsCID.h"
|
#include "nsWidgetsCID.h"
|
||||||
#include "nsAppShellCID.h"
|
#include "nsAppShellCID.h"
|
||||||
|
@ -41,49 +40,13 @@
|
||||||
#include "mozilla/mozPoisonWrite.h"
|
#include "mozilla/mozPoisonWrite.h"
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
#include <windows.h>
|
// Prevent collisions with nsAppStartup::GetStartupInfo()
|
||||||
// windows.h can go to hell
|
|
||||||
#undef 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
|
#endif
|
||||||
|
|
||||||
#include "mozilla/Telemetry.h"
|
#include "mozilla/Telemetry.h"
|
||||||
#include "mozilla/StartupTimeline.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);
|
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||||
|
|
||||||
#define kPrefLastSuccess "toolkit.startup.last_success"
|
#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
|
// nsAppStartup
|
||||||
//
|
//
|
||||||
|
@ -383,8 +363,9 @@ nsAppStartup::Quit(uint32_t aMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mRestart) {
|
if (mRestart) {
|
||||||
// Firefox-restarts reuse the process. Process start-time isn't a useful indicator of startup time
|
/* Firefox-restarts reuse the process so regular process start-time isn't
|
||||||
PR_SetEnv(PR_smprintf("MOZ_APP_RESTART=%lld", (int64_t) PR_Now() / PR_USEC_PER_MSEC));
|
a useful indicator of startup time anymore. */
|
||||||
|
TimeStamp::RecordProcessRestart();
|
||||||
}
|
}
|
||||||
|
|
||||||
obsService = mozilla::services::GetObserverService();
|
obsService = mozilla::services::GetObserverService();
|
||||||
|
@ -666,160 +647,53 @@ nsAppStartup::Observe(nsISupports *aSubject,
|
||||||
return NS_OK;
|
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<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
|
NS_IMETHODIMP
|
||||||
nsAppStartup::GetStartupInfo(JSContext* aCx, JS::Value* aRetval)
|
nsAppStartup::GetStartupInfo(JSContext* aCx, JS::Value* aRetval)
|
||||||
{
|
{
|
||||||
JS::Rooted<JSObject*> obj(aCx, JS_NewObject(aCx, NULL, NULL, NULL));
|
JS::Rooted<JSObject*> obj(aCx, JS_NewObject(aCx, NULL, NULL, NULL));
|
||||||
*aRetval = OBJECT_TO_JSVAL(obj);
|
*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) {
|
if (procTime.IsNull()) {
|
||||||
PRTime MainTimestamp = StartupTimeline::Get(StartupTimeline::MAIN);
|
bool error = false;
|
||||||
char *moz_app_restart = PR_GetEnv("MOZ_APP_RESTART");
|
|
||||||
if (moz_app_restart) {
|
procTime = TimeStamp::ProcessCreation(error);
|
||||||
ProcessCreationTimestamp = nsCRT::atoll(moz_app_restart) * PR_USEC_PER_MSEC;
|
|
||||||
} else {
|
if (error) {
|
||||||
ProcessCreationTimestamp = CalculateProcessCreationTimestamp();
|
Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS,
|
||||||
|
StartupTimeline::PROCESS_CREATION);
|
||||||
}
|
}
|
||||||
// Bug 670008 & 689256: Avoid obviously invalid process creation times
|
|
||||||
if ((PR_Now() <= ProcessCreationTimestamp) ||
|
StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, procTime);
|
||||||
(MainTimestamp && (ProcessCreationTimestamp > MainTimestamp)))
|
|
||||||
{
|
|
||||||
ProcessCreationTimestamp = MainTimestamp ? MainTimestamp : -1;
|
|
||||||
Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, StartupTimeline::PROCESS_CREATION);
|
|
||||||
}
|
|
||||||
StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, ProcessCreationTimestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
StartupTimeline::Event ev = static_cast<StartupTimeline::Event>(i);
|
||||||
if (StartupTimeline::Get(ev) > 0) {
|
TimeStamp stamp = StartupTimeline::Get(ev);
|
||||||
// always define main to aid with bug 689256
|
|
||||||
if ((ev != StartupTimeline::MAIN) &&
|
if (stamp.IsNull() && (ev == StartupTimeline::MAIN)) {
|
||||||
(StartupTimeline::Get(ev) < StartupTimeline::Get(StartupTimeline::PROCESS_CREATION))) {
|
// Always define main to aid with bug 689256.
|
||||||
Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, i);
|
stamp = procTime;
|
||||||
StartupTimeline::Record(ev, -1);
|
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 {
|
} else {
|
||||||
JSObject *date = JS_NewDateObjectMsec(aCx, StartupTimeline::Get(ev) / PR_USEC_PER_MSEC);
|
Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, ev);
|
||||||
JS_DefineProperty(aCx, obj, StartupTimeline::Describe(ev), OBJECT_TO_JSVAL(date), NULL, NULL, JSPROP_ENUMERATE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -967,14 +841,21 @@ nsAppStartup::TrackStartupCrashEnd()
|
||||||
|
|
||||||
// Use the timestamp of XRE_main as an approximation for the lock file timestamp.
|
// Use the timestamp of XRE_main as an approximation for the lock file timestamp.
|
||||||
// See MAX_STARTUP_BUFFER for the buffer time period.
|
// 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;
|
nsresult rv;
|
||||||
PRTime mainTime = StartupTimeline::Get(StartupTimeline::MAIN);
|
|
||||||
if (mainTime <= 0) {
|
if (mainTime.IsNull()) {
|
||||||
NS_WARNING("Could not get StartupTimeline::MAIN time.");
|
NS_WARNING("Could not get StartupTimeline::MAIN time.");
|
||||||
} else {
|
} else {
|
||||||
int32_t lockFileTime = (int32_t)(mainTime / PR_USEC_PER_SEC);
|
uint64_t lockFileTime = ComputeAbsoluteTimestamp(prNow, now, mainTime);
|
||||||
rv = Preferences::SetInt(kPrefLastSuccess, lockFileTime);
|
|
||||||
if (NS_FAILED(rv)) NS_WARNING("Could not set startup crash detection pref.");
|
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) {
|
if (inSafeMode && mIsSafeModeNecessary) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче