From a2abcfe177aad15e6273da0952b8c70ecc89bfdb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 Apr 2008 18:14:14 +0000 Subject: [PATCH] more intelligent values for hashtable sizes. --- src/common/kernel/building.c | 20 ++++++------- src/common/kernel/eressea.h | 4 +-- src/common/kernel/region.c | 58 +++++++++++++++++++++++------------- src/common/kernel/region.h | 2 -- src/common/kernel/reports.h | 2 ++ src/common/kernel/unit.c | 34 --------------------- src/common/util/goodies.h | 32 +++++++++++++------- src/common/util/strings.c | 21 +++++++++++++ src/res/messages.xml | 1 + 9 files changed, 96 insertions(+), 78 deletions(-) diff --git a/src/common/kernel/building.c b/src/common/kernel/building.c index 5ec4c5124..be63e145c 100644 --- a/src/common/kernel/building.c +++ b/src/common/kernel/building.c @@ -211,17 +211,17 @@ bhash(building * b) void bunhash(building * b) { - building **show; + building **show; - for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == b->no) - break; - } - if (*show) { - assert(*show == b); - *show = (*show)->nexthash; - b->nexthash = 0; - } + for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == b->no) + break; + } + if (*show) { + assert(*show == b); + *show = (*show)->nexthash; + b->nexthash = 0; + } } static building * diff --git a/src/common/kernel/eressea.h b/src/common/kernel/eressea.h index f45188c75..2370bbb7a 100644 --- a/src/common/kernel/eressea.h +++ b/src/common/kernel/eressea.h @@ -41,10 +41,10 @@ extern "C" { /* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ #ifndef MAXREGIONS -# define MAXREGIONS 262139 /* must be prime for hashing. */ +# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ #endif #ifndef MAXUNITS -# define MAXUNITS 524287 /* must be prime for hashing. */ +# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ #endif #define MONSTER_FACTION 0 /* Die Partei, in der die Monster sind. */ diff --git a/src/common/kernel/region.c b/src/common/kernel/region.c index c4ff12ef2..16c54765b 100644 --- a/src/common/kernel/region.c +++ b/src/common/kernel/region.c @@ -42,6 +42,7 @@ /* util includes */ #include +#include #include #include #include @@ -379,8 +380,10 @@ attrib_type at_moveblock = { }; -#define RMAXHASH 65521 /* last prime <2^16 */ -static region *regionhash[RMAXHASH]; +#define coor_hashkey(x, y) (unsigned int)((x<<16) + y) +#define RMAXHASH MAXREGIONS +static region * regionhash[RMAXHASH]; +static region * delmarker = (region*)regionhash; /* a funny hack */ static unsigned int uidhash[MAXREGIONS]; unsigned int @@ -402,29 +405,49 @@ generate_region_id(void) return uid; } +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + static region * rfindhash(short x, short y) { - region *old; - for (old = regionhash[coor_hashkey(x, y) % RMAXHASH]; old; old = old->nexthash) - if (old->x == x && old->y == y) - return old; - return 0; + unsigned int rid = coor_hashkey(x, y); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (rid>=0) { + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && (regionhash[key]==delmarker || regionhash[key]->x!=x || regionhash[key]->y!=y)) { + key = (key + gk) % RMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return regionhash[key]; + } + return NULL; } void rhash(region * r) { - int key = coor_hashkey(r->x, r->y) % RMAXHASH; - region *old = regionhash[key]; + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && regionhash[key]!=delmarker && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]!=r || !"trying to add the same region twice"); regionhash[key] = r; - r->nexthash = old; } void runhash(region * r) { - region **show; + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); #ifdef FAST_CONNECT int d, di; @@ -437,16 +460,11 @@ runhash(region * r) } } #endif - for (show = ®ionhash[coor_hashkey(r->x, r->y) % RMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->x == r->x && (*show)->y == r->y) { - break; - } - } - if (*show) { - assert(*show == r); - *show = (*show)->nexthash; - r->nexthash = 0; + while (regionhash[key]!=NULL && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; } + assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); + regionhash[key] = delmarker; } region * diff --git a/src/common/kernel/region.h b/src/common/kernel/region.h index d991af5a7..c92a19286 100644 --- a/src/common/kernel/region.h +++ b/src/common/kernel/region.h @@ -109,7 +109,6 @@ typedef struct region { struct message_list *msgs; } * individual_messages; struct attrib *attribs; - struct region *nexthash; struct donation * donations; const struct terrain_type * terrain; struct rawmaterial * resources; @@ -142,7 +141,6 @@ typedef struct { } moveblock; #define reg_hashkey(r) (r->index) -#define coor_hashkey(x, y) (abs(x + 0x100 * y)) int distance(const struct region*, const struct region*); int koor_distance(int ax, int ay, int bx, int by) ; diff --git a/src/common/kernel/reports.h b/src/common/kernel/reports.h index d2afd3002..e8c4f1e4b 100644 --- a/src/common/kernel/reports.h +++ b/src/common/kernel/reports.h @@ -118,6 +118,8 @@ extern const char * report_kampfstatus(const struct unit * u, const struct local extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); +#define GR_PLURAL 0x01 /* grammar: plural */ + #ifdef __cplusplus } #endif diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c index b572889db..782bff972 100644 --- a/src/common/kernel/unit.c +++ b/src/common/kernel/unit.c @@ -77,40 +77,6 @@ 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) { diff --git a/src/common/util/goodies.h b/src/common/util/goodies.h index 044e2770e..693c8ebdd 100644 --- a/src/common/util/goodies.h +++ b/src/common/util/goodies.h @@ -18,6 +18,10 @@ extern "C" { #endif +extern boolean locale_check(void); +extern char * set_string(char **s, const char *neu); +extern int set_email(char** pemail, const char *newmail); + extern int *intlist_init(void); extern int *intlist_add(int *i_p, int i); extern int *intlist_find(int *i_p, int i); @@ -27,19 +31,27 @@ extern int *intlist_find(int *i_p, int i); #else extern unsigned int hashstring(const char* s); extern const char *escape_string(const char * str, char * buffer, unsigned int len); +extern unsigned int jenkins_hash(unsigned int a); +extern unsigned int wang_hash(unsigned int a); #endif -extern boolean locale_check(void); -extern char * set_string(char **s, const char *neu); +/* benchmark for units: + * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) + * WANG_HASH: 5.33 misses/hit (with good cache behavior) + * KNUTH_HASH: 1.93 misses/hit (with bad cache behavior) + * CF_HASH: fucking awful! + */ +#define KNUTH_HASH1(a, m) ((a) % m) +#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2)) +#define CF_HASH1(a, m) ((a) % m) +#define CF_HASH2(a, m) (8 - ((a) & 7)) +#define JENKINS_HASH1(a, m) (jenkins_hash(a) % m) +#define JENKINS_HASH2(a, m) 1 +#define WANG_HASH1(a, m) (wang_hash(a) % m) +#define WANG_HASH2(a, m) 1 - -extern int set_email(char** pemail, const char *newmail); -/* fast strncat */ -/* grammar constants: */ -#define GR_PLURAL 0x01 -/* 0x02-0x08 left unused for individual use */ -#define GR_ARTICLE 0x10 -#define GR_INDEFINITE_ARTICLE 0x20 +#define HASH1 JENKINS_HASH1 +#define HASH2 JENKINS_HASH2 #ifdef __cplusplus } diff --git a/src/common/util/strings.c b/src/common/util/strings.c index c866fbdd1..d01fef0a8 100644 --- a/src/common/util/strings.c +++ b/src/common/util/strings.c @@ -56,3 +56,24 @@ escape_string(const char * str, char * buffer, unsigned int len) return buffer; } +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; +} diff --git a/src/res/messages.xml b/src/res/messages.xml index ca3136079..1da1422ff 100644 --- a/src/res/messages.xml +++ b/src/res/messages.xml @@ -7605,6 +7605,7 @@ "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren kurzzeitig ihr Gedächtnis." + "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories."