OSDN Git Service

Resync from Xorg head: conditional include of xorg-config.h
[android-x86/external-libdrm.git] / libdrm / xf86drmSL.c
1 /* xf86drmSL.c -- Skip list support
2  * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com
3  *
4  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  * 
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  * 
26  * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
27  *
28  * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmSL.c,v 1.3 2000/06/17 00:03:34 martin Exp $
29  *
30  * DESCRIPTION
31  *
32  * This file contains a straightforward skip list implementation.n
33  *
34  * FUTURE ENHANCEMENTS
35  *
36  * REFERENCES
37  *
38  * [Pugh90] William Pugh.  Skip Lists: A Probabilistic Alternative to
39  * Balanced Trees. CACM 33(6), June 1990, pp. 668-676.
40  *
41  */
42
43 #ifdef HAVE_XORG_CONFIG_H
44 #include <xorg-config.h>
45 #endif
46
47 #define SL_MAIN 0
48
49 #if SL_MAIN
50 # include <stdio.h>
51 # include <stdlib.h>
52 #  include <sys/time.h>
53 #else
54 # include "drm.h"
55 # include "xf86drm.h"
56 # ifdef XFree86LOADER
57 #  include "xf86.h"
58 #  include "xf86_ansic.h"
59 # else
60 #  include <stdio.h>
61 #  include <stdlib.h>
62 # endif
63 #endif
64
65 #define N(x)  drm##x
66
67 #define SL_LIST_MAGIC  0xfacade00LU
68 #define SL_ENTRY_MAGIC 0x00fab1edLU
69 #define SL_FREED_MAGIC 0xdecea5edLU
70 #define SL_MAX_LEVEL   16
71 #define SL_DEBUG       0
72 #define SL_RANDOM_SEED 0xc01055a1LU
73
74 #if SL_MAIN
75 #define SL_ALLOC malloc
76 #define SL_FREE  free
77 #define SL_RANDOM_DECL        static int state = 0;
78 #define SL_RANDOM_INIT(seed)  if (!state) { srandom(seed); ++state; }
79 #define SL_RANDOM             random()
80 #else
81 #define SL_ALLOC drmMalloc
82 #define SL_FREE  drmFree
83 #define SL_RANDOM_DECL        static void *state = NULL
84 #define SL_RANDOM_INIT(seed)  if (!state) state = drmRandomCreate(seed)
85 #define SL_RANDOM             drmRandom(state)
86
87 #endif
88
89 typedef struct SLEntry {
90     unsigned long     magic;       /* SL_ENTRY_MAGIC */
91     unsigned long     key;
92     void              *value;
93     int               levels;
94     struct SLEntry    *forward[1]; /* variable sized array */
95 } SLEntry, *SLEntryPtr;
96
97 typedef struct SkipList {
98     unsigned long    magic;     /* SL_LIST_MAGIC */
99     int              level;
100     int              count;
101     SLEntryPtr       head;
102     SLEntryPtr       p0;        /* Position for iteration */
103 } SkipList, *SkipListPtr;
104
105 #if SL_MAIN
106 extern void *N(SLCreate)(void);
107 extern int  N(SLDestroy)(void *l);
108 extern int  N(SLLookup)(void *l, unsigned long key, void **value);
109 extern int  N(SLInsert)(void *l, unsigned long key, void *value);
110 extern int  N(SLDelete)(void *l, unsigned long key);
111 extern int  N(SLNext)(void *l, unsigned long *key, void **value);
112 extern int  N(SLFirst)(void *l, unsigned long *key, void **value);
113 extern void N(SLDump)(void *l);
114 extern int  N(SLLookupNeighbors)(void *l, unsigned long key,
115                                  unsigned long *prev_key, void **prev_value,
116                                  unsigned long *next_key, void **next_value);
117 #endif
118
119 static SLEntryPtr SLCreateEntry(int max_level, unsigned long key, void *value)
120 {
121     SLEntryPtr entry;
122     
123     if (max_level < 0 || max_level > SL_MAX_LEVEL) max_level = SL_MAX_LEVEL;
124
125     entry         = SL_ALLOC(sizeof(*entry)
126                              + (max_level + 1) * sizeof(entry->forward[0]));
127     if (!entry) return NULL;
128     entry->magic  = SL_ENTRY_MAGIC;
129     entry->key    = key;
130     entry->value  = value;
131     entry->levels = max_level + 1;
132
133     return entry;
134 }
135
136 static int SLRandomLevel(void)
137 {
138     int level = 1;
139     SL_RANDOM_DECL;
140
141     SL_RANDOM_INIT(SL_RANDOM_SEED);
142     
143     while ((SL_RANDOM & 0x01) && level < SL_MAX_LEVEL) ++level;
144     return level;
145 }
146
147 void *N(SLCreate)(void)
148 {
149     SkipListPtr  list;
150     int          i;
151
152     list           = SL_ALLOC(sizeof(*list));
153     if (!list) return NULL;
154     list->magic    = SL_LIST_MAGIC;
155     list->level    = 0;
156     list->head     = SLCreateEntry(SL_MAX_LEVEL, 0, NULL);
157     list->count    = 0;
158
159     for (i = 0; i <= SL_MAX_LEVEL; i++) list->head->forward[i] = NULL;
160     
161     return list;
162 }
163
164 int N(SLDestroy)(void *l)
165 {
166     SkipListPtr   list  = (SkipListPtr)l;
167     SLEntryPtr    entry;
168     SLEntryPtr    next;
169
170     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
171
172     for (entry = list->head; entry; entry = next) {
173         if (entry->magic != SL_ENTRY_MAGIC) return -1; /* Bad magic */
174         next         = entry->forward[0];
175         entry->magic = SL_FREED_MAGIC;
176         SL_FREE(entry);
177     }
178
179     list->magic = SL_FREED_MAGIC;
180     SL_FREE(list);
181     return 0;
182 }
183
184 static SLEntryPtr SLLocate(void *l, unsigned long key, SLEntryPtr *update)
185 {
186     SkipListPtr   list  = (SkipListPtr)l;
187     SLEntryPtr    entry;
188     int           i;
189
190     if (list->magic != SL_LIST_MAGIC) return NULL;
191
192     for (i = list->level, entry = list->head; i >= 0; i--) {
193         while (entry->forward[i] && entry->forward[i]->key < key)
194             entry = entry->forward[i];
195         update[i] = entry;
196     }
197
198     return entry->forward[0];
199 }
200
201 int N(SLInsert)(void *l, unsigned long key, void *value)
202 {
203     SkipListPtr   list  = (SkipListPtr)l;
204     SLEntryPtr    entry;
205     SLEntryPtr    update[SL_MAX_LEVEL + 1];
206     int           level;
207     int           i;
208
209     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
210
211     entry = SLLocate(list, key, update);
212
213     if (entry && entry->key == key) return 1; /* Already in list */
214
215
216     level = SLRandomLevel();
217     if (level > list->level) {
218         level = ++list->level;
219         update[level] = list->head;
220     }
221
222     entry = SLCreateEntry(level, key, value);
223
224                                 /* Fix up forward pointers */
225     for (i = 0; i <= level; i++) {
226         entry->forward[i]     = update[i]->forward[i];
227         update[i]->forward[i] = entry;
228     }
229
230     ++list->count;
231     return 0;                   /* Added to table */
232 }
233
234 int N(SLDelete)(void *l, unsigned long key)
235 {
236     SkipListPtr   list = (SkipListPtr)l;
237     SLEntryPtr    update[SL_MAX_LEVEL + 1];
238     SLEntryPtr    entry;
239     int           i;
240
241     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
242
243     entry = SLLocate(list, key, update);
244
245     if (!entry || entry->key != key) return 1; /* Not found */
246
247                                 /* Fix up forward pointers */
248     for (i = 0; i <= list->level; i++) {
249         if (update[i]->forward[i] == entry)
250             update[i]->forward[i] = entry->forward[i];
251     }
252
253     entry->magic = SL_FREED_MAGIC;
254     SL_FREE(entry);
255
256     while (list->level && !list->head->forward[list->level]) --list->level;
257     --list->count;
258     return 0;
259 }
260
261 int N(SLLookup)(void *l, unsigned long key, void **value)
262 {
263     SkipListPtr   list = (SkipListPtr)l;
264     SLEntryPtr    update[SL_MAX_LEVEL + 1];
265     SLEntryPtr    entry;
266
267     entry = SLLocate(list, key, update);
268
269     if (entry && entry->key == key) {
270         *value = entry;
271         return 0;
272     }
273     *value = NULL;
274     return -1;
275 }
276
277 int N(SLLookupNeighbors)(void *l, unsigned long key,
278                          unsigned long *prev_key, void **prev_value,
279                          unsigned long *next_key, void **next_value)
280 {
281     SkipListPtr   list = (SkipListPtr)l;
282     SLEntryPtr    update[SL_MAX_LEVEL + 1];
283     SLEntryPtr    entry;
284     int           retcode = 0;
285
286     entry = SLLocate(list, key, update);
287
288     *prev_key   = *next_key   = key;
289     *prev_value = *next_value = NULL;
290         
291     if (update[0]) {
292         *prev_key   = update[0]->key;
293         *prev_value = update[0]->value;
294         ++retcode;
295         if (update[0]->forward[0]) {
296             *next_key   = update[0]->forward[0]->key;
297             *next_value = update[0]->forward[0]->value;
298             ++retcode;
299         }
300     }
301     return retcode;
302 }
303
304 int N(SLNext)(void *l, unsigned long *key, void **value)
305 {
306     SkipListPtr   list = (SkipListPtr)l;
307     SLEntryPtr    entry;
308     
309     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
310
311     entry    = list->p0;
312
313     if (entry) {
314         list->p0 = entry->forward[0];
315         *key     = entry->key;
316         *value   = entry->value;
317         return 1;
318     }
319     list->p0 = NULL;
320     return 0;
321 }
322
323 int N(SLFirst)(void *l, unsigned long *key, void **value)
324 {
325     SkipListPtr   list = (SkipListPtr)l;
326     
327     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
328     
329     list->p0 = list->head->forward[0];
330     return N(SLNext)(list, key, value);
331 }
332
333 /* Dump internal data structures for debugging. */
334 void N(SLDump)(void *l)
335 {
336     SkipListPtr   list = (SkipListPtr)l;
337     SLEntryPtr    entry;
338     int           i;
339     
340     if (list->magic != SL_LIST_MAGIC) {
341         printf("Bad magic: 0x%08lx (expected 0x%08lx)\n",
342                list->magic, SL_LIST_MAGIC);
343         return;
344     }
345
346     printf("Level = %d, count = %d\n", list->level, list->count);
347     for (entry = list->head; entry; entry = entry->forward[0]) {
348         if (entry->magic != SL_ENTRY_MAGIC) {
349             printf("Bad magic: 0x%08lx (expected 0x%08lx)\n",
350                    list->magic, SL_ENTRY_MAGIC);
351         }
352         printf("\nEntry %p <0x%08lx, %p> has %2d levels\n",
353                entry, entry->key, entry->value, entry->levels);
354         for (i = 0; i < entry->levels; i++) {
355             if (entry->forward[i]) {
356                 printf("   %2d: %p <0x%08lx, %p>\n",
357                        i,
358                        entry->forward[i],
359                        entry->forward[i]->key,
360                        entry->forward[i]->value);
361             } else {
362                 printf("   %2d: %p\n", i, entry->forward[i]);
363             }
364         }
365     }
366 }
367
368 #if SL_MAIN
369 static void print(SkipListPtr list)
370 {
371     unsigned long key;
372     void          *value;
373     
374     if (N(SLFirst)(list, &key, &value)) {
375         do {
376             printf("key = %5lu, value = %p\n", key, value);
377         } while (N(SLNext)(list, &key, &value));
378     }
379 }
380
381 static double do_time(int size, int iter)
382 {
383     SkipListPtr    list;
384     int            i, j;
385     unsigned long  keys[1000000];
386     unsigned long  previous;
387     unsigned long  key;
388     void           *value;
389     struct timeval start, stop;
390     double         usec;
391     SL_RANDOM_DECL;
392
393     SL_RANDOM_INIT(12345);
394     
395     list = N(SLCreate)();
396
397     for (i = 0; i < size; i++) {
398         keys[i] = SL_RANDOM;
399         N(SLInsert)(list, keys[i], NULL);
400     }
401
402     previous = 0;
403     if (N(SLFirst)(list, &key, &value)) {
404         do {
405             if (key <= previous) {
406                 printf( "%lu !< %lu\n", previous, key);
407             }
408             previous = key;
409         } while (N(SLNext)(list, &key, &value));
410     }
411     
412     gettimeofday(&start, NULL);
413     for (j = 0; j < iter; j++) {
414         for (i = 0; i < size; i++) {
415             if (N(SLLookup)(list, keys[i], &value))
416                 printf("Error %lu %d\n", keys[i], i);
417         }
418     }
419     gettimeofday(&stop, NULL);
420     
421     usec = (double)(stop.tv_sec * 1000000 + stop.tv_usec
422                     - start.tv_sec * 1000000 - start.tv_usec) / (size * iter);
423     
424     printf("%0.2f microseconds for list length %d\n", usec, size);
425
426     N(SLDestroy)(list);
427     
428     return usec;
429 }
430
431 static void print_neighbors(void *list, unsigned long key)
432 {
433     unsigned long prev_key = 0;
434     unsigned long next_key = 0;
435     void          *prev_value;
436     void          *next_value;
437     int           retval;
438
439     retval = drmSLLookupNeighbors(list, key,
440                                   &prev_key, &prev_value,
441                                   &next_key, &next_value);
442     printf("Neighbors of %5lu: %d %5lu %5lu\n",
443            key, retval, prev_key, next_key);
444 }
445
446 int main(void)
447 {
448     SkipListPtr    list;
449     double         usec, usec2, usec3, usec4;
450
451     list = N(SLCreate)();
452     printf( "list at %p\n", list);
453
454     print(list);
455     printf("\n==============================\n\n");
456
457     N(SLInsert)(list, 123, NULL);
458     N(SLInsert)(list, 213, NULL);
459     N(SLInsert)(list, 50, NULL);
460     print(list);
461     printf("\n==============================\n\n");
462     
463     print_neighbors(list, 0);
464     print_neighbors(list, 50);
465     print_neighbors(list, 51);
466     print_neighbors(list, 123);
467     print_neighbors(list, 200);
468     print_neighbors(list, 213);
469     print_neighbors(list, 256);
470     printf("\n==============================\n\n");    
471     
472     N(SLDelete)(list, 50);
473     print(list);
474     printf("\n==============================\n\n");
475
476     N(SLDump)(list);
477     N(SLDestroy)(list);
478     printf("\n==============================\n\n");
479
480     usec  = do_time(100, 10000);
481     usec2 = do_time(1000, 500);
482     printf("Table size increased by %0.2f, search time increased by %0.2f\n",
483            1000.0/100.0, usec2 / usec);
484     
485     usec3 = do_time(10000, 50);
486     printf("Table size increased by %0.2f, search time increased by %0.2f\n",
487            10000.0/100.0, usec3 / usec);
488     
489     usec4 = do_time(100000, 4);
490     printf("Table size increased by %0.2f, search time increased by %0.2f\n",
491            100000.0/100.0, usec4 / usec);
492
493     return 0;
494 }
495 #endif