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 *
@ -1446,12 +1415,12 @@ findunitg (int n, const region * hint)
{ {
/* Abfangen von Syntaxfehlern. */ /* Abfangen von Syntaxfehlern. */
if(n <= 0) if (n <= 0)
return NULL; return NULL;
/* findunit global! */ /* findunit global! */
hint = 0; hint = 0;
return ufindhash (n); 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

@ -76,48 +76,47 @@ extern int countheroes(const struct faction * f);
#endif #endif
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;
int hp; int hp;
char *name; char *name;
char *display; char *display;
struct faction *faction; struct faction *faction;
struct building *building; struct building *building;
struct ship *ship; struct ship *ship;
unsigned short number; unsigned short number;
short age; short age;
/* skill data */ /* skill data */
short skill_size; short skill_size;
struct skill *skills; struct skill *skills;
struct item * items; struct item * items;
struct reservation { struct reservation {
struct reservation * next; struct reservation * next;
const struct resource_type * type; const struct resource_type * type;
int value; int value;
} * reservations; } * reservations;
/* orders */ /* orders */
struct order * orders; struct order * orders;
struct order * thisorder; struct order * thisorder;
#ifdef LASTORDER #ifdef LASTORDER
struct order * lastorder; struct order * lastorder;
#else #else
struct order * old_orders; struct order * old_orders;
#endif #endif
/* race and illusionary race */ /* race and illusionary race */
const struct race * race; const struct race * race;
const struct race * irace; const struct race * irace;
unsigned int flags; unsigned int flags;
struct attrib * attribs; struct attrib * attribs;
status_t status; status_t status;
int n; /* enno: attribut? */ int n; /* enno: attribut? */
int wants; /* enno: attribut? */ int wants; /* enno: attribut? */
} unit; } unit;
typedef struct unit_list { typedef struct unit_list {
@ -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
} }