зеркало из 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 {
|
||||
|
||||
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(×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
|
||||
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)))
|
||||
|
||||
StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, procTime);
|
||||
}
|
||||
|
||||
for (int i = StartupTimeline::PROCESS_CREATION;
|
||||
i < StartupTimeline::MAX_EVENT_ID;
|
||||
++i)
|
||||
{
|
||||
ProcessCreationTimestamp = MainTimestamp ? MainTimestamp : -1;
|
||||
Telemetry::Accumulate(Telemetry::STARTUP_MEASUREMENT_ERRORS, StartupTimeline::PROCESS_CREATION);
|
||||
}
|
||||
StartupTimeline::Record(StartupTimeline::PROCESS_CREATION, ProcessCreationTimestamp);
|
||||
StartupTimeline::Event ev = static_cast<StartupTimeline::Event>(i);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче