| 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 |