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

Side by Side Diff: Source/wtf/HashTable.h

Issue 17583004: Improve WTF::HashTable performance by changing probing method (Closed) Base URL: https://chromium.googlesource.com/chromium/blink@master
Patch Set: Created 7 years, 6 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 | « Source/wtf/HashFunctions.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserv ed. 2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserv ed.
3 * Copyright (C) 2008 David Levin <levin@chromium.org> 3 * Copyright (C) 2008 David Levin <levin@chromium.org>
4 * 4 *
5 * This library is free software; you can redistribute it and/or 5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public 6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either 7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version. 8 * version 2 of the License, or (at your option) any later version.
9 * 9 *
10 * This library is distributed in the hope that it will be useful, 10 * This library is distributed in the hope that it will be useful,
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 #endif 478 #endif
479 479
480 #if CHECK_HASHTABLE_ITERATORS 480 #if CHECK_HASHTABLE_ITERATORS
481 void invalidateIterators(); 481 void invalidateIterators();
482 #else 482 #else
483 static void invalidateIterators() { } 483 static void invalidateIterators() { }
484 #endif 484 #endif
485 485
486 static const int m_maxLoad = 2; 486 static const int m_maxLoad = 2;
487 static const int m_minLoad = 6; 487 static const int m_minLoad = 6;
488 static const int perturbShift = 5;
488 489
489 ValueType* m_table; 490 ValueType* m_table;
490 int m_tableSize; 491 int m_tableSize;
491 int m_tableSizeMask; 492 int m_tableSizeMask;
492 int m_keyCount; 493 int m_keyCount;
493 int m_deletedCount; 494 int m_deletedCount;
494 495
495 #if CHECK_HASHTABLE_ITERATORS 496 #if CHECK_HASHTABLE_ITERATORS
496 public: 497 public:
497 // All access to m_iterators should be guarded with m_mutex. 498 // All access to m_iterators should be guarded with m_mutex.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 #if CHECK_HASHTABLE_ITERATORS 555 #if CHECK_HASHTABLE_ITERATORS
555 , m_iterators(0) 556 , m_iterators(0)
556 , m_mutex(adoptPtr(new Mutex)) 557 , m_mutex(adoptPtr(new Mutex))
557 #endif 558 #endif
558 #if DUMP_HASHTABLE_STATS_PER_TABLE 559 #if DUMP_HASHTABLE_STATS_PER_TABLE
559 , m_stats(adoptPtr(new Stats)) 560 , m_stats(adoptPtr(new Stats))
560 #endif 561 #endif
561 { 562 {
562 } 563 }
563 564
564 inline unsigned doubleHash(unsigned key)
565 {
566 key = ~key + (key >> 23);
567 key ^= (key << 12);
568 key ^= (key >> 7);
569 key ^= (key << 2);
570 key ^= (key >> 20);
571 return key;
572 }
573
574 #if ASSERT_DISABLED 565 #if ASSERT_DISABLED
575 566
576 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits> 567 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits>
577 template<typename HashTranslator, typename T> 568 template<typename HashTranslator, typename T>
578 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait s>::checkKey(const T&) 569 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait s>::checkKey(const T&)
579 { 570 {
580 } 571 }
581 572
582 #else 573 #else
583 574
(...skipping 12 matching lines...) Expand all
596 } 587 }
597 588
598 #endif 589 #endif
599 590
600 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits> 591 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits>
601 template<typename HashTranslator, typename T> 592 template<typename HashTranslator, typename T>
602 inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTra its>::lookup(const T& key) 593 inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTra its>::lookup(const T& key)
603 { 594 {
604 checkKey<HashTranslator>(key); 595 checkKey<HashTranslator>(key);
605 596
606 int k = 0;
607 int sizeMask = m_tableSizeMask;
608 ValueType* table = m_table; 597 ValueType* table = m_table;
609 unsigned h = HashTranslator::hash(key); 598 unsigned h = HashTranslator::hash(key);
610 int i = h & sizeMask; 599 unsigned i = h;
600 unsigned perturb = h;
611 601
612 if (!table) 602 if (!table)
613 return 0; 603 return 0;
614 604
615 #if DUMP_HASHTABLE_STATS 605 #if DUMP_HASHTABLE_STATS
616 atomicIncrement(&HashTableStats::numAccesses); 606 atomicIncrement(&HashTableStats::numAccesses);
617 int probeCount = 0; 607 int probeCount = 0;
618 #endif 608 #endif
619 609
620 #if DUMP_HASHTABLE_STATS_PER_TABLE 610 #if DUMP_HASHTABLE_STATS_PER_TABLE
621 ++m_stats->numAccesses; 611 ++m_stats->numAccesses;
622 int perTableProbeCount = 0; 612 int perTableProbeCount = 0;
623 #endif 613 #endif
624 614
625 while (1) { 615 while (1) {
626 ValueType* entry = table + i; 616 ValueType* entry = table + (i & m_tableSizeMask);
627 617
628 // we count on the compiler to optimize out this branch 618 // we count on the compiler to optimize out this branch
629 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 619 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
630 if (HashTranslator::equal(Extractor::extract(*entry), key)) 620 if (HashTranslator::equal(Extractor::extract(*entry), key))
631 return entry; 621 return entry;
632 622
633 if (isEmptyBucket(*entry)) 623 if (isEmptyBucket(*entry))
634 return 0; 624 return 0;
635 } else { 625 } else {
636 if (isEmptyBucket(*entry)) 626 if (isEmptyBucket(*entry))
637 return 0; 627 return 0;
638 628
639 if (!isDeletedBucket(*entry) && HashTranslator::equal(Extractor: :extract(*entry), key)) 629 if (!isDeletedBucket(*entry) && HashTranslator::equal(Extractor: :extract(*entry), key))
640 return entry; 630 return entry;
641 } 631 }
642 #if DUMP_HASHTABLE_STATS 632 #if DUMP_HASHTABLE_STATS
643 ++probeCount; 633 ++probeCount;
644 HashTableStats::recordCollisionAtCount(probeCount); 634 HashTableStats::recordCollisionAtCount(probeCount);
645 #endif 635 #endif
646 636
647 #if DUMP_HASHTABLE_STATS_PER_TABLE 637 #if DUMP_HASHTABLE_STATS_PER_TABLE
648 ++perTableProbeCount; 638 ++perTableProbeCount;
649 m_stats->recordCollisionAtCount(perTableProbeCount); 639 m_stats->recordCollisionAtCount(perTableProbeCount);
650 #endif 640 #endif
651 641
652 if (k == 0) 642 perturb >>= perturbShift;
653 k = 1 | doubleHash(h); 643 i = i*5 + perturb + 1;
654 i = (i + k) & sizeMask;
655 } 644 }
656 } 645 }
657 646
658 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits> 647 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits>
659 template<typename HashTranslator, typename T> 648 template<typename HashTranslator, typename T>
660 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyT raits>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTr aits>::lookupForWriting(const T& key) 649 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyT raits>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTr aits>::lookupForWriting(const T& key)
661 { 650 {
662 ASSERT(m_table); 651 ASSERT(m_table);
663 checkKey<HashTranslator>(key); 652 checkKey<HashTranslator>(key);
664 653
665 int k = 0;
666 ValueType* table = m_table; 654 ValueType* table = m_table;
667 int sizeMask = m_tableSizeMask;
abarth-chromium 2013/06/25 05:03:38 Is there a reason you remove the copy of m_tableSi
668 unsigned h = HashTranslator::hash(key); 655 unsigned h = HashTranslator::hash(key);
669 int i = h & sizeMask; 656 unsigned i = h;
657 unsigned perturb = h;
670 658
671 #if DUMP_HASHTABLE_STATS 659 #if DUMP_HASHTABLE_STATS
672 atomicIncrement(&HashTableStats::numAccesses); 660 atomicIncrement(&HashTableStats::numAccesses);
673 int probeCount = 0; 661 int probeCount = 0;
674 #endif 662 #endif
675 663
676 #if DUMP_HASHTABLE_STATS_PER_TABLE 664 #if DUMP_HASHTABLE_STATS_PER_TABLE
677 ++m_stats->numAccesses; 665 ++m_stats->numAccesses;
678 int perTableProbeCount = 0; 666 int perTableProbeCount = 0;
679 #endif 667 #endif
680 668
681 ValueType* deletedEntry = 0; 669 ValueType* deletedEntry = 0;
682 670
683 while (1) { 671 while (1) {
684 ValueType* entry = table + i; 672 ValueType* entry = table + (i & m_tableSizeMask);
685 673
686 // we count on the compiler to optimize out this branch 674 // we count on the compiler to optimize out this branch
687 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 675 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
688 if (isEmptyBucket(*entry)) 676 if (isEmptyBucket(*entry))
689 return LookupType(deletedEntry ? deletedEntry : entry, false ); 677 return LookupType(deletedEntry ? deletedEntry : entry, false );
690 678
691 if (HashTranslator::equal(Extractor::extract(*entry), key)) 679 if (HashTranslator::equal(Extractor::extract(*entry), key))
692 return LookupType(entry, true); 680 return LookupType(entry, true);
693 681
694 if (isDeletedBucket(*entry)) 682 if (isDeletedBucket(*entry))
(...skipping 10 matching lines...) Expand all
705 #if DUMP_HASHTABLE_STATS 693 #if DUMP_HASHTABLE_STATS
706 ++probeCount; 694 ++probeCount;
707 HashTableStats::recordCollisionAtCount(probeCount); 695 HashTableStats::recordCollisionAtCount(probeCount);
708 #endif 696 #endif
709 697
710 #if DUMP_HASHTABLE_STATS_PER_TABLE 698 #if DUMP_HASHTABLE_STATS_PER_TABLE
711 ++perTableProbeCount; 699 ++perTableProbeCount;
712 m_stats->recordCollisionAtCount(perTableProbeCount); 700 m_stats->recordCollisionAtCount(perTableProbeCount);
713 #endif 701 #endif
714 702
715 if (k == 0) 703 perturb >>= perturbShift;
716 k = 1 | doubleHash(h); 704 i = i*5 + perturb + 1;
717 i = (i + k) & sizeMask;
718 } 705 }
719 } 706 }
720 707
721 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits> 708 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits>
722 template<typename HashTranslator, typename T> 709 template<typename HashTranslator, typename T>
723 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyT raits>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, K eyTraits>::fullLookupForWriting(const T& key) 710 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyT raits>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, K eyTraits>::fullLookupForWriting(const T& key)
724 { 711 {
725 ASSERT(m_table); 712 ASSERT(m_table);
726 checkKey<HashTranslator>(key); 713 checkKey<HashTranslator>(key);
727 714
728 int k = 0;
729 ValueType* table = m_table; 715 ValueType* table = m_table;
730 int sizeMask = m_tableSizeMask;
731 unsigned h = HashTranslator::hash(key); 716 unsigned h = HashTranslator::hash(key);
732 int i = h & sizeMask; 717 unsigned i = h;
718 unsigned perturb = h;
733 719
734 #if DUMP_HASHTABLE_STATS 720 #if DUMP_HASHTABLE_STATS
735 atomicIncrement(&HashTableStats::numAccesses); 721 atomicIncrement(&HashTableStats::numAccesses);
736 int probeCount = 0; 722 int probeCount = 0;
737 #endif 723 #endif
738 724
739 #if DUMP_HASHTABLE_STATS_PER_TABLE 725 #if DUMP_HASHTABLE_STATS_PER_TABLE
740 ++m_stats->numAccesses; 726 ++m_stats->numAccesses;
741 int perTableProbeCount = 0; 727 int perTableProbeCount = 0;
742 #endif 728 #endif
743 729
744 ValueType* deletedEntry = 0; 730 ValueType* deletedEntry = 0;
745 731
746 while (1) { 732 while (1) {
747 ValueType* entry = table + i; 733 ValueType* entry = table + (i & m_tableSizeMask);
748 734
749 // we count on the compiler to optimize out this branch 735 // we count on the compiler to optimize out this branch
750 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 736 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
751 if (isEmptyBucket(*entry)) 737 if (isEmptyBucket(*entry))
752 return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h); 738 return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h);
753 739
754 if (HashTranslator::equal(Extractor::extract(*entry), key)) 740 if (HashTranslator::equal(Extractor::extract(*entry), key))
755 return makeLookupResult(entry, true, h); 741 return makeLookupResult(entry, true, h);
756 742
757 if (isDeletedBucket(*entry)) 743 if (isDeletedBucket(*entry))
(...skipping 10 matching lines...) Expand all
768 #if DUMP_HASHTABLE_STATS 754 #if DUMP_HASHTABLE_STATS
769 ++probeCount; 755 ++probeCount;
770 HashTableStats::recordCollisionAtCount(probeCount); 756 HashTableStats::recordCollisionAtCount(probeCount);
771 #endif 757 #endif
772 758
773 #if DUMP_HASHTABLE_STATS_PER_TABLE 759 #if DUMP_HASHTABLE_STATS_PER_TABLE
774 ++perTableProbeCount; 760 ++perTableProbeCount;
775 m_stats->recordCollisionAtCount(perTableProbeCount); 761 m_stats->recordCollisionAtCount(perTableProbeCount);
776 #endif 762 #endif
777 763
778 if (k == 0) 764 perturb >>= perturbShift;
779 k = 1 | doubleHash(h); 765 i = i*5 + perturb + 1;
780 i = (i + k) & sizeMask;
781 } 766 }
782 } 767 }
783 768
784 template<bool emptyValueIsZero> struct HashTableBucketInitializer; 769 template<bool emptyValueIsZero> struct HashTableBucketInitializer;
785 770
786 template<> struct HashTableBucketInitializer<false> { 771 template<> struct HashTableBucketInitializer<false> {
787 template<typename Traits, typename Value> static void initialize(Value& bucket) 772 template<typename Traits, typename Value> static void initialize(Value& bucket)
788 { 773 {
789 new (NotNull, &bucket) Value(Traits::emptyValue()); 774 new (NotNull, &bucket) Value(Traits::emptyValue());
790 } 775 }
(...skipping 23 matching lines...) Expand all
814 799
815 invalidateIterators(); 800 invalidateIterators();
816 801
817 if (!m_table) 802 if (!m_table)
818 expand(); 803 expand();
819 804
820 internalCheckTableConsistency(); 805 internalCheckTableConsistency();
821 806
822 ASSERT(m_table); 807 ASSERT(m_table);
823 808
824 int k = 0;
825 ValueType* table = m_table; 809 ValueType* table = m_table;
826 int sizeMask = m_tableSizeMask;
827 unsigned h = HashTranslator::hash(key); 810 unsigned h = HashTranslator::hash(key);
828 int i = h & sizeMask; 811 unsigned i = h;
812 unsigned perturb = h;
829 813
830 #if DUMP_HASHTABLE_STATS 814 #if DUMP_HASHTABLE_STATS
831 atomicIncrement(&HashTableStats::numAccesses); 815 atomicIncrement(&HashTableStats::numAccesses);
832 int probeCount = 0; 816 int probeCount = 0;
833 #endif 817 #endif
834 818
835 #if DUMP_HASHTABLE_STATS_PER_TABLE 819 #if DUMP_HASHTABLE_STATS_PER_TABLE
836 ++m_stats->numAccesses; 820 ++m_stats->numAccesses;
837 int perTableProbeCount = 0; 821 int perTableProbeCount = 0;
838 #endif 822 #endif
839 823
840 ValueType* deletedEntry = 0; 824 ValueType* deletedEntry = 0;
841 ValueType* entry; 825 ValueType* entry;
842 while (1) { 826 while (1) {
843 entry = table + i; 827 entry = table + (i & m_tableSizeMask);
844 828
845 // we count on the compiler to optimize out this branch 829 // we count on the compiler to optimize out this branch
846 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 830 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
847 if (isEmptyBucket(*entry)) 831 if (isEmptyBucket(*entry))
848 break; 832 break;
849 833
850 if (HashTranslator::equal(Extractor::extract(*entry), key)) 834 if (HashTranslator::equal(Extractor::extract(*entry), key))
851 return AddResult(makeKnownGoodIterator(entry), false); 835 return AddResult(makeKnownGoodIterator(entry), false);
852 836
853 if (isDeletedBucket(*entry)) 837 if (isDeletedBucket(*entry))
(...skipping 10 matching lines...) Expand all
864 #if DUMP_HASHTABLE_STATS 848 #if DUMP_HASHTABLE_STATS
865 ++probeCount; 849 ++probeCount;
866 HashTableStats::recordCollisionAtCount(probeCount); 850 HashTableStats::recordCollisionAtCount(probeCount);
867 #endif 851 #endif
868 852
869 #if DUMP_HASHTABLE_STATS_PER_TABLE 853 #if DUMP_HASHTABLE_STATS_PER_TABLE
870 ++perTableProbeCount; 854 ++perTableProbeCount;
871 m_stats->recordCollisionAtCount(perTableProbeCount); 855 m_stats->recordCollisionAtCount(perTableProbeCount);
872 #endif 856 #endif
873 857
874 if (k == 0) 858 perturb >>= perturbShift;
875 k = 1 | doubleHash(h); 859 i = i*5 + perturb + 1;
876 i = (i + k) & sizeMask;
877 } 860 }
878 861
879 if (deletedEntry) { 862 if (deletedEntry) {
880 initializeBucket(*deletedEntry); 863 initializeBucket(*deletedEntry);
881 entry = deletedEntry; 864 entry = deletedEntry;
882 --m_deletedCount; 865 --m_deletedCount;
883 } 866 }
884 867
885 HashTranslator::translate(*entry, key, extra); 868 HashTranslator::translate(*entry, key, extra);
886 869
(...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after
1411 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTa bleConstIteratorAdapter<T, U>& b) 1394 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTa bleConstIteratorAdapter<T, U>& b)
1412 { 1395 {
1413 return a.m_impl != b.m_impl; 1396 return a.m_impl != b.m_impl;
1414 } 1397 }
1415 1398
1416 } // namespace WTF 1399 } // namespace WTF
1417 1400
1418 #include <wtf/HashIterators.h> 1401 #include <wtf/HashIterators.h>
1419 1402
1420 #endif // WTF_HashTable_h 1403 #endif // WTF_HashTable_h
OLDNEW
« no previous file with comments | « Source/wtf/HashFunctions.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698