| Index: runtime/vm/hash_table.h
|
| diff --git a/runtime/vm/hash_table.h b/runtime/vm/hash_table.h
|
| index f4eb3758ff36dec5345dc16977adff755131c13f..15317a17fa45d720af013076fb89fe779e63d276 100644
|
| --- a/runtime/vm/hash_table.h
|
| +++ b/runtime/vm/hash_table.h
|
| @@ -137,6 +137,14 @@ class HashTable : public ValueObject {
|
| smi_handle_ = Smi::New(0);
|
| data_->SetAt(kOccupiedEntriesIndex, smi_handle_);
|
| data_->SetAt(kDeletedEntriesIndex, smi_handle_);
|
| +
|
| +NOT_IN_PRODUCT(
|
| + data_->SetAt(kNumGrowsIndex, smi_handle_);
|
| + data_->SetAt(kNumLT5LookupsIndex, smi_handle_);
|
| + data_->SetAt(kNumLT25LookupsIndex, smi_handle_);
|
| + data_->SetAt(kNumGT25LookupsIndex, smi_handle_);
|
| +) // !PRODUCT
|
| +
|
| for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) {
|
| data_->SetAt(i, Object::sentinel());
|
| }
|
| @@ -154,17 +162,21 @@ class HashTable : public ValueObject {
|
| const intptr_t num_entries = NumEntries();
|
| ASSERT(NumOccupied() < num_entries);
|
| // TODO(koda): Add salt.
|
| + NOT_IN_PRODUCT(intptr_t collisions = 0;)
|
| uword hash = KeyTraits::Hash(key);
|
| intptr_t probe = hash % num_entries;
|
| // TODO(koda): Consider quadratic probing.
|
| while (true) {
|
| if (IsUnused(probe)) {
|
| + NOT_IN_PRODUCT(UpdateCollisions(collisions);)
|
| return -1;
|
| } else if (!IsDeleted(probe)) {
|
| key_handle_ = GetKey(probe);
|
| if (KeyTraits::IsMatch(key, key_handle_)) {
|
| + NOT_IN_PRODUCT(UpdateCollisions(collisions);)
|
| return probe;
|
| }
|
| + NOT_IN_PRODUCT(collisions += 1;)
|
| }
|
| // Advance probe.
|
| probe++;
|
| @@ -183,6 +195,7 @@ class HashTable : public ValueObject {
|
| const intptr_t num_entries = NumEntries();
|
| ASSERT(entry != NULL);
|
| ASSERT(NumOccupied() < num_entries);
|
| + NOT_IN_PRODUCT(intptr_t collisions = 0;)
|
| uword hash = KeyTraits::Hash(key);
|
| intptr_t probe = hash % num_entries;
|
| intptr_t deleted = -1;
|
| @@ -190,6 +203,7 @@ class HashTable : public ValueObject {
|
| while (true) {
|
| if (IsUnused(probe)) {
|
| *entry = (deleted != -1) ? deleted : probe;
|
| + NOT_IN_PRODUCT(UpdateCollisions(collisions);)
|
| return false;
|
| } else if (IsDeleted(probe)) {
|
| if (deleted == -1) {
|
| @@ -199,8 +213,10 @@ class HashTable : public ValueObject {
|
| key_handle_ = GetKey(probe);
|
| if (KeyTraits::IsMatch(key, key_handle_)) {
|
| *entry = probe;
|
| + NOT_IN_PRODUCT(UpdateCollisions(collisions);)
|
| return true;
|
| }
|
| + NOT_IN_PRODUCT(collisions += 1;)
|
| }
|
| // Advance probe.
|
| probe++;
|
| @@ -279,10 +295,63 @@ class HashTable : public ValueObject {
|
| return smi_handle_;
|
| }
|
|
|
| +NOT_IN_PRODUCT(
|
| + intptr_t NumGrows() const {
|
| + return GetSmiValueAt(kNumGrowsIndex);
|
| + }
|
| + intptr_t NumLT5Collisions() const {
|
| + return GetSmiValueAt(kNumLT5LookupsIndex);
|
| + }
|
| + intptr_t NumLT25Collisions() const {
|
| + return GetSmiValueAt(kNumLT25LookupsIndex);
|
| + }
|
| + intptr_t NumGT25Collisions() const {
|
| + return GetSmiValueAt(kNumGT25LookupsIndex);
|
| + }
|
| + void UpdateGrowth() const {
|
| + AdjustSmiValueAt(kNumGrowsIndex, 1);
|
| + }
|
| + void UpdateCollisions(intptr_t collisions) const {
|
| + if (data_->raw()->IsVMHeapObject()) {
|
| + return;
|
| + }
|
| + if (collisions < 5) {
|
| + AdjustSmiValueAt(kNumLT5LookupsIndex, 1);
|
| + } else if (collisions < 25) {
|
| + AdjustSmiValueAt(kNumLT25LookupsIndex, 1);
|
| + } else {
|
| + AdjustSmiValueAt(kNumGT25LookupsIndex, 1);
|
| + }
|
| + }
|
| + void PrintStats() const {
|
| + if (!KeyTraits::ReportStats()) {
|
| + return;
|
| + }
|
| + OS::Print("Stats for %s table :\n"
|
| + " Size of table = %" Pd ",Number of Occupied entries = %" Pd "\n"
|
| + " Number of Grows = %" Pd "\n"
|
| + " Number of look ups with < 5 collisions = %" Pd "\n"
|
| + " Number of look ups with < 25 collisions = %" Pd "\n"
|
| + " Number of look ups with > 25 collisions = %" Pd "\n",
|
| + KeyTraits::Name(),
|
| + NumEntries(), NumOccupied(),
|
| + NumGrows(),
|
| + NumLT5Collisions(), NumLT25Collisions(), NumGT25Collisions());
|
| + }
|
| +) // !PRODUCT
|
| +
|
| protected:
|
| static const intptr_t kOccupiedEntriesIndex = 0;
|
| static const intptr_t kDeletedEntriesIndex = 1;
|
| +#if defined(PRODUCT)
|
| static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1;
|
| +#else
|
| + static const intptr_t kNumGrowsIndex = 2;
|
| + static const intptr_t kNumLT5LookupsIndex = 3;
|
| + static const intptr_t kNumLT25LookupsIndex = 4;
|
| + static const intptr_t kNumGT25LookupsIndex = 5;
|
| + static const intptr_t kHeaderSize = kNumGT25LookupsIndex + 1;
|
| +#endif
|
| static const intptr_t kMetaDataIndex = kHeaderSize;
|
| static const intptr_t kFirstKeyIndex = kHeaderSize + kMetaDataSize;
|
| static const intptr_t kEntrySize = 1 + kPayloadSize;
|
| @@ -491,6 +560,7 @@ class HashTables : public AllStatic {
|
| table.data_->IsOld() ? Heap::kOld : Heap::kNew));
|
| Copy(table, new_table);
|
| *table.data_ = new_table.Release().raw();
|
| + NOT_IN_PRODUCT(table.UpdateGrowth(); table.PrintStats();)
|
| }
|
|
|
| // Serializes a table by concatenating its entries as an array.
|
|
|