Slightly more cache-friendly hashing (WIP)

This commit is contained in:
Enno Rehling 2008-04-24 01:37:47 +00:00
parent 34edc042bc
commit 23505d2b84
4 changed files with 130 additions and 73 deletions

View File

@ -633,40 +633,6 @@ shipspeed (const ship * sh, const unit * u)
return k; return k;
} }
/* erwartete Anzahl Einheiten x 2 */
#define UMAXHASH 199999
unit *unithash[UMAXHASH];
void
uhash (unit * u)
{
assert(!u->nexthash || !"unit ist bereits gehasht");
u->nexthash = unithash[u->no % UMAXHASH];
unithash[u->no % UMAXHASH] = u;
}
void
uunhash (unit * u)
{
unit ** x = &(unithash[u->no % UMAXHASH]);
while (*x && *x!=u) x = &(*x)->nexthash;
assert(*x || !"unit nicht gefunden");
*x = u->nexthash;
u->nexthash=NULL;
}
unit *
ufindhash (int i)
{
assert(i>=0);
if (i>=0) {
unit * u = unithash[i % UMAXHASH];
while (u && u->no!=i) u = u->nexthash;
return u;
}
return NULL;
}
#define FMAXHASH 2039 #define FMAXHASH 2039
faction * factionhash[FMAXHASH]; faction * factionhash[FMAXHASH];
@ -1438,7 +1404,10 @@ findunitr (const region * r, int n)
unit *findunit(int n) unit *findunit(int n)
{ {
return findunitg(n, NULL); if (n <= 0) {
return NULL;
}
return ufindhash(n);
} }
unit * unit *

View File

@ -39,8 +39,12 @@ extern "C" {
#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) #define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance))
/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */
#ifndef MAXREGIONS #ifndef MAXREGIONS
# define MAXREGIONS 262139 /* must be prime for hashing. 262139=last<2^18 */ # define MAXREGIONS 262139 /* must be prime for hashing. */
#endif
#ifndef MAXUNITS
# define MAXUNITS 524287 /* must be prime for hashing. */
#endif #endif
#define MONSTER_FACTION 0 /* Die Partei, in der die Monster sind. */ #define MONSTER_FACTION 0 /* Die Partei, in der die Monster sind. */
@ -274,11 +278,6 @@ void changeblockchaos(void);
extern struct region *firstregion(struct faction * f); extern struct region *firstregion(struct faction * f);
extern struct region *lastregion(struct faction * f); extern struct region *lastregion(struct faction * f);
void inituhash(void);
void uhash(struct unit * u);
void uunhash(struct unit * u);
struct unit *ufindhash(int i);
void fhash(struct faction * f); void fhash(struct faction * f);
void funhash(struct faction * f); void funhash(struct faction * f);

View File

@ -67,6 +67,92 @@ attrib_type at_creator = {
/* Rest ist NULL; temporäres, nicht alterndes Attribut */ /* Rest ist NULL; temporäres, nicht alterndes Attribut */
}; };
#define UMAXHASH MAXUNITS
static unit * unithash[UMAXHASH];
static unit * delmarker = (unit*)unithash; /* a funny hack */
#define HASH_STATISTICS 1
#if HASH_STATISTICS
static int hash_requests;
static int hash_misses;
#endif
/* benchmark:
* jenkins_hash: 5.25 misses/hit
* wang_hash: 5.33 misses/hit
*/
INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a)
{
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
a = (a+0x165667b1) + (a<<5);
a = (a+0xd3a2646c) ^ (a<<9);
a = (a+0xfd7046c5) + (a<<3);
a = (a^0xb55a4f09) ^ (a>>16);
return a;
}
INLINE_FUNCTION unsigned int wang_hash(unsigned int a)
{
a = ~a + (a << 15); // a = (a << 15) - a - 1;
a = a ^ (a >> 12);
a = a + (a << 2);
a = a ^ (a >> 4);
a = a * 2057; // a = (a + (a << 3)) + (a << 11);
a = a ^ (a >> 16);
return a;
}
#define HASH1(a, m) (jenkins_hash(a) % m)
#define HASH2(a, m) 1
/*
#define HASH1(a, m) ((a) % m)
#define HASH2(a, m) (m - 2 - a % (m-2))
*/
void
uhash(unit * u)
{
int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH);
while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) {
key = (key + gk) % UMAXHASH;
}
assert(unithash[key]!=u || !"trying to add the same unit twice");
unithash[key] = u;
}
void
uunhash(unit * u)
{
int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH);
while (unithash[key]!=NULL && unithash[key]!=u) {
key = (key + gk) % UMAXHASH;
}
assert(unithash[key]==u || !"trying to remove a unit that is not hashed");
unithash[key] = delmarker;
}
unit *
ufindhash(int uid)
{
assert(uid>=0);
#if HASH_STATISTICS
++hash_requests;
#endif
if (uid>=0) {
int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH);
while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) {
key = (key + gk) % UMAXHASH;
#if HASH_STATISTICS
++hash_misses;
#endif
}
return unithash[key];
}
return NULL;
}
#define DMAXHASH 7919 #define DMAXHASH 7919
typedef struct dead { typedef struct dead {
struct dead * nexthash; struct dead * nexthash;

View File

@ -77,7 +77,6 @@ extern int countheroes(const struct faction * f);
typedef struct unit { typedef struct unit {
struct unit *next; /* needs to be first entry, for region's unitlist */ struct unit *next; /* needs to be first entry, for region's unitlist */
struct unit *nexthash;
struct unit *nextF; /* nächste Einheit der Partei */ struct unit *nextF; /* nächste Einheit der Partei */
struct region *region; struct region *region;
int no; int no;
@ -217,6 +216,10 @@ extern void stripunit(struct unit * u);
extern void name_unit(struct unit *u); extern void name_unit(struct unit *u);
extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator);
extern void uhash(struct unit * u);
extern void uunhash(struct unit * u);
extern struct unit *ufindhash(int i);
extern struct attrib_type at_creator; extern struct attrib_type at_creator;
#ifdef __cplusplus #ifdef __cplusplus
} }