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

Side by Side Diff: runtime/vm/hash_table.h

Issue 1882763002: Add usage and collision details to the hash table data structure in order to determine effectivenes… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: self-review-comments Created 4 years, 8 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
« no previous file with comments | « runtime/vm/compiler.cc ('k') | runtime/vm/hash_table_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #ifndef VM_HASH_TABLE_H_ 5 #ifndef VM_HASH_TABLE_H_
6 #define VM_HASH_TABLE_H_ 6 #define VM_HASH_TABLE_H_
7 7
8 // Temporarily used when sorting the indices in EnumIndexHashTable. 8 // Temporarily used when sorting the indices in EnumIndexHashTable.
9 // TODO(koda): Remove these dependencies before using in production. 9 // TODO(koda): Remove these dependencies before using in production.
10 #include <map> 10 #include <map>
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 intptr_t num_entries = num_occupied + 1; 130 intptr_t num_entries = num_occupied + 1;
131 return kFirstKeyIndex + (kEntrySize * num_entries); 131 return kFirstKeyIndex + (kEntrySize * num_entries);
132 } 132 }
133 133
134 // Initializes an empty table. 134 // Initializes an empty table.
135 void Initialize() const { 135 void Initialize() const {
136 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0)); 136 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0));
137 smi_handle_ = Smi::New(0); 137 smi_handle_ = Smi::New(0);
138 data_->SetAt(kOccupiedEntriesIndex, smi_handle_); 138 data_->SetAt(kOccupiedEntriesIndex, smi_handle_);
139 data_->SetAt(kDeletedEntriesIndex, smi_handle_); 139 data_->SetAt(kDeletedEntriesIndex, smi_handle_);
140
141 NOT_IN_PRODUCT(
142 data_->SetAt(kNumGrowsIndex, smi_handle_);
143 data_->SetAt(kNumLT5LookupsIndex, smi_handle_);
144 data_->SetAt(kNumLT25LookupsIndex, smi_handle_);
145 data_->SetAt(kNumGT25LookupsIndex, smi_handle_);
146 ) // !PRODUCT
147
140 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) { 148 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) {
141 data_->SetAt(i, Object::sentinel()); 149 data_->SetAt(i, Object::sentinel());
142 } 150 }
143 } 151 }
144 152
145 // Returns whether 'key' matches any key in the table. 153 // Returns whether 'key' matches any key in the table.
146 template<typename Key> 154 template<typename Key>
147 bool ContainsKey(const Key& key) const { 155 bool ContainsKey(const Key& key) const {
148 return FindKey(key) != -1; 156 return FindKey(key) != -1;
149 } 157 }
150 158
151 // Returns the entry that matches 'key', or -1 if none exists. 159 // Returns the entry that matches 'key', or -1 if none exists.
152 template<typename Key> 160 template<typename Key>
153 intptr_t FindKey(const Key& key) const { 161 intptr_t FindKey(const Key& key) const {
154 const intptr_t num_entries = NumEntries(); 162 const intptr_t num_entries = NumEntries();
155 ASSERT(NumOccupied() < num_entries); 163 ASSERT(NumOccupied() < num_entries);
156 // TODO(koda): Add salt. 164 // TODO(koda): Add salt.
165 NOT_IN_PRODUCT(intptr_t collisions = 0;)
157 uword hash = KeyTraits::Hash(key); 166 uword hash = KeyTraits::Hash(key);
158 intptr_t probe = hash % num_entries; 167 intptr_t probe = hash % num_entries;
159 // TODO(koda): Consider quadratic probing. 168 // TODO(koda): Consider quadratic probing.
160 while (true) { 169 while (true) {
161 if (IsUnused(probe)) { 170 if (IsUnused(probe)) {
171 NOT_IN_PRODUCT(UpdateCollisions(collisions);)
162 return -1; 172 return -1;
163 } else if (!IsDeleted(probe)) { 173 } else if (!IsDeleted(probe)) {
164 key_handle_ = GetKey(probe); 174 key_handle_ = GetKey(probe);
165 if (KeyTraits::IsMatch(key, key_handle_)) { 175 if (KeyTraits::IsMatch(key, key_handle_)) {
176 NOT_IN_PRODUCT(UpdateCollisions(collisions);)
166 return probe; 177 return probe;
167 } 178 }
179 NOT_IN_PRODUCT(collisions += 1;)
168 } 180 }
169 // Advance probe. 181 // Advance probe.
170 probe++; 182 probe++;
171 probe = (probe == num_entries) ? 0 : probe; 183 probe = (probe == num_entries) ? 0 : probe;
172 } 184 }
173 UNREACHABLE(); 185 UNREACHABLE();
174 return -1; 186 return -1;
175 } 187 }
176 188
177 // Sets *entry to either: 189 // Sets *entry to either:
178 // - an occupied entry matching 'key', and returns true, or 190 // - an occupied entry matching 'key', and returns true, or
179 // - an unused/deleted entry where a matching key may be inserted, 191 // - an unused/deleted entry where a matching key may be inserted,
180 // and returns false. 192 // and returns false.
181 template<typename Key> 193 template<typename Key>
182 bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const { 194 bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const {
183 const intptr_t num_entries = NumEntries(); 195 const intptr_t num_entries = NumEntries();
184 ASSERT(entry != NULL); 196 ASSERT(entry != NULL);
185 ASSERT(NumOccupied() < num_entries); 197 ASSERT(NumOccupied() < num_entries);
198 NOT_IN_PRODUCT(intptr_t collisions = 0;)
186 uword hash = KeyTraits::Hash(key); 199 uword hash = KeyTraits::Hash(key);
187 intptr_t probe = hash % num_entries; 200 intptr_t probe = hash % num_entries;
188 intptr_t deleted = -1; 201 intptr_t deleted = -1;
189 // TODO(koda): Consider quadratic probing. 202 // TODO(koda): Consider quadratic probing.
190 while (true) { 203 while (true) {
191 if (IsUnused(probe)) { 204 if (IsUnused(probe)) {
192 *entry = (deleted != -1) ? deleted : probe; 205 *entry = (deleted != -1) ? deleted : probe;
206 NOT_IN_PRODUCT(UpdateCollisions(collisions);)
193 return false; 207 return false;
194 } else if (IsDeleted(probe)) { 208 } else if (IsDeleted(probe)) {
195 if (deleted == -1) { 209 if (deleted == -1) {
196 deleted = probe; 210 deleted = probe;
197 } 211 }
198 } else { 212 } else {
199 key_handle_ = GetKey(probe); 213 key_handle_ = GetKey(probe);
200 if (KeyTraits::IsMatch(key, key_handle_)) { 214 if (KeyTraits::IsMatch(key, key_handle_)) {
201 *entry = probe; 215 *entry = probe;
216 NOT_IN_PRODUCT(UpdateCollisions(collisions);)
202 return true; 217 return true;
203 } 218 }
219 NOT_IN_PRODUCT(collisions += 1;)
204 } 220 }
205 // Advance probe. 221 // Advance probe.
206 probe++; 222 probe++;
207 probe = (probe == num_entries) ? 0 : probe; 223 probe = (probe == num_entries) ? 0 : probe;
208 } 224 }
209 UNREACHABLE(); 225 UNREACHABLE();
210 return false; 226 return false;
211 } 227 }
212 228
213 // Sets the key of a previously unoccupied entry. This must not be the last 229 // Sets the key of a previously unoccupied entry. This must not be the last
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 intptr_t NumDeleted() const { 288 intptr_t NumDeleted() const {
273 return GetSmiValueAt(kDeletedEntriesIndex); 289 return GetSmiValueAt(kDeletedEntriesIndex);
274 } 290 }
275 Object& KeyHandle() const { 291 Object& KeyHandle() const {
276 return key_handle_; 292 return key_handle_;
277 } 293 }
278 Smi& SmiHandle() const { 294 Smi& SmiHandle() const {
279 return smi_handle_; 295 return smi_handle_;
280 } 296 }
281 297
298 NOT_IN_PRODUCT(
299 intptr_t NumGrows() const {
300 return GetSmiValueAt(kNumGrowsIndex);
301 }
302 intptr_t NumLT5Collisions() const {
303 return GetSmiValueAt(kNumLT5LookupsIndex);
304 }
305 intptr_t NumLT25Collisions() const {
306 return GetSmiValueAt(kNumLT25LookupsIndex);
307 }
308 intptr_t NumGT25Collisions() const {
309 return GetSmiValueAt(kNumGT25LookupsIndex);
310 }
311 void UpdateGrowth() const {
312 AdjustSmiValueAt(kNumGrowsIndex, 1);
313 }
314 void UpdateCollisions(intptr_t collisions) const {
315 if (data_->raw()->IsVMHeapObject()) {
316 return;
317 }
318 if (collisions < 5) {
319 AdjustSmiValueAt(kNumLT5LookupsIndex, 1);
320 } else if (collisions < 25) {
321 AdjustSmiValueAt(kNumLT25LookupsIndex, 1);
322 } else {
323 AdjustSmiValueAt(kNumGT25LookupsIndex, 1);
324 }
325 }
326 void PrintStats() const {
327 if (!KeyTraits::ReportStats()) {
328 return;
329 }
330 OS::Print("Stats for %s table :\n"
331 " Size of table = %" Pd ",Number of Occupied entries = %" Pd "\n"
332 " Number of Grows = %" Pd "\n"
333 " Number of look ups with < 5 collisions = %" Pd "\n"
334 " Number of look ups with < 25 collisions = %" Pd "\n"
335 " Number of look ups with > 25 collisions = %" Pd "\n",
336 KeyTraits::Name(),
337 NumEntries(), NumOccupied(),
338 NumGrows(),
339 NumLT5Collisions(), NumLT25Collisions(), NumGT25Collisions());
340 }
341 ) // !PRODUCT
342
282 protected: 343 protected:
283 static const intptr_t kOccupiedEntriesIndex = 0; 344 static const intptr_t kOccupiedEntriesIndex = 0;
284 static const intptr_t kDeletedEntriesIndex = 1; 345 static const intptr_t kDeletedEntriesIndex = 1;
346 #if defined(PRODUCT)
285 static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1; 347 static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1;
348 #else
349 static const intptr_t kNumGrowsIndex = 2;
350 static const intptr_t kNumLT5LookupsIndex = 3;
351 static const intptr_t kNumLT25LookupsIndex = 4;
352 static const intptr_t kNumGT25LookupsIndex = 5;
353 static const intptr_t kHeaderSize = kNumGT25LookupsIndex + 1;
354 #endif
286 static const intptr_t kMetaDataIndex = kHeaderSize; 355 static const intptr_t kMetaDataIndex = kHeaderSize;
287 static const intptr_t kFirstKeyIndex = kHeaderSize + kMetaDataSize; 356 static const intptr_t kFirstKeyIndex = kHeaderSize + kMetaDataSize;
288 static const intptr_t kEntrySize = 1 + kPayloadSize; 357 static const intptr_t kEntrySize = 1 + kPayloadSize;
289 358
290 intptr_t KeyIndex(intptr_t entry) const { 359 intptr_t KeyIndex(intptr_t entry) const {
291 ASSERT(0 <= entry && entry < NumEntries()); 360 ASSERT(0 <= entry && entry < NumEntries());
292 return kFirstKeyIndex + (kEntrySize * entry); 361 return kFirstKeyIndex + (kEntrySize * entry);
293 } 362 }
294 363
295 intptr_t PayloadIndex(intptr_t entry, intptr_t component) const { 364 intptr_t PayloadIndex(intptr_t entry, intptr_t component) const {
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 if (low <= current && current < high) { 553 if (low <= current && current < high) {
485 return; 554 return;
486 } 555 }
487 double target = (low + high) / 2.0; 556 double target = (low + high) / 2.0;
488 intptr_t new_capacity = (1 + table.NumOccupied()) / target; 557 intptr_t new_capacity = (1 + table.NumOccupied()) / target;
489 Table new_table(New<Table>( 558 Table new_table(New<Table>(
490 new_capacity, 559 new_capacity,
491 table.data_->IsOld() ? Heap::kOld : Heap::kNew)); 560 table.data_->IsOld() ? Heap::kOld : Heap::kNew));
492 Copy(table, new_table); 561 Copy(table, new_table);
493 *table.data_ = new_table.Release().raw(); 562 *table.data_ = new_table.Release().raw();
563 NOT_IN_PRODUCT(table.UpdateGrowth(); table.PrintStats();)
494 } 564 }
495 565
496 // Serializes a table by concatenating its entries as an array. 566 // Serializes a table by concatenating its entries as an array.
497 template<typename Table> 567 template<typename Table>
498 static RawArray* ToArray(const Table& table, bool include_payload) { 568 static RawArray* ToArray(const Table& table, bool include_payload) {
499 const intptr_t entry_size = include_payload ? (1 + Table::kPayloadSize) : 1; 569 const intptr_t entry_size = include_payload ? (1 + Table::kPayloadSize) : 1;
500 Array& result = Array::Handle(Array::New(table.NumOccupied() * entry_size)); 570 Array& result = Array::Handle(Array::New(table.NumOccupied() * entry_size));
501 typename Table::Iterator it(&table); 571 typename Table::Iterator it(&table);
502 Object& obj = Object::Handle(); 572 Object& obj = Object::Handle();
503 intptr_t result_index = 0; 573 intptr_t result_index = 0;
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { 781 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > {
712 public: 782 public:
713 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; 783 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet;
714 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {} 784 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {}
715 EnumIndexHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} 785 EnumIndexHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {}
716 }; 786 };
717 787
718 } // namespace dart 788 } // namespace dart
719 789
720 #endif // VM_HASH_TABLE_H_ 790 #endif // VM_HASH_TABLE_H_
OLDNEW
« no previous file with comments | « runtime/vm/compiler.cc ('k') | runtime/vm/hash_table_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698