Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/base/intrusive_heap.h

Issue 2419793002: [Reland] Optimize blink scheduler with an intrusive heap (Closed)
Patch Set: Tiny optimization of MoveHoleDownAndFillWithLeafElement Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
6 #define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
7
8 #include <vector>
9
10 #include "base/logging.h"
11 #include "public/platform/WebCommon.h"
12
13 namespace blink {
14 namespace scheduler {
15
16 // A standard min-heap with the following assumptions:
17 // 1. T has operator <=
18 // 2. T has method void SetHeapIndex(size_t index)
altimin 2016/10/14 17:06:36 I'd like to suggest using a callback, passed to co
altimin 2016/10/14 17:06:36 3. T is moveable? 4. T is default-constructible? (
alex clarke (OOO till 29th) 2016/10/14 21:49:46 Please bear in mind this probably isn't going to b
alex clarke (OOO till 29th) 2016/10/14 21:49:46 That will be a performance regression. The method
19 template <typename T>
20 class BLINK_PLATFORM_EXPORT IntrusiveHeap {
21 public:
22 IntrusiveHeap() : nodes_(kMinimumHeapSize), size_(0) {}
23
24 bool empty() const { return size_ == 0; }
25
26 size_t size() const { return size_; }
27
28 void clear() {
29 nodes_.resize(kMinimumHeapSize);
30 size_ = 0;
31 }
32
33 const T& min() const {
34 DCHECK_GE(size_, 1u);
35 return nodes_[1];
36 }
37
38 void pop() {
altimin 2016/10/14 17:06:36 It may be a good idea for pop and EraseHeapIndex t
alex clarke (OOO till 29th) 2016/10/14 21:49:46 Two points: 1. In general it's a good idea for co
39 DCHECK_GE(size_, 1u);
40 size_t top_index = size_--;
altimin 2016/10/14 17:06:36 Do we want to shrink down the size of the underlyi
alex clarke (OOO till 29th) 2016/10/14 21:49:45 No. These never get very large anyway (perhaps 100
41 MakeHole(1u);
42 if (!empty())
43 MoveHoleDownAndFillWithLeafElement(1u, std::move(nodes_[top_index]));
altimin 2016/10/14 17:06:35 Should we report to SetHeapIndex about element bei
alex clarke (OOO till 29th) 2016/10/14 21:49:46 We know when that happens already since we call er
44 }
45
46 void insert(T&& element) {
47 size_++;
48 if (size_ >= nodes_.size())
49 nodes_.resize(size_ * 2);
50 // Notionally we have a hole in the tree at index |size_|, move this up
51 // to find the right insertion point.
52 MoveHoleUpAndFillWithElement(size_, std::move(element));
53 }
54
55 void EraseHeapIndex(size_t index) {
56 DCHECK_GT(index, kInvalidIndex);
57 DCHECK_LE(index, size_);
58 size_t top_index = size_--;
59 if (empty() || top_index == index)
60 return;
61 MakeHole(index);
62 if (nodes_[index] <= nodes_[top_index]) {
63 MoveHoleDownAndFillWithLeafElement(index, std::move(nodes_[top_index]));
64 } else {
65 MoveHoleUpAndFillWithElement(index, std::move(nodes_[top_index]));
66 }
67 }
68
69 void ReplaceMin(T&& element) {
70 // Note |element| might not be a leaf node so we can't use
71 // MoveHoleDownAndFillWithLeafElement.
72 MoveHoleDownAndFillWithElement(1u, std::move(element));
73 }
74
75 const std::vector<T>& GetNodesForTesting() const { return nodes_; }
altimin 2016/10/14 17:06:36 I believe that we can replace this method with: 1.
alex clarke (OOO till 29th) 2016/10/14 21:49:46 I'd rather not.
76
77 enum { kInvalidIndex = 0u };
altimin 2016/10/14 17:06:35 For my curiosity — what's the advantage of using e
alex clarke (OOO till 29th) 2016/10/14 21:49:46 None. It's just the old school way of doing it.
78
79 private:
80 enum {
81 // The majority of sets in the scheduler have 0-3 items in them (a few will
82 // have perhaps up to 100), so this means we usually only have to allocate
83 // memory once.
84 kMinimumHeapSize = 4u
85 };
86
87 size_t MoveHole(size_t new_hole_pos, size_t old_hole_pos) {
88 DCHECK_GT(new_hole_pos, kInvalidIndex);
89 DCHECK_LE(new_hole_pos, size_);
90 DCHECK_GT(new_hole_pos, kInvalidIndex);
91 DCHECK_LE(new_hole_pos, size_);
92 DCHECK_NE(old_hole_pos, new_hole_pos);
93 nodes_[old_hole_pos] = std::move(nodes_[new_hole_pos]);
94 nodes_[old_hole_pos].SetHeapIndex(old_hole_pos);
95 return new_hole_pos;
96 }
97
98 // Notionally creates a hole in the tree at |index|.
99 void MakeHole(size_t index) { nodes_[index].SetHeapIndex(kInvalidIndex); }
100
101 void FillHole(size_t hole, T&& element) {
102 nodes_[hole] = std::move(element);
103 nodes_[hole].SetHeapIndex(hole);
104 }
105
106 // Moves the |hole| up the tree and when the right position has been found
107 // |element| is moved in.
108 void MoveHoleUpAndFillWithElement(size_t hole, T&& element) {
109 DCHECK_GT(hole, kInvalidIndex);
110 DCHECK_LE(hole, size_);
111 while (hole >= 2u) {
112 size_t parent_pos = hole / 2;
113 if (nodes_[parent_pos] <= element)
114 break;
115
116 hole = MoveHole(parent_pos, hole);
117 }
118 FillHole(hole, std::move(element));
119 }
120
121 // Moves the |hole| down the tree and when the right position has been found
122 // |element| is moved in.
123 void MoveHoleDownAndFillWithElement(size_t hole, T&& element) {
124 DCHECK_GT(hole, kInvalidIndex);
125 DCHECK_LE(hole, size_);
126 size_t child_pos = hole * 2;
127 while (child_pos < size_) {
128 if (nodes_[child_pos + 1] <= nodes_[child_pos])
129 child_pos++;
130
131 if (element <= nodes_[child_pos])
132 break;
133
134 hole = MoveHole(child_pos, hole);
135 child_pos *= 2;
136 }
137 if (child_pos == size_ && !(element <= nodes_[child_pos]))
138 hole = MoveHole(child_pos, hole);
139 FillHole(hole, std::move(element));
140 }
141
142 // Moves the |hole| down the tree and when the right position has been found
143 // |leaf_element| is moved in. Faster than MoveHoleDownAndFillWithElement
144 // (it does one key comparison per level instead of two) but only valid for
145 // leaf elements (i.e. one of the max values).
146 void MoveHoleDownAndFillWithLeafElement(size_t hole, T&& leaf_element) {
147 DCHECK_GT(hole, kInvalidIndex);
148 DCHECK_LE(hole, size_);
149 size_t child_pos = hole * 2;
150 while (child_pos < size_) {
151 size_t second_child = child_pos + 1;
152 if (nodes_[second_child] <= nodes_[child_pos])
153 child_pos = second_child;
154 hole = MoveHole(child_pos, hole);
155 child_pos *= 2;
156 }
157 if (child_pos == size_)
158 hole = MoveHole(child_pos, hole);
159 MoveHoleUpAndFillWithElement(hole, std::move(leaf_element));
160 }
161
162 std::vector<T> nodes_; // NOTE we use 1-based indexing
163 size_t size_;
164 };
165
166 } // namespace scheduler
167 } // namespace blink
168
169 #endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698