HashTable performance: find(), found() check nElmts_ instead of tableSize_

- much better performance on empty tables (4-6x speedup), neutral
  performance change on filled tables. Since tableSize_ is non-zero when
  nElmts_ is, there is no modulus zero problem.
This commit is contained in:
Mark Olesen
2009-02-25 18:58:48 +01:00
parent 9c8432a002
commit e562aecb73
8 changed files with 94 additions and 48 deletions

View File

@ -32,6 +32,7 @@ Description
#include "boolList.H" #include "boolList.H"
#include "PackedBoolList.H" #include "PackedBoolList.H"
#include "HashSet.H" #include "HashSet.H"
#include "StaticHashTable.H"
#include "cpuTime.H" #include "cpuTime.H"
#include <vector> #include <vector>
@ -60,6 +61,9 @@ int main(int argc, char *argv[])
fullHash.insert(i); fullHash.insert(i);
} }
// don't use fullStaticHash, it's too slow
StaticHashTable<nil, label, Hash<label> > emptyStaticHash;
cpuTime timer; cpuTime timer;
for (label iter = 0; iter < nIters; ++iter) for (label iter = 0; iter < nIters; ++iter)
@ -235,6 +239,22 @@ int main(int argc, char *argv[])
Info<< " sum " << sum << endl; Info<< " sum " << sum << endl;
// Read empty static hash
sum = 0;
for (label iter = 0; iter < nIters; ++iter)
{
forAll(unpacked, i)
{
sum += emptyStaticHash.found(i);
}
}
Info<< "Reading empty StaticHash:" << timer.cpuTimeIncrement()
<< " s" << endl;
Info<< " sum " << sum << endl;
Info<< "Starting write tests" << endl;
// //
// Write // Write
// //

View File

@ -33,14 +33,14 @@ License
template<class Key, class Hash> template<class Key, class Hash>
template<class AnyType> template<class AnyType>
Foam::HashSet<Key, Hash>::HashSet(const HashTable<AnyType, Key, Hash>& ht) Foam::HashSet<Key, Hash>::HashSet(const HashTable<AnyType, Key, Hash>& h)
: :
HashTable<nil, Key, Hash>(ht.size()) HashTable<nil, Key, Hash>(h.size())
{ {
for for
( (
typename HashTable<AnyType, Key, Hash>::const_iterator cit = ht.begin(); typename HashTable<AnyType, Key, Hash>::const_iterator cit = h.cbegin();
cit != ht.end(); cit != h.cend();
++cit ++cit
) )
{ {
@ -62,7 +62,7 @@ template<class Key, class Hash>
bool Foam::HashSet<Key, Hash>::operator==(const HashSet<Key, Hash>& rhs) const bool Foam::HashSet<Key, Hash>::operator==(const HashSet<Key, Hash>& rhs) const
{ {
// Are all lhs elements in rhs? // Are all lhs elements in rhs?
for (const_iterator iter = this->begin(); iter != this->end(); ++iter) for (const_iterator iter = this->cbegin(); iter != this->cend(); ++iter)
{ {
if (!rhs.found(iter.key())) if (!rhs.found(iter.key()))
{ {
@ -71,7 +71,7 @@ bool Foam::HashSet<Key, Hash>::operator==(const HashSet<Key, Hash>& rhs) const
} }
// Are all rhs elements in lhs? // Are all rhs elements in lhs?
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{ {
if (!found(iter.key())) if (!found(iter.key()))
{ {
@ -94,7 +94,7 @@ template<class Key, class Hash>
void Foam::HashSet<Key, Hash>::operator|=(const HashSet<Key, Hash>& rhs) void Foam::HashSet<Key, Hash>::operator|=(const HashSet<Key, Hash>& rhs)
{ {
// Add rhs elements into lhs // Add rhs elements into lhs
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{ {
insert(iter.key()); insert(iter.key());
} }
@ -105,7 +105,7 @@ template<class Key, class Hash>
void Foam::HashSet<Key, Hash>::operator&=(const HashSet<Key, Hash>& rhs) void Foam::HashSet<Key, Hash>::operator&=(const HashSet<Key, Hash>& rhs)
{ {
// Remove elements not also found in rhs // Remove elements not also found in rhs
for (iterator iter = this->begin(); iter != this->end(); ++iter) for (iterator iter = this->cbegin(); iter != this->cend(); ++iter)
{ {
if (!rhs.found(iter.key())) if (!rhs.found(iter.key()))
{ {
@ -119,7 +119,7 @@ template<class Key, class Hash>
void Foam::HashSet<Key, Hash>::operator^=(const HashSet<Key, Hash>& rhs) void Foam::HashSet<Key, Hash>::operator^=(const HashSet<Key, Hash>& rhs)
{ {
// Add missed rhs elements, remove duplicate elements // Add missed rhs elements, remove duplicate elements
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{ {
if (found(iter.key())) if (found(iter.key()))
{ {
@ -138,7 +138,7 @@ template<class Key, class Hash>
void Foam::HashSet<Key, Hash>::operator-=(const HashSet<Key, Hash>& rhs) void Foam::HashSet<Key, Hash>::operator-=(const HashSet<Key, Hash>& rhs)
{ {
// Remove rhs elements from lhs // Remove rhs elements from lhs
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{ {
erase(iter.key()); erase(iter.key());
} }

View File

@ -71,7 +71,7 @@ Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
table_[hashIdx] = 0; table_[hashIdx] = 0;
} }
for (const_iterator iter = ht.begin(); iter != ht.end(); ++iter) for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
{ {
insert(iter.key(), *iter); insert(iter.key(), *iter);
} }
@ -113,9 +113,9 @@ Foam::HashTable<T, Key, Hash>::~HashTable()
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
{ {
if (tableSize_) if (nElmts_)
{ {
label hashIdx = Hash()(key, tableSize_); const label hashIdx = Hash()(key, tableSize_);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{ {
@ -145,9 +145,9 @@ Foam::HashTable<T, Key, Hash>::find
const Key& key const Key& key
) )
{ {
if (tableSize_) if (nElmts_)
{ {
label hashIdx = Hash()(key, tableSize_); const label hashIdx = Hash()(key, tableSize_);
for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
{ {
@ -177,7 +177,7 @@ Foam::HashTable<T, Key, Hash>::find
const Key& key const Key& key
) const ) const
{ {
if (tableSize_) if (nElmts_)
{ {
label hashIdx = Hash()(key, tableSize_); label hashIdx = Hash()(key, tableSize_);
@ -198,7 +198,7 @@ Foam::HashTable<T, Key, Hash>::find
} }
# endif # endif
return end(); return cend();
} }
@ -209,7 +209,7 @@ Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
List<Key> tofc(nElmts_); List<Key> tofc(nElmts_);
label i = 0; label i = 0;
for (const_iterator iter = begin(); iter != end(); ++iter) for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{ {
tofc[i++] = iter.key(); tofc[i++] = iter.key();
} }
@ -351,7 +351,7 @@ bool Foam::HashTable<T, Key, Hash>::erase(const iterator& cit)
else else
{ {
// No previous found. Mark with special value which is // No previous found. Mark with special value which is
// - not end() // - not end()/cend()
// - handled by operator++ // - handled by operator++
it.elmtPtr_ = reinterpret_cast<hashedEntry*>(this); it.elmtPtr_ = reinterpret_cast<hashedEntry*>(this);
it.hashIndex_ = -1; it.hashIndex_ = -1;
@ -466,7 +466,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label newSize)
HashTable<T, Key, Hash>* newTable = new HashTable<T, Key, Hash>(newSize); HashTable<T, Key, Hash>* newTable = new HashTable<T, Key, Hash>(newSize);
for (const_iterator iter = begin(); iter != end(); ++iter) for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{ {
newTable->insert(iter.key(), *iter); newTable->insert(iter.key(), *iter);
} }
@ -565,7 +565,7 @@ void Foam::HashTable<T, Key, Hash>::operator=
clear(); clear();
} }
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{ {
insert(iter.key(), *iter); insert(iter.key(), *iter);
} }
@ -579,22 +579,22 @@ bool Foam::HashTable<T, Key, Hash>::operator==
) const ) const
{ {
// Are all my elements in rhs? // Are all my elements in rhs?
for (const_iterator iter = begin(); iter != end(); ++iter) for (const_iterator iter = cbegin(); iter != cend(); ++iter)
{ {
const_iterator fnd = rhs.find(iter.key()); const_iterator fnd = rhs.find(iter.key());
if (fnd == rhs.end() || fnd() != iter()) if (fnd == rhs.cend() || fnd() != iter())
{ {
return false; return false;
} }
} }
// Are all rhs elements in me? // Are all rhs elements in me?
for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
{ {
const_iterator fnd = find(iter.key()); const_iterator fnd = find(iter.key());
if (fnd == end() || fnd() != iter()) if (fnd == cend() || fnd() != iter())
{ {
return false; return false;
} }

View File

@ -112,7 +112,7 @@ inline const T& Foam::HashTable<T, Key, Hash>::operator[](const Key& key) const
{ {
const_iterator iter = find(key); const_iterator iter = find(key);
if (iter == end()) if (iter == cend())
{ {
FatalErrorIn("HashTable<T, Key, Hash>::operator[](const Key&) const") FatalErrorIn("HashTable<T, Key, Hash>::operator[](const Key&) const")
<< key << " not found in table. Valid entries: " << key << " not found in table. Valid entries: "
@ -283,8 +283,15 @@ Foam::HashTable<T, Key, Hash>::begin()
{ {
label i = 0; label i = 0;
if (nElmts_)
{
while (table_ && !table_[i] && ++i < tableSize_) while (table_ && !table_[i] && ++i < tableSize_)
{} {}
}
else
{
i = tableSize_;
}
if (i == tableSize_) if (i == tableSize_)
{ {
@ -456,8 +463,15 @@ Foam::HashTable<T, Key, Hash>::cbegin() const
{ {
label i = 0; label i = 0;
if (nElmts_)
{
while (table_ && !table_[i] && ++i < tableSize_) while (table_ && !table_[i] && ++i < tableSize_)
{} {}
}
else
{
i = tableSize_;
}
if (i == tableSize_) if (i == tableSize_)
{ {

View File

@ -133,10 +133,13 @@ Foam::Istream& Foam::operator>>(Istream& is, HashTable<T, Key, Hash>& L)
) )
{ {
is.putBack(lastToken); is.putBack(lastToken);
Key key; Key key;
is >> key; is >> key;
T element; T element;
is >> element; is >> element;
L.insert(key, element); L.insert(key, element);
is.fatalCheck is.fatalCheck
@ -174,8 +177,8 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const HashTable<T, Key, Hash>& L)
// Write contents // Write contents
for for
( (
typename HashTable<T, Key, Hash>::const_iterator iter = L.begin(); typename HashTable<T, Key, Hash>::const_iterator iter = L.cbegin();
iter != L.end(); iter != L.cend();
++iter ++iter
) )
{ {

View File

@ -100,6 +100,8 @@ Foam::StaticHashTable<T, Key, Hash>::~StaticHashTable()
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
bool Foam::StaticHashTable<T, Key, Hash>::found(const Key& key) const bool Foam::StaticHashTable<T, Key, Hash>::found(const Key& key) const
{
if (nElmts_)
{ {
label hashIdx = Hash()(key, keys_.size()); label hashIdx = Hash()(key, keys_.size());
const List<Key>& localKeys = keys_[hashIdx]; const List<Key>& localKeys = keys_[hashIdx];
@ -111,6 +113,7 @@ bool Foam::StaticHashTable<T, Key, Hash>::found(const Key& key) const
return true; return true;
} }
} }
}
# ifdef FULLDEBUG # ifdef FULLDEBUG
if (debug) if (debug)
@ -130,6 +133,8 @@ Foam::StaticHashTable<T, Key, Hash>::find
( (
const Key& key const Key& key
) )
{
if (nElmts_)
{ {
label hashIdx = Hash()(key, keys_.size()); label hashIdx = Hash()(key, keys_.size());
const List<Key>& localKeys = keys_[hashIdx]; const List<Key>& localKeys = keys_[hashIdx];
@ -141,6 +146,7 @@ Foam::StaticHashTable<T, Key, Hash>::find
return iterator(*this, hashIdx, elemIdx); return iterator(*this, hashIdx, elemIdx);
} }
} }
}
# ifdef FULLDEBUG # ifdef FULLDEBUG
if (debug) if (debug)

View File

@ -102,7 +102,7 @@ inline const T& Foam::StaticHashTable<T, Key, Hash>::operator[]
{ {
const_iterator iter = find(key); const_iterator iter = find(key);
if (iter == end()) if (iter == cend())
{ {
FatalErrorIn FatalErrorIn
( (

View File

@ -142,10 +142,13 @@ Foam::Istream& Foam::operator>>(Istream& is, StaticHashTable<T, Key, Hash>& L)
) )
{ {
is.putBack(lastToken); is.putBack(lastToken);
Key key; Key key;
is >> key; is >> key;
T element; T element;
is >> element; is >> element;
L.insert(key, element); L.insert(key, element);
is.fatalCheck is.fatalCheck