1e6188e58Smrg/* xf86drmHash.c -- Small hash table support for integer -> integer mapping 2e6188e58Smrg * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com 3e6188e58Smrg * 4e6188e58Smrg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 5e6188e58Smrg * All Rights Reserved. 6e6188e58Smrg * 7e6188e58Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8e6188e58Smrg * copy of this software and associated documentation files (the "Software"), 9e6188e58Smrg * to deal in the Software without restriction, including without limitation 10e6188e58Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11e6188e58Smrg * and/or sell copies of the Software, and to permit persons to whom the 12e6188e58Smrg * Software is furnished to do so, subject to the following conditions: 13e6188e58Smrg * 14e6188e58Smrg * The above copyright notice and this permission notice (including the next 15e6188e58Smrg * paragraph) shall be included in all copies or substantial portions of the 16e6188e58Smrg * Software. 17e6188e58Smrg * 18e6188e58Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19e6188e58Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20e6188e58Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21e6188e58Smrg * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22e6188e58Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23e6188e58Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24e6188e58Smrg * DEALINGS IN THE SOFTWARE. 25e6188e58Smrg * 26e6188e58Smrg * Authors: Rickard E. (Rik) Faith <faith@valinux.com> 27e6188e58Smrg * 28e6188e58Smrg * DESCRIPTION 29e6188e58Smrg * 30e6188e58Smrg * This file contains a straightforward implementation of a fixed-sized 31e6188e58Smrg * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for 32e6188e58Smrg * collision resolution. There are two potentially interesting things 33e6188e58Smrg * about this implementation: 34e6188e58Smrg * 35e6188e58Smrg * 1) The table is power-of-two sized. Prime sized tables are more 36e6188e58Smrg * traditional, but do not have a significant advantage over power-of-two 37e6188e58Smrg * sized table, especially when double hashing is not used for collision 38e6188e58Smrg * resolution. 39e6188e58Smrg * 40e6188e58Smrg * 2) The hash computation uses a table of random integers [Hanson97, 41e6188e58Smrg * pp. 39-41]. 42e6188e58Smrg * 43e6188e58Smrg * FUTURE ENHANCEMENTS 44e6188e58Smrg * 45e6188e58Smrg * With a table size of 512, the current implementation is sufficient for a 46e6188e58Smrg * few hundred keys. Since this is well above the expected size of the 47e6188e58Smrg * tables for which this implementation was designed, the implementation of 48e6188e58Smrg * dynamic hash tables was postponed until the need arises. A common (and 49e6188e58Smrg * naive) approach to dynamic hash table implementation simply creates a 50e6188e58Smrg * new hash table when necessary, rehashes all the data into the new table, 51e6188e58Smrg * and destroys the old table. The approach in [Larson88] is superior in 52e6188e58Smrg * two ways: 1) only a portion of the table is expanded when needed, 53e6188e58Smrg * distributing the expansion cost over several insertions, and 2) portions 54e6188e58Smrg * of the table can be locked, enabling a scalable thread-safe 55e6188e58Smrg * implementation. 56e6188e58Smrg * 57e6188e58Smrg * REFERENCES 58e6188e58Smrg * 59e6188e58Smrg * [Hanson97] David R. Hanson. C Interfaces and Implementations: 60e6188e58Smrg * Techniques for Creating Reusable Software. Reading, Massachusetts: 61e6188e58Smrg * Addison-Wesley, 1997. 62e6188e58Smrg * 63e6188e58Smrg * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: 64e6188e58Smrg * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. 65e6188e58Smrg * 66e6188e58Smrg * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April 67e6188e58Smrg * 1988, pp. 446-457. 68e6188e58Smrg * 69e6188e58Smrg */ 70e6188e58Smrg 71e6188e58Smrg#include <stdio.h> 72e6188e58Smrg#include <stdlib.h> 73e6188e58Smrg 74e6188e58Smrg#include "xf86drm.h" 75e6188e58Smrg#include "xf86drmHash.h" 76e6188e58Smrg 77e6188e58Smrg#define DIST_LIMIT 10 78e6188e58Smrgstatic int dist[DIST_LIMIT]; 79e6188e58Smrg 80e6188e58Smrgstatic void clear_dist(void) { 81e6188e58Smrg int i; 82e6188e58Smrg 83e6188e58Smrg for (i = 0; i < DIST_LIMIT; i++) 84e6188e58Smrg dist[i] = 0; 85e6188e58Smrg} 86e6188e58Smrg 87e6188e58Smrgstatic int count_entries(HashBucketPtr bucket) 88e6188e58Smrg{ 89e6188e58Smrg int count = 0; 90e6188e58Smrg 91e6188e58Smrg for (; bucket; bucket = bucket->next) 92e6188e58Smrg ++count; 93e6188e58Smrg return count; 94e6188e58Smrg} 95e6188e58Smrg 96e6188e58Smrgstatic void update_dist(int count) 97e6188e58Smrg{ 98e6188e58Smrg if (count >= DIST_LIMIT) 99e6188e58Smrg ++dist[DIST_LIMIT-1]; 100e6188e58Smrg else 101e6188e58Smrg ++dist[count]; 102e6188e58Smrg} 103e6188e58Smrg 104e6188e58Smrgstatic void compute_dist(HashTablePtr table) 105e6188e58Smrg{ 106e6188e58Smrg int i; 107e6188e58Smrg HashBucketPtr bucket; 108e6188e58Smrg 109e6188e58Smrg printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", 110e6188e58Smrg table->entries, table->hits, table->partials, table->misses); 111e6188e58Smrg clear_dist(); 112e6188e58Smrg for (i = 0; i < HASH_SIZE; i++) { 113e6188e58Smrg bucket = table->buckets[i]; 114e6188e58Smrg update_dist(count_entries(bucket)); 115e6188e58Smrg } 116e6188e58Smrg for (i = 0; i < DIST_LIMIT; i++) { 117e6188e58Smrg if (i != DIST_LIMIT-1) 118e6188e58Smrg printf("%5d %10d\n", i, dist[i]); 119e6188e58Smrg else 120e6188e58Smrg printf("other %10d\n", dist[i]); 121e6188e58Smrg } 122e6188e58Smrg} 123e6188e58Smrg 124e6188e58Smrgstatic int check_table(HashTablePtr table, 125e6188e58Smrg unsigned long key, void * value) 126e6188e58Smrg{ 127e6188e58Smrg void *retval; 128e6188e58Smrg int retcode = drmHashLookup(table, key, &retval); 129e6188e58Smrg 130e6188e58Smrg switch (retcode) { 131e6188e58Smrg case -1: 132e6188e58Smrg printf("Bad magic = 0x%08lx:" 133e6188e58Smrg " key = %lu, expected = %p, returned = %p\n", 134e6188e58Smrg table->magic, key, value, retval); 135e6188e58Smrg break; 136e6188e58Smrg case 1: 137e6188e58Smrg printf("Not found: key = %lu, expected = %p, returned = %p\n", 138e6188e58Smrg key, value, retval); 139e6188e58Smrg break; 140e6188e58Smrg case 0: 141e6188e58Smrg if (value != retval) { 142e6188e58Smrg printf("Bad value: key = %lu, expected = %p, returned = %p\n", 143e6188e58Smrg key, value, retval); 144e6188e58Smrg retcode = -1; 145e6188e58Smrg } 146e6188e58Smrg break; 147e6188e58Smrg default: 148e6188e58Smrg printf("Bad retcode = %d: key = %lu, expected = %p, returned = %p\n", 149e6188e58Smrg retcode, key, value, retval); 150e6188e58Smrg break; 151e6188e58Smrg } 152e6188e58Smrg return retcode; 153e6188e58Smrg} 154e6188e58Smrg 155e6188e58Smrgint main(void) 156e6188e58Smrg{ 157e6188e58Smrg HashTablePtr table; 158e6188e58Smrg unsigned long i; 159e6188e58Smrg int ret = 0; 160e6188e58Smrg 161e6188e58Smrg printf("\n***** 256 consecutive integers ****\n"); 162e6188e58Smrg table = drmHashCreate(); 163e6188e58Smrg for (i = 0; i < 256; i++) 164e6188e58Smrg drmHashInsert(table, i, (void *)(i << 16 | i)); 165e6188e58Smrg for (i = 0; i < 256; i++) 166e6188e58Smrg ret |= check_table(table, i, (void *)(i << 16 | i)); 167e6188e58Smrg compute_dist(table); 168e6188e58Smrg drmHashDestroy(table); 169e6188e58Smrg 170e6188e58Smrg printf("\n***** 1024 consecutive integers ****\n"); 171e6188e58Smrg table = drmHashCreate(); 172e6188e58Smrg for (i = 0; i < 1024; i++) 173e6188e58Smrg drmHashInsert(table, i, (void *)(i << 16 | i)); 174e6188e58Smrg for (i = 0; i < 1024; i++) 175e6188e58Smrg ret |= check_table(table, i, (void *)(i << 16 | i)); 176e6188e58Smrg compute_dist(table); 177e6188e58Smrg drmHashDestroy(table); 178e6188e58Smrg 179e6188e58Smrg printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); 180e6188e58Smrg table = drmHashCreate(); 181e6188e58Smrg for (i = 0; i < 1024; i++) 182e6188e58Smrg drmHashInsert(table, i*4096, (void *)(i << 16 | i)); 183e6188e58Smrg for (i = 0; i < 1024; i++) 184e6188e58Smrg ret |= check_table(table, i*4096, (void *)(i << 16 | i)); 185e6188e58Smrg compute_dist(table); 186e6188e58Smrg drmHashDestroy(table); 187e6188e58Smrg 188e6188e58Smrg printf("\n***** 1024 random integers ****\n"); 189e6188e58Smrg table = drmHashCreate(); 190e6188e58Smrg srandom(0xbeefbeef); 191e6188e58Smrg for (i = 0; i < 1024; i++) 192e6188e58Smrg drmHashInsert(table, random(), (void *)(i << 16 | i)); 193e6188e58Smrg srandom(0xbeefbeef); 194e6188e58Smrg for (i = 0; i < 1024; i++) 195e6188e58Smrg ret |= check_table(table, random(), (void *)(i << 16 | i)); 196e6188e58Smrg srandom(0xbeefbeef); 197e6188e58Smrg for (i = 0; i < 1024; i++) 198e6188e58Smrg ret |= check_table(table, random(), (void *)(i << 16 | i)); 199e6188e58Smrg compute_dist(table); 200e6188e58Smrg drmHashDestroy(table); 201e6188e58Smrg 202e6188e58Smrg printf("\n***** 5000 random integers ****\n"); 203e6188e58Smrg table = drmHashCreate(); 204e6188e58Smrg srandom(0xbeefbeef); 205e6188e58Smrg for (i = 0; i < 5000; i++) 206e6188e58Smrg drmHashInsert(table, random(), (void *)(i << 16 | i)); 207e6188e58Smrg srandom(0xbeefbeef); 208e6188e58Smrg for (i = 0; i < 5000; i++) 209e6188e58Smrg ret |= check_table(table, random(), (void *)(i << 16 | i)); 210e6188e58Smrg srandom(0xbeefbeef); 211e6188e58Smrg for (i = 0; i < 5000; i++) 212e6188e58Smrg ret |= check_table(table, random(), (void *)(i << 16 | i)); 213e6188e58Smrg compute_dist(table); 214e6188e58Smrg drmHashDestroy(table); 215e6188e58Smrg 216e6188e58Smrg return ret; 217e6188e58Smrg} 218