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

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

Issue 2428073002: Revert of [Reland] Optimize blink scheduler with an intrusive heap (Closed)
Patch Set: 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 <algorithm>
9 #include <vector>
10
11 #include "base/logging.h"
12
13 namespace blink {
14 namespace scheduler {
15
16 template <typename T>
17 class IntrusiveHeap;
18
19 // Intended as an opaque wrapper around |index_|.
20 class HeapHandle {
21 public:
22 HeapHandle() : index_(0u) {}
23
24 bool IsValid() const { return index_ != 0u; }
25
26 private:
27 template <typename T>
28 friend class IntrusiveHeap;
29
30 HeapHandle(size_t index) : index_(index) {}
31
32 size_t index_;
33 };
34
35 // A standard min-heap with the following assumptions:
36 // 1. T has operator <=
37 // 2. T has method void SetHeapHandle(HeapHandle handle)
38 // 3. T is moveable
39 // 4. T is default constructible
40 // 5. The heap size never gets terribly big so reclaiming memory on pop/erase
41 // isn't a priority.
42 //
43 // The reason IntrusiveHeap exists is to provide similar performance to
44 // std::priority_queue while allowing removal of arbitrary elements.
45 template <typename T>
46 class IntrusiveHeap {
47 public:
48 IntrusiveHeap() : nodes_(kMinimumHeapSize), size_(0) {}
49
50 bool empty() const { return size_ == 0; }
51
52 size_t size() const { return size_; }
53
54 void clear() {
55 nodes_.resize(kMinimumHeapSize);
56 size_ = 0;
57 }
58
59 const T& min() const {
60 DCHECK_GE(size_, 1u);
61 return nodes_[1];
62 }
63
64 void pop() {
65 DCHECK_GE(size_, 1u);
66 MakeHole(1u);
67 size_t top_index = size_--;
68 if (!empty())
69 MoveHoleDownAndFillWithLeafElement(1u, std::move(nodes_[top_index]));
70 }
71
72 void insert(T&& element) {
73 size_++;
74 if (size_ >= nodes_.size())
75 nodes_.resize(nodes_.size() * 2);
76 // Notionally we have a hole in the tree at index |size_|, move this up
77 // to find the right insertion point.
78 MoveHoleUpAndFillWithElement(size_, std::move(element));
79 }
80
81 void erase(HeapHandle handle) {
82 DCHECK_GT(handle.index_, 0u);
83 DCHECK_LE(handle.index_, size_);
84 MakeHole(handle.index_);
85 size_t top_index = size_--;
86 if (empty() || top_index == handle.index_)
87 return;
88 if (nodes_[handle.index_] <= nodes_[top_index]) {
89 MoveHoleDownAndFillWithLeafElement(handle.index_,
90 std::move(nodes_[top_index]));
91 } else {
92 MoveHoleUpAndFillWithElement(handle.index_, std::move(nodes_[top_index]));
93 }
94 }
95
96 void ReplaceMin(T&& element) {
97 // Note |element| might not be a leaf node so we can't use
98 // MoveHoleDownAndFillWithLeafElement.
99 MoveHoleDownAndFillWithElement(1u, std::move(element));
100 }
101
102 // Caution mutating the heap invalidates the iterators.
103 const T* begin() const { return &nodes_[1u]; }
104 const T* end() const { return begin() + size_; }
105
106 private:
107 enum {
108 // The majority of sets in the scheduler have 0-3 items in them (a few will
109 // have perhaps up to 100), so this means we usually only have to allocate
110 // memory once.
111 kMinimumHeapSize = 4u
112 };
113
114 size_t MoveHole(size_t new_hole_pos, size_t old_hole_pos) {
115 DCHECK_GT(new_hole_pos, 0u);
116 DCHECK_LE(new_hole_pos, size_);
117 DCHECK_GT(new_hole_pos, 0u);
118 DCHECK_LE(new_hole_pos, size_);
119 DCHECK_NE(old_hole_pos, new_hole_pos);
120 nodes_[old_hole_pos] = std::move(nodes_[new_hole_pos]);
121 nodes_[old_hole_pos].SetHeapHandle(HeapHandle(old_hole_pos));
122 return new_hole_pos;
123 }
124
125 // Notionally creates a hole in the tree at |index|.
126 void MakeHole(size_t index) {
127 DCHECK_GT(index, 0u);
128 DCHECK_LE(index, size_);
129 nodes_[index].SetHeapHandle(HeapHandle(0u));
130 }
131
132 void FillHole(size_t hole, T&& element) {
133 DCHECK_GT(hole, 0u);
134 DCHECK_LE(hole, size_);
135 nodes_[hole] = std::move(element);
136 nodes_[hole].SetHeapHandle(HeapHandle(hole));
137 DCHECK(std::is_heap(begin(), end(), CompareNodes));
138 }
139
140 static bool CompareNodes(const T& a, const T& b) { return b <= a; }
141
142 // Moves the |hole| up the tree and when the right position has been found
143 // |element| is moved in.
144 void MoveHoleUpAndFillWithElement(size_t hole, T&& element) {
145 DCHECK_GT(hole, 0u);
146 DCHECK_LE(hole, size_);
147 while (hole >= 2u) {
148 size_t parent_pos = hole / 2;
149 if (nodes_[parent_pos] <= element)
150 break;
151
152 hole = MoveHole(parent_pos, hole);
153 }
154 FillHole(hole, std::move(element));
155 }
156
157 // Moves the |hole| down the tree and when the right position has been found
158 // |element| is moved in.
159 void MoveHoleDownAndFillWithElement(size_t hole, T&& element) {
160 DCHECK_GT(hole, 0u);
161 DCHECK_LE(hole, size_);
162 size_t child_pos = hole * 2;
163 while (child_pos < size_) {
164 if (nodes_[child_pos + 1] <= nodes_[child_pos])
165 child_pos++;
166
167 if (element <= nodes_[child_pos])
168 break;
169
170 hole = MoveHole(child_pos, hole);
171 child_pos *= 2;
172 }
173 if (child_pos == size_ && !(element <= nodes_[child_pos]))
174 hole = MoveHole(child_pos, hole);
175 FillHole(hole, std::move(element));
176 }
177
178 // Moves the |hole| down the tree and when the right position has been found
179 // |leaf_element| is moved in. Faster than MoveHoleDownAndFillWithElement
180 // (it does one key comparison per level instead of two) but only valid for
181 // leaf elements (i.e. one of the max values).
182 void MoveHoleDownAndFillWithLeafElement(size_t hole, T&& leaf_element) {
183 DCHECK_GT(hole, 0u);
184 DCHECK_LE(hole, size_);
185 size_t child_pos = hole * 2;
186 while (child_pos < size_) {
187 size_t second_child = child_pos + 1;
188 if (nodes_[second_child] <= nodes_[child_pos])
189 child_pos = second_child;
190
191 hole = MoveHole(child_pos, hole);
192 child_pos *= 2;
193 }
194 if (child_pos == size_)
195 hole = MoveHole(child_pos, hole);
196 MoveHoleUpAndFillWithElement(hole, std::move(leaf_element));
197 }
198
199 std::vector<T> nodes_; // NOTE we use 1-based indexing
200 size_t size_;
201 };
202
203 } // namespace scheduler
204 } // namespace blink
205
206 #endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698