Message ID | 1427414231-11385-1-git-send-email-emil.l.velikov@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, 2015-03-26 at 23:57 +0000, Emil Velikov wrote: > This way with follow up commits we can fix it and wire it up to > make check > > v2: > - Use xf86drmHash.h for common structs.(Jan) > - Add test to .gitignore. > > Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> > --- > .gitignore | 1 + > Makefile.sources | 1 + > tests/Makefile.am | 3 +- > tests/hash.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > xf86drmHash.c | 196 +++-------------------------------------------------- > xf86drmHash.h | 47 +++++++++++++ > 6 files changed, 260 insertions(+), 186 deletions(-) > create mode 100644 tests/hash.c > create mode 100644 xf86drmHash.h > > diff --git a/.gitignore b/.gitignore > index 06cc928..0faa825 100644 > --- a/.gitignore > +++ b/.gitignore > @@ -78,6 +78,7 @@ tests/drmstat > tests/getclient > tests/getstats > tests/getversion > +tests/hash > tests/lock > tests/openclose > tests/setversion > diff --git a/Makefile.sources b/Makefile.sources > index 566f7b5..ff4fe5e 100644 > --- a/Makefile.sources > +++ b/Makefile.sources > @@ -1,6 +1,7 @@ > LIBDRM_FILES := \ > xf86drm.c \ > xf86drmHash.c \ > + xf86drmHash.h \ > xf86drmRandom.c \ > xf86drmSL.c \ > xf86drmMode.c \ > diff --git a/tests/Makefile.am b/tests/Makefile.am > index 10f54e3..ea826b5 100644 > --- a/tests/Makefile.am > +++ b/tests/Makefile.am > @@ -29,7 +29,8 @@ LDADD = $(top_builddir)/libdrm.la > > check_PROGRAMS = \ > dristat \ > - drmstat > + drmstat \ > + hash > > if HAVE_NOUVEAU > SUBDIRS += nouveau > diff --git a/tests/hash.c b/tests/hash.c > new file mode 100644 > index 0000000..517a667 > --- /dev/null > +++ b/tests/hash.c > @@ -0,0 +1,198 @@ > +/* xf86drmHash.c -- Small hash table support for integer -> integer mapping > + * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com > + * > + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. > + * All Rights Reserved. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + * > + * Authors: Rickard E. (Rik) Faith <faith@valinux.com> > + * > + * DESCRIPTION > + * > + * This file contains a straightforward implementation of a fixed-sized > + * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for > + * collision resolution. There are two potentially interesting things > + * about this implementation: > + * > + * 1) The table is power-of-two sized. Prime sized tables are more > + * traditional, but do not have a significant advantage over power-of-two > + * sized table, especially when double hashing is not used for collision > + * resolution. > + * > + * 2) The hash computation uses a table of random integers [Hanson97, > + * pp. 39-41]. > + * > + * FUTURE ENHANCEMENTS > + * > + * With a table size of 512, the current implementation is sufficient for a > + * few hundred keys. Since this is well above the expected size of the > + * tables for which this implementation was designed, the implementation of > + * dynamic hash tables was postponed until the need arises. A common (and > + * naive) approach to dynamic hash table implementation simply creates a > + * new hash table when necessary, rehashes all the data into the new table, > + * and destroys the old table. The approach in [Larson88] is superior in > + * two ways: 1) only a portion of the table is expanded when needed, > + * distributing the expansion cost over several insertions, and 2) portions > + * of the table can be locked, enabling a scalable thread-safe > + * implementation. > + * > + * REFERENCES > + * > + * [Hanson97] David R. Hanson. C Interfaces and Implementations: > + * Techniques for Creating Reusable Software. Reading, Massachusetts: > + * Addison-Wesley, 1997. > + * > + * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: > + * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. > + * > + * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April > + * 1988, pp. 446-457. > + * > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > + > +#include "xf86drm.h" > +#include "xf86drmHash.h" > + > +#define DIST_LIMIT 10 > +static int dist[DIST_LIMIT]; > + > +static void clear_dist(void) { > + int i; > + > + for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; > +} > + > +static int count_entries(HashBucketPtr bucket) > +{ > + int count = 0; > + > + for (; bucket; bucket = bucket->next) ++count; > + return count; > +} > + > +static void update_dist(int count) > +{ > + if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; > + else ++dist[count]; > +} > + > +static void compute_dist(HashTablePtr table) > +{ > + int i; > + HashBucketPtr bucket; > + > + printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", > + table->entries, table->hits, table->partials, table->misses); > + clear_dist(); > + for (i = 0; i < HASH_SIZE; i++) { > + bucket = table->buckets[i]; > + update_dist(count_entries(bucket)); > + } > + for (i = 0; i < DIST_LIMIT; i++) { > + if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); > + else printf("other %10d\n", dist[i]); > + } > +} > + > +static void check_table(HashTablePtr table, > + unsigned long key, unsigned long value) > +{ > + unsigned long retval = 0; > + int retcode = drmHashLookup(table, key, &retval); > + > + switch (retcode) { > + case -1: > + printf("Bad magic = 0x%08lx:" > + " key = %lu, expected = %lu, returned = %lu\n", > + table->magic, key, value, retval); > + break; > + case 1: > + printf("Not found: key = %lu, expected = %lu returned = %lu\n", > + key, value, retval); > + break; > + case 0: > + if (value != retval) > + printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", > + key, value, retval); > + break; > + default: > + printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", > + retcode, key, value, retval); > + break; > + } > +} > + > +int main(void) > +{ > + HashTablePtr table; > + int i; > + > + printf("\n***** 256 consecutive integers ****\n"); > + table = drmHashCreate(); > + for (i = 0; i < 256; i++) drmHashInsert(table, i, i); > + for (i = 0; i < 256; i++) check_table(table, i, i); > + for (i = 256; i >= 0; i--) check_table(table, i, i); > + compute_dist(table); > + drmHashDestroy(table); > + > + printf("\n***** 1024 consecutive integers ****\n"); > + table = drmHashCreate(); > + for (i = 0; i < 1024; i++) drmHashInsert(table, i, i); > + for (i = 0; i < 1024; i++) check_table(table, i, i); > + for (i = 1024; i >= 0; i--) check_table(table, i, i); > + compute_dist(table); > + drmHashDestroy(table); > + > + printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); > + table = drmHashCreate(); > + for (i = 0; i < 1024; i++) drmHashInsert(table, i*4096, i); > + for (i = 0; i < 1024; i++) check_table(table, i*4096, i); > + for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); > + compute_dist(table); > + drmHashDestroy(table); > + > + printf("\n***** 1024 random integers ****\n"); > + table = drmHashCreate(); > + srandom(0xbeefbeef); > + for (i = 0; i < 1024; i++) drmHashInsert(table, random(), i); > + srandom(0xbeefbeef); > + for (i = 0; i < 1024; i++) check_table(table, random(), i); > + srandom(0xbeefbeef); > + for (i = 0; i < 1024; i++) check_table(table, random(), i); > + compute_dist(table); > + drmHashDestroy(table); > + > + printf("\n***** 5000 random integers ****\n"); > + table = drmHashCreate(); > + srandom(0xbeefbeef); > + for (i = 0; i < 5000; i++) drmHashInsert(table, random(), i); > + srandom(0xbeefbeef); > + for (i = 0; i < 5000; i++) check_table(table, random(), i); > + srandom(0xbeefbeef); > + for (i = 0; i < 5000; i++) check_table(table, random(), i); > + compute_dist(table); > + drmHashDestroy(table); > + > + return 0; > +} > diff --git a/xf86drmHash.c b/xf86drmHash.c > index 82cbc2a..f7d7f73 100644 > --- a/xf86drmHash.c > +++ b/xf86drmHash.c > @@ -71,60 +71,11 @@ > #include <stdio.h> > #include <stdlib.h> > > -#define HASH_MAIN 0 > - > -#if !HASH_MAIN > -# include "xf86drm.h" > -#endif > +#include "xf86drm.h" > +#include "xf86drmHash.h" > > #define HASH_MAGIC 0xdeadbeef > #define HASH_DEBUG 0 > -#define HASH_SIZE 512 /* Good for about 100 entries */ > - /* If you change this value, you probably > - have to change the HashHash hashing > - function! */ > - > -#if HASH_MAIN > -#define HASH_ALLOC malloc > -#define HASH_FREE free > -#define HASH_RANDOM_DECL > -#define HASH_RANDOM_INIT(seed) srandom(seed) > -#define HASH_RANDOM random() > -#define HASH_RANDOM_DESTROY > -#else > -#define HASH_ALLOC drmMalloc > -#define HASH_FREE drmFree > -#define HASH_RANDOM_DECL void *state > -#define HASH_RANDOM_INIT(seed) state = drmRandomCreate(seed) > -#define HASH_RANDOM drmRandom(state) > -#define HASH_RANDOM_DESTROY drmRandomDestroy(state) > - > -#endif > - > -typedef struct HashBucket { > - unsigned long key; > - void *value; > - struct HashBucket *next; > -} HashBucket, *HashBucketPtr; > - > -typedef struct HashTable { > - unsigned long magic; > - unsigned long entries; > - unsigned long hits; /* At top of linked list */ > - unsigned long partials; /* Not at top of linked list */ > - unsigned long misses; /* Not in table */ > - HashBucketPtr buckets[HASH_SIZE]; > - int p0; > - HashBucketPtr p1; > -} HashTable, *HashTablePtr; > - > -#if HASH_MAIN > -extern void *drmHashCreate(void); > -extern int drmHashDestroy(void *t); > -extern int drmHashLookup(void *t, unsigned long key, unsigned long *value); > -extern int drmHashInsert(void *t, unsigned long key, unsigned long value); > -extern int drmHashDelete(void *t, unsigned long key); > -#endif > > static unsigned long HashHash(unsigned long key) > { > @@ -135,10 +86,10 @@ static unsigned long HashHash(unsigned long key) > int i; > > if (!init) { > - HASH_RANDOM_DECL; > - HASH_RANDOM_INIT(37); > - for (i = 0; i < 256; i++) scatter[i] = HASH_RANDOM; > - HASH_RANDOM_DESTROY; > + void *state; > + state = drmRandomCreate(37); > + for (i = 0; i < 256; i++) scatter[i] = drmRandom(state); > + drmRandomDestroy(state); > ++init; > } > > @@ -159,7 +110,7 @@ void *drmHashCreate(void) > HashTablePtr table; > int i; > > - table = HASH_ALLOC(sizeof(*table)); > + table = drmMalloc(sizeof(*table)); > if (!table) return NULL; > table->magic = HASH_MAGIC; > table->entries = 0; > @@ -183,11 +134,11 @@ int drmHashDestroy(void *t) > for (i = 0; i < HASH_SIZE; i++) { > for (bucket = table->buckets[i]; bucket;) { > next = bucket->next; > - HASH_FREE(bucket); > + drmFree(bucket); > bucket = next; > } > } > - HASH_FREE(table); > + drmFree(table); > return 0; > } > > @@ -245,7 +196,7 @@ int drmHashInsert(void *t, unsigned long key, void *value) > > if (HashFind(table, key, &hash)) return 1; /* Already in table */ > > - bucket = HASH_ALLOC(sizeof(*bucket)); > + bucket = drmMalloc(sizeof(*bucket)); > if (!bucket) return -1; /* Error */ > bucket->key = key; > bucket->value = value; > @@ -270,7 +221,7 @@ int drmHashDelete(void *t, unsigned long key) > if (!bucket) return 1; /* Not found */ > > table->buckets[hash] = bucket->next; > - HASH_FREE(bucket); > + drmFree(bucket); > return 0; > } > > @@ -301,128 +252,3 @@ int drmHashFirst(void *t, unsigned long *key, void **value) > table->p1 = table->buckets[0]; > return drmHashNext(table, key, value); > } > - > -#if HASH_MAIN > -#define DIST_LIMIT 10 > -static int dist[DIST_LIMIT]; > - > -static void clear_dist(void) { > - int i; > - > - for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; > -} > - > -static int count_entries(HashBucketPtr bucket) > -{ > - int count = 0; > - > - for (; bucket; bucket = bucket->next) ++count; > - return count; > -} > - > -static void update_dist(int count) > -{ > - if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; > - else ++dist[count]; > -} > - > -static void compute_dist(HashTablePtr table) > -{ > - int i; > - HashBucketPtr bucket; > - > - printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", > - table->entries, table->hits, table->partials, table->misses); > - clear_dist(); > - for (i = 0; i < HASH_SIZE; i++) { > - bucket = table->buckets[i]; > - update_dist(count_entries(bucket)); > - } > - for (i = 0; i < DIST_LIMIT; i++) { > - if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); > - else printf("other %10d\n", dist[i]); > - } > -} > - > -static void check_table(HashTablePtr table, > - unsigned long key, unsigned long value) > -{ > - unsigned long retval = 0; > - int retcode = drmHashLookup(table, key, &retval); > - > - switch (retcode) { > - case -1: > - printf("Bad magic = 0x%08lx:" > - " key = %lu, expected = %lu, returned = %lu\n", > - table->magic, key, value, retval); > - break; > - case 1: > - printf("Not found: key = %lu, expected = %lu returned = %lu\n", > - key, value, retval); > - break; > - case 0: > - if (value != retval) > - printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", > - key, value, retval); > - break; > - default: > - printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", > - retcode, key, value, retval); > - break; > - } > -} > - > -int main(void) > -{ > - HashTablePtr table; > - int i; > - > - printf("\n***** 256 consecutive integers ****\n"); > - table = drmHashCreate(); > - for (i = 0; i < 256; i++) drmHashInsert(table, i, i); > - for (i = 0; i < 256; i++) check_table(table, i, i); > - for (i = 256; i >= 0; i--) check_table(table, i, i); > - compute_dist(table); > - drmHashDestroy(table); > - > - printf("\n***** 1024 consecutive integers ****\n"); > - table = drmHashCreate(); > - for (i = 0; i < 1024; i++) drmHashInsert(table, i, i); > - for (i = 0; i < 1024; i++) check_table(table, i, i); > - for (i = 1024; i >= 0; i--) check_table(table, i, i); > - compute_dist(table); > - drmHashDestroy(table); > - > - printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); > - table = drmHashCreate(); > - for (i = 0; i < 1024; i++) drmHashInsert(table, i*4096, i); > - for (i = 0; i < 1024; i++) check_table(table, i*4096, i); > - for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); > - compute_dist(table); > - drmHashDestroy(table); > - > - printf("\n***** 1024 random integers ****\n"); > - table = drmHashCreate(); > - srandom(0xbeefbeef); > - for (i = 0; i < 1024; i++) drmHashInsert(table, random(), i); > - srandom(0xbeefbeef); > - for (i = 0; i < 1024; i++) check_table(table, random(), i); > - srandom(0xbeefbeef); > - for (i = 0; i < 1024; i++) check_table(table, random(), i); > - compute_dist(table); > - drmHashDestroy(table); > - > - printf("\n***** 5000 random integers ****\n"); > - table = drmHashCreate(); > - srandom(0xbeefbeef); > - for (i = 0; i < 5000; i++) drmHashInsert(table, random(), i); > - srandom(0xbeefbeef); > - for (i = 0; i < 5000; i++) check_table(table, random(), i); > - srandom(0xbeefbeef); > - for (i = 0; i < 5000; i++) check_table(table, random(), i); > - compute_dist(table); > - drmHashDestroy(table); > - > - return 0; > -} > -#endif > diff --git a/xf86drmHash.h b/xf86drmHash.h > new file mode 100644 > index 0000000..38fd84b > --- /dev/null > +++ b/xf86drmHash.h > @@ -0,0 +1,47 @@ > +/* > + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. > + * All Rights Reserved. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + * > + * Authors: Rickard E. (Rik) Faith <faith@valinux.com> > + */ > + > +#define HASH_SIZE 512 /* Good for about 100 entries */ > + /* If you change this value, you probably > + have to change the HashHash hashing > + function! */ > + > +typedef struct HashBucket { > + unsigned long key; > + void *value; > + struct HashBucket *next; > +} HashBucket, *HashBucketPtr; > + > +typedef struct HashTable { > + unsigned long magic; > + unsigned long entries; > + unsigned long hits; /* At top of linked list */ > + unsigned long partials; /* Not at top of linked list */ > + unsigned long misses; /* Not in table */ > + HashBucketPtr buckets[HASH_SIZE]; > + int p0; > + HashBucketPtr p1; > +} HashTable, *HashTablePtr; For the series: Reviewed-by: Jan Vesely <jan.vesely@rutgers.edu>
diff --git a/.gitignore b/.gitignore index 06cc928..0faa825 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ tests/drmstat tests/getclient tests/getstats tests/getversion +tests/hash tests/lock tests/openclose tests/setversion diff --git a/Makefile.sources b/Makefile.sources index 566f7b5..ff4fe5e 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -1,6 +1,7 @@ LIBDRM_FILES := \ xf86drm.c \ xf86drmHash.c \ + xf86drmHash.h \ xf86drmRandom.c \ xf86drmSL.c \ xf86drmMode.c \ diff --git a/tests/Makefile.am b/tests/Makefile.am index 10f54e3..ea826b5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -29,7 +29,8 @@ LDADD = $(top_builddir)/libdrm.la check_PROGRAMS = \ dristat \ - drmstat + drmstat \ + hash if HAVE_NOUVEAU SUBDIRS += nouveau diff --git a/tests/hash.c b/tests/hash.c new file mode 100644 index 0000000..517a667 --- /dev/null +++ b/tests/hash.c @@ -0,0 +1,198 @@ +/* xf86drmHash.c -- Small hash table support for integer -> integer mapping + * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith <faith@valinux.com> + * + * DESCRIPTION + * + * This file contains a straightforward implementation of a fixed-sized + * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for + * collision resolution. There are two potentially interesting things + * about this implementation: + * + * 1) The table is power-of-two sized. Prime sized tables are more + * traditional, but do not have a significant advantage over power-of-two + * sized table, especially when double hashing is not used for collision + * resolution. + * + * 2) The hash computation uses a table of random integers [Hanson97, + * pp. 39-41]. + * + * FUTURE ENHANCEMENTS + * + * With a table size of 512, the current implementation is sufficient for a + * few hundred keys. Since this is well above the expected size of the + * tables for which this implementation was designed, the implementation of + * dynamic hash tables was postponed until the need arises. A common (and + * naive) approach to dynamic hash table implementation simply creates a + * new hash table when necessary, rehashes all the data into the new table, + * and destroys the old table. The approach in [Larson88] is superior in + * two ways: 1) only a portion of the table is expanded when needed, + * distributing the expansion cost over several insertions, and 2) portions + * of the table can be locked, enabling a scalable thread-safe + * implementation. + * + * REFERENCES + * + * [Hanson97] David R. Hanson. C Interfaces and Implementations: + * Techniques for Creating Reusable Software. Reading, Massachusetts: + * Addison-Wesley, 1997. + * + * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: + * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. + * + * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April + * 1988, pp. 446-457. + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "xf86drm.h" +#include "xf86drmHash.h" + +#define DIST_LIMIT 10 +static int dist[DIST_LIMIT]; + +static void clear_dist(void) { + int i; + + for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; +} + +static int count_entries(HashBucketPtr bucket) +{ + int count = 0; + + for (; bucket; bucket = bucket->next) ++count; + return count; +} + +static void update_dist(int count) +{ + if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; + else ++dist[count]; +} + +static void compute_dist(HashTablePtr table) +{ + int i; + HashBucketPtr bucket; + + printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", + table->entries, table->hits, table->partials, table->misses); + clear_dist(); + for (i = 0; i < HASH_SIZE; i++) { + bucket = table->buckets[i]; + update_dist(count_entries(bucket)); + } + for (i = 0; i < DIST_LIMIT; i++) { + if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); + else printf("other %10d\n", dist[i]); + } +} + +static void check_table(HashTablePtr table, + unsigned long key, unsigned long value) +{ + unsigned long retval = 0; + int retcode = drmHashLookup(table, key, &retval); + + switch (retcode) { + case -1: + printf("Bad magic = 0x%08lx:" + " key = %lu, expected = %lu, returned = %lu\n", + table->magic, key, value, retval); + break; + case 1: + printf("Not found: key = %lu, expected = %lu returned = %lu\n", + key, value, retval); + break; + case 0: + if (value != retval) + printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", + key, value, retval); + break; + default: + printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", + retcode, key, value, retval); + break; + } +} + +int main(void) +{ + HashTablePtr table; + int i; + + printf("\n***** 256 consecutive integers ****\n"); + table = drmHashCreate(); + for (i = 0; i < 256; i++) drmHashInsert(table, i, i); + for (i = 0; i < 256; i++) check_table(table, i, i); + for (i = 256; i >= 0; i--) check_table(table, i, i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 consecutive integers ****\n"); + table = drmHashCreate(); + for (i = 0; i < 1024; i++) drmHashInsert(table, i, i); + for (i = 0; i < 1024; i++) check_table(table, i, i); + for (i = 1024; i >= 0; i--) check_table(table, i, i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); + table = drmHashCreate(); + for (i = 0; i < 1024; i++) drmHashInsert(table, i*4096, i); + for (i = 0; i < 1024; i++) check_table(table, i*4096, i); + for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 random integers ****\n"); + table = drmHashCreate(); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) drmHashInsert(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) check_table(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) check_table(table, random(), i); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 5000 random integers ****\n"); + table = drmHashCreate(); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) drmHashInsert(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) check_table(table, random(), i); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) check_table(table, random(), i); + compute_dist(table); + drmHashDestroy(table); + + return 0; +} diff --git a/xf86drmHash.c b/xf86drmHash.c index 82cbc2a..f7d7f73 100644 --- a/xf86drmHash.c +++ b/xf86drmHash.c @@ -71,60 +71,11 @@ #include <stdio.h> #include <stdlib.h> -#define HASH_MAIN 0 - -#if !HASH_MAIN -# include "xf86drm.h" -#endif +#include "xf86drm.h" +#include "xf86drmHash.h" #define HASH_MAGIC 0xdeadbeef #define HASH_DEBUG 0 -#define HASH_SIZE 512 /* Good for about 100 entries */ - /* If you change this value, you probably - have to change the HashHash hashing - function! */ - -#if HASH_MAIN -#define HASH_ALLOC malloc -#define HASH_FREE free -#define HASH_RANDOM_DECL -#define HASH_RANDOM_INIT(seed) srandom(seed) -#define HASH_RANDOM random() -#define HASH_RANDOM_DESTROY -#else -#define HASH_ALLOC drmMalloc -#define HASH_FREE drmFree -#define HASH_RANDOM_DECL void *state -#define HASH_RANDOM_INIT(seed) state = drmRandomCreate(seed) -#define HASH_RANDOM drmRandom(state) -#define HASH_RANDOM_DESTROY drmRandomDestroy(state) - -#endif - -typedef struct HashBucket { - unsigned long key; - void *value; - struct HashBucket *next; -} HashBucket, *HashBucketPtr; - -typedef struct HashTable { - unsigned long magic; - unsigned long entries; - unsigned long hits; /* At top of linked list */ - unsigned long partials; /* Not at top of linked list */ - unsigned long misses; /* Not in table */ - HashBucketPtr buckets[HASH_SIZE]; - int p0; - HashBucketPtr p1; -} HashTable, *HashTablePtr; - -#if HASH_MAIN -extern void *drmHashCreate(void); -extern int drmHashDestroy(void *t); -extern int drmHashLookup(void *t, unsigned long key, unsigned long *value); -extern int drmHashInsert(void *t, unsigned long key, unsigned long value); -extern int drmHashDelete(void *t, unsigned long key); -#endif static unsigned long HashHash(unsigned long key) { @@ -135,10 +86,10 @@ static unsigned long HashHash(unsigned long key) int i; if (!init) { - HASH_RANDOM_DECL; - HASH_RANDOM_INIT(37); - for (i = 0; i < 256; i++) scatter[i] = HASH_RANDOM; - HASH_RANDOM_DESTROY; + void *state; + state = drmRandomCreate(37); + for (i = 0; i < 256; i++) scatter[i] = drmRandom(state); + drmRandomDestroy(state); ++init; } @@ -159,7 +110,7 @@ void *drmHashCreate(void) HashTablePtr table; int i; - table = HASH_ALLOC(sizeof(*table)); + table = drmMalloc(sizeof(*table)); if (!table) return NULL; table->magic = HASH_MAGIC; table->entries = 0; @@ -183,11 +134,11 @@ int drmHashDestroy(void *t) for (i = 0; i < HASH_SIZE; i++) { for (bucket = table->buckets[i]; bucket;) { next = bucket->next; - HASH_FREE(bucket); + drmFree(bucket); bucket = next; } } - HASH_FREE(table); + drmFree(table); return 0; } @@ -245,7 +196,7 @@ int drmHashInsert(void *t, unsigned long key, void *value) if (HashFind(table, key, &hash)) return 1; /* Already in table */ - bucket = HASH_ALLOC(sizeof(*bucket)); + bucket = drmMalloc(sizeof(*bucket)); if (!bucket) return -1; /* Error */ bucket->key = key; bucket->value = value; @@ -270,7 +221,7 @@ int drmHashDelete(void *t, unsigned long key) if (!bucket) return 1; /* Not found */ table->buckets[hash] = bucket->next; - HASH_FREE(bucket); + drmFree(bucket); return 0; } @@ -301,128 +252,3 @@ int drmHashFirst(void *t, unsigned long *key, void **value) table->p1 = table->buckets[0]; return drmHashNext(table, key, value); } - -#if HASH_MAIN -#define DIST_LIMIT 10 -static int dist[DIST_LIMIT]; - -static void clear_dist(void) { - int i; - - for (i = 0; i < DIST_LIMIT; i++) dist[i] = 0; -} - -static int count_entries(HashBucketPtr bucket) -{ - int count = 0; - - for (; bucket; bucket = bucket->next) ++count; - return count; -} - -static void update_dist(int count) -{ - if (count >= DIST_LIMIT) ++dist[DIST_LIMIT-1]; - else ++dist[count]; -} - -static void compute_dist(HashTablePtr table) -{ - int i; - HashBucketPtr bucket; - - printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", - table->entries, table->hits, table->partials, table->misses); - clear_dist(); - for (i = 0; i < HASH_SIZE; i++) { - bucket = table->buckets[i]; - update_dist(count_entries(bucket)); - } - for (i = 0; i < DIST_LIMIT; i++) { - if (i != DIST_LIMIT-1) printf("%5d %10d\n", i, dist[i]); - else printf("other %10d\n", dist[i]); - } -} - -static void check_table(HashTablePtr table, - unsigned long key, unsigned long value) -{ - unsigned long retval = 0; - int retcode = drmHashLookup(table, key, &retval); - - switch (retcode) { - case -1: - printf("Bad magic = 0x%08lx:" - " key = %lu, expected = %lu, returned = %lu\n", - table->magic, key, value, retval); - break; - case 1: - printf("Not found: key = %lu, expected = %lu returned = %lu\n", - key, value, retval); - break; - case 0: - if (value != retval) - printf("Bad value: key = %lu, expected = %lu, returned = %lu\n", - key, value, retval); - break; - default: - printf("Bad retcode = %d: key = %lu, expected = %lu, returned = %lu\n", - retcode, key, value, retval); - break; - } -} - -int main(void) -{ - HashTablePtr table; - int i; - - printf("\n***** 256 consecutive integers ****\n"); - table = drmHashCreate(); - for (i = 0; i < 256; i++) drmHashInsert(table, i, i); - for (i = 0; i < 256; i++) check_table(table, i, i); - for (i = 256; i >= 0; i--) check_table(table, i, i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 1024 consecutive integers ****\n"); - table = drmHashCreate(); - for (i = 0; i < 1024; i++) drmHashInsert(table, i, i); - for (i = 0; i < 1024; i++) check_table(table, i, i); - for (i = 1024; i >= 0; i--) check_table(table, i, i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); - table = drmHashCreate(); - for (i = 0; i < 1024; i++) drmHashInsert(table, i*4096, i); - for (i = 0; i < 1024; i++) check_table(table, i*4096, i); - for (i = 1024; i >= 0; i--) check_table(table, i*4096, i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 1024 random integers ****\n"); - table = drmHashCreate(); - srandom(0xbeefbeef); - for (i = 0; i < 1024; i++) drmHashInsert(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 1024; i++) check_table(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 1024; i++) check_table(table, random(), i); - compute_dist(table); - drmHashDestroy(table); - - printf("\n***** 5000 random integers ****\n"); - table = drmHashCreate(); - srandom(0xbeefbeef); - for (i = 0; i < 5000; i++) drmHashInsert(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 5000; i++) check_table(table, random(), i); - srandom(0xbeefbeef); - for (i = 0; i < 5000; i++) check_table(table, random(), i); - compute_dist(table); - drmHashDestroy(table); - - return 0; -} -#endif diff --git a/xf86drmHash.h b/xf86drmHash.h new file mode 100644 index 0000000..38fd84b --- /dev/null +++ b/xf86drmHash.h @@ -0,0 +1,47 @@ +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Rickard E. (Rik) Faith <faith@valinux.com> + */ + +#define HASH_SIZE 512 /* Good for about 100 entries */ + /* If you change this value, you probably + have to change the HashHash hashing + function! */ + +typedef struct HashBucket { + unsigned long key; + void *value; + struct HashBucket *next; +} HashBucket, *HashBucketPtr; + +typedef struct HashTable { + unsigned long magic; + unsigned long entries; + unsigned long hits; /* At top of linked list */ + unsigned long partials; /* Not at top of linked list */ + unsigned long misses; /* Not in table */ + HashBucketPtr buckets[HASH_SIZE]; + int p0; + HashBucketPtr p1; +} HashTable, *HashTablePtr;
This way with follow up commits we can fix it and wire it up to make check v2: - Use xf86drmHash.h for common structs.(Jan) - Add test to .gitignore. Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com> --- .gitignore | 1 + Makefile.sources | 1 + tests/Makefile.am | 3 +- tests/hash.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ xf86drmHash.c | 196 +++-------------------------------------------------- xf86drmHash.h | 47 +++++++++++++ 6 files changed, 260 insertions(+), 186 deletions(-) create mode 100644 tests/hash.c create mode 100644 xf86drmHash.h