fstat(fd, &statbuf);
*mapping = statbuf.st_size;
*baseAddress = mmap(nullptr, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ madvise(*baseAddress, statbuf.st_size, MADV_RANDOM);
::close(fd);
if (*baseAddress == MAP_FAILED) {
exit(1);
}
#else
+ // Note FILE_FLAG_RANDOM_ACCESS is only a hint to Windows and as such may get ignored.
HANDLE fd = CreateFile(fname.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, nullptr);
if (fd == INVALID_HANDLE_VALUE)
return *baseAddress = nullptr, nullptr;
typedef std::tuple<Key, TBTable<WDL>*, TBTable<DTZ>*> Entry;
- static const int Size = 1 << 16; // 64K table, indexed by key's 16 lsb
+ static constexpr int Size = 1 << 12; // 4K table, indexed by key's 12 lsb
+ static constexpr int Overflow = 1; // Number of elements allowed to map to the last bucket
- Entry hashTable[Size];
+ Entry hashTable[Size + Overflow];
std::deque<TBTable<WDL>> wdlTable;
std::deque<TBTable<DTZ>> dtzTable;
void insert(Key key, TBTable<WDL>* wdl, TBTable<DTZ>* dtz) {
- Entry* entry = &hashTable[(uint32_t)key & (Size - 1)];
+ uint32_t homeBucket = (uint32_t)key & (Size - 1);
+ Entry entry = std::make_tuple(key, wdl, dtz);
// Ensure last element is empty to avoid overflow when looking up
- for ( ; entry - hashTable < Size - 1; ++entry)
- if (std::get<KEY>(*entry) == key || !std::get<WDL>(*entry)) {
- *entry = std::make_tuple(key, wdl, dtz);
+ for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket) {
+ Key otherKey = std::get<KEY>(hashTable[bucket]);
+ if (otherKey == key || !std::get<WDL>(hashTable[bucket])) {
+ hashTable[bucket] = entry;
return;
}
+
+ // Robin Hood hashing: If we've probed for longer than this element,
+ // insert here and search for a new spot for the other element instead.
+ uint32_t otherHomeBucket = (uint32_t)otherKey & (Size - 1);
+ if (otherHomeBucket > homeBucket) {
+ swap(entry, hashTable[bucket]);
+ key = otherKey;
+ homeBucket = otherHomeBucket;
+ }
+ }
std::cerr << "TB hash table size too low!" << std::endl;
exit(1);
}
static Mutex mutex;
- // Use 'aquire' to avoid a thread reads 'ready' == true while another is
- // still working, this could happen due to compiler reordering.
+ // Use 'acquire' to avoid a thread reading 'ready' == true while
+ // another is still working. (compiler reordering may cause this).
if (e.ready.load(std::memory_order_acquire))
- return e.baseAddress; // Could be nullptr if file does not exsist
+ return e.baseAddress; // Could be nullptr if file does not exist
std::unique_lock<Mutex> lk(mutex);
continue; // First on diagonal, second above
else if (!off_A1H8(s1) && !off_A1H8(s2))
- bothOnDiagonal.push_back(std::make_pair(idx, s2));
+ bothOnDiagonal.emplace_back(idx, s2);
else
MapKK[idx][s2] = code++;