emergency commit
[cl-cudd.git] / distr / cudd / cuddLCache.c
blobf617d84d6b264472dc9e4e89dbfc733a153f4a3f
1 /**CFile***********************************************************************
3 FileName [cuddLCache.c]
5 PackageName [cudd]
7 Synopsis [Functions for local caches.]
9 Description [Internal procedures included in this module:
10 <ul>
11 <li> cuddLocalCacheInit()
12 <li> cuddLocalCacheQuit()
13 <li> cuddLocalCacheInsert()
14 <li> cuddLocalCacheLookup()
15 <li> cuddLocalCacheClearDead()
16 <li> cuddLocalCacheClearAll()
17 <li> cuddLocalCacheProfile()
18 <li> cuddHashTableInit()
19 <li> cuddHashTableQuit()
20 <li> cuddHashTableInsert()
21 <li> cuddHashTableLookup()
22 <li> cuddHashTableInsert2()
23 <li> cuddHashTableLookup2()
24 <li> cuddHashTableInsert3()
25 <li> cuddHashTableLookup3()
26 </ul>
27 Static procedures included in this module:
28 <ul>
29 <li> cuddLocalCacheResize()
30 <li> ddLCHash()
31 <li> cuddLocalCacheAddToList()
32 <li> cuddLocalCacheRemoveFromList()
33 <li> cuddHashTableResize()
34 <li> cuddHashTableAlloc()
35 </ul> ]
37 SeeAlso []
39 Author [Fabio Somenzi]
41 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
43 All rights reserved.
45 Redistribution and use in source and binary forms, with or without
46 modification, are permitted provided that the following conditions
47 are met:
49 Redistributions of source code must retain the above copyright
50 notice, this list of conditions and the following disclaimer.
52 Redistributions in binary form must reproduce the above copyright
53 notice, this list of conditions and the following disclaimer in the
54 documentation and/or other materials provided with the distribution.
56 Neither the name of the University of Colorado nor the names of its
57 contributors may be used to endorse or promote products derived from
58 this software without specific prior written permission.
60 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
61 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
62 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
63 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
64 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
65 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
66 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
67 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
68 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
70 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
71 POSSIBILITY OF SUCH DAMAGE.]
73 ******************************************************************************/
75 #include "util.h"
76 #include "cuddInt.h"
78 /*---------------------------------------------------------------------------*/
79 /* Constant declarations */
80 /*---------------------------------------------------------------------------*/
82 #define DD_MAX_HASHTABLE_DENSITY 2 /* tells when to resize a table */
84 /*---------------------------------------------------------------------------*/
85 /* Stucture declarations */
86 /*---------------------------------------------------------------------------*/
89 /*---------------------------------------------------------------------------*/
90 /* Type declarations */
91 /*---------------------------------------------------------------------------*/
94 /*---------------------------------------------------------------------------*/
95 /* Variable declarations */
96 /*---------------------------------------------------------------------------*/
98 #ifndef lint
99 static char rcsid[] DD_UNUSED = "$Id: cuddLCache.c,v 1.24 2009/03/08 02:49:02 fabio Exp $";
100 #endif
102 /*---------------------------------------------------------------------------*/
103 /* Macro declarations */
104 /*---------------------------------------------------------------------------*/
106 /**Macro***********************************************************************
108 Synopsis [Computes hash function for keys of two operands.]
110 Description []
112 SideEffects [None]
114 SeeAlso [ddLCHash3 ddLCHash]
116 ******************************************************************************/
117 #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
118 #define ddLCHash2(f,g,shift) \
119 ((((unsigned)(ptruint)(f) * DD_P1 + \
120 (unsigned)(ptruint)(g)) * DD_P2) >> (shift))
121 #else
122 #define ddLCHash2(f,g,shift) \
123 ((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift))
124 #endif
127 /**Macro***********************************************************************
129 Synopsis [Computes hash function for keys of three operands.]
131 Description []
133 SideEffects [None]
135 SeeAlso [ddLCHash2 ddLCHash]
137 ******************************************************************************/
138 #define ddLCHash3(f,g,h,shift) ddCHash2(f,g,h,shift)
141 /**AutomaticStart*************************************************************/
143 /*---------------------------------------------------------------------------*/
144 /* Static function prototypes */
145 /*---------------------------------------------------------------------------*/
147 static void cuddLocalCacheResize (DdLocalCache *cache);
148 DD_INLINE static unsigned int ddLCHash (DdNodePtr *key, unsigned int keysize, int shift);
149 static void cuddLocalCacheAddToList (DdLocalCache *cache);
150 static void cuddLocalCacheRemoveFromList (DdLocalCache *cache);
151 static int cuddHashTableResize (DdHashTable *hash);
152 DD_INLINE static DdHashItem * cuddHashTableAlloc (DdHashTable *hash);
154 /**AutomaticEnd***************************************************************/
157 /*---------------------------------------------------------------------------*/
158 /* Definition of exported functions */
159 /*---------------------------------------------------------------------------*/
161 /*---------------------------------------------------------------------------*/
162 /* Definition of internal functions */
163 /*---------------------------------------------------------------------------*/
166 /**Function********************************************************************
168 Synopsis [Initializes a local computed table.]
170 Description [Initializes a computed table. Returns a pointer the
171 the new local cache in case of success; NULL otherwise.]
173 SideEffects [None]
175 SeeAlso [cuddInitCache]
177 ******************************************************************************/
178 DdLocalCache *
179 cuddLocalCacheInit(
180 DdManager * manager /* manager */,
181 unsigned int keySize /* size of the key (number of operands) */,
182 unsigned int cacheSize /* Initial size of the cache */,
183 unsigned int maxCacheSize /* Size of the cache beyond which no resizing occurs */)
185 DdLocalCache *cache;
186 int logSize;
188 cache = ALLOC(DdLocalCache,1);
189 if (cache == NULL) {
190 manager->errorCode = CUDD_MEMORY_OUT;
191 return(NULL);
193 cache->manager = manager;
194 cache->keysize = keySize;
195 cache->itemsize = (keySize + 1) * sizeof(DdNode *);
196 #ifdef DD_CACHE_PROFILE
197 cache->itemsize += sizeof(ptrint);
198 #endif
199 logSize = cuddComputeFloorLog2(ddMax(cacheSize,manager->slots/2));
200 cacheSize = 1 << logSize;
201 cache->item = (DdLocalCacheItem *)
202 ALLOC(char, cacheSize * cache->itemsize);
203 if (cache->item == NULL) {
204 manager->errorCode = CUDD_MEMORY_OUT;
205 FREE(cache);
206 return(NULL);
208 cache->slots = cacheSize;
209 cache->shift = sizeof(int) * 8 - logSize;
210 cache->maxslots = ddMin(maxCacheSize,manager->slots);
211 cache->minHit = manager->minHit;
212 /* Initialize to avoid division by 0 and immediate resizing. */
213 cache->lookUps = (double) (int) (cacheSize * cache->minHit + 1);
214 cache->hits = 0;
215 manager->memused += cacheSize * cache->itemsize + sizeof(DdLocalCache);
217 /* Initialize the cache. */
218 memset(cache->item, 0, cacheSize * cache->itemsize);
220 /* Add to manager's list of local caches for GC. */
221 cuddLocalCacheAddToList(cache);
223 return(cache);
225 } /* end of cuddLocalCacheInit */
228 /**Function********************************************************************
230 Synopsis [Shuts down a local computed table.]
232 Description [Initializes the computed table. It is called by
233 Cudd_Init. Returns a pointer the the new local cache in case of
234 success; NULL otherwise.]
236 SideEffects [None]
238 SeeAlso [cuddLocalCacheInit]
240 ******************************************************************************/
241 void
242 cuddLocalCacheQuit(
243 DdLocalCache * cache /* cache to be shut down */)
245 cache->manager->memused -=
246 cache->slots * cache->itemsize + sizeof(DdLocalCache);
247 cuddLocalCacheRemoveFromList(cache);
248 FREE(cache->item);
249 FREE(cache);
251 return;
253 } /* end of cuddLocalCacheQuit */
256 /**Function********************************************************************
258 Synopsis [Inserts a result in a local cache.]
260 Description []
262 SideEffects [None]
264 SeeAlso []
266 ******************************************************************************/
267 void
268 cuddLocalCacheInsert(
269 DdLocalCache * cache,
270 DdNodePtr * key,
271 DdNode * value)
273 unsigned int posn;
274 DdLocalCacheItem *entry;
276 posn = ddLCHash(key,cache->keysize,cache->shift);
277 entry = (DdLocalCacheItem *) ((char *) cache->item +
278 posn * cache->itemsize);
279 memcpy(entry->key,key,cache->keysize * sizeof(DdNode *));
280 entry->value = value;
281 #ifdef DD_CACHE_PROFILE
282 entry->count++;
283 #endif
285 } /* end of cuddLocalCacheInsert */
288 /**Function********************************************************************
290 Synopsis [Looks up in a local cache.]
292 Description [Looks up in a local cache. Returns the result if found;
293 it returns NULL if no result is found.]
295 SideEffects [None]
297 SeeAlso []
299 ******************************************************************************/
300 DdNode *
301 cuddLocalCacheLookup(
302 DdLocalCache * cache,
303 DdNodePtr * key)
305 unsigned int posn;
306 DdLocalCacheItem *entry;
307 DdNode *value;
309 cache->lookUps++;
310 posn = ddLCHash(key,cache->keysize,cache->shift);
311 entry = (DdLocalCacheItem *) ((char *) cache->item +
312 posn * cache->itemsize);
313 if (entry->value != NULL &&
314 memcmp(key,entry->key,cache->keysize*sizeof(DdNode *)) == 0) {
315 cache->hits++;
316 value = Cudd_Regular(entry->value);
317 if (value->ref == 0) {
318 cuddReclaim(cache->manager,value);
320 return(entry->value);
323 /* Cache miss: decide whether to resize */
325 if (cache->slots < cache->maxslots &&
326 cache->hits > cache->lookUps * cache->minHit) {
327 cuddLocalCacheResize(cache);
330 return(NULL);
332 } /* end of cuddLocalCacheLookup */
335 /**Function********************************************************************
337 Synopsis [Clears the dead entries of the local caches of a manager.]
339 Description [Clears the dead entries of the local caches of a manager.
340 Used during garbage collection.]
342 SideEffects [None]
344 SeeAlso []
346 ******************************************************************************/
347 void
348 cuddLocalCacheClearDead(
349 DdManager * manager)
351 DdLocalCache *cache = manager->localCaches;
352 unsigned int keysize;
353 unsigned int itemsize;
354 unsigned int slots;
355 DdLocalCacheItem *item;
356 DdNodePtr *key;
357 unsigned int i, j;
359 while (cache != NULL) {
360 keysize = cache->keysize;
361 itemsize = cache->itemsize;
362 slots = cache->slots;
363 item = cache->item;
364 for (i = 0; i < slots; i++) {
365 if (item->value != NULL) {
366 if (Cudd_Regular(item->value)->ref == 0) {
367 item->value = NULL;
368 } else {
369 key = item->key;
370 for (j = 0; j < keysize; j++) {
371 if (Cudd_Regular(key[j])->ref == 0) {
372 item->value = NULL;
373 break;
378 item = (DdLocalCacheItem *) ((char *) item + itemsize);
380 cache = cache->next;
382 return;
384 } /* end of cuddLocalCacheClearDead */
387 /**Function********************************************************************
389 Synopsis [Clears the local caches of a manager.]
391 Description [Clears the local caches of a manager.
392 Used before reordering.]
394 SideEffects [None]
396 SeeAlso []
398 ******************************************************************************/
399 void
400 cuddLocalCacheClearAll(
401 DdManager * manager)
403 DdLocalCache *cache = manager->localCaches;
405 while (cache != NULL) {
406 memset(cache->item, 0, cache->slots * cache->itemsize);
407 cache = cache->next;
409 return;
411 } /* end of cuddLocalCacheClearAll */
414 #ifdef DD_CACHE_PROFILE
416 #define DD_HYSTO_BINS 8
418 /**Function********************************************************************
420 Synopsis [Computes and prints a profile of a local cache usage.]
422 Description [Computes and prints a profile of a local cache usage.
423 Returns 1 if successful; 0 otherwise.]
425 SideEffects [None]
427 SeeAlso []
429 ******************************************************************************/
431 cuddLocalCacheProfile(
432 DdLocalCache * cache)
434 double count, mean, meansq, stddev, expected;
435 long max, min;
436 int imax, imin;
437 int i, retval, slots;
438 long *hystogram;
439 int nbins = DD_HYSTO_BINS;
440 int bin;
441 long thiscount;
442 double totalcount;
443 int nzeroes;
444 DdLocalCacheItem *entry;
445 FILE *fp = cache->manager->out;
447 slots = cache->slots;
449 meansq = mean = expected = 0.0;
450 max = min = (long) cache->item[0].count;
451 imax = imin = nzeroes = 0;
452 totalcount = 0.0;
454 hystogram = ALLOC(long, nbins);
455 if (hystogram == NULL) {
456 return(0);
458 for (i = 0; i < nbins; i++) {
459 hystogram[i] = 0;
462 for (i = 0; i < slots; i++) {
463 entry = (DdLocalCacheItem *) ((char *) cache->item +
464 i * cache->itemsize);
465 thiscount = (long) entry->count;
466 if (thiscount > max) {
467 max = thiscount;
468 imax = i;
470 if (thiscount < min) {
471 min = thiscount;
472 imin = i;
474 if (thiscount == 0) {
475 nzeroes++;
477 count = (double) thiscount;
478 mean += count;
479 meansq += count * count;
480 totalcount += count;
481 expected += count * (double) i;
482 bin = (i * nbins) / slots;
483 hystogram[bin] += thiscount;
485 mean /= (double) slots;
486 meansq /= (double) slots;
487 stddev = sqrt(meansq - mean*mean);
489 retval = fprintf(fp,"Cache stats: slots = %d average = %g ", slots, mean);
490 if (retval == EOF) return(0);
491 retval = fprintf(fp,"standard deviation = %g\n", stddev);
492 if (retval == EOF) return(0);
493 retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
494 if (retval == EOF) return(0);
495 retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
496 if (retval == EOF) return(0);
497 retval = fprintf(fp,"Cache unused slots = %d\n", nzeroes);
498 if (retval == EOF) return(0);
500 if (totalcount) {
501 expected /= totalcount;
502 retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
503 if (retval == EOF) return(0);
504 retval = fprintf(fp," (expected bin value = %g)\n# ", expected);
505 if (retval == EOF) return(0);
506 for (i = nbins - 1; i>=0; i--) {
507 retval = fprintf(fp,"%ld ", hystogram[i]);
508 if (retval == EOF) return(0);
510 retval = fprintf(fp,"\n");
511 if (retval == EOF) return(0);
514 FREE(hystogram);
515 return(1);
517 } /* end of cuddLocalCacheProfile */
518 #endif
521 /**Function********************************************************************
523 Synopsis [Initializes a hash table.]
525 Description [Initializes a hash table. Returns a pointer to the new
526 table if successful; NULL otherwise.]
528 SideEffects [None]
530 SeeAlso [cuddHashTableQuit]
532 ******************************************************************************/
533 DdHashTable *
534 cuddHashTableInit(
535 DdManager * manager,
536 unsigned int keySize,
537 unsigned int initSize)
539 DdHashTable *hash;
540 int logSize;
542 #ifdef __osf__
543 #pragma pointer_size save
544 #pragma pointer_size short
545 #endif
546 hash = ALLOC(DdHashTable, 1);
547 if (hash == NULL) {
548 manager->errorCode = CUDD_MEMORY_OUT;
549 return(NULL);
551 hash->keysize = keySize;
552 hash->manager = manager;
553 hash->memoryList = NULL;
554 hash->nextFree = NULL;
555 hash->itemsize = (keySize + 1) * sizeof(DdNode *) +
556 sizeof(ptrint) + sizeof(DdHashItem *);
557 /* We have to guarantee that the shift be < 32. */
558 if (initSize < 2) initSize = 2;
559 logSize = cuddComputeFloorLog2(initSize);
560 hash->numBuckets = 1 << logSize;
561 hash->shift = sizeof(int) * 8 - logSize;
562 hash->bucket = ALLOC(DdHashItem *, hash->numBuckets);
563 if (hash->bucket == NULL) {
564 manager->errorCode = CUDD_MEMORY_OUT;
565 FREE(hash);
566 return(NULL);
568 memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *));
569 hash->size = 0;
570 hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY;
571 #ifdef __osf__
572 #pragma pointer_size restore
573 #endif
574 return(hash);
576 } /* end of cuddHashTableInit */
579 /**Function********************************************************************
581 Synopsis [Shuts down a hash table.]
583 Description [Shuts down a hash table, dereferencing all the values.]
585 SideEffects [None]
587 SeeAlso [cuddHashTableInit]
589 ******************************************************************************/
590 void
591 cuddHashTableQuit(
592 DdHashTable * hash)
594 #ifdef __osf__
595 #pragma pointer_size save
596 #pragma pointer_size short
597 #endif
598 unsigned int i;
599 DdManager *dd = hash->manager;
600 DdHashItem *bucket;
601 DdHashItem **memlist, **nextmem;
602 unsigned int numBuckets = hash->numBuckets;
604 for (i = 0; i < numBuckets; i++) {
605 bucket = hash->bucket[i];
606 while (bucket != NULL) {
607 Cudd_RecursiveDeref(dd, bucket->value);
608 bucket = bucket->next;
612 memlist = hash->memoryList;
613 while (memlist != NULL) {
614 nextmem = (DdHashItem **) memlist[0];
615 FREE(memlist);
616 memlist = nextmem;
619 FREE(hash->bucket);
620 FREE(hash);
621 #ifdef __osf__
622 #pragma pointer_size restore
623 #endif
625 return;
627 } /* end of cuddHashTableQuit */
630 /**Function********************************************************************
632 Synopsis [Inserts an item in a hash table.]
634 Description [Inserts an item in a hash table when the key has more than
635 three pointers. Returns 1 if successful; 0 otherwise.]
637 SideEffects [None]
639 SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3
640 cuddHashTableLookup]
642 ******************************************************************************/
644 cuddHashTableInsert(
645 DdHashTable * hash,
646 DdNodePtr * key,
647 DdNode * value,
648 ptrint count)
650 int result;
651 unsigned int posn;
652 DdHashItem *item;
653 unsigned int i;
655 #ifdef DD_DEBUG
656 assert(hash->keysize > 3);
657 #endif
659 if (hash->size > hash->maxsize) {
660 result = cuddHashTableResize(hash);
661 if (result == 0) return(0);
663 item = cuddHashTableAlloc(hash);
664 if (item == NULL) return(0);
665 hash->size++;
666 item->value = value;
667 cuddRef(value);
668 item->count = count;
669 for (i = 0; i < hash->keysize; i++) {
670 item->key[i] = key[i];
672 posn = ddLCHash(key,hash->keysize,hash->shift);
673 item->next = hash->bucket[posn];
674 hash->bucket[posn] = item;
676 return(1);
678 } /* end of cuddHashTableInsert */
681 /**Function********************************************************************
683 Synopsis [Looks up a key in a hash table.]
685 Description [Looks up a key consisting of more than three pointers
686 in a hash table. Returns the value associated to the key if there
687 is an entry for the given key in the table; NULL otherwise. If the
688 entry is present, its reference counter is decremented if not
689 saturated. If the counter reaches 0, the value of the entry is
690 dereferenced, and the entry is returned to the free list.]
692 SideEffects [None]
694 SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3
695 cuddHashTableInsert]
697 ******************************************************************************/
698 DdNode *
699 cuddHashTableLookup(
700 DdHashTable * hash,
701 DdNodePtr * key)
703 unsigned int posn;
704 DdHashItem *item, *prev;
705 unsigned int i, keysize;
707 #ifdef DD_DEBUG
708 assert(hash->keysize > 3);
709 #endif
711 posn = ddLCHash(key,hash->keysize,hash->shift);
712 item = hash->bucket[posn];
713 prev = NULL;
715 keysize = hash->keysize;
716 while (item != NULL) {
717 DdNodePtr *key2 = item->key;
718 int equal = 1;
719 for (i = 0; i < keysize; i++) {
720 if (key[i] != key2[i]) {
721 equal = 0;
722 break;
725 if (equal) {
726 DdNode *value = item->value;
727 cuddSatDec(item->count);
728 if (item->count == 0) {
729 cuddDeref(value);
730 if (prev == NULL) {
731 hash->bucket[posn] = item->next;
732 } else {
733 prev->next = item->next;
735 item->next = hash->nextFree;
736 hash->nextFree = item;
737 hash->size--;
739 return(value);
741 prev = item;
742 item = item->next;
744 return(NULL);
746 } /* end of cuddHashTableLookup */
749 /**Function********************************************************************
751 Synopsis [Inserts an item in a hash table.]
753 Description [Inserts an item in a hash table when the key is one pointer.
754 Returns 1 if successful; 0 otherwise.]
756 SideEffects [None]
758 SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3
759 cuddHashTableLookup1]
761 ******************************************************************************/
763 cuddHashTableInsert1(
764 DdHashTable * hash,
765 DdNode * f,
766 DdNode * value,
767 ptrint count)
769 int result;
770 unsigned int posn;
771 DdHashItem *item;
773 #ifdef DD_DEBUG
774 assert(hash->keysize == 1);
775 #endif
777 if (hash->size > hash->maxsize) {
778 result = cuddHashTableResize(hash);
779 if (result == 0) return(0);
781 item = cuddHashTableAlloc(hash);
782 if (item == NULL) return(0);
783 hash->size++;
784 item->value = value;
785 cuddRef(value);
786 item->count = count;
787 item->key[0] = f;
788 posn = ddLCHash2(f,f,hash->shift);
789 item->next = hash->bucket[posn];
790 hash->bucket[posn] = item;
792 return(1);
794 } /* end of cuddHashTableInsert1 */
797 /**Function********************************************************************
799 Synopsis [Looks up a key consisting of one pointer in a hash table.]
801 Description [Looks up a key consisting of one pointer in a hash table.
802 Returns the value associated to the key if there is an entry for the given
803 key in the table; NULL otherwise. If the entry is present, its reference
804 counter is decremented if not saturated. If the counter reaches 0, the
805 value of the entry is dereferenced, and the entry is returned to the free
806 list.]
808 SideEffects [None]
810 SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3
811 cuddHashTableInsert1]
813 ******************************************************************************/
814 DdNode *
815 cuddHashTableLookup1(
816 DdHashTable * hash,
817 DdNode * f)
819 unsigned int posn;
820 DdHashItem *item, *prev;
822 #ifdef DD_DEBUG
823 assert(hash->keysize == 1);
824 #endif
826 posn = ddLCHash2(f,f,hash->shift);
827 item = hash->bucket[posn];
828 prev = NULL;
830 while (item != NULL) {
831 DdNodePtr *key = item->key;
832 if (f == key[0]) {
833 DdNode *value = item->value;
834 cuddSatDec(item->count);
835 if (item->count == 0) {
836 cuddDeref(value);
837 if (prev == NULL) {
838 hash->bucket[posn] = item->next;
839 } else {
840 prev->next = item->next;
842 item->next = hash->nextFree;
843 hash->nextFree = item;
844 hash->size--;
846 return(value);
848 prev = item;
849 item = item->next;
851 return(NULL);
853 } /* end of cuddHashTableLookup1 */
856 /**Function********************************************************************
858 Synopsis [Inserts an item in a hash table.]
860 Description [Inserts an item in a hash table when the key is
861 composed of two pointers. Returns 1 if successful; 0 otherwise.]
863 SideEffects [None]
865 SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3
866 cuddHashTableLookup2]
868 ******************************************************************************/
870 cuddHashTableInsert2(
871 DdHashTable * hash,
872 DdNode * f,
873 DdNode * g,
874 DdNode * value,
875 ptrint count)
877 int result;
878 unsigned int posn;
879 DdHashItem *item;
881 #ifdef DD_DEBUG
882 assert(hash->keysize == 2);
883 #endif
885 if (hash->size > hash->maxsize) {
886 result = cuddHashTableResize(hash);
887 if (result == 0) return(0);
889 item = cuddHashTableAlloc(hash);
890 if (item == NULL) return(0);
891 hash->size++;
892 item->value = value;
893 cuddRef(value);
894 item->count = count;
895 item->key[0] = f;
896 item->key[1] = g;
897 posn = ddLCHash2(f,g,hash->shift);
898 item->next = hash->bucket[posn];
899 hash->bucket[posn] = item;
901 return(1);
903 } /* end of cuddHashTableInsert2 */
906 /**Function********************************************************************
908 Synopsis [Looks up a key consisting of two pointers in a hash table.]
910 Description [Looks up a key consisting of two pointer in a hash table.
911 Returns the value associated to the key if there is an entry for the given
912 key in the table; NULL otherwise. If the entry is present, its reference
913 counter is decremented if not saturated. If the counter reaches 0, the
914 value of the entry is dereferenced, and the entry is returned to the free
915 list.]
917 SideEffects [None]
919 SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3
920 cuddHashTableInsert2]
922 ******************************************************************************/
923 DdNode *
924 cuddHashTableLookup2(
925 DdHashTable * hash,
926 DdNode * f,
927 DdNode * g)
929 unsigned int posn;
930 DdHashItem *item, *prev;
932 #ifdef DD_DEBUG
933 assert(hash->keysize == 2);
934 #endif
936 posn = ddLCHash2(f,g,hash->shift);
937 item = hash->bucket[posn];
938 prev = NULL;
940 while (item != NULL) {
941 DdNodePtr *key = item->key;
942 if ((f == key[0]) && (g == key[1])) {
943 DdNode *value = item->value;
944 cuddSatDec(item->count);
945 if (item->count == 0) {
946 cuddDeref(value);
947 if (prev == NULL) {
948 hash->bucket[posn] = item->next;
949 } else {
950 prev->next = item->next;
952 item->next = hash->nextFree;
953 hash->nextFree = item;
954 hash->size--;
956 return(value);
958 prev = item;
959 item = item->next;
961 return(NULL);
963 } /* end of cuddHashTableLookup2 */
966 /**Function********************************************************************
968 Synopsis [Inserts an item in a hash table.]
970 Description [Inserts an item in a hash table when the key is
971 composed of three pointers. Returns 1 if successful; 0 otherwise.]
973 SideEffects [None]
975 SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2
976 cuddHashTableLookup3]
978 ******************************************************************************/
980 cuddHashTableInsert3(
981 DdHashTable * hash,
982 DdNode * f,
983 DdNode * g,
984 DdNode * h,
985 DdNode * value,
986 ptrint count)
988 int result;
989 unsigned int posn;
990 DdHashItem *item;
992 #ifdef DD_DEBUG
993 assert(hash->keysize == 3);
994 #endif
996 if (hash->size > hash->maxsize) {
997 result = cuddHashTableResize(hash);
998 if (result == 0) return(0);
1000 item = cuddHashTableAlloc(hash);
1001 if (item == NULL) return(0);
1002 hash->size++;
1003 item->value = value;
1004 cuddRef(value);
1005 item->count = count;
1006 item->key[0] = f;
1007 item->key[1] = g;
1008 item->key[2] = h;
1009 posn = ddLCHash3(f,g,h,hash->shift);
1010 item->next = hash->bucket[posn];
1011 hash->bucket[posn] = item;
1013 return(1);
1015 } /* end of cuddHashTableInsert3 */
1018 /**Function********************************************************************
1020 Synopsis [Looks up a key consisting of three pointers in a hash table.]
1022 Description [Looks up a key consisting of three pointers in a hash table.
1023 Returns the value associated to the key if there is an entry for the given
1024 key in the table; NULL otherwise. If the entry is present, its reference
1025 counter is decremented if not saturated. If the counter reaches 0, the
1026 value of the entry is dereferenced, and the entry is returned to the free
1027 list.]
1029 SideEffects [None]
1031 SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2
1032 cuddHashTableInsert3]
1034 ******************************************************************************/
1035 DdNode *
1036 cuddHashTableLookup3(
1037 DdHashTable * hash,
1038 DdNode * f,
1039 DdNode * g,
1040 DdNode * h)
1042 unsigned int posn;
1043 DdHashItem *item, *prev;
1045 #ifdef DD_DEBUG
1046 assert(hash->keysize == 3);
1047 #endif
1049 posn = ddLCHash3(f,g,h,hash->shift);
1050 item = hash->bucket[posn];
1051 prev = NULL;
1053 while (item != NULL) {
1054 DdNodePtr *key = item->key;
1055 if ((f == key[0]) && (g == key[1]) && (h == key[2])) {
1056 DdNode *value = item->value;
1057 cuddSatDec(item->count);
1058 if (item->count == 0) {
1059 cuddDeref(value);
1060 if (prev == NULL) {
1061 hash->bucket[posn] = item->next;
1062 } else {
1063 prev->next = item->next;
1065 item->next = hash->nextFree;
1066 hash->nextFree = item;
1067 hash->size--;
1069 return(value);
1071 prev = item;
1072 item = item->next;
1074 return(NULL);
1076 } /* end of cuddHashTableLookup3 */
1079 /*---------------------------------------------------------------------------*/
1080 /* Definition of static functions */
1081 /*---------------------------------------------------------------------------*/
1084 /**Function********************************************************************
1086 Synopsis [Resizes a local cache.]
1088 Description []
1090 SideEffects [None]
1092 SeeAlso []
1094 ******************************************************************************/
1095 static void
1096 cuddLocalCacheResize(
1097 DdLocalCache * cache)
1099 DdLocalCacheItem *item, *olditem, *entry, *old;
1100 int i, shift;
1101 unsigned int posn;
1102 unsigned int slots, oldslots;
1103 extern DD_OOMFP MMoutOfMemory;
1104 DD_OOMFP saveHandler;
1106 olditem = cache->item;
1107 oldslots = cache->slots;
1108 slots = cache->slots = oldslots << 1;
1110 #ifdef DD_VERBOSE
1111 (void) fprintf(cache->manager->err,
1112 "Resizing local cache from %d to %d entries\n",
1113 oldslots, slots);
1114 (void) fprintf(cache->manager->err,
1115 "\thits = %.0f\tlookups = %.0f\thit ratio = %5.3f\n",
1116 cache->hits, cache->lookUps, cache->hits / cache->lookUps);
1117 #endif
1119 saveHandler = MMoutOfMemory;
1120 MMoutOfMemory = Cudd_OutOfMem;
1121 cache->item = item =
1122 (DdLocalCacheItem *) ALLOC(char, slots * cache->itemsize);
1123 MMoutOfMemory = saveHandler;
1124 /* If we fail to allocate the new table we just give up. */
1125 if (item == NULL) {
1126 #ifdef DD_VERBOSE
1127 (void) fprintf(cache->manager->err,"Resizing failed. Giving up.\n");
1128 #endif
1129 cache->slots = oldslots;
1130 cache->item = olditem;
1131 /* Do not try to resize again. */
1132 cache->maxslots = oldslots - 1;
1133 return;
1135 shift = --(cache->shift);
1136 cache->manager->memused += (slots - oldslots) * cache->itemsize;
1138 /* Clear new cache. */
1139 memset(item, 0, slots * cache->itemsize);
1141 /* Copy from old cache to new one. */
1142 for (i = 0; (unsigned) i < oldslots; i++) {
1143 old = (DdLocalCacheItem *) ((char *) olditem + i * cache->itemsize);
1144 if (old->value != NULL) {
1145 posn = ddLCHash(old->key,cache->keysize,shift);
1146 entry = (DdLocalCacheItem *) ((char *) item +
1147 posn * cache->itemsize);
1148 memcpy(entry->key,old->key,cache->keysize*sizeof(DdNode *));
1149 entry->value = old->value;
1153 FREE(olditem);
1155 /* Reinitialize measurements so as to avoid division by 0 and
1156 ** immediate resizing.
1158 cache->lookUps = (double) (int) (slots * cache->minHit + 1);
1159 cache->hits = 0;
1161 } /* end of cuddLocalCacheResize */
1164 /**Function********************************************************************
1166 Synopsis [Computes the hash value for a local cache.]
1168 Description [Computes the hash value for a local cache. Returns the
1169 bucket index.]
1171 SideEffects [None]
1173 SeeAlso []
1175 ******************************************************************************/
1176 DD_INLINE
1177 static unsigned int
1178 ddLCHash(
1179 DdNodePtr * key,
1180 unsigned int keysize,
1181 int shift)
1183 unsigned int val = (unsigned int) (ptrint) key[0] * DD_P2;
1184 unsigned int i;
1186 for (i = 1; i < keysize; i++) {
1187 val = val * DD_P1 + (int) (ptrint) key[i];
1190 return(val >> shift);
1192 } /* end of ddLCHash */
1195 /**Function********************************************************************
1197 Synopsis [Inserts a local cache in the manager list.]
1199 Description []
1201 SideEffects [None]
1203 SeeAlso []
1205 ******************************************************************************/
1206 static void
1207 cuddLocalCacheAddToList(
1208 DdLocalCache * cache)
1210 DdManager *manager = cache->manager;
1212 cache->next = manager->localCaches;
1213 manager->localCaches = cache;
1214 return;
1216 } /* end of cuddLocalCacheAddToList */
1219 /**Function********************************************************************
1221 Synopsis [Removes a local cache from the manager list.]
1223 Description []
1225 SideEffects [None]
1227 SeeAlso []
1229 ******************************************************************************/
1230 static void
1231 cuddLocalCacheRemoveFromList(
1232 DdLocalCache * cache)
1234 DdManager *manager = cache->manager;
1235 #ifdef __osf__
1236 #pragma pointer_size save
1237 #pragma pointer_size short
1238 #endif
1239 DdLocalCache **prevCache, *nextCache;
1240 #ifdef __osf__
1241 #pragma pointer_size restore
1242 #endif
1244 prevCache = &(manager->localCaches);
1245 nextCache = manager->localCaches;
1247 while (nextCache != NULL) {
1248 if (nextCache == cache) {
1249 *prevCache = nextCache->next;
1250 return;
1252 prevCache = &(nextCache->next);
1253 nextCache = nextCache->next;
1255 return; /* should never get here */
1257 } /* end of cuddLocalCacheRemoveFromList */
1260 /**Function********************************************************************
1262 Synopsis [Resizes a hash table.]
1264 Description [Resizes a hash table. Returns 1 if successful; 0
1265 otherwise.]
1267 SideEffects [None]
1269 SeeAlso [cuddHashTableInsert]
1271 ******************************************************************************/
1272 static int
1273 cuddHashTableResize(
1274 DdHashTable * hash)
1276 int j;
1277 unsigned int posn;
1278 DdHashItem *item;
1279 DdHashItem *next;
1280 #ifdef __osf__
1281 #pragma pointer_size save
1282 #pragma pointer_size short
1283 #endif
1284 DdNode **key;
1285 int numBuckets;
1286 DdHashItem **buckets;
1287 DdHashItem **oldBuckets = hash->bucket;
1288 #ifdef __osf__
1289 #pragma pointer_size restore
1290 #endif
1291 int shift;
1292 int oldNumBuckets = hash->numBuckets;
1293 extern DD_OOMFP MMoutOfMemory;
1294 DD_OOMFP saveHandler;
1296 /* Compute the new size of the table. */
1297 numBuckets = oldNumBuckets << 1;
1298 saveHandler = MMoutOfMemory;
1299 MMoutOfMemory = Cudd_OutOfMem;
1300 #ifdef __osf__
1301 #pragma pointer_size save
1302 #pragma pointer_size short
1303 #endif
1304 buckets = ALLOC(DdHashItem *, numBuckets);
1305 MMoutOfMemory = saveHandler;
1306 if (buckets == NULL) {
1307 hash->maxsize <<= 1;
1308 return(1);
1311 hash->bucket = buckets;
1312 hash->numBuckets = numBuckets;
1313 shift = --(hash->shift);
1314 hash->maxsize <<= 1;
1315 memset(buckets, 0, numBuckets * sizeof(DdHashItem *));
1316 #ifdef __osf__
1317 #pragma pointer_size restore
1318 #endif
1319 if (hash->keysize == 1) {
1320 for (j = 0; j < oldNumBuckets; j++) {
1321 item = oldBuckets[j];
1322 while (item != NULL) {
1323 next = item->next;
1324 key = item->key;
1325 posn = ddLCHash2(key[0], key[0], shift);
1326 item->next = buckets[posn];
1327 buckets[posn] = item;
1328 item = next;
1331 } else if (hash->keysize == 2) {
1332 for (j = 0; j < oldNumBuckets; j++) {
1333 item = oldBuckets[j];
1334 while (item != NULL) {
1335 next = item->next;
1336 key = item->key;
1337 posn = ddLCHash2(key[0], key[1], shift);
1338 item->next = buckets[posn];
1339 buckets[posn] = item;
1340 item = next;
1343 } else if (hash->keysize == 3) {
1344 for (j = 0; j < oldNumBuckets; j++) {
1345 item = oldBuckets[j];
1346 while (item != NULL) {
1347 next = item->next;
1348 key = item->key;
1349 posn = ddLCHash3(key[0], key[1], key[2], shift);
1350 item->next = buckets[posn];
1351 buckets[posn] = item;
1352 item = next;
1355 } else {
1356 for (j = 0; j < oldNumBuckets; j++) {
1357 item = oldBuckets[j];
1358 while (item != NULL) {
1359 next = item->next;
1360 posn = ddLCHash(item->key, hash->keysize, shift);
1361 item->next = buckets[posn];
1362 buckets[posn] = item;
1363 item = next;
1367 FREE(oldBuckets);
1368 return(1);
1370 } /* end of cuddHashTableResize */
1373 /**Function********************************************************************
1375 Synopsis [Fast storage allocation for items in a hash table.]
1377 Description [Fast storage allocation for items in a hash table. The
1378 first 4 bytes of a chunk contain a pointer to the next block; the
1379 rest contains DD_MEM_CHUNK spaces for hash items. Returns a pointer to
1380 a new item if successful; NULL is memory is full.]
1382 SideEffects [None]
1384 SeeAlso [cuddAllocNode cuddDynamicAllocNode]
1386 ******************************************************************************/
1387 DD_INLINE
1388 static DdHashItem *
1389 cuddHashTableAlloc(
1390 DdHashTable * hash)
1392 int i;
1393 unsigned int itemsize = hash->itemsize;
1394 extern DD_OOMFP MMoutOfMemory;
1395 DD_OOMFP saveHandler;
1396 #ifdef __osf__
1397 #pragma pointer_size save
1398 #pragma pointer_size short
1399 #endif
1400 DdHashItem **mem, *thisOne, *next, *item;
1402 if (hash->nextFree == NULL) {
1403 saveHandler = MMoutOfMemory;
1404 MMoutOfMemory = Cudd_OutOfMem;
1405 mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
1406 MMoutOfMemory = saveHandler;
1407 #ifdef __osf__
1408 #pragma pointer_size restore
1409 #endif
1410 if (mem == NULL) {
1411 if (hash->manager->stash != NULL) {
1412 FREE(hash->manager->stash);
1413 hash->manager->stash = NULL;
1414 /* Inhibit resizing of tables. */
1415 hash->manager->maxCacheHard = hash->manager->cacheSlots - 1;
1416 hash->manager->cacheSlack = - (int) (hash->manager->cacheSlots + 1);
1417 for (i = 0; i < hash->manager->size; i++) {
1418 hash->manager->subtables[i].maxKeys <<= 2;
1420 hash->manager->gcFrac = 0.2;
1421 hash->manager->minDead =
1422 (unsigned) (0.2 * (double) hash->manager->slots);
1423 #ifdef __osf__
1424 #pragma pointer_size save
1425 #pragma pointer_size short
1426 #endif
1427 mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
1428 #ifdef __osf__
1429 #pragma pointer_size restore
1430 #endif
1432 if (mem == NULL) {
1433 (*MMoutOfMemory)((long)((DD_MEM_CHUNK + 1) * itemsize));
1434 hash->manager->errorCode = CUDD_MEMORY_OUT;
1435 return(NULL);
1439 mem[0] = (DdHashItem *) hash->memoryList;
1440 hash->memoryList = mem;
1442 thisOne = (DdHashItem *) ((char *) mem + itemsize);
1443 hash->nextFree = thisOne;
1444 for (i = 1; i < DD_MEM_CHUNK; i++) {
1445 next = (DdHashItem *) ((char *) thisOne + itemsize);
1446 thisOne->next = next;
1447 thisOne = next;
1450 thisOne->next = NULL;
1453 item = hash->nextFree;
1454 hash->nextFree = item->next;
1455 return(item);
1457 } /* end of cuddHashTableAlloc */