Skip to content

Commit

Permalink
Switch hash to rapidhash.
Browse files Browse the repository at this point in the history
This is the currently fastest hash that passes SMHasher and does not
require special instructions (e.g. SIMD). Like emhash8, it is
MIT-licensed, and we include the .h file directly.

For a no-op build of Chromium (Linux, Zen 2),
this reduces time spent from 4.62 to 4.22 seconds.
(NOTE: This is a more difficult measurement than the previous ones,
as it necessarily involves removing the entire build log and doing
a clean build. However, just switching the HashMap hash takes
to 4.47 seconds or so.)
  • Loading branch information
Steinar H. Gunderson committed Nov 1, 2024
1 parent feaba49 commit 19396e6
Show file tree
Hide file tree
Showing 3 changed files with 328 additions and 86 deletions.
55 changes: 3 additions & 52 deletions src/build_log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,63 +53,14 @@ using namespace std;
namespace {

const char kFileSignature[] = "# ninja log v%d\n";
const int kOldestSupportedVersion = 6;
const int kCurrentVersion = 6;

// 64bit MurmurHash2, by Austin Appleby
#if defined(_MSC_VER)
#define BIG_CONSTANT(x) (x)
#else // defined(_MSC_VER)
#define BIG_CONSTANT(x) (x##LLU)
#endif // !defined(_MSC_VER)
inline
uint64_t MurmurHash64A(const void* key, size_t len) {
static const uint64_t seed = 0xDECAFBADDECAFBADull;
const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995);
const int r = 47;
uint64_t h = seed ^ (len * m);
const unsigned char* data = static_cast<const unsigned char*>(key);
while (len >= 8) {
uint64_t k;
memcpy(&k, data, sizeof k);
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
data += 8;
len -= 8;
}
switch (len & 7)
{
case 7: h ^= uint64_t(data[6]) << 48;
NINJA_FALLTHROUGH;
case 6: h ^= uint64_t(data[5]) << 40;
NINJA_FALLTHROUGH;
case 5: h ^= uint64_t(data[4]) << 32;
NINJA_FALLTHROUGH;
case 4: h ^= uint64_t(data[3]) << 24;
NINJA_FALLTHROUGH;
case 3: h ^= uint64_t(data[2]) << 16;
NINJA_FALLTHROUGH;
case 2: h ^= uint64_t(data[1]) << 8;
NINJA_FALLTHROUGH;
case 1: h ^= uint64_t(data[0]);
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
#undef BIG_CONSTANT

const int kOldestSupportedVersion = 7;
const int kCurrentVersion = 7;

} // namespace

// static
uint64_t BuildLog::LogEntry::HashCommand(StringPiece command) {
return MurmurHash64A(command.str_, command.len_);
return rapidhash(command.str_, command.len_);
}

BuildLog::LogEntry::LogEntry(const string& output)
Expand Down
36 changes: 2 additions & 34 deletions src/hash_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,39 +20,7 @@
#include "string_piece.h"
#include "util.h"
#include "hash_table8.hpp"

// MurmurHash2, by Austin Appleby
static inline
unsigned int MurmurHash2(const void* key, size_t len) {
static const unsigned int seed = 0xDECAFBAD;
const unsigned int m = 0x5bd1e995;
const int r = 24;
unsigned int h = seed ^ len;
const unsigned char* data = static_cast<const unsigned char*>(key);
while (len >= 4) {
unsigned int k;
memcpy(&k, data, sizeof k);
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
data += 4;
len -= 4;
}
switch (len) {
case 3: h ^= data[2] << 16;
NINJA_FALLTHROUGH;
case 2: h ^= data[1] << 8;
NINJA_FALLTHROUGH;
case 1: h ^= data[0];
h *= m;
};
h ^= h >> 13;
h *= m;
h ^= h >> 15;
return h;
}
#include "rapidhash.h"

namespace std {
template<>
Expand All @@ -61,7 +29,7 @@ struct hash<StringPiece> {
typedef size_t result_type;

size_t operator()(StringPiece key) const {
return MurmurHash2(key.str_, key.len_);
return rapidhash(key.str_, key.len_);
}
};
}
Expand Down
Loading

0 comments on commit 19396e6

Please sign in to comment.