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