OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "courgette/label_manager.h" | 5 #include "courgette/label_manager.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/numerics/safe_conversions.h" | 13 #include "base/numerics/safe_conversions.h" |
14 #include "base/numerics/safe_math.h" | 14 #include "base/numerics/safe_math.h" |
15 #include "courgette/consecutive_range_visitor.h" | 15 #include "courgette/consecutive_range_visitor.h" |
16 | 16 |
17 namespace courgette { | 17 namespace courgette { |
18 | 18 |
19 LabelManager::LabelManager() {} | 19 LabelManager::SimpleIndexAssigner::SimpleIndexAssigner(LabelVector* labels) |
20 | |
21 LabelManager::~LabelManager() {} | |
22 | |
23 // static | |
24 int LabelManager::GetIndexBound(const LabelVector& labels) { | |
25 int max_index = -1; | |
26 for (const Label& label : labels) { | |
27 if (label.index_ != Label::kNoIndex) | |
28 max_index = std::max(max_index, label.index_); | |
29 } | |
30 return max_index + 1; | |
31 } | |
32 | |
33 // static | |
34 int LabelManager::GetIndexBound(const RVAToLabel& labels_map) { | |
35 int max_index = -1; | |
36 for (const auto& rva_and_label : labels_map) { | |
37 const Label& label = *rva_and_label.second; | |
38 if (label.index_ != Label::kNoIndex) | |
39 max_index = std::max(max_index, label.index_); | |
40 } | |
41 return max_index + 1; | |
42 } | |
43 | |
44 LabelManagerImpl::RvaVisitor::~RvaVisitor() {} | |
45 | |
46 LabelManagerImpl::SimpleIndexAssigner::SimpleIndexAssigner(LabelVector* labels) | |
47 : labels_(labels) { | 20 : labels_(labels) { |
48 // Initialize |num_index_| and |available_|. | 21 // Initialize |num_index_| and |available_|. |
49 num_index_ = std::max(base::checked_cast<int>(labels_->size()), | 22 num_index_ = std::max(base::checked_cast<int>(labels_->size()), |
50 LabelManager::GetIndexBound(*labels_)); | 23 GetLabelIndexBound(*labels_)); |
51 available_.resize(num_index_, true); | 24 available_.resize(num_index_, true); |
52 size_t used = 0; | 25 size_t used = 0; |
53 for (const Label& label : *labels_) { | 26 for (const Label& label : *labels_) { |
54 if (label.index_ != Label::kNoIndex) { | 27 if (label.index_ != Label::kNoIndex) { |
55 available_.at(label.index_) = false; | 28 available_.at(label.index_) = false; |
56 ++used; | 29 ++used; |
57 } | 30 } |
58 } | 31 } |
59 VLOG(1) << used << " of " << labels_->size() << " labels pre-assigned."; | 32 VLOG(1) << used << " of " << labels_->size() << " labels pre-assigned."; |
60 } | 33 } |
61 | 34 |
62 LabelManagerImpl::SimpleIndexAssigner::~SimpleIndexAssigner() {} | 35 LabelManager::SimpleIndexAssigner::~SimpleIndexAssigner() {} |
63 | 36 |
64 void LabelManagerImpl::SimpleIndexAssigner::DoForwardFill() { | 37 void LabelManager::SimpleIndexAssigner::DoForwardFill() { |
65 size_t count = 0; | 38 size_t count = 0; |
66 // Inside the loop, if |prev_index| == |kNoIndex| then we try to assign 0. | 39 // Inside the loop, if |prev_index| == |kNoIndex| then we try to assign 0. |
67 // This allows 0 (if unused) to be assigned in middle of |labels_|. | 40 // This allows 0 (if unused) to be assigned in middle of |labels_|. |
68 int prev_index = Label::kNoIndex; | 41 int prev_index = Label::kNoIndex; |
69 for (auto p = labels_->begin(); p != labels_->end(); ++p) { | 42 for (auto p = labels_->begin(); p != labels_->end(); ++p) { |
70 if (p->index_ == Label::kNoIndex) { | 43 if (p->index_ == Label::kNoIndex) { |
71 int index = (prev_index == Label::kNoIndex) ? 0 : prev_index + 1; | 44 int index = (prev_index == Label::kNoIndex) ? 0 : prev_index + 1; |
72 if (index < num_index_ && available_.at(index)) { | 45 if (index < num_index_ && available_.at(index)) { |
73 p->index_ = index; | 46 p->index_ = index; |
74 available_.at(index) = false; | 47 available_.at(index) = false; |
75 ++count; | 48 ++count; |
76 } | 49 } |
77 } | 50 } |
78 prev_index = p->index_; | 51 prev_index = p->index_; |
79 } | 52 } |
80 VLOG(1) << " fill forward " << count; | 53 VLOG(1) << " fill forward " << count; |
81 } | 54 } |
82 | 55 |
83 void LabelManagerImpl::SimpleIndexAssigner::DoBackwardFill() { | 56 void LabelManager::SimpleIndexAssigner::DoBackwardFill() { |
84 size_t count = 0; | 57 size_t count = 0; |
85 // This is asymmetric from DoForwardFill(), to preserve old behavior. | 58 // This is asymmetric from DoForwardFill(), to preserve old behavior. |
86 // Inside the loop, if |prev_index| == |kNoIndex| then we skip assignment. | 59 // Inside the loop, if |prev_index| == |kNoIndex| then we skip assignment. |
87 // But we initilaize |prev_index| = |num_index_|, so if the last element in | 60 // But we initilaize |prev_index| = |num_index_|, so if the last element in |
88 // |labels_| has no index, then can use |num_index_| - 1 (if unused). We don't | 61 // |labels_| has no index, then can use |num_index_| - 1 (if unused). We don't |
89 // try this assignment elsewhere. | 62 // try this assignment elsewhere. |
90 int prev_index = num_index_; | 63 int prev_index = num_index_; |
91 for (auto p = labels_->rbegin(); p != labels_->rend(); ++p) { | 64 for (auto p = labels_->rbegin(); p != labels_->rend(); ++p) { |
92 if (p->index_ == Label::kNoIndex && prev_index != Label::kNoIndex) { | 65 if (p->index_ == Label::kNoIndex && prev_index != Label::kNoIndex) { |
93 int index = prev_index - 1; | 66 int index = prev_index - 1; |
94 if (index >= 0 && available_.at(index)) { | 67 if (index >= 0 && available_.at(index)) { |
95 p->index_ = index; | 68 p->index_ = index; |
96 available_.at(index) = false; | 69 available_.at(index) = false; |
97 ++count; | 70 ++count; |
98 } | 71 } |
99 } | 72 } |
100 prev_index = p->index_; | 73 prev_index = p->index_; |
101 } | 74 } |
102 VLOG(1) << " fill backward " << count; | 75 VLOG(1) << " fill backward " << count; |
103 } | 76 } |
104 | 77 |
105 void LabelManagerImpl::SimpleIndexAssigner::DoInFill() { | 78 void LabelManager::SimpleIndexAssigner::DoInFill() { |
106 size_t count = 0; | 79 size_t count = 0; |
107 int index = 0; | 80 int index = 0; |
108 for (Label& label : *labels_) { | 81 for (Label& label : *labels_) { |
109 if (label.index_ == Label::kNoIndex) { | 82 if (label.index_ == Label::kNoIndex) { |
110 while (!available_.at(index)) | 83 while (!available_.at(index)) |
111 ++index; | 84 ++index; |
112 label.index_ = index; | 85 label.index_ = index; |
113 available_.at(index) = false; | 86 available_.at(index) = false; |
114 ++index; | 87 ++index; |
115 ++count; | 88 ++count; |
116 } | 89 } |
117 } | 90 } |
118 VLOG(1) << " infill " << count; | 91 VLOG(1) << " infill " << count; |
119 } | 92 } |
120 | 93 |
121 LabelManagerImpl::LabelManagerImpl() {} | 94 LabelManager::LabelManager() {} |
122 | 95 |
123 LabelManagerImpl::~LabelManagerImpl() {} | 96 LabelManager::~LabelManager() {} |
124 | 97 |
125 // We wish to minimize peak memory usage here. Analysis: Let | 98 // static |
126 // m = number of (RVA) elements in |rva_visitor|, | 99 int LabelManager::GetIndexBound(const RVAToLabel& labels_map) { |
127 // n = number of distinct (RVA) elements in |rva_visitor|. | 100 int max_index = -1; |
128 // The final storage is n * sizeof(Label) bytes. During computation we uniquify | 101 for (const auto& rva_and_label : labels_map) { |
129 // m RVAs, and count repeats. Taking sizeof(RVA) = 4, an implementation using | 102 const Label& label = *rva_and_label.second; |
130 // std::map or std::unordered_map would consume additionally 32 * n bytes. | 103 if (label.index_ != Label::kNoIndex) |
131 // Meanwhile, our std::vector implementation consumes additionally 4 * m bytes | 104 max_index = std::max(max_index, label.index_); |
132 // For our typical usage (i.e. Chrome) we see m = ~4n, so we use 16 * n bytes of | |
133 // extra contiguous memory during computation. Assuming memory fragmentation | |
134 // would not be an issue, this is much better than using std::map. | |
135 void LabelManagerImpl::Read(RvaVisitor* rva_visitor) { | |
136 // Write all values in |rva_visitor| to |rvas|. | |
137 size_t num_rva = rva_visitor->Remaining(); | |
138 std::vector<RVA> rvas(num_rva); | |
139 for (size_t i = 0; i < num_rva; ++i, rva_visitor->Next()) | |
140 rvas[i] = rva_visitor->Get(); | |
141 | |
142 // Sort |rvas|, then count the number of distinct values. | |
143 using CRV = ConsecutiveRangeVisitor<std::vector<RVA>::iterator>; | |
144 std::sort(rvas.begin(), rvas.end()); | |
145 DCHECK(rvas.empty() || rvas.back() != kUnassignedRVA); | |
146 | |
147 size_t num_distinct_rva = 0; | |
148 for (CRV it(rvas.begin(), rvas.end()); it.has_more(); it.advance()) | |
149 ++num_distinct_rva; | |
150 | |
151 // Reserve space for |labels_|, populate with sorted RVA and repeats. | |
152 DCHECK(labels_.empty()); | |
153 labels_.reserve(num_distinct_rva); | |
154 for (CRV it(rvas.begin(), rvas.end()); it.has_more(); it.advance()) { | |
155 labels_.push_back(Label(*it.cur())); | |
156 base::CheckedNumeric<uint32_t> count = it.repeat(); | |
157 labels_.back().count_ = count.ValueOrDie(); | |
158 } | 105 } |
| 106 return max_index + 1; |
159 } | 107 } |
160 | 108 |
161 size_t LabelManagerImpl::Size() const { | 109 // static |
162 return labels_.size(); | 110 int LabelManager::GetLabelIndexBound(const LabelVector& labels) { |
| 111 int max_index = -1; |
| 112 for (const Label& label : labels) { |
| 113 if (label.index_ != Label::kNoIndex) |
| 114 max_index = std::max(max_index, label.index_); |
| 115 } |
| 116 return max_index + 1; |
163 } | 117 } |
164 | 118 |
165 // Uses binary search to find |rva|. | 119 // Uses binary search to find |rva|. |
166 Label* LabelManagerImpl::Find(RVA rva) { | 120 Label* LabelManager::Find(RVA rva) { |
167 auto it = std::lower_bound( | 121 auto it = std::lower_bound( |
168 labels_.begin(), labels_.end(), Label(rva), | 122 labels_.begin(), labels_.end(), Label(rva), |
169 [](const Label& l1, const Label& l2) { return l1.rva_ < l2.rva_; }); | 123 [](const Label& l1, const Label& l2) { return l1.rva_ < l2.rva_; }); |
170 return it == labels_.end() || it->rva_ != rva ? nullptr : &(*it); | 124 return it == labels_.end() || it->rva_ != rva ? nullptr : &(*it); |
171 } | 125 } |
172 | 126 |
173 void LabelManagerImpl::RemoveUnderusedLabels(int32_t count_threshold) { | 127 void LabelManager::RemoveUnderusedLabels(int32_t count_threshold) { |
174 if (count_threshold <= 0) | 128 if (count_threshold <= 0) |
175 return; | 129 return; |
176 labels_.erase(std::remove_if(labels_.begin(), labels_.end(), | 130 labels_.erase(std::remove_if(labels_.begin(), labels_.end(), |
177 [count_threshold](const Label& label) { | 131 [count_threshold](const Label& label) { |
178 return label.count_ < count_threshold; | 132 return label.count_ < count_threshold; |
179 }), | 133 }), |
180 labels_.end()); | 134 labels_.end()); |
181 // Not shrinking |labels_|, since this may cause reallocation. | 135 // Not shrinking |labels_|, since this may cause reallocation. |
182 } | 136 } |
183 | 137 |
184 void LabelManagerImpl::UnassignIndexes() { | 138 void LabelManager::UnassignIndexes() { |
185 for (Label& label : labels_) | 139 for (Label& label : labels_) |
186 label.index_ = Label::kNoIndex; | 140 label.index_ = Label::kNoIndex; |
187 } | 141 } |
188 | 142 |
189 void LabelManagerImpl::DefaultAssignIndexes() { | 143 void LabelManager::DefaultAssignIndexes() { |
190 int cur_index = 0; | 144 int cur_index = 0; |
191 for (Label& label : labels_) { | 145 for (Label& label : labels_) { |
192 CHECK_EQ(Label::kNoIndex, label.index_); | 146 CHECK_EQ(Label::kNoIndex, label.index_); |
193 label.index_ = cur_index++; | 147 label.index_ = cur_index++; |
194 } | 148 } |
195 } | 149 } |
196 | 150 |
197 void LabelManagerImpl::AssignRemainingIndexes() { | 151 void LabelManager::AssignRemainingIndexes() { |
198 // This adds some memory overhead, about 1 bit per Label (more if indexes >= | 152 // This adds some memory overhead, about 1 bit per Label (more if indexes >= |
199 // |labels_.size()| get used). | 153 // |labels_.size()| get used). |
200 SimpleIndexAssigner assigner(&labels_); | 154 SimpleIndexAssigner assigner(&labels_); |
201 assigner.DoForwardFill(); | 155 assigner.DoForwardFill(); |
202 assigner.DoBackwardFill(); | 156 assigner.DoBackwardFill(); |
203 assigner.DoInFill(); | 157 assigner.DoInFill(); |
204 } | 158 } |
205 | 159 |
206 void LabelManagerImpl::SetLabels(const LabelVector& labels) { | 160 // We wish to minimize peak memory usage here. Analysis: Let |
207 labels_ = labels; | 161 // m = number of (RVA) elements in |rva_visitor|, |
| 162 // n = number of distinct (RVA) elements in |rva_visitor|. |
| 163 // The final storage is n * sizeof(Label) bytes. During computation we uniquify |
| 164 // m RVAs, and count repeats. Taking sizeof(RVA) = 4, an implementation using |
| 165 // std::map or std::unordered_map would consume additionally 32 * n bytes. |
| 166 // Meanwhile, our std::vector implementation consumes additionally 4 * m bytes |
| 167 // For our typical usage (i.e. Chrome) we see m = ~4n, so we use 16 * n bytes of |
| 168 // extra contiguous memory during computation. Assuming memory fragmentation |
| 169 // would not be an issue, this is much better than using std::map. |
| 170 void LabelManager::Read(RvaVisitor* rva_visitor) { |
| 171 // Write all values in |rva_visitor| to |rvas|. |
| 172 size_t num_rva = rva_visitor->Remaining(); |
| 173 std::vector<RVA> rvas(num_rva); |
| 174 for (size_t i = 0; i < num_rva; ++i, rva_visitor->Next()) |
| 175 rvas[i] = rva_visitor->Get(); |
| 176 |
| 177 // Sort |rvas|, then count the number of distinct values. |
| 178 using CRV = ConsecutiveRangeVisitor<std::vector<RVA>::iterator>; |
| 179 std::sort(rvas.begin(), rvas.end()); |
| 180 DCHECK(rvas.empty() || rvas.back() != kUnassignedRVA); |
| 181 |
| 182 size_t num_distinct_rva = 0; |
| 183 for (CRV it(rvas.begin(), rvas.end()); it.has_more(); it.advance()) |
| 184 ++num_distinct_rva; |
| 185 |
| 186 // Reserve space for |labels_|, populate with sorted RVA and repeats. |
| 187 DCHECK(labels_.empty()); |
| 188 labels_.reserve(num_distinct_rva); |
| 189 for (CRV it(rvas.begin(), rvas.end()); it.has_more(); it.advance()) { |
| 190 labels_.push_back(Label(*it.cur())); |
| 191 base::CheckedNumeric<uint32_t> count = it.repeat(); |
| 192 labels_.back().count_ = count.ValueOrDie(); |
| 193 } |
208 } | 194 } |
209 | 195 |
210 } // namespace courgette | 196 } // namespace courgette |
OLD | NEW |