/**CFile*********************************************************************** FileName [cuddLCache.c] PackageName [cudd] Synopsis [Functions for local caches.] Description [Internal procedures included in this module: Static procedures included in this module: ] SeeAlso [] Author [Fabio Somenzi] Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the University of Colorado nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.] ******************************************************************************/ #include "misc/util/util_hack.h" #include "cuddInt.h" ABC_NAMESPACE_IMPL_START /*---------------------------------------------------------------------------*/ /* Constant declarations */ /*---------------------------------------------------------------------------*/ #define DD_MAX_HASHTABLE_DENSITY 2 /* tells when to resize a table */ /*---------------------------------------------------------------------------*/ /* Stucture declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Type declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Variable declarations */ /*---------------------------------------------------------------------------*/ #ifndef lint static char rcsid[] DD_UNUSED = "$Id: cuddLCache.c,v 1.24 2009/03/08 02:49:02 fabio Exp $"; #endif /*---------------------------------------------------------------------------*/ /* Macro declarations */ /*---------------------------------------------------------------------------*/ /**Macro*********************************************************************** Synopsis [Computes hash function for keys of two operands.] Description [] SideEffects [None] SeeAlso [ddLCHash3 ddLCHash] ******************************************************************************/ #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4 #define ddLCHash2(f,g,shift) \ ((((unsigned)(ptruint)(f) * DD_P1 + \ (unsigned)(ptruint)(g)) * DD_P2) >> (shift)) #else #define ddLCHash2(f,g,shift) \ ((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift)) #endif /**Macro*********************************************************************** Synopsis [Computes hash function for keys of three operands.] Description [] SideEffects [None] SeeAlso [ddLCHash2 ddLCHash] ******************************************************************************/ #define ddLCHash3(f,g,h,shift) ddCHash2(f,g,h,shift) /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Static function prototypes */ /*---------------------------------------------------------------------------*/ static void cuddLocalCacheResize (DdLocalCache *cache); DD_INLINE static unsigned int ddLCHash (DdNodePtr *key, unsigned int keysize, int shift); static void cuddLocalCacheAddToList (DdLocalCache *cache); static void cuddLocalCacheRemoveFromList (DdLocalCache *cache); static int cuddHashTableResize (DdHashTable *hash); DD_INLINE static DdHashItem * cuddHashTableAlloc (DdHashTable *hash); /**AutomaticEnd***************************************************************/ /*---------------------------------------------------------------------------*/ /* Definition of exported functions */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Definition of internal functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Initializes a local computed table.] Description [Initializes a computed table. Returns a pointer the the new local cache in case of success; NULL otherwise.] SideEffects [None] SeeAlso [cuddInitCache] ******************************************************************************/ DdLocalCache * cuddLocalCacheInit( DdManager * manager /* manager */, unsigned int keySize /* size of the key (number of operands) */, unsigned int cacheSize /* Initial size of the cache */, unsigned int maxCacheSize /* Size of the cache beyond which no resizing occurs */) { DdLocalCache *cache; int logSize; cache = ABC_ALLOC(DdLocalCache,1); if (cache == NULL) { manager->errorCode = CUDD_MEMORY_OUT; return(NULL); } cache->manager = manager; cache->keysize = keySize; cache->itemsize = (keySize + 1) * sizeof(DdNode *); #ifdef DD_CACHE_PROFILE cache->itemsize += sizeof(ptrint); #endif logSize = cuddComputeFloorLog2(ddMax(cacheSize,manager->slots/2)); cacheSize = 1 << logSize; cache->item = (DdLocalCacheItem *) ABC_ALLOC(char, cacheSize * cache->itemsize); if (cache->item == NULL) { manager->errorCode = CUDD_MEMORY_OUT; ABC_FREE(cache); return(NULL); } cache->slots = cacheSize; cache->shift = sizeof(int) * 8 - logSize; cache->maxslots = ddMin(maxCacheSize,manager->slots); cache->minHit = manager->minHit; /* Initialize to avoid division by 0 and immediate resizing. */ cache->lookUps = (double) (int) (cacheSize * cache->minHit + 1); cache->hits = 0; manager->memused += cacheSize * cache->itemsize + sizeof(DdLocalCache); /* Initialize the cache. */ memset(cache->item, 0, cacheSize * cache->itemsize); /* Add to manager's list of local caches for GC. */ cuddLocalCacheAddToList(cache); return(cache); } /* end of cuddLocalCacheInit */ /**Function******************************************************************** Synopsis [Shuts down a local computed table.] Description [Initializes the computed table. It is called by Cudd_Init. Returns a pointer the the new local cache in case of success; NULL otherwise.] SideEffects [None] SeeAlso [cuddLocalCacheInit] ******************************************************************************/ void cuddLocalCacheQuit( DdLocalCache * cache /* cache to be shut down */) { cache->manager->memused -= cache->slots * cache->itemsize + sizeof(DdLocalCache); cuddLocalCacheRemoveFromList(cache); ABC_FREE(cache->item); ABC_FREE(cache); return; } /* end of cuddLocalCacheQuit */ /**Function******************************************************************** Synopsis [Inserts a result in a local cache.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ void cuddLocalCacheInsert( DdLocalCache * cache, DdNodePtr * key, DdNode * value) { unsigned int posn; DdLocalCacheItem *entry; posn = ddLCHash(key,cache->keysize,cache->shift); entry = (DdLocalCacheItem *) ((char *) cache->item + posn * cache->itemsize); memcpy(entry->key,key,cache->keysize * sizeof(DdNode *)); entry->value = value; #ifdef DD_CACHE_PROFILE entry->count++; #endif } /* end of cuddLocalCacheInsert */ /**Function******************************************************************** Synopsis [Looks up in a local cache.] Description [Looks up in a local cache. Returns the result if found; it returns NULL if no result is found.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddLocalCacheLookup( DdLocalCache * cache, DdNodePtr * key) { unsigned int posn; DdLocalCacheItem *entry; DdNode *value; cache->lookUps++; posn = ddLCHash(key,cache->keysize,cache->shift); entry = (DdLocalCacheItem *) ((char *) cache->item + posn * cache->itemsize); if (entry->value != NULL && memcmp(key,entry->key,cache->keysize*sizeof(DdNode *)) == 0) { cache->hits++; value = Cudd_Regular(entry->value); if (value->ref == 0) { cuddReclaim(cache->manager,value); } return(entry->value); } /* Cache miss: decide whether to resize */ if (cache->slots < cache->maxslots && cache->hits > cache->lookUps * cache->minHit) { cuddLocalCacheResize(cache); } return(NULL); } /* end of cuddLocalCacheLookup */ /**Function******************************************************************** Synopsis [Clears the dead entries of the local caches of a manager.] Description [Clears the dead entries of the local caches of a manager. Used during garbage collection.] SideEffects [None] SeeAlso [] ******************************************************************************/ void cuddLocalCacheClearDead( DdManager * manager) { DdLocalCache *cache = manager->localCaches; unsigned int keysize; unsigned int itemsize; unsigned int slots; DdLocalCacheItem *item; DdNodePtr *key; unsigned int i, j; while (cache != NULL) { keysize = cache->keysize; itemsize = cache->itemsize; slots = cache->slots; item = cache->item; for (i = 0; i < slots; i++) { if (item->value != NULL) { if (Cudd_Regular(item->value)->ref == 0) { item->value = NULL; } else { key = item->key; for (j = 0; j < keysize; j++) { if (Cudd_Regular(key[j])->ref == 0) { item->value = NULL; break; } } } } item = (DdLocalCacheItem *) ((char *) item + itemsize); } cache = cache->next; } return; } /* end of cuddLocalCacheClearDead */ /**Function******************************************************************** Synopsis [Clears the local caches of a manager.] Description [Clears the local caches of a manager. Used before reordering.] SideEffects [None] SeeAlso [] ******************************************************************************/ void cuddLocalCacheClearAll( DdManager * manager) { DdLocalCache *cache = manager->localCaches; while (cache != NULL) { memset(cache->item, 0, cache->slots * cache->itemsize); cache = cache->next; } return; } /* end of cuddLocalCacheClearAll */ #ifdef DD_CACHE_PROFILE #define DD_HYSTO_BINS 8 /**Function******************************************************************** Synopsis [Computes and prints a profile of a local cache usage.] Description [Computes and prints a profile of a local cache usage. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddLocalCacheProfile( DdLocalCache * cache) { double count, mean, meansq, stddev, expected; long max, min; int imax, imin; int i, retval, slots; long *hystogram; int nbins = DD_HYSTO_BINS; int bin; long thiscount; double totalcount; int nzeroes; DdLocalCacheItem *entry; FILE *fp = cache->manager->out; slots = cache->slots; meansq = mean = expected = 0.0; max = min = (long) cache->item[0].count; imax = imin = nzeroes = 0; totalcount = 0.0; hystogram = ABC_ALLOC(long, nbins); if (hystogram == NULL) { return(0); } for (i = 0; i < nbins; i++) { hystogram[i] = 0; } for (i = 0; i < slots; i++) { entry = (DdLocalCacheItem *) ((char *) cache->item + i * cache->itemsize); thiscount = (long) entry->count; if (thiscount > max) { max = thiscount; imax = i; } if (thiscount < min) { min = thiscount; imin = i; } if (thiscount == 0) { nzeroes++; } count = (double) thiscount; mean += count; meansq += count * count; totalcount += count; expected += count * (double) i; bin = (i * nbins) / slots; hystogram[bin] += thiscount; } mean /= (double) slots; meansq /= (double) slots; stddev = sqrt(meansq - mean*mean); retval = fprintf(fp,"Cache stats: slots = %d average = %g ", slots, mean); if (retval == EOF) return(0); retval = fprintf(fp,"standard deviation = %g\n", stddev); if (retval == EOF) return(0); retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax); if (retval == EOF) return(0); retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin); if (retval == EOF) return(0); retval = fprintf(fp,"Cache unused slots = %d\n", nzeroes); if (retval == EOF) return(0); if (totalcount) { expected /= totalcount; retval = fprintf(fp,"Cache access hystogram for %d bins", nbins); if (retval == EOF) return(0); retval = fprintf(fp," (expected bin value = %g)\n# ", expected); if (retval == EOF) return(0); for (i = nbins - 1; i>=0; i--) { retval = fprintf(fp,"%ld ", hystogram[i]); if (retval == EOF) return(0); } retval = fprintf(fp,"\n"); if (retval == EOF) return(0); } ABC_FREE(hystogram); return(1); } /* end of cuddLocalCacheProfile */ #endif /**Function******************************************************************** Synopsis [Initializes a hash table.] Description [Initializes a hash table. Returns a pointer to the new table if successful; NULL otherwise.] SideEffects [None] SeeAlso [cuddHashTableQuit] ******************************************************************************/ DdHashTable * cuddHashTableInit( DdManager * manager, unsigned int keySize, unsigned int initSize) { DdHashTable *hash; int logSize; #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif hash = ABC_ALLOC(DdHashTable, 1); if (hash == NULL) { manager->errorCode = CUDD_MEMORY_OUT; return(NULL); } hash->keysize = keySize; hash->manager = manager; hash->memoryList = NULL; hash->nextFree = NULL; hash->itemsize = (keySize + 1) * sizeof(DdNode *) + sizeof(ptrint) + sizeof(DdHashItem *); /* We have to guarantee that the shift be < 32. */ if (initSize < 2) initSize = 2; logSize = cuddComputeFloorLog2(initSize); hash->numBuckets = 1 << logSize; hash->shift = sizeof(int) * 8 - logSize; hash->bucket = ABC_ALLOC(DdHashItem *, hash->numBuckets); if (hash->bucket == NULL) { manager->errorCode = CUDD_MEMORY_OUT; ABC_FREE(hash); return(NULL); } memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *)); hash->size = 0; hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY; #ifdef __osf__ #pragma pointer_size restore #endif return(hash); } /* end of cuddHashTableInit */ /**Function******************************************************************** Synopsis [Shuts down a hash table.] Description [Shuts down a hash table, dereferencing all the values.] SideEffects [None] SeeAlso [cuddHashTableInit] ******************************************************************************/ void cuddHashTableQuit( DdHashTable * hash) { #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif unsigned int i; DdManager *dd = hash->manager; DdHashItem *bucket; DdHashItem **memlist, **nextmem; unsigned int numBuckets = hash->numBuckets; for (i = 0; i < numBuckets; i++) { bucket = hash->bucket[i]; while (bucket != NULL) { Cudd_RecursiveDeref(dd, bucket->value); bucket = bucket->next; } } memlist = hash->memoryList; while (memlist != NULL) { nextmem = (DdHashItem **) memlist[0]; ABC_FREE(memlist); memlist = nextmem; } ABC_FREE(hash->bucket); ABC_FREE(hash); #ifdef __osf__ #pragma pointer_size restore #endif return; } /* end of cuddHashTableQuit */ /**Function******************************************************************** Synopsis [Inserts an item in a hash table.] Description [Inserts an item in a hash table when the key has more than three pointers. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3 cuddHashTableLookup] ******************************************************************************/ int cuddHashTableInsert( DdHashTable * hash, DdNodePtr * key, DdNode * value, ptrint count) { int result; unsigned int posn; DdHashItem *item; unsigned int i; #ifdef DD_DEBUG assert(hash->keysize > 3); #endif if (hash->size > hash->maxsize) { result = cuddHashTableResize(hash); if (result == 0) return(0); } item = cuddHashTableAlloc(hash); if (item == NULL) return(0); hash->size++; item->value = value; cuddRef(value); item->count = count; for (i = 0; i < hash->keysize; i++) { item->key[i] = key[i]; } posn = ddLCHash(key,hash->keysize,hash->shift); item->next = hash->bucket[posn]; hash->bucket[posn] = item; return(1); } /* end of cuddHashTableInsert */ /**Function******************************************************************** Synopsis [Looks up a key in a hash table.] Description [Looks up a key consisting of more than three pointers in a hash table. Returns the value associated to the key if there is an entry for the given key in the table; NULL otherwise. If the entry is present, its reference counter is decremented if not saturated. If the counter reaches 0, the value of the entry is dereferenced, and the entry is returned to the free list.] SideEffects [None] SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3 cuddHashTableInsert] ******************************************************************************/ DdNode * cuddHashTableLookup( DdHashTable * hash, DdNodePtr * key) { unsigned int posn; DdHashItem *item, *prev; unsigned int i, keysize; #ifdef DD_DEBUG assert(hash->keysize > 3); #endif posn = ddLCHash(key,hash->keysize,hash->shift); item = hash->bucket[posn]; prev = NULL; keysize = hash->keysize; while (item != NULL) { DdNodePtr *key2 = item->key; int equal = 1; for (i = 0; i < keysize; i++) { if (key[i] != key2[i]) { equal = 0; break; } } if (equal) { DdNode *value = item->value; cuddSatDec(item->count); if (item->count == 0) { cuddDeref(value); if (prev == NULL) { hash->bucket[posn] = item->next; } else { prev->next = item->next; } item->next = hash->nextFree; hash->nextFree = item; hash->size--; } return(value); } prev = item; item = item->next; } return(NULL); } /* end of cuddHashTableLookup */ /**Function******************************************************************** Synopsis [Inserts an item in a hash table.] Description [Inserts an item in a hash table when the key is one pointer. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3 cuddHashTableLookup1] ******************************************************************************/ int cuddHashTableInsert1( DdHashTable * hash, DdNode * f, DdNode * value, ptrint count) { int result; unsigned int posn; DdHashItem *item; #ifdef DD_DEBUG assert(hash->keysize == 1); #endif if (hash->size > hash->maxsize) { result = cuddHashTableResize(hash); if (result == 0) return(0); } item = cuddHashTableAlloc(hash); if (item == NULL) return(0); hash->size++; item->value = value; cuddRef(value); item->count = count; item->key[0] = f; posn = ddLCHash2(cuddF2L(f),cuddF2L(f),hash->shift); item->next = hash->bucket[posn]; hash->bucket[posn] = item; return(1); } /* end of cuddHashTableInsert1 */ /**Function******************************************************************** Synopsis [Looks up a key consisting of one pointer in a hash table.] Description [Looks up a key consisting of one pointer in a hash table. Returns the value associated to the key if there is an entry for the given key in the table; NULL otherwise. If the entry is present, its reference counter is decremented if not saturated. If the counter reaches 0, the value of the entry is dereferenced, and the entry is returned to the free list.] SideEffects [None] SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3 cuddHashTableInsert1] ******************************************************************************/ DdNode * cuddHashTableLookup1( DdHashTable * hash, DdNode * f) { unsigned int posn; DdHashItem *item, *prev; #ifdef DD_DEBUG assert(hash->keysize == 1); #endif posn = ddLCHash2(cuddF2L(f),cuddF2L(f),hash->shift); item = hash->bucket[posn]; prev = NULL; while (item != NULL) { DdNodePtr *key = item->key; if (f == key[0]) { DdNode *value = item->value; cuddSatDec(item->count); if (item->count == 0) { cuddDeref(value); if (prev == NULL) { hash->bucket[posn] = item->next; } else { prev->next = item->next; } item->next = hash->nextFree; hash->nextFree = item; hash->size--; } return(value); } prev = item; item = item->next; } return(NULL); } /* end of cuddHashTableLookup1 */ /**Function******************************************************************** Synopsis [Inserts an item in a hash table.] Description [Inserts an item in a hash table when the key is composed of two pointers. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3 cuddHashTableLookup2] ******************************************************************************/ int cuddHashTableInsert2( DdHashTable * hash, DdNode * f, DdNode * g, DdNode * value, ptrint count) { int result; unsigned int posn; DdHashItem *item; #ifdef DD_DEBUG assert(hash->keysize == 2); #endif if (hash->size > hash->maxsize) { result = cuddHashTableResize(hash); if (result == 0) return(0); } item = cuddHashTableAlloc(hash); if (item == NULL) return(0); hash->size++; item->value = value; cuddRef(value); item->count = count; item->key[0] = f; item->key[1] = g; posn = ddLCHash2(cuddF2L(f),cuddF2L(g),hash->shift); item->next = hash->bucket[posn]; hash->bucket[posn] = item; return(1); } /* end of cuddHashTableInsert2 */ /**Function******************************************************************** Synopsis [Looks up a key consisting of two pointers in a hash table.] Description [Looks up a key consisting of two pointer in a hash table. Returns the value associated to the key if there is an entry for the given key in the table; NULL otherwise. If the entry is present, its reference counter is decremented if not saturated. If the counter reaches 0, the value of the entry is dereferenced, and the entry is returned to the free list.] SideEffects [None] SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3 cuddHashTableInsert2] ******************************************************************************/ DdNode * cuddHashTableLookup2( DdHashTable * hash, DdNode * f, DdNode * g) { unsigned int posn; DdHashItem *item, *prev; #ifdef DD_DEBUG assert(hash->keysize == 2); #endif posn = ddLCHash2(cuddF2L(f),cuddF2L(g),hash->shift); item = hash->bucket[posn]; prev = NULL; while (item != NULL) { DdNodePtr *key = item->key; if ((f == key[0]) && (g == key[1])) { DdNode *value = item->value; cuddSatDec(item->count); if (item->count == 0) { cuddDeref(value); if (prev == NULL) { hash->bucket[posn] = item->next; } else { prev->next = item->next; } item->next = hash->nextFree; hash->nextFree = item; hash->size--; } return(value); } prev = item; item = item->next; } return(NULL); } /* end of cuddHashTableLookup2 */ /**Function******************************************************************** Synopsis [Inserts an item in a hash table.] Description [Inserts an item in a hash table when the key is composed of three pointers. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableLookup3] ******************************************************************************/ int cuddHashTableInsert3( DdHashTable * hash, DdNode * f, DdNode * g, DdNode * h, DdNode * value, ptrint count) { int result; unsigned int posn; DdHashItem *item; #ifdef DD_DEBUG assert(hash->keysize == 3); #endif if (hash->size > hash->maxsize) { result = cuddHashTableResize(hash); if (result == 0) return(0); } item = cuddHashTableAlloc(hash); if (item == NULL) return(0); hash->size++; item->value = value; cuddRef(value); item->count = count; item->key[0] = f; item->key[1] = g; item->key[2] = h; posn = ddLCHash3(cuddF2L(f),cuddF2L(g),cuddF2L(h),hash->shift); item->next = hash->bucket[posn]; hash->bucket[posn] = item; return(1); } /* end of cuddHashTableInsert3 */ /**Function******************************************************************** Synopsis [Looks up a key consisting of three pointers in a hash table.] Description [Looks up a key consisting of three pointers in a hash table. Returns the value associated to the key if there is an entry for the given key in the table; NULL otherwise. If the entry is present, its reference counter is decremented if not saturated. If the counter reaches 0, the value of the entry is dereferenced, and the entry is returned to the free list.] SideEffects [None] SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableInsert3] ******************************************************************************/ DdNode * cuddHashTableLookup3( DdHashTable * hash, DdNode * f, DdNode * g, DdNode * h) { unsigned int posn; DdHashItem *item, *prev; #ifdef DD_DEBUG assert(hash->keysize == 3); #endif posn = ddLCHash3(cuddF2L(f),cuddF2L(g),cuddF2L(h),hash->shift); item = hash->bucket[posn]; prev = NULL; while (item != NULL) { DdNodePtr *key = item->key; if ((f == key[0]) && (g == key[1]) && (h == key[2])) { DdNode *value = item->value; cuddSatDec(item->count); if (item->count == 0) { cuddDeref(value); if (prev == NULL) { hash->bucket[posn] = item->next; } else { prev->next = item->next; } item->next = hash->nextFree; hash->nextFree = item; hash->size--; } return(value); } prev = item; item = item->next; } return(NULL); } /* end of cuddHashTableLookup3 */ /*---------------------------------------------------------------------------*/ /* Definition of static functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Resizes a local cache.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static void cuddLocalCacheResize( DdLocalCache * cache) { DdLocalCacheItem *item, *olditem, *entry, *old; int i, shift; unsigned int posn; unsigned int slots, oldslots; extern DD_OOMFP MMoutOfMemory; DD_OOMFP saveHandler; olditem = cache->item; oldslots = cache->slots; slots = cache->slots = oldslots << 1; #ifdef DD_VERBOSE (void) fprintf(cache->manager->err, "Resizing local cache from %d to %d entries\n", oldslots, slots); (void) fprintf(cache->manager->err, "\thits = %.0f\tlookups = %.0f\thit ratio = %5.3f\n", cache->hits, cache->lookUps, cache->hits / cache->lookUps); #endif saveHandler = MMoutOfMemory; MMoutOfMemory = Cudd_OutOfMem; cache->item = item = (DdLocalCacheItem *) ABC_ALLOC(char, slots * cache->itemsize); MMoutOfMemory = saveHandler; /* If we fail to allocate the new table we just give up. */ if (item == NULL) { #ifdef DD_VERBOSE (void) fprintf(cache->manager->err,"Resizing failed. Giving up.\n"); #endif cache->slots = oldslots; cache->item = olditem; /* Do not try to resize again. */ cache->maxslots = oldslots - 1; return; } shift = --(cache->shift); cache->manager->memused += (slots - oldslots) * cache->itemsize; /* Clear new cache. */ memset(item, 0, slots * cache->itemsize); /* Copy from old cache to new one. */ for (i = 0; (unsigned) i < oldslots; i++) { old = (DdLocalCacheItem *) ((char *) olditem + i * cache->itemsize); if (old->value != NULL) { posn = ddLCHash(old->key,cache->keysize,shift); entry = (DdLocalCacheItem *) ((char *) item + posn * cache->itemsize); memcpy(entry->key,old->key,cache->keysize*sizeof(DdNode *)); entry->value = old->value; } } ABC_FREE(olditem); /* Reinitialize measurements so as to avoid division by 0 and ** immediate resizing. */ cache->lookUps = (double) (int) (slots * cache->minHit + 1); cache->hits = 0; } /* end of cuddLocalCacheResize */ /**Function******************************************************************** Synopsis [Computes the hash value for a local cache.] Description [Computes the hash value for a local cache. Returns the bucket index.] SideEffects [None] SeeAlso [] ******************************************************************************/ DD_INLINE static unsigned int ddLCHash( DdNodePtr * key, unsigned int keysize, int shift) { unsigned int val = (unsigned int) (ptrint) key[0] * DD_P2; unsigned int i; for (i = 1; i < keysize; i++) { val = val * DD_P1 + (int) (ptrint) key[i]; } return(val >> shift); } /* end of ddLCHash */ /**Function******************************************************************** Synopsis [Inserts a local cache in the manager list.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static void cuddLocalCacheAddToList( DdLocalCache * cache) { DdManager *manager = cache->manager; cache->next = manager->localCaches; manager->localCaches = cache; return; } /* end of cuddLocalCacheAddToList */ /**Function******************************************************************** Synopsis [Removes a local cache from the manager list.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static void cuddLocalCacheRemoveFromList( DdLocalCache * cache) { DdManager *manager = cache->manager; #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif DdLocalCache **prevCache, *nextCache; #ifdef __osf__ #pragma pointer_size restore #endif prevCache = &(manager->localCaches); nextCache = manager->localCaches; while (nextCache != NULL) { if (nextCache == cache) { *prevCache = nextCache->next; return; } prevCache = &(nextCache->next); nextCache = nextCache->next; } return; /* should never get here */ } /* end of cuddLocalCacheRemoveFromList */ /**Function******************************************************************** Synopsis [Resizes a hash table.] Description [Resizes a hash table. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddHashTableInsert] ******************************************************************************/ static int cuddHashTableResize( DdHashTable * hash) { int j; unsigned int posn; DdHashItem *item; DdHashItem *next; #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif DdNode **key; int numBuckets; DdHashItem **buckets; DdHashItem **oldBuckets = hash->bucket; #ifdef __osf__ #pragma pointer_size restore #endif int shift; int oldNumBuckets = hash->numBuckets; extern DD_OOMFP MMoutOfMemory; DD_OOMFP saveHandler; /* Compute the new size of the table. */ numBuckets = oldNumBuckets << 1; saveHandler = MMoutOfMemory; MMoutOfMemory = Cudd_OutOfMem; #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif buckets = ABC_ALLOC(DdHashItem *, numBuckets); MMoutOfMemory = saveHandler; if (buckets == NULL) { hash->maxsize <<= 1; return(1); } hash->bucket = buckets; hash->numBuckets = numBuckets; shift = --(hash->shift); hash->maxsize <<= 1; memset(buckets, 0, numBuckets * sizeof(DdHashItem *)); #ifdef __osf__ #pragma pointer_size restore #endif if (hash->keysize == 1) { for (j = 0; j < oldNumBuckets; j++) { item = oldBuckets[j]; while (item != NULL) { next = item->next; key = item->key; posn = ddLCHash2(cuddF2L(key[0]), cuddF2L(key[0]), shift); item->next = buckets[posn]; buckets[posn] = item; item = next; } } } else if (hash->keysize == 2) { for (j = 0; j < oldNumBuckets; j++) { item = oldBuckets[j]; while (item != NULL) { next = item->next; key = item->key; posn = ddLCHash2(cuddF2L(key[0]), cuddF2L(key[1]), shift); item->next = buckets[posn]; buckets[posn] = item; item = next; } } } else if (hash->keysize == 3) { for (j = 0; j < oldNumBuckets; j++) { item = oldBuckets[j]; while (item != NULL) { next = item->next; key = item->key; posn = ddLCHash3(cuddF2L(key[0]), cuddF2L(key[1]), cuddF2L(key[2]), shift); item->next = buckets[posn]; buckets[posn] = item; item = next; } } } else { for (j = 0; j < oldNumBuckets; j++) { item = oldBuckets[j]; while (item != NULL) { next = item->next; posn = ddLCHash(item->key, hash->keysize, shift); item->next = buckets[posn]; buckets[posn] = item; item = next; } } } ABC_FREE(oldBuckets); return(1); } /* end of cuddHashTableResize */ /**Function******************************************************************** Synopsis [Fast storage allocation for items in a hash table.] Description [Fast storage allocation for items in a hash table. The first 4 bytes of a chunk contain a pointer to the next block; the rest contains DD_MEM_CHUNK spaces for hash items. Returns a pointer to a new item if successful; NULL is memory is full.] SideEffects [None] SeeAlso [cuddAllocNode cuddDynamicAllocNode] ******************************************************************************/ DD_INLINE static DdHashItem * cuddHashTableAlloc( DdHashTable * hash) { int i; unsigned int itemsize = hash->itemsize; extern DD_OOMFP MMoutOfMemory; DD_OOMFP saveHandler; #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif DdHashItem **mem, *thisOne, *next, *item; if (hash->nextFree == NULL) { saveHandler = MMoutOfMemory; MMoutOfMemory = Cudd_OutOfMem; mem = (DdHashItem **) ABC_ALLOC(char,(DD_MEM_CHUNK+1) * itemsize); MMoutOfMemory = saveHandler; #ifdef __osf__ #pragma pointer_size restore #endif if (mem == NULL) { if (hash->manager->stash != NULL) { ABC_FREE(hash->manager->stash); hash->manager->stash = NULL; /* Inhibit resizing of tables. */ hash->manager->maxCacheHard = hash->manager->cacheSlots - 1; hash->manager->cacheSlack = - (int) (hash->manager->cacheSlots + 1); for (i = 0; i < hash->manager->size; i++) { hash->manager->subtables[i].maxKeys <<= 2; } hash->manager->gcFrac = 0.2; hash->manager->minDead = (unsigned) (0.2 * (double) hash->manager->slots); #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif mem = (DdHashItem **) ABC_ALLOC(char,(DD_MEM_CHUNK+1) * itemsize); #ifdef __osf__ #pragma pointer_size restore #endif } if (mem == NULL) { (*MMoutOfMemory)((long)((DD_MEM_CHUNK + 1) * itemsize)); hash->manager->errorCode = CUDD_MEMORY_OUT; return(NULL); } } mem[0] = (DdHashItem *) hash->memoryList; hash->memoryList = mem; thisOne = (DdHashItem *) ((char *) mem + itemsize); hash->nextFree = thisOne; for (i = 1; i < DD_MEM_CHUNK; i++) { next = (DdHashItem *) ((char *) thisOne + itemsize); thisOne->next = next; thisOne = next; } thisOne->next = NULL; } item = hash->nextFree; hash->nextFree = item->next; return(item); } /* end of cuddHashTableAlloc */ ABC_NAMESPACE_IMPL_END