hash chunk cache line boundary alignment optimization

master
Daniel Kolesa 2015-07-20 18:51:16 +01:00
parent cc0fccb8cf
commit 0c297af0bd
1 changed files with 62 additions and 10 deletions

View File

@ -7,6 +7,7 @@
#define OSTD_INTERNAL_HASHTABLE_HH
#include <string.h>
#include <math.h>
#include "ostd/types.hh"
#include "ostd/utility.hh"
@ -120,6 +121,63 @@ public:
};
namespace detail {
/* Use template metaprogramming to figure out a correct number
* of elements to use per chunk for proper cache alignment
* (i.e. sizeof(Chunk) % CACHE_LINE_SIZE == 0).
*
* If this is not possible, use the upper bound and pad the
* structure with some extra bytes.
*/
static constexpr Size CACHE_LINE_SIZE = 64;
static constexpr Size CHUNK_LOWER_BOUND = 32;
static constexpr Size CHUNK_UPPER_BOUND = 128;
template<typename E, Size N>
struct HashChainAlign {
static constexpr Size csize = sizeof(HashChain<E>[N]) + sizeof(void *);
static constexpr Size value = ((csize % CACHE_LINE_SIZE) == 0)
? N : HashChainAlign<E, N + 1>::value;
};
template<typename E>
struct HashChainAlign<E, CHUNK_UPPER_BOUND> {
static constexpr Size value = CHUNK_UPPER_BOUND;
};
template<Size N, bool B>
struct HashChainPad;
template<Size N>
struct HashChainPad<N, true> {};
template<Size N>
struct HashChainPad<N, false> {
byte pad[CACHE_LINE_SIZE - (N % CACHE_LINE_SIZE)];
};
template<Size N>
struct HashPad: HashChainPad<N, N % CACHE_LINE_SIZE == 0> {};
template<typename E, Size V = HashChainAlign<E, CHUNK_LOWER_BOUND>::value,
bool P = (V == CHUNK_UPPER_BOUND)
> struct HashChunk;
template<typename E, Size V>
struct HashChunk<E, V, false> {
static constexpr Size num = V;
HashChain<E> chains[num];
HashChunk *next;
};
template<typename E, Size V>
struct HashChunk<E, V, true>: HashPad<
sizeof(HashChain<E>[V]) + sizeof(void *)
> {
static constexpr Size num = V;
HashChain<E> chains[num];
HashChunk *next;
};
template<
typename B, /* contains methods specific to each ht type */
typename E, /* element type */
@ -131,14 +189,8 @@ namespace detail {
bool Multihash
> struct Hashtable {
private:
static constexpr Size CHUNKSIZE = 64;
using Chain = detail::HashChain<E>;
struct Chunk {
Chain chains[CHUNKSIZE];
Chunk *next;
};
using Chain = HashChain<E>;
using Chunk = HashChunk<E>;
Size p_size;
Size p_len;
@ -203,9 +255,9 @@ private:
allocator_construct(get_challoc(), chunk);
chunk->next = p_chunks;
p_chunks = chunk;
for (Size i = 0; i < (CHUNKSIZE - 1); ++i)
for (Size i = 0; i < (Chunk::num - 1); ++i)
chunk->chains[i].next = &chunk->chains[i + 1];
chunk->chains[CHUNKSIZE - 1].next = p_unused;
chunk->chains[Chunk::num - 1].next = p_unused;
p_unused = chunk->chains;
}
++p_len;