зеркало из https://github.com/mozilla/gecko-dev.git
[mq]: sinkstuff
This commit is contained in:
Родитель
1922412388
Коммит
74d960d045
|
@ -274,36 +274,33 @@ nsContentSink::Init(nsIDocument* aDoc,
|
|||
mNotificationInterval =
|
||||
nsContentUtils::GetIntPref("content.notify.interval", 120000);
|
||||
|
||||
// The mMaxTokenProcessingTime controls how long we stay away from
|
||||
// the event loop when processing token. A lower value makes the app
|
||||
// more responsive, but may increase page load time. The content
|
||||
// sink mNotificationInterval gates how frequently the content is
|
||||
// processed so it will also affect how interactive the app is
|
||||
// during page load also. The mNotification prevents contents
|
||||
// flushes from happening too frequently. while
|
||||
// mMaxTokenProcessingTime prevents flushes from happening too
|
||||
// infrequently.
|
||||
mInteractiveDeflectCount =
|
||||
nsContentUtils::GetIntPref("content.sink.interactive_deflect_count", 0);
|
||||
mPerfDeflectCount =
|
||||
nsContentUtils::GetIntPref("content.sink.perf_deflect_count", 200);
|
||||
mPendingEventMode =
|
||||
nsContentUtils::GetIntPref("content.sink.pending_event_mode", 1);
|
||||
mEventProbeRate =
|
||||
nsContentUtils::GetIntPref("content.sink.event_probe_rate", 1);
|
||||
mInteractiveParseTime =
|
||||
nsContentUtils::GetIntPref("content.sink.interactive_parse_time", 3000);
|
||||
mPerfParseTime =
|
||||
nsContentUtils::GetIntPref("content.sink.perf_parse_time", 360000);
|
||||
mInteractiveTime =
|
||||
nsContentUtils::GetIntPref("content.sink.interactive_time", 750000);
|
||||
mInitialPerfTime =
|
||||
nsContentUtils::GetIntPref("content.sink.initial_perf_time", 2000000);
|
||||
mEnablePerfMode =
|
||||
nsContentUtils::GetIntPref("content.sink.enable_perf_mode", 0);
|
||||
|
||||
// The current ratio of 3 to 1 was determined to be the lowest
|
||||
// mMaxTokenProcessingTime which does not impact page load
|
||||
// performance. See bugzilla bug 76722 for details.
|
||||
|
||||
mMaxTokenProcessingTime =
|
||||
nsContentUtils::GetIntPref("content.max.tokenizing.time",
|
||||
mNotificationInterval * 3);
|
||||
|
||||
// 3/4 second (750000us) default for switching
|
||||
mDynamicIntervalSwitchThreshold =
|
||||
nsContentUtils::GetIntPref("content.switch.threshold", 750000);
|
||||
if (mEnablePerfMode != 0) {
|
||||
mDynamicLowerValue = mEnablePerfMode == 1;
|
||||
FavorPerformanceHint(!mDynamicLowerValue, 0);
|
||||
}
|
||||
|
||||
mCanInterruptParser =
|
||||
nsContentUtils::GetBoolPref("content.interrupt.parsing", PR_TRUE);
|
||||
|
||||
// 200 determined empirically to provide good user response without
|
||||
// sampling the clock too often.
|
||||
mMaxTokensDeflectedInLowFreqMode =
|
||||
nsContentUtils::GetIntPref("content.max.deflected.tokens", 200);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
@ -407,6 +404,8 @@ nsContentSink::ScriptEvaluated(nsresult aResult,
|
|||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline)
|
||||
{
|
||||
mDeflectedCount = mPerfDeflectCount;
|
||||
|
||||
if (mParser) {
|
||||
mParser->ScriptDidExecute();
|
||||
}
|
||||
|
@ -1519,111 +1518,51 @@ nsContentSink::WillResumeImpl()
|
|||
nsresult
|
||||
nsContentSink::DidProcessATokenImpl()
|
||||
{
|
||||
if (!mCanInterruptParser) {
|
||||
if (!mCanInterruptParser || !mParser->CanInterrupt()) {
|
||||
return NS_OK;
|
||||
}
|
||||
// There is both a high frequency interrupt mode and a low
|
||||
// frequency interupt mode controlled by the flag
|
||||
// mDynamicLowerValue The high frequency mode
|
||||
// interupts the parser frequently to provide UI responsiveness at
|
||||
// the expense of page load time. The low frequency mode
|
||||
// interrupts the parser and samples the system clock infrequently
|
||||
// to provide fast page load time. When the user moves the mouse,
|
||||
// clicks or types the mode switches to the high frequency
|
||||
// interrupt mode. If the user stops moving the mouse or typing
|
||||
// for a duration of time (mDynamicIntervalSwitchThreshold) it
|
||||
// switches to low frequency interrupt mode.
|
||||
|
||||
|
||||
// Get the current user event time
|
||||
nsIPresShell *shell = mDocument->GetPrimaryShell();
|
||||
|
||||
if (!shell) {
|
||||
// If there's no pres shell in the document, return early since
|
||||
// we're not laying anything out here.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Increase before comparing to mEventProbeRate
|
||||
++mDeflectedCount;
|
||||
|
||||
// Check if there's a pending event
|
||||
if (mPendingEventMode != 0 && !mHasPendingEvent &&
|
||||
(mDeflectedCount % mEventProbeRate) == 0) {
|
||||
nsIViewManager* vm = shell->GetViewManager();
|
||||
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
|
||||
PRUint32 eventTime;
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
nsresult rv = vm->GetWidget(getter_AddRefs(widget));
|
||||
if (!widget || NS_FAILED(widget->GetLastInputEventTime(eventTime))) {
|
||||
// If we can't get the last input time from the widget
|
||||
// then we will get it from the viewmanager.
|
||||
rv = vm->GetLastUserEventTime(eventTime);
|
||||
PRBool hasPendingEvent;
|
||||
if (widget && NS_SUCCEEDED(widget->HasPendingEvent(hasPendingEvent)) &&
|
||||
hasPendingEvent) {
|
||||
mHasPendingEvent = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
|
||||
if (!mDynamicLowerValue && mLastSampledUserEventTime == eventTime) {
|
||||
// The default value of mMaxTokensDeflectedInLowFreqMode (200)
|
||||
// was selected by empirical testing. It provides reasonable
|
||||
// user response and prevents us from sampling the clock too
|
||||
// frequently. This value may be decreased if responsiveness is
|
||||
// valued more than end-to-end pageload time (e.g., for mobile).
|
||||
if (mDeflectedCount < mMaxTokensDeflectedInLowFreqMode) {
|
||||
mDeflectedCount++;
|
||||
// return early to prevent sampling the clock. Note: This
|
||||
// prevents us from switching to higher frequency (better UI
|
||||
// responsive) mode, so limit ourselves to doing for no more
|
||||
// than mMaxTokensDeflectedInLowFreqMode tokens.
|
||||
if (mHasPendingEvent && mPendingEventMode == 2) {
|
||||
return NS_ERROR_HTMLPARSER_INTERRUPTED;
|
||||
}
|
||||
|
||||
// Have we processed enough tokens to check time?
|
||||
if (!mHasPendingEvent &&
|
||||
mDeflectedCount < (mDynamicLowerValue ? mInteractiveDeflectCount :
|
||||
mPerfDeflectCount)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// reset count and drop through to the code which samples the
|
||||
// clock and does the dynamic switch between the high
|
||||
// frequency and low frequency interruption of the parser.
|
||||
mDeflectedCount = 0;
|
||||
}
|
||||
mLastSampledUserEventTime = eventTime;
|
||||
|
||||
PRUint32 currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
||||
|
||||
// Get the last user event time and compare it with the current
|
||||
// time to determine if the lower value for content notification
|
||||
// and max token processing should be used. But only consider
|
||||
// using the lower value if the document has already been loading
|
||||
// for 2 seconds. 2 seconds was chosen because it is greater than
|
||||
// the default 3/4 of second that is used to determine when to
|
||||
// switch between the modes and it gives the document a little
|
||||
// time to create windows. This is important because on some
|
||||
// systems (Windows, for example) when a window is created and the
|
||||
// mouse is over it, a mouse move event is sent, which will kick
|
||||
// us into interactive mode otherwise. It also suppresses reaction
|
||||
// to pressing the ENTER key in the URL bar...
|
||||
|
||||
PRUint32 delayBeforeLoweringThreshold =
|
||||
static_cast<PRUint32>(((2 * mDynamicIntervalSwitchThreshold) +
|
||||
NS_DELAY_FOR_WINDOW_CREATION));
|
||||
|
||||
if ((currentTime - mBeginLoadTime) > delayBeforeLoweringThreshold) {
|
||||
if ((currentTime - eventTime) <
|
||||
static_cast<PRUint32>(mDynamicIntervalSwitchThreshold)) {
|
||||
|
||||
if (!mDynamicLowerValue) {
|
||||
// lower the dynamic values to favor application
|
||||
// responsiveness over page load time.
|
||||
mDynamicLowerValue = PR_TRUE;
|
||||
// Set the performance hint to prevent event starvation when
|
||||
// dispatching PLEvents. This improves application responsiveness
|
||||
// during page loads.
|
||||
FavorPerformanceHint(PR_FALSE, 0);
|
||||
}
|
||||
|
||||
}
|
||||
else if (mDynamicLowerValue) {
|
||||
// raise the content notification and MaxTokenProcessing time
|
||||
// to favor overall page load speed over responsiveness.
|
||||
mDynamicLowerValue = PR_FALSE;
|
||||
// Reset the hint that to favoring performance for PLEvent dispatch.
|
||||
FavorPerformanceHint(PR_TRUE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((currentTime - mDelayTimerStart) >
|
||||
static_cast<PRUint32>(GetMaxTokenProcessingTime())) {
|
||||
// Check if it's time to return to the main event loop
|
||||
if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
|
||||
return NS_ERROR_HTMLPARSER_INTERRUPTED;
|
||||
}
|
||||
|
||||
|
@ -1739,10 +1678,39 @@ nsContentSink::DropParserAndPerfHint(void)
|
|||
nsresult
|
||||
nsContentSink::WillParseImpl(void)
|
||||
{
|
||||
if (mCanInterruptParser) {
|
||||
mDelayTimerStart = PR_IntervalToMicroseconds(PR_IntervalNow());
|
||||
if (!mCanInterruptParser || !mParser->CanInterrupt()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIPresShell *shell = mDocument->GetPrimaryShell();
|
||||
if (!shell) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32 currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
||||
|
||||
if (mEnablePerfMode == 0) {
|
||||
nsIViewManager* vm = shell->GetViewManager();
|
||||
NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
|
||||
PRUint32 lastEventTime;
|
||||
vm->GetLastUserEventTime(lastEventTime);
|
||||
|
||||
PRBool newDynLower =
|
||||
(currentTime - mBeginLoadTime) > mInitialPerfTime &&
|
||||
(currentTime - lastEventTime) < mInteractiveTime;
|
||||
|
||||
if (mDynamicLowerValue != newDynLower) {
|
||||
FavorPerformanceHint(!newDynLower, 0);
|
||||
mDynamicLowerValue = newDynLower;
|
||||
}
|
||||
}
|
||||
|
||||
mDeflectedCount = 0;
|
||||
mHasPendingEvent = PR_FALSE;
|
||||
|
||||
mCurrentParseEndTime = currentTime +
|
||||
(mDynamicLowerValue ? mInteractiveParseTime : mPerfParseTime);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -270,15 +270,6 @@ protected:
|
|||
return mNotificationInterval;
|
||||
}
|
||||
|
||||
inline PRInt32 GetMaxTokenProcessingTime()
|
||||
{
|
||||
if (mDynamicLowerValue) {
|
||||
return 3000;
|
||||
}
|
||||
|
||||
return mMaxTokenProcessingTime;
|
||||
}
|
||||
|
||||
// Overridable hooks into script evaluation
|
||||
virtual void PreEvaluateScript() {return;}
|
||||
virtual void PostEvaluateScript(nsIScriptElement *aElement) {return;}
|
||||
|
@ -325,12 +316,6 @@ protected:
|
|||
// Timer used for notification
|
||||
nsCOMPtr<nsITimer> mNotificationTimer;
|
||||
|
||||
// The number of tokens that have been processed while in the low
|
||||
// frequency parser interrupt mode without falling through to the
|
||||
// logic which decides whether to switch to the high frequency
|
||||
// parser interrupt mode.
|
||||
PRUint8 mDeflectedCount;
|
||||
|
||||
// Do we notify based on time?
|
||||
PRPackedBool mNotifyOnTimer;
|
||||
|
||||
|
@ -350,16 +335,43 @@ protected:
|
|||
// If true, we did get a ReadyToCallDidBuildModel call
|
||||
PRUint8 mDidGetReadyToCallDidBuildModelCall : 1;
|
||||
|
||||
//
|
||||
// -- Can interrupt parsing members --
|
||||
PRUint32 mDelayTimerStart;
|
||||
//
|
||||
|
||||
// Interrupt parsing during token procesing after # of microseconds
|
||||
PRInt32 mMaxTokenProcessingTime;
|
||||
// The number of tokens that have been processed since we measured
|
||||
// if it's time to return to the main event loop.
|
||||
PRUint32 mDeflectedCount;
|
||||
|
||||
// Switch between intervals when time is exceeded
|
||||
PRInt32 mDynamicIntervalSwitchThreshold;
|
||||
// How many times to deflect in interactive/perf modes
|
||||
PRInt32 mInteractiveDeflectCount;
|
||||
PRInt32 mPerfDeflectCount;
|
||||
|
||||
PRInt32 mMaxTokensDeflectedInLowFreqMode;
|
||||
// 0 = don't check for pending events
|
||||
// 1 = don't deflect if there are pending events
|
||||
// 2 = bail if there are pending events
|
||||
PRInt32 mPendingEventMode;
|
||||
|
||||
// How often to probe for pending events. 1=every token
|
||||
PRInt32 mEventProbeRate;
|
||||
|
||||
// Is there currently a pending event?
|
||||
PRBool mHasPendingEvent;
|
||||
|
||||
// When to return to the main event loop
|
||||
PRInt32 mCurrentParseEndTime;
|
||||
|
||||
// How long to stay off the event loop in interactive/perf modes
|
||||
PRInt32 mInteractiveParseTime;
|
||||
PRInt32 mPerfParseTime;
|
||||
|
||||
// How long to be in interactive mode after an event
|
||||
PRInt32 mInteractiveTime;
|
||||
// How long to stay in perf mode after initial loading
|
||||
PRInt32 mInitialPerfTime;
|
||||
|
||||
// Should we switch between perf-mode and interactive-mode
|
||||
PRBool mEnablePerfMode;
|
||||
|
||||
PRInt32 mBeginLoadTime;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
|
@ -300,6 +300,12 @@ class nsIParser : public nsISupports {
|
|||
* continue the regular parsing process.
|
||||
*/
|
||||
virtual void ScriptDidExecute() = 0;
|
||||
|
||||
/**
|
||||
* True if the parser can currently be interrupted. Returns false when
|
||||
* parsing for example document.write or innerHTML.
|
||||
*/
|
||||
virtual PRBool CanInterrupt() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIParser, NS_IPARSER_IID)
|
||||
|
|
|
@ -339,7 +339,7 @@ class nsParser : public nsIParser,
|
|||
* @return PR_TRUE if parser can be interrupted, PR_FALSE if it can not be interrupted.
|
||||
* @update kmcclusk 5/18/98
|
||||
*/
|
||||
PRBool CanInterrupt(void);
|
||||
virtual PRBool CanInterrupt();
|
||||
|
||||
/**
|
||||
* Set to parser state to indicate whether parsing tokens can be interrupted
|
||||
|
|
|
@ -917,7 +917,7 @@ class nsIWidget : public nsISupports {
|
|||
* is platform dependent, but is compatible with the expression
|
||||
* PR_IntervalToMicroseconds(PR_IntervalNow()).
|
||||
*/
|
||||
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime) = 0;
|
||||
NS_IMETHOD HasPendingEvent(PRBool& aHasPending) = 0;
|
||||
|
||||
/**
|
||||
* Called when when we need to begin secure keyboard input, such as when a password field
|
||||
|
|
|
@ -3549,16 +3549,12 @@ NS_METHOD nsWindow::SetPreferredSize(PRInt32 aWidth, PRInt32 aHeight)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::GetLastInputEventTime(PRUint32& aTime)
|
||||
nsWindow::HasPendingEvent(PRBool& aHasPending)
|
||||
{
|
||||
ULONG ulStatus = WinQueryQueueStatus(HWND_DESKTOP);
|
||||
|
||||
// If there is pending input then return the current time.
|
||||
if (ulStatus & (QS_KEY | QS_MOUSE)) {
|
||||
gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
|
||||
}
|
||||
|
||||
aTime = gLastInputEventTime;
|
||||
*aHasPending = !!(ulStatus & (QS_KEY | QS_MOUSE));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ class nsWindow : public nsBaseWidget,
|
|||
NS_IMETHOD DispatchEvent( struct nsGUIEvent *event, nsEventStatus &aStatus);
|
||||
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent);
|
||||
|
||||
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime);
|
||||
NS_IMETHOD HasPendingEvent(PRBool& aHasPending);
|
||||
|
||||
// Widget appearance
|
||||
NS_IMETHOD SetColorMap( nsColorMap *aColorMap);
|
||||
|
|
|
@ -209,7 +209,7 @@ public:
|
|||
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent);
|
||||
|
||||
NS_IMETHOD GetAttention(PRInt32 aCycleCount);
|
||||
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime);
|
||||
NS_IMETHOD HasPendingEvent(PRBool& aHasPending);
|
||||
|
||||
// Note that the result of GetTopLevelWindow method can be different from the
|
||||
// result of GetTopLevelHWND method. The result can be non-floating window.
|
||||
|
|
|
@ -843,7 +843,7 @@ nsBaseWidget::GetAttention(PRInt32 aCycleCount) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseWidget::GetLastInputEventTime(PRUint32& aTime) {
|
||||
nsBaseWidget::HasPendingEvent(PRBool& aHasPending) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ public:
|
|||
NS_IMETHOD ScrollWidgets(PRInt32 aDx, PRInt32 aDy);
|
||||
NS_IMETHOD EnableDragDrop(PRBool aEnable);
|
||||
NS_IMETHOD GetAttention(PRInt32 aCycleCount);
|
||||
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime);
|
||||
NS_IMETHOD HasPendingEvent(PRBool& aHasPending);
|
||||
NS_IMETHOD SetIcon(const nsAString &anIconSpec);
|
||||
NS_IMETHOD BeginSecureKeyboardInput();
|
||||
NS_IMETHOD EndSecureKeyboardInput();
|
||||
|
|
Загрузка…
Ссылка в новой задаче