Title: [142764] trunk/Source/WebCore
Revision
142764
Author
[email protected]
Date
2013-02-13 11:30:53 -0800 (Wed, 13 Feb 2013)

Log Message

Avoid updating timer heap when nothing changes
https://bugs.webkit.org/show_bug.cgi?id=109630

Reviewed by Andreas Kling.

When the fire time of a Timer is changed we remove it from the timer heap and reinsert it. This is pretty slow. 
Turns out that in ~80% of cases we are already in the heap and the insertion position is the same as the 
original position. We can check if anything is actually going to change before doing this work.
        
This makes starting a timer ~30% faster in average, ~0.1% progression in PLT3.
        
* platform/Timer.cpp:
(TimerHeapLessThanFunction):
(WebCore::TimerHeapLessThanFunction::operator()):
(WebCore::parentHeapPropertyHolds):
(WebCore):
(WebCore::childHeapPropertyHolds):
(WebCore::TimerBase::hasValidHeapPosition):
        
    The code here assumes that STL heap is a normal binary heap. If there is a different implementation
    somewhere the assertions will catch it.

(WebCore::TimerBase::updateHeapIfNeeded):
        
    Skip updating the heap if it is already valid.

(WebCore::TimerBase::setNextFireTime):
* platform/Timer.h:
(TimerBase):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (142763 => 142764)


--- trunk/Source/WebCore/ChangeLog	2013-02-13 19:18:43 UTC (rev 142763)
+++ trunk/Source/WebCore/ChangeLog	2013-02-13 19:30:53 UTC (rev 142764)
@@ -1,3 +1,35 @@
+2013-02-12  Antti Koivisto  <[email protected]>
+
+        Avoid updating timer heap when nothing changes
+        https://bugs.webkit.org/show_bug.cgi?id=109630
+
+        Reviewed by Andreas Kling.
+
+        When the fire time of a Timer is changed we remove it from the timer heap and reinsert it. This is pretty slow. 
+        Turns out that in ~80% of cases we are already in the heap and the insertion position is the same as the 
+        original position. We can check if anything is actually going to change before doing this work.
+        
+        This makes starting a timer ~30% faster in average, ~0.1% progression in PLT3.
+        
+        * platform/Timer.cpp:
+        (TimerHeapLessThanFunction):
+        (WebCore::TimerHeapLessThanFunction::operator()):
+        (WebCore::parentHeapPropertyHolds):
+        (WebCore):
+        (WebCore::childHeapPropertyHolds):
+        (WebCore::TimerBase::hasValidHeapPosition):
+        
+            The code here assumes that STL heap is a normal binary heap. If there is a different implementation
+            somewhere the assertions will catch it.
+
+        (WebCore::TimerBase::updateHeapIfNeeded):
+        
+            Skip updating the heap if it is already valid.
+
+        (WebCore::TimerBase::setNextFireTime):
+        * platform/Timer.h:
+        (TimerBase):
+
 2013-02-13  Martin Robinson  <[email protected]>
 
         [GTK] Remove remaining dead code from the GLib unicode backend

Modified: trunk/Source/WebCore/platform/Timer.cpp (142763 => 142764)


--- trunk/Source/WebCore/platform/Timer.cpp	2013-02-13 19:18:43 UTC (rev 142763)
+++ trunk/Source/WebCore/platform/Timer.cpp	2013-02-13 19:30:53 UTC (rev 142764)
@@ -167,10 +167,10 @@
 
 class TimerHeapLessThanFunction {
 public:
-    bool operator()(TimerBase*, TimerBase*) const;
+    bool operator()(const TimerBase*, const TimerBase*) const;
 };
 
-inline bool TimerHeapLessThanFunction::operator()(TimerBase* a, TimerBase* b) const
+inline bool TimerHeapLessThanFunction::operator()(const TimerBase* a, const TimerBase* b) const
 {
     // The comparisons below are "backwards" because the heap puts the largest 
     // element first and we want the lowest time to be the first one in the heap.
@@ -312,6 +312,58 @@
     ASSERT(this == timerHeap().last());
 }
 
+static inline bool parentHeapPropertyHolds(const TimerBase* current, const Vector<TimerBase*>& heap, unsigned currentIndex)
+{
+    if (!currentIndex)
+        return true;
+    unsigned parentIndex = (currentIndex - 1) / 2;
+    TimerHeapLessThanFunction compareHeapPosition;
+    return compareHeapPosition(current, heap[parentIndex]);
+}
+
+static inline bool childHeapPropertyHolds(const TimerBase* current, const Vector<TimerBase*>& heap, unsigned childIndex)
+{
+    if (childIndex >= heap.size())
+        return true;
+    TimerHeapLessThanFunction compareHeapPosition;
+    return compareHeapPosition(heap[childIndex], current);
+}
+
+bool TimerBase::hasValidHeapPosition() const
+{
+    ASSERT(m_nextFireTime);
+    if (!inHeap())
+        return false;
+    // Check if the heap property still holds with the new fire time. If it does we don't need to do anything.
+    // This assumes that the STL heap is a standard binary heap. In an unlikely event it is not, the assertions
+    // in updateHeapIfNeeded() will get hit.
+    const Vector<TimerBase*>& heap = timerHeap();
+    if (!parentHeapPropertyHolds(this, heap, m_heapIndex))
+        return false;
+    unsigned childIndex1 = 2 * m_heapIndex + 1;
+    unsigned childIndex2 = childIndex1 + 1;
+    return childHeapPropertyHolds(this, heap, childIndex1) && childHeapPropertyHolds(this, heap, childIndex2);
+}
+
+void TimerBase::updateHeapIfNeeded(double oldTime)
+{
+    if (m_nextFireTime && hasValidHeapPosition())
+        return;
+#ifndef NDEBUG
+    int oldHeapIndex = m_heapIndex;
+#endif
+    if (!oldTime)
+        heapInsert();
+    else if (!m_nextFireTime)
+        heapDelete();
+    else if (m_nextFireTime < oldTime)
+        heapDecreaseKey();
+    else
+        heapIncreaseKey();
+    ASSERT(m_heapIndex != oldHeapIndex);
+    ASSERT(!inHeap() || hasValidHeapPosition());
+}
+
 void TimerBase::setNextFireTime(double newUnalignedTime)
 {
     ASSERT(m_thread == currentThread());
@@ -333,14 +385,7 @@
 
         bool wasFirstTimerInHeap = m_heapIndex == 0;
 
-        if (oldTime == 0)
-            heapInsert();
-        else if (newTime == 0)
-            heapDelete();
-        else if (newTime < oldTime)
-            heapDecreaseKey();
-        else
-            heapIncreaseKey();
+        updateHeapIfNeeded(oldTime);
 
         bool isFirstTimerInHeap = m_heapIndex == 0;
 

Modified: trunk/Source/WebCore/platform/Timer.h (142763 => 142764)


--- trunk/Source/WebCore/platform/Timer.h	2013-02-13 19:18:43 UTC (rev 142763)
+++ trunk/Source/WebCore/platform/Timer.h	2013-02-13 19:30:53 UTC (rev 142764)
@@ -73,6 +73,9 @@
 
     bool inHeap() const { return m_heapIndex != -1; }
 
+    bool hasValidHeapPosition() const;
+    void updateHeapIfNeeded(double oldTime);
+
     void heapDecreaseKey();
     void heapDelete();
     void heapDeleteMin();
@@ -81,8 +84,7 @@
     void heapPop();
     void heapPopMin();
 
-    const Vector<TimerBase*>& timerHeap() const { ASSERT(m_cachedThreadGlobalTimerHeap); return *m_cachedThreadGlobalTimerHeap; }
-    Vector<TimerBase*>& timerHeap() { ASSERT(m_cachedThreadGlobalTimerHeap); return *m_cachedThreadGlobalTimerHeap; }
+    Vector<TimerBase*>& timerHeap() const { ASSERT(m_cachedThreadGlobalTimerHeap); return *m_cachedThreadGlobalTimerHeap; }
 
     double m_nextFireTime; // 0 if inactive
     double m_unalignedNextFireTime; // m_nextFireTime not considering alignment interval
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to