1 /**CFile***********************************************************************
3 FileName [cuddLCache.c]
7 Synopsis [Functions for local caches.]
9 Description [Internal procedures included in this module:
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()
27 Static procedures included in this module:
29 <li> cuddLocalCacheResize()
31 <li> cuddLocalCacheAddToList()
32 <li> cuddLocalCacheRemoveFromList()
33 <li> cuddHashTableResize()
34 <li> cuddHashTableAlloc()
39 Author [Fabio Somenzi]
41 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
45 Redistribution and use in source and binary forms, with or without
46 modification, are permitted provided that the following conditions
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 ******************************************************************************/
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 /*---------------------------------------------------------------------------*/
99 static char rcsid
[] DD_UNUSED
= "$Id: cuddLCache.c,v 1.24 2009/03/08 02:49:02 fabio Exp $";
102 /*---------------------------------------------------------------------------*/
103 /* Macro declarations */
104 /*---------------------------------------------------------------------------*/
106 /**Macro***********************************************************************
108 Synopsis [Computes hash function for keys of two operands.]
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))
122 #define ddLCHash2(f,g,shift) \
123 ((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift))
127 /**Macro***********************************************************************
129 Synopsis [Computes hash function for keys of three operands.]
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.]
175 SeeAlso [cuddInitCache]
177 ******************************************************************************/
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 */)
188 cache
= ALLOC(DdLocalCache
,1);
190 manager
->errorCode
= CUDD_MEMORY_OUT
;
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
);
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
;
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);
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
);
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.]
238 SeeAlso [cuddLocalCacheInit]
240 ******************************************************************************/
243 DdLocalCache
* cache
/* cache to be shut down */)
245 cache
->manager
->memused
-=
246 cache
->slots
* cache
->itemsize
+ sizeof(DdLocalCache
);
247 cuddLocalCacheRemoveFromList(cache
);
253 } /* end of cuddLocalCacheQuit */
256 /**Function********************************************************************
258 Synopsis [Inserts a result in a local cache.]
266 ******************************************************************************/
268 cuddLocalCacheInsert(
269 DdLocalCache
* cache
,
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
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.]
299 ******************************************************************************/
301 cuddLocalCacheLookup(
302 DdLocalCache
* cache
,
306 DdLocalCacheItem
*entry
;
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) {
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
);
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.]
346 ******************************************************************************/
348 cuddLocalCacheClearDead(
351 DdLocalCache
*cache
= manager
->localCaches
;
352 unsigned int keysize
;
353 unsigned int itemsize
;
355 DdLocalCacheItem
*item
;
359 while (cache
!= NULL
) {
360 keysize
= cache
->keysize
;
361 itemsize
= cache
->itemsize
;
362 slots
= cache
->slots
;
364 for (i
= 0; i
< slots
; i
++) {
365 if (item
->value
!= NULL
) {
366 if (Cudd_Regular(item
->value
)->ref
== 0) {
370 for (j
= 0; j
< keysize
; j
++) {
371 if (Cudd_Regular(key
[j
])->ref
== 0) {
378 item
= (DdLocalCacheItem
*) ((char *) item
+ itemsize
);
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.]
398 ******************************************************************************/
400 cuddLocalCacheClearAll(
403 DdLocalCache
*cache
= manager
->localCaches
;
405 while (cache
!= NULL
) {
406 memset(cache
->item
, 0, cache
->slots
* cache
->itemsize
);
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.]
429 ******************************************************************************/
431 cuddLocalCacheProfile(
432 DdLocalCache
* cache
)
434 double count
, mean
, meansq
, stddev
, expected
;
437 int i
, retval
, slots
;
439 int nbins
= DD_HYSTO_BINS
;
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;
454 hystogram
= ALLOC(long, nbins
);
455 if (hystogram
== NULL
) {
458 for (i
= 0; i
< nbins
; i
++) {
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
) {
470 if (thiscount
< min
) {
474 if (thiscount
== 0) {
477 count
= (double) thiscount
;
479 meansq
+= count
* 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);
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);
517 } /* end of cuddLocalCacheProfile */
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.]
530 SeeAlso [cuddHashTableQuit]
532 ******************************************************************************/
536 unsigned int keySize
,
537 unsigned int initSize
)
543 #pragma pointer_size save
544 #pragma pointer_size short
546 hash
= ALLOC(DdHashTable
, 1);
548 manager
->errorCode
= CUDD_MEMORY_OUT
;
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
;
568 memset(hash
->bucket
, 0, hash
->numBuckets
* sizeof(DdHashItem
*));
570 hash
->maxsize
= hash
->numBuckets
* DD_MAX_HASHTABLE_DENSITY
;
572 #pragma pointer_size restore
576 } /* end of cuddHashTableInit */
579 /**Function********************************************************************
581 Synopsis [Shuts down a hash table.]
583 Description [Shuts down a hash table, dereferencing all the values.]
587 SeeAlso [cuddHashTableInit]
589 ******************************************************************************/
595 #pragma pointer_size save
596 #pragma pointer_size short
599 DdManager
*dd
= hash
->manager
;
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];
622 #pragma pointer_size restore
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.]
639 SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3
642 ******************************************************************************/
656 assert(hash
->keysize
> 3);
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);
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
;
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.]
694 SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3
697 ******************************************************************************/
704 DdHashItem
*item
, *prev
;
705 unsigned int i
, keysize
;
708 assert(hash
->keysize
> 3);
711 posn
= ddLCHash(key
,hash
->keysize
,hash
->shift
);
712 item
= hash
->bucket
[posn
];
715 keysize
= hash
->keysize
;
716 while (item
!= NULL
) {
717 DdNodePtr
*key2
= item
->key
;
719 for (i
= 0; i
< keysize
; i
++) {
720 if (key
[i
] != key2
[i
]) {
726 DdNode
*value
= item
->value
;
727 cuddSatDec(item
->count
);
728 if (item
->count
== 0) {
731 hash
->bucket
[posn
] = item
->next
;
733 prev
->next
= item
->next
;
735 item
->next
= hash
->nextFree
;
736 hash
->nextFree
= item
;
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.]
758 SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3
759 cuddHashTableLookup1]
761 ******************************************************************************/
763 cuddHashTableInsert1(
774 assert(hash
->keysize
== 1);
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);
788 posn
= ddLCHash2(f
,f
,hash
->shift
);
789 item
->next
= hash
->bucket
[posn
];
790 hash
->bucket
[posn
] = item
;
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
810 SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3
811 cuddHashTableInsert1]
813 ******************************************************************************/
815 cuddHashTableLookup1(
820 DdHashItem
*item
, *prev
;
823 assert(hash
->keysize
== 1);
826 posn
= ddLCHash2(f
,f
,hash
->shift
);
827 item
= hash
->bucket
[posn
];
830 while (item
!= NULL
) {
831 DdNodePtr
*key
= item
->key
;
833 DdNode
*value
= item
->value
;
834 cuddSatDec(item
->count
);
835 if (item
->count
== 0) {
838 hash
->bucket
[posn
] = item
->next
;
840 prev
->next
= item
->next
;
842 item
->next
= hash
->nextFree
;
843 hash
->nextFree
= item
;
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.]
865 SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3
866 cuddHashTableLookup2]
868 ******************************************************************************/
870 cuddHashTableInsert2(
882 assert(hash
->keysize
== 2);
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);
897 posn
= ddLCHash2(f
,g
,hash
->shift
);
898 item
->next
= hash
->bucket
[posn
];
899 hash
->bucket
[posn
] = item
;
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
919 SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3
920 cuddHashTableInsert2]
922 ******************************************************************************/
924 cuddHashTableLookup2(
930 DdHashItem
*item
, *prev
;
933 assert(hash
->keysize
== 2);
936 posn
= ddLCHash2(f
,g
,hash
->shift
);
937 item
= hash
->bucket
[posn
];
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) {
948 hash
->bucket
[posn
] = item
->next
;
950 prev
->next
= item
->next
;
952 item
->next
= hash
->nextFree
;
953 hash
->nextFree
= item
;
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.]
975 SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2
976 cuddHashTableLookup3]
978 ******************************************************************************/
980 cuddHashTableInsert3(
993 assert(hash
->keysize
== 3);
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);
1003 item
->value
= value
;
1005 item
->count
= count
;
1009 posn
= ddLCHash3(f
,g
,h
,hash
->shift
);
1010 item
->next
= hash
->bucket
[posn
];
1011 hash
->bucket
[posn
] = item
;
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
1031 SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2
1032 cuddHashTableInsert3]
1034 ******************************************************************************/
1036 cuddHashTableLookup3(
1043 DdHashItem
*item
, *prev
;
1046 assert(hash
->keysize
== 3);
1049 posn
= ddLCHash3(f
,g
,h
,hash
->shift
);
1050 item
= hash
->bucket
[posn
];
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) {
1061 hash
->bucket
[posn
] = item
->next
;
1063 prev
->next
= item
->next
;
1065 item
->next
= hash
->nextFree
;
1066 hash
->nextFree
= item
;
1076 } /* end of cuddHashTableLookup3 */
1079 /*---------------------------------------------------------------------------*/
1080 /* Definition of static functions */
1081 /*---------------------------------------------------------------------------*/
1084 /**Function********************************************************************
1086 Synopsis [Resizes a local cache.]
1094 ******************************************************************************/
1096 cuddLocalCacheResize(
1097 DdLocalCache
* cache
)
1099 DdLocalCacheItem
*item
, *olditem
, *entry
, *old
;
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;
1111 (void) fprintf(cache
->manager
->err
,
1112 "Resizing local cache from %d to %d entries\n",
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
);
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. */
1127 (void) fprintf(cache
->manager
->err
,"Resizing failed. Giving up.\n");
1129 cache
->slots
= oldslots
;
1130 cache
->item
= olditem
;
1131 /* Do not try to resize again. */
1132 cache
->maxslots
= oldslots
- 1;
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
;
1155 /* Reinitialize measurements so as to avoid division by 0 and
1156 ** immediate resizing.
1158 cache
->lookUps
= (double) (int) (slots
* cache
->minHit
+ 1);
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
1175 ******************************************************************************/
1180 unsigned int keysize
,
1183 unsigned int val
= (unsigned int) (ptrint
) key
[0] * DD_P2
;
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.]
1205 ******************************************************************************/
1207 cuddLocalCacheAddToList(
1208 DdLocalCache
* cache
)
1210 DdManager
*manager
= cache
->manager
;
1212 cache
->next
= manager
->localCaches
;
1213 manager
->localCaches
= cache
;
1216 } /* end of cuddLocalCacheAddToList */
1219 /**Function********************************************************************
1221 Synopsis [Removes a local cache from the manager list.]
1229 ******************************************************************************/
1231 cuddLocalCacheRemoveFromList(
1232 DdLocalCache
* cache
)
1234 DdManager
*manager
= cache
->manager
;
1236 #pragma pointer_size save
1237 #pragma pointer_size short
1239 DdLocalCache
**prevCache
, *nextCache
;
1241 #pragma pointer_size restore
1244 prevCache
= &(manager
->localCaches
);
1245 nextCache
= manager
->localCaches
;
1247 while (nextCache
!= NULL
) {
1248 if (nextCache
== cache
) {
1249 *prevCache
= nextCache
->next
;
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
1269 SeeAlso [cuddHashTableInsert]
1271 ******************************************************************************/
1273 cuddHashTableResize(
1281 #pragma pointer_size save
1282 #pragma pointer_size short
1286 DdHashItem
**buckets
;
1287 DdHashItem
**oldBuckets
= hash
->bucket
;
1289 #pragma pointer_size restore
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
;
1301 #pragma pointer_size save
1302 #pragma pointer_size short
1304 buckets
= ALLOC(DdHashItem
*, numBuckets
);
1305 MMoutOfMemory
= saveHandler
;
1306 if (buckets
== NULL
) {
1307 hash
->maxsize
<<= 1;
1311 hash
->bucket
= buckets
;
1312 hash
->numBuckets
= numBuckets
;
1313 shift
= --(hash
->shift
);
1314 hash
->maxsize
<<= 1;
1315 memset(buckets
, 0, numBuckets
* sizeof(DdHashItem
*));
1317 #pragma pointer_size restore
1319 if (hash
->keysize
== 1) {
1320 for (j
= 0; j
< oldNumBuckets
; j
++) {
1321 item
= oldBuckets
[j
];
1322 while (item
!= NULL
) {
1325 posn
= ddLCHash2(key
[0], key
[0], shift
);
1326 item
->next
= buckets
[posn
];
1327 buckets
[posn
] = item
;
1331 } else if (hash
->keysize
== 2) {
1332 for (j
= 0; j
< oldNumBuckets
; j
++) {
1333 item
= oldBuckets
[j
];
1334 while (item
!= NULL
) {
1337 posn
= ddLCHash2(key
[0], key
[1], shift
);
1338 item
->next
= buckets
[posn
];
1339 buckets
[posn
] = item
;
1343 } else if (hash
->keysize
== 3) {
1344 for (j
= 0; j
< oldNumBuckets
; j
++) {
1345 item
= oldBuckets
[j
];
1346 while (item
!= NULL
) {
1349 posn
= ddLCHash3(key
[0], key
[1], key
[2], shift
);
1350 item
->next
= buckets
[posn
];
1351 buckets
[posn
] = item
;
1356 for (j
= 0; j
< oldNumBuckets
; j
++) {
1357 item
= oldBuckets
[j
];
1358 while (item
!= NULL
) {
1360 posn
= ddLCHash(item
->key
, hash
->keysize
, shift
);
1361 item
->next
= buckets
[posn
];
1362 buckets
[posn
] = item
;
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.]
1384 SeeAlso [cuddAllocNode cuddDynamicAllocNode]
1386 ******************************************************************************/
1393 unsigned int itemsize
= hash
->itemsize
;
1394 extern DD_OOMFP MMoutOfMemory
;
1395 DD_OOMFP saveHandler
;
1397 #pragma pointer_size save
1398 #pragma pointer_size short
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
;
1408 #pragma pointer_size restore
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
);
1424 #pragma pointer_size save
1425 #pragma pointer_size short
1427 mem
= (DdHashItem
**) ALLOC(char,(DD_MEM_CHUNK
+1) * itemsize
);
1429 #pragma pointer_size restore
1433 (*MMoutOfMemory
)((long)((DD_MEM_CHUNK
+ 1) * itemsize
));
1434 hash
->manager
->errorCode
= CUDD_MEMORY_OUT
;
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
;
1450 thisOne
->next
= NULL
;
1453 item
= hash
->nextFree
;
1454 hash
->nextFree
= item
->next
;
1457 } /* end of cuddHashTableAlloc */