Changeset 175441 in webkit


Ignore:
Timestamp:
Oct 31, 2014 5:12:51 PM (9 years ago)
Author:
Chris Dumez
Message:

Support throttling of DOMTimers using nested setTimeout() calls
https://bugs.webkit.org/show_bug.cgi?id=138262

Reviewed by Gavin Barraclough.

Extend DOMTimers throttling support to timers that are using nested
setTimeout() calls instead of a setInterval(). To achieve this, this
patch introduces a NestedTimersVector singleton class where nested
timers are appended, and for which we potentially update the next
firing time, after the parent timer is done executing.

I have verified this helps on cnn.com for example, which has timers
interacting with non-visible plugins that are scheduled using nested
setTimeout() calls with a frequency of 150 / 200 ms.

  • page/DOMTimer.cpp:

(WebCore::NestedTimersVector::NestedTimersVector):
(WebCore::NestedTimersVector::~NestedTimersVector):
(WebCore::NestedTimersVector::registerTimer):
(WebCore::NestedTimersVector::begin):
(WebCore::NestedTimersVector::end):
(WebCore::DOMTimer::install):
(WebCore::DOMTimer::updateThrottlingStateIfNecessary):
(WebCore::DOMTimer::fired):

  • page/DOMTimer.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r175439 r175441  
     12014-10-31  Chris Dumez  <cdumez@apple.com>
     2
     3        Support throttling of DOMTimers using nested setTimeout() calls
     4        https://bugs.webkit.org/show_bug.cgi?id=138262
     5
     6        Reviewed by Gavin Barraclough.
     7
     8        Extend DOMTimers throttling support to timers that are using nested
     9        setTimeout() calls instead of a setInterval(). To achieve this, this
     10        patch introduces a NestedTimersVector singleton class where nested
     11        timers are appended, and for which we potentially update the next
     12        firing time, after the parent timer is done executing.
     13
     14        I have verified this helps on cnn.com for example, which has timers
     15        interacting with non-visible plugins that are scheduled using nested
     16        setTimeout() calls with a frequency of 150 / 200 ms.
     17
     18        * page/DOMTimer.cpp:
     19        (WebCore::NestedTimersVector::NestedTimersVector):
     20        (WebCore::NestedTimersVector::~NestedTimersVector):
     21        (WebCore::NestedTimersVector::registerTimer):
     22        (WebCore::NestedTimersVector::begin):
     23        (WebCore::NestedTimersVector::end):
     24        (WebCore::DOMTimer::install):
     25        (WebCore::DOMTimer::updateThrottlingStateIfNecessary):
     26        (WebCore::DOMTimer::fired):
     27        * page/DOMTimer.h:
     28
    1292014-10-31  Chris Dumez  <cdumez@apple.com>
    230
  • trunk/Source/WebCore/page/DOMTimer.cpp

    r174225 r175441  
    8585DOMTimerFireState* DOMTimerFireState::current = nullptr;
    8686
     87struct NestedTimersVector {
     88    typedef Vector<DOMTimer*, 1>::const_iterator const_iterator;
     89
     90    NestedTimersVector(ScriptExecutionContext* context)
     91        : shouldSetCurrent(context->isDocument())
     92    {
     93        if (shouldSetCurrent) {
     94            previous = current;
     95            current = this;
     96        }
     97    }
     98
     99    ~NestedTimersVector()
     100    {
     101        if (shouldSetCurrent)
     102            current = previous;
     103    }
     104
     105    static NestedTimersVector* current;
     106
     107    void registerTimer(DOMTimer* timer)
     108    {
     109        nestedTimers.append(timer);
     110    }
     111
     112    const_iterator begin() const { return nestedTimers.begin(); }
     113    const_iterator end() const { return nestedTimers.end(); }
     114
     115private:
     116    bool shouldSetCurrent;
     117    NestedTimersVector* previous;
     118    Vector<DOMTimer*, 1> nestedTimers;
     119};
     120
     121NestedTimersVector* NestedTimersVector::current = nullptr;
     122
    87123static inline bool shouldForwardUserGesture(int interval, int nestingLevel)
    88124{
     
    134170    InspectorInstrumentation::didInstallTimer(context, timer->m_timeoutId, timeout, singleShot);
    135171
     172    // Keep track of nested timer installs.
     173    if (NestedTimersVector::current)
     174        NestedTimersVector::current->registerTimer(timer);
     175
    136176    return timer->m_timeoutId;
    137177}
     
    147187    InspectorInstrumentation::didRemoveTimer(context, timeoutId);
    148188    context->removeTimeout(timeoutId);
     189}
     190
     191void DOMTimer::updateThrottlingStateIfNecessary(const DOMTimerFireState& fireState)
     192{
     193    if (fireState.scriptDidInteractWithUserObservablePlugin && m_throttleState != ShouldNotThrottle) {
     194        m_throttleState = ShouldNotThrottle;
     195        updateTimerIntervalIfNecessary();
     196    } else if (fireState.scriptDidInteractWithNonUserObservablePlugin && m_throttleState == Undetermined) {
     197        m_throttleState = ShouldThrottle;
     198        updateTimerIntervalIfNecessary();
     199    }
    149200}
    150201
     
    199250
    200251        InspectorInstrumentation::didFireTimer(cookie);
    201 
    202         if (fireState.scriptDidInteractWithUserObservablePlugin && m_throttleState != ShouldNotThrottle) {
    203             m_throttleState = ShouldNotThrottle;
    204             updateTimerIntervalIfNecessary();
    205         } else if (fireState.scriptDidInteractWithNonUserObservablePlugin && m_throttleState == Undetermined) {
    206             m_throttleState = ShouldThrottle;
    207             updateTimerIntervalIfNecessary();
    208         }
     252        updateThrottlingStateIfNecessary(fireState);
    209253
    210254        return;
     
    230274#endif
    231275
     276    // Keep track nested timer installs.
     277    NestedTimersVector nestedTimers(context);
    232278    m_action->execute(context);
    233279
     
    243289
    244290    InspectorInstrumentation::didFireTimer(cookie);
     291
     292    // Check if we should throttle nested single-shot timers.
     293    for (auto* timer : nestedTimers) {
     294        if (!timer->repeatInterval())
     295            timer->updateThrottlingStateIfNecessary(fireState);
     296    }
    245297
    246298    context->setTimerNestingLevel(0);
  • trunk/Source/WebCore/page/DOMTimer.h

    r173694 r175441  
    3434namespace WebCore {
    3535
     36    struct DOMTimerFireState;
    3637    class HTMLPlugInElement;
    3738    class ScheduledAction;
     
    5556        DOMTimer(ScriptExecutionContext*, std::unique_ptr<ScheduledAction>, int interval, bool singleShot);
    5657        double intervalClampedToMinimum() const;
     58        void updateThrottlingStateIfNecessary(const DOMTimerFireState&);
    5759
    5860        // SuspendableTimer
Note: See TracChangeset for help on using the changeset viewer.