Changeset 241351 in webkit
- Timestamp:
- Feb 13, 2019 12:41:22 AM (5 years ago)
- Location:
- trunk/Source/WebKit
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r241349 r241351 1 2019-02-13 Benjamin Poulain <benjamin@webkit.org> 2 3 Responsiveness timers are too expensive for frequent events 4 https://bugs.webkit.org/show_bug.cgi?id=194003 5 6 Reviewed by Geoffrey Garen. 7 8 With each event, we set a responsivness timer to check if the WebProcess 9 is responsive, and reset the timer when the WebProcess sends an answer. 10 11 For frequent events (e.g. wheel events, mouse force events, etc), 12 we are spamming the kernel with hundreds of timers per second. 13 That is a bit inefficient. 14 15 Another source of inefficiency comes from the timer implementation 16 itself. Stopping a RunLoop::Timer removes the timer from every mode 17 and invalidate the timer. It becomes costly since we do it a lot. 18 19 With this patch, I tweak ResponsivenessTimer and its use to minimize 20 how often we schedule system timers. 21 22 The first change is to not stop the timer when we get the stop() 23 calls if we expect more events to come in. Instead, we keep track 24 if we care about the timeout or not in the attribute "m_waitingForTimer". 25 When the next event starts, we can reschedule the timer without ever 26 having told the kernel about the stop. 27 If there are no next events, the timeout fires but m_waitingForTimer 28 is false. To avoid idle wake up, the lazy stop is only used when having 29 following events is common. 30 31 The second improvements comes from not even rescheduling the timer 32 when restarted. Instead of changing the timer, we let the original timer 33 fire and re-shedule a new one with the missing time. 34 35 For more context, also see patches r240759 and r240944. 36 37 * UIProcess/ResponsivenessTimer.cpp: 38 (WebKit::ResponsivenessTimer::ResponsivenessTimer): 39 (WebKit::ResponsivenessTimer::invalidate): 40 (WebKit::ResponsivenessTimer::timerFired): 41 (WebKit::ResponsivenessTimer::start): 42 (WebKit::ResponsivenessTimer::startWithLazyStop): 43 (WebKit::ResponsivenessTimer::stop): 44 (WebKit::ResponsivenessTimer::processTerminated): 45 (WebKit::ResponsivenessTimer::~ResponsivenessTimer): Deleted. 46 * UIProcess/ResponsivenessTimer.h: 47 (WebKit::ResponsivenessTimer::hasActiveTimer const): 48 * UIProcess/WebPageProxy.cpp: 49 (WebKit::WebPageProxy::processNextQueuedMouseEvent): 50 (WebKit::WebPageProxy::sendWheelEvent): 51 (WebKit::WebPageProxy::handleKeyboardEvent): 52 (WebKit::WebPageProxy::handleGestureEvent): 53 * UIProcess/WebProcessProxy.cpp: 54 (WebKit::WebProcessProxy::isResponsiveWithLazyStop): 55 * UIProcess/WebProcessProxy.h: 56 1 57 2019-02-12 Tim Horton <timothy_horton@apple.com> 2 58 -
trunk/Source/WebKit/UIProcess/ResponsivenessTimer.cpp
r241113 r241351 33 33 ResponsivenessTimer::ResponsivenessTimer(ResponsivenessTimer::Client& client) 34 34 : m_client(client) 35 , m_isResponsive(true)36 35 , m_timer(RunLoop::main(), this, &ResponsivenessTimer::timerFired) 37 36 { 38 37 } 39 38 40 ResponsivenessTimer::~ResponsivenessTimer() 41 { 42 m_timer.stop(); 43 } 39 ResponsivenessTimer::~ResponsivenessTimer() = default; 44 40 45 41 void ResponsivenessTimer::invalidate() 46 42 { 47 43 m_timer.stop(); 44 m_restartFireTime = MonotonicTime(); 45 m_waitingForTimer = false; 46 m_useLazyStop = false; 48 47 } 49 48 50 49 void ResponsivenessTimer::timerFired() 51 50 { 51 if (!m_waitingForTimer) 52 return; 53 54 if (m_restartFireTime) { 55 MonotonicTime now = MonotonicTime::now(); 56 MonotonicTime restartFireTime = m_restartFireTime; 57 m_restartFireTime = MonotonicTime(); 58 59 if (restartFireTime > now) { 60 m_timer.startOneShot(now - restartFireTime); 61 return; 62 } 63 } 64 65 m_waitingForTimer = false; 66 m_useLazyStop = false; 67 52 68 if (!m_isResponsive) 53 69 return; 54 70 55 71 if (!m_client.mayBecomeUnresponsive()) { 72 m_waitingForTimer = true; 56 73 m_timer.startOneShot(responsivenessTimeout); 57 74 return; … … 67 84 void ResponsivenessTimer::start() 68 85 { 69 if (m_ timer.isActive())86 if (m_waitingForTimer) 70 87 return; 71 88 72 m_timer.startOneShot(responsivenessTimeout); 89 m_waitingForTimer = true; 90 m_useLazyStop = false; 91 92 if (m_timer.isActive()) { 93 // The timer is still active from a lazy stop. 94 // Instead of restarting the timer, we schedule a new delay after this one finishes. 95 // 96 // In most cases, stop is called before we get to schedule the second timer, saving us 97 // the scheduling of the timer entirely. 98 m_restartFireTime = MonotonicTime::now() + responsivenessTimeout; 99 } else { 100 m_restartFireTime = MonotonicTime(); 101 m_timer.startOneShot(responsivenessTimeout); 102 } 103 } 104 105 void ResponsivenessTimer::startWithLazyStop() 106 { 107 if (!m_waitingForTimer) { 108 start(); 109 m_useLazyStop = true; 110 } 73 111 } 74 112 … … 84 122 } 85 123 86 m_timer.stop(); 124 m_waitingForTimer = false; 125 126 if (m_useLazyStop) 127 m_useLazyStop = false; 128 else 129 m_timer.stop(); 87 130 } 88 131 89 132 void ResponsivenessTimer::processTerminated() 90 133 { 91 // Since there is no web process, we must not be waiting for it anymore. 92 stop(); 134 invalidate(); 93 135 } 94 136 -
trunk/Source/WebKit/UIProcess/ResponsivenessTimer.h
r241113 r241351 47 47 explicit ResponsivenessTimer(ResponsivenessTimer::Client&); 48 48 ~ResponsivenessTimer(); 49 49 50 50 void start(); 51 52 // A responsiveness timer with lazy stop does not stop the underlying system timer when stopped. 53 // Instead, it ignores the timeout if stop() was already called. 54 // 55 // This exists to reduce the rate at which we reset the timer. 56 // 57 // With a non lazy timer, we may set a timer and reset it soon after because the process is responsive. 58 // For events, this means reseting a timer 120 times/s for a 60 Hz event source. 59 // By not reseting the timer when responsive, we cut that in half to 60 timeout changes. 60 void startWithLazyStop(); 61 51 62 void stop(); 52 63 53 64 void invalidate(); 54 65 66 // Return true if stop() was not called betfore the responsiveness timeout. 55 67 bool isResponsive() const { return m_isResponsive; } 68 69 // Return true if there is an active timer. The state could be responsive or not. 70 bool hasActiveTimer() const { return m_waitingForTimer; } 56 71 57 72 void processTerminated(); … … 61 76 62 77 ResponsivenessTimer::Client& m_client; 63 bool m_isResponsive;64 78 65 79 RunLoop::Timer<ResponsivenessTimer> m_timer; 80 MonotonicTime m_restartFireTime; 81 82 bool m_isResponsive { true }; 83 bool m_waitingForTimer { false }; 84 bool m_useLazyStop { false }; 66 85 }; 67 86 -
trunk/Source/WebKit/UIProcess/WebPageProxy.cpp
r241336 r241351 2233 2233 2234 2234 const NativeWebMouseEvent& event = m_mouseEventQueue.first(); 2235 2235 2236 2236 if (pageClient().windowIsFrontWindowUnderMouse(event)) 2237 2237 setToolTip(String()); 2238 2238 2239 // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction. 2240 if (event.type() != WebEvent::MouseMove) 2239 WebEvent::Type eventType = event.type(); 2240 if (eventType == WebEvent::MouseDown || eventType == WebEvent::MouseForceChanged || eventType == WebEvent::MouseForceDown) 2241 m_process->responsivenessTimer().startWithLazyStop(); 2242 else if (eventType != WebEvent::MouseMove) { 2243 // NOTE: This does not start the responsiveness timer because mouse move should not indicate interaction. 2241 2244 m_process->responsivenessTimer().start(); 2242 2243 LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(event.type()), m_mouseEventQueue.size()); 2245 } 2246 2247 LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size()); 2244 2248 m_process->send(Messages::WebPage::MouseEvent(event), m_pageID); 2245 2249 } … … 2361 2365 // Manually ping the web process to check for responsiveness since our wheel 2362 2366 // event will dispatch to a non-main thread, which always responds. 2363 m_process->isResponsive (nullptr);2367 m_process->isResponsiveWithLazyStop(); 2364 2368 } 2365 2369 … … 2394 2398 m_keyEventQueue.append(event); 2395 2399 2396 m_process->responsivenessTimer().start(); 2400 ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer(); 2401 if (event.type() == WebEvent::KeyDown) 2402 responsivenessTimer.startWithLazyStop(); 2403 else 2404 responsivenessTimer.start(); 2405 2397 2406 if (m_keyEventQueue.size() == 1) { // Otherwise, sent from DidReceiveEvent message handler. 2398 2407 LOG(KeyHandling, " UI process: sent keyEvent from handleKeyboardEvent"); … … 2556 2565 m_gestureEventQueue.append(event); 2557 2566 // FIXME: Consider doing some coalescing here. 2558 m_process->responsivenessTimer().start(); 2567 2568 ResponsivenessTimer& responsivenessTimer = m_process->responsivenessTimer(); 2569 if (event.type() == WebEvent::GestureStart || event.type() == WebEvent::GestureChange) 2570 responsivenessTimer.startWithLazyStop(); 2571 else 2572 responsivenessTimer.start(); 2559 2573 2560 2574 m_process->send(Messages::EventDispatcher::GestureEvent(m_pageID, event), 0); -
trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp
r241232 r241351 1134 1134 } 1135 1135 1136 void WebProcessProxy::isResponsiveWithLazyStop() 1137 { 1138 if (m_isResponsive == NoOrMaybe::No) 1139 return; 1140 1141 if (!responsivenessTimer().hasActiveTimer()) { 1142 // We do not send a ping if we are already waiting for the WebProcess. 1143 // Spamming pings on a slow web process is not helpful. 1144 responsivenessTimer().startWithLazyStop(); 1145 send(Messages::WebProcess::MainThreadPing(), 0); 1146 } 1147 } 1148 1136 1149 bool WebProcessProxy::isJITEnabled() const 1137 1150 { -
trunk/Source/WebKit/UIProcess/WebProcessProxy.h
r241232 r241351 203 203 204 204 void isResponsive(WTF::Function<void(bool isWebProcessResponsive)>&&); 205 void isResponsiveWithLazyStop(); 205 206 void didReceiveMainThreadPing(); 206 207 void didReceiveBackgroundResponsivenessPing();
Note: See TracChangeset
for help on using the changeset viewer.