Bug 1275048 - Speed up hashing in SharedImmutableStringsCache; r=luke

This commit does two things to speed up hashing in the
SharedImmutableStringsCache:

* We eagerly compute a string's hash when we create a lookup for it. This means
  that we compute the hash before we take the lock, which reduces the length of
  time the lock is held.

* For strings longer than SHORT_STRING_MAX_LENGTH (currently 8192), we only hash
  the first N and last N characters in the string, where N =
  SHORT_STRING_MAX_LENGTH / 2. This increases the risk of collisions, but in
  practice it should be rare, and this yields a large speedup for hashing long
  strings.
This commit is contained in:
Nick Fitzgerald 2016-05-23 19:39:27 -07:00
parent 305e2e0825
commit db44608144
2 changed files with 29 additions and 16 deletions

View File

@ -18,7 +18,7 @@ SharedImmutableStringsCache::getOrCreate(const char* chars, size_t length,
{
MOZ_ASSERT(inner_);
MOZ_ASSERT(chars);
Hasher::Lookup lookup(chars, length);
Hasher::Lookup lookup(Hasher::hashLongString(chars, length), chars, length);
auto locked = inner_->lock();
if (!locked->set.initialized() && !locked->set.init())
@ -46,7 +46,9 @@ SharedImmutableStringsCache::getOrCreate(const char16_t* chars, size_t length,
IntoOwnedTwoByteChars intoOwnedTwoByteChars) {
MOZ_ASSERT(inner_);
MOZ_ASSERT(chars);
Hasher::Lookup lookup(chars, length);
auto hash = Hasher::hashLongString(reinterpret_cast<const char*>(chars),
length * sizeof(char16_t));
Hasher::Lookup lookup(hash, chars, length);
auto locked = inner_->lock();
if (!locked->set.initialized() && !locked->set.init())

View File

@ -274,33 +274,44 @@ class SharedImmutableStringsCache
{
friend struct Hasher;
HashNumber hash_;
const char* chars_;
size_t length_;
public:
Lookup(const char* chars, size_t length)
: chars_(chars)
Lookup(HashNumber hash, const char* chars, size_t length)
: hash_(hash)
, chars_(chars)
, length_(length)
{
MOZ_ASSERT(chars_);
MOZ_ASSERT(hash == Hasher::hashLongString(chars, length));
}
explicit Lookup(const char* chars)
: Lookup(chars, strlen(chars))
{ }
Lookup(const char16_t* chars, size_t length)
: Lookup(reinterpret_cast<const char*>(chars), length * sizeof(char16_t))
{ }
explicit Lookup(const char16_t* chars)
: Lookup(chars, js_strlen(chars))
Lookup(HashNumber hash, const char16_t* chars, size_t length)
: Lookup(hash, reinterpret_cast<const char*>(chars), length * sizeof(char16_t))
{ }
};
static const size_t SHORT_STRING_MAX_LENGTH = 8192;
static const size_t HASH_CHUNK_LENGTH = SHORT_STRING_MAX_LENGTH / 2;
// For strings longer than SHORT_STRING_MAX_LENGTH, we only hash the
// first HASH_CHUNK_LENGTH and last HASH_CHUNK_LENGTH characters in the
// string. This increases the risk of collisions, but in practice it
// should be rare, and it yields a large speedup for hashing long
// strings.
static HashNumber hashLongString(const char* chars, size_t length) {
MOZ_ASSERT(chars);
return length <= SHORT_STRING_MAX_LENGTH
? mozilla::HashString(chars, length)
: mozilla::AddToHash(mozilla::HashString(chars, HASH_CHUNK_LENGTH),
mozilla::HashString(chars + length - HASH_CHUNK_LENGTH,
HASH_CHUNK_LENGTH));
}
static HashNumber hash(const Lookup& lookup) {
MOZ_ASSERT(lookup.chars_);
return mozilla::HashString(lookup.chars_, lookup.length_);
return lookup.hash_;
}
static bool match(const StringBox::Ptr& key, const Lookup& lookup) {