You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1557 lines
40 KiB

  1. /**CFile***********************************************************************
  2. FileName [cuddLCache.c]
  3. PackageName [cudd]
  4. Synopsis [Functions for local caches.]
  5. Description [Internal procedures included in this module:
  6. <ul>
  7. <li> cuddLocalCacheInit()
  8. <li> cuddLocalCacheQuit()
  9. <li> cuddLocalCacheInsert()
  10. <li> cuddLocalCacheLookup()
  11. <li> cuddLocalCacheClearDead()
  12. <li> cuddLocalCacheClearAll()
  13. <li> cuddLocalCacheProfile()
  14. <li> cuddHashTableInit()
  15. <li> cuddHashTableQuit()
  16. <li> cuddHashTableGenericQuit()
  17. <li> cuddHashTableInsert()
  18. <li> cuddHashTableLookup()
  19. <li> cuddHashTableGenericInsert()
  20. <li> cuddHashTableGenericLookup()
  21. <li> cuddHashTableInsert2()
  22. <li> cuddHashTableLookup2()
  23. <li> cuddHashTableInsert3()
  24. <li> cuddHashTableLookup3()
  25. </ul>
  26. Static procedures included in this module:
  27. <ul>
  28. <li> cuddLocalCacheResize()
  29. <li> ddLCHash()
  30. <li> cuddLocalCacheAddToList()
  31. <li> cuddLocalCacheRemoveFromList()
  32. <li> cuddHashTableResize()
  33. <li> cuddHashTableAlloc()
  34. </ul> ]
  35. SeeAlso []
  36. Author [Fabio Somenzi]
  37. Copyright [Copyright (c) 1995-2012, Regents of the University of Colorado
  38. All rights reserved.
  39. Redistribution and use in source and binary forms, with or without
  40. modification, are permitted provided that the following conditions
  41. are met:
  42. Redistributions of source code must retain the above copyright
  43. notice, this list of conditions and the following disclaimer.
  44. Redistributions in binary form must reproduce the above copyright
  45. notice, this list of conditions and the following disclaimer in the
  46. documentation and/or other materials provided with the distribution.
  47. Neither the name of the University of Colorado nor the names of its
  48. contributors may be used to endorse or promote products derived from
  49. this software without specific prior written permission.
  50. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  51. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  52. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  53. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  54. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  55. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  56. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  57. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  58. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  59. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  60. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  61. POSSIBILITY OF SUCH DAMAGE.]
  62. ******************************************************************************/
  63. #include "util.h"
  64. #include "cuddInt.h"
  65. /*---------------------------------------------------------------------------*/
  66. /* Constant declarations */
  67. /*---------------------------------------------------------------------------*/
  68. #define DD_MAX_HASHTABLE_DENSITY 2 /* tells when to resize a table */
  69. /*---------------------------------------------------------------------------*/
  70. /* Stucture declarations */
  71. /*---------------------------------------------------------------------------*/
  72. /*---------------------------------------------------------------------------*/
  73. /* Type declarations */
  74. /*---------------------------------------------------------------------------*/
  75. /*---------------------------------------------------------------------------*/
  76. /* Variable declarations */
  77. /*---------------------------------------------------------------------------*/
  78. #ifndef lint
  79. static char rcsid[] DD_UNUSED = "$Id: cuddLCache.c,v 1.27 2012/02/05 01:07:19 fabio Exp $";
  80. #endif
  81. /*---------------------------------------------------------------------------*/
  82. /* Macro declarations */
  83. /*---------------------------------------------------------------------------*/
  84. /**Macro***********************************************************************
  85. Synopsis [Computes hash function for keys of one operand.]
  86. Description []
  87. SideEffects [None]
  88. SeeAlso [ddLCHash3 ddLCHash]
  89. ******************************************************************************/
  90. #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
  91. #define ddLCHash1(f,shift) \
  92. (((unsigned)(ptruint)(f) * DD_P1) >> (shift))
  93. #else
  94. #define ddLCHash1(f,shift) \
  95. (((unsigned)(f) * DD_P1) >> (shift))
  96. #endif
  97. /**Macro***********************************************************************
  98. Synopsis [Computes hash function for keys of two operands.]
  99. Description []
  100. SideEffects [None]
  101. SeeAlso [ddLCHash3 ddLCHash]
  102. ******************************************************************************/
  103. #if SIZEOF_VOID_P == 8 && SIZEOF_INT == 4
  104. #define ddLCHash2(f,g,shift) \
  105. ((((unsigned)(ptruint)(f) * DD_P1 + \
  106. (unsigned)(ptruint)(g)) * DD_P2) >> (shift))
  107. #else
  108. #define ddLCHash2(f,g,shift) \
  109. ((((unsigned)(f) * DD_P1 + (unsigned)(g)) * DD_P2) >> (shift))
  110. #endif
  111. /**Macro***********************************************************************
  112. Synopsis [Computes hash function for keys of three operands.]
  113. Description []
  114. SideEffects [None]
  115. SeeAlso [ddLCHash2 ddLCHash]
  116. ******************************************************************************/
  117. #define ddLCHash3(f,g,h,shift) ddCHash2(f,g,h,shift)
  118. /**AutomaticStart*************************************************************/
  119. /*---------------------------------------------------------------------------*/
  120. /* Static function prototypes */
  121. /*---------------------------------------------------------------------------*/
  122. static void cuddLocalCacheResize (DdLocalCache *cache);
  123. DD_INLINE static unsigned int ddLCHash (DdNodePtr *key, unsigned int keysize, int shift);
  124. static void cuddLocalCacheAddToList (DdLocalCache *cache);
  125. static void cuddLocalCacheRemoveFromList (DdLocalCache *cache);
  126. static int cuddHashTableResize (DdHashTable *hash);
  127. DD_INLINE static DdHashItem * cuddHashTableAlloc (DdHashTable *hash);
  128. /**AutomaticEnd***************************************************************/
  129. /*---------------------------------------------------------------------------*/
  130. /* Definition of exported functions */
  131. /*---------------------------------------------------------------------------*/
  132. /*---------------------------------------------------------------------------*/
  133. /* Definition of internal functions */
  134. /*---------------------------------------------------------------------------*/
  135. /**Function********************************************************************
  136. Synopsis [Initializes a local computed table.]
  137. Description [Initializes a computed table. Returns a pointer the
  138. the new local cache in case of success; NULL otherwise.]
  139. SideEffects [None]
  140. SeeAlso [cuddInitCache]
  141. ******************************************************************************/
  142. DdLocalCache *
  143. cuddLocalCacheInit(
  144. DdManager * manager /* manager */,
  145. unsigned int keySize /* size of the key (number of operands) */,
  146. unsigned int cacheSize /* Initial size of the cache */,
  147. unsigned int maxCacheSize /* Size of the cache beyond which no resizing occurs */)
  148. {
  149. DdLocalCache *cache;
  150. int logSize;
  151. cache = ALLOC(DdLocalCache,1);
  152. if (cache == NULL) {
  153. manager->errorCode = CUDD_MEMORY_OUT;
  154. return(NULL);
  155. }
  156. cache->manager = manager;
  157. cache->keysize = keySize;
  158. cache->itemsize = (keySize + 1) * sizeof(DdNode *);
  159. #ifdef DD_CACHE_PROFILE
  160. cache->itemsize += sizeof(ptrint);
  161. #endif
  162. logSize = cuddComputeFloorLog2(ddMax(cacheSize,manager->slots/2));
  163. cacheSize = 1 << logSize;
  164. cache->item = (DdLocalCacheItem *)
  165. ALLOC(char, cacheSize * cache->itemsize);
  166. if (cache->item == NULL) {
  167. manager->errorCode = CUDD_MEMORY_OUT;
  168. FREE(cache);
  169. return(NULL);
  170. }
  171. cache->slots = cacheSize;
  172. cache->shift = sizeof(int) * 8 - logSize;
  173. cache->maxslots = ddMin(maxCacheSize,manager->slots);
  174. cache->minHit = manager->minHit;
  175. /* Initialize to avoid division by 0 and immediate resizing. */
  176. cache->lookUps = (double) (int) (cacheSize * cache->minHit + 1);
  177. cache->hits = 0;
  178. manager->memused += cacheSize * cache->itemsize + sizeof(DdLocalCache);
  179. /* Initialize the cache. */
  180. memset(cache->item, 0, cacheSize * cache->itemsize);
  181. /* Add to manager's list of local caches for GC. */
  182. cuddLocalCacheAddToList(cache);
  183. return(cache);
  184. } /* end of cuddLocalCacheInit */
  185. /**Function********************************************************************
  186. Synopsis [Shuts down a local computed table.]
  187. Description [Initializes the computed table. It is called by
  188. Cudd_Init. Returns a pointer the the new local cache in case of
  189. success; NULL otherwise.]
  190. SideEffects [None]
  191. SeeAlso [cuddLocalCacheInit]
  192. ******************************************************************************/
  193. void
  194. cuddLocalCacheQuit(
  195. DdLocalCache * cache /* cache to be shut down */)
  196. {
  197. cache->manager->memused -=
  198. cache->slots * cache->itemsize + sizeof(DdLocalCache);
  199. cuddLocalCacheRemoveFromList(cache);
  200. FREE(cache->item);
  201. FREE(cache);
  202. return;
  203. } /* end of cuddLocalCacheQuit */
  204. /**Function********************************************************************
  205. Synopsis [Inserts a result in a local cache.]
  206. Description []
  207. SideEffects [None]
  208. SeeAlso []
  209. ******************************************************************************/
  210. void
  211. cuddLocalCacheInsert(
  212. DdLocalCache * cache,
  213. DdNodePtr * key,
  214. DdNode * value)
  215. {
  216. unsigned int posn;
  217. DdLocalCacheItem *entry;
  218. posn = ddLCHash(key,cache->keysize,cache->shift);
  219. entry = (DdLocalCacheItem *) ((char *) cache->item +
  220. posn * cache->itemsize);
  221. memcpy(entry->key,key,cache->keysize * sizeof(DdNode *));
  222. entry->value = value;
  223. #ifdef DD_CACHE_PROFILE
  224. entry->count++;
  225. #endif
  226. } /* end of cuddLocalCacheInsert */
  227. /**Function********************************************************************
  228. Synopsis [Looks up in a local cache.]
  229. Description [Looks up in a local cache. Returns the result if found;
  230. it returns NULL if no result is found.]
  231. SideEffects [None]
  232. SeeAlso []
  233. ******************************************************************************/
  234. DdNode *
  235. cuddLocalCacheLookup(
  236. DdLocalCache * cache,
  237. DdNodePtr * key)
  238. {
  239. unsigned int posn;
  240. DdLocalCacheItem *entry;
  241. DdNode *value;
  242. cache->lookUps++;
  243. posn = ddLCHash(key,cache->keysize,cache->shift);
  244. entry = (DdLocalCacheItem *) ((char *) cache->item +
  245. posn * cache->itemsize);
  246. if (entry->value != NULL &&
  247. memcmp(key,entry->key,cache->keysize*sizeof(DdNode *)) == 0) {
  248. cache->hits++;
  249. value = Cudd_Regular(entry->value);
  250. if (value->ref == 0) {
  251. cuddReclaim(cache->manager,value);
  252. }
  253. return(entry->value);
  254. }
  255. /* Cache miss: decide whether to resize */
  256. if (cache->slots < cache->maxslots &&
  257. cache->hits > cache->lookUps * cache->minHit) {
  258. cuddLocalCacheResize(cache);
  259. }
  260. return(NULL);
  261. } /* end of cuddLocalCacheLookup */
  262. /**Function********************************************************************
  263. Synopsis [Clears the dead entries of the local caches of a manager.]
  264. Description [Clears the dead entries of the local caches of a manager.
  265. Used during garbage collection.]
  266. SideEffects [None]
  267. SeeAlso []
  268. ******************************************************************************/
  269. void
  270. cuddLocalCacheClearDead(
  271. DdManager * manager)
  272. {
  273. DdLocalCache *cache = manager->localCaches;
  274. unsigned int keysize;
  275. unsigned int itemsize;
  276. unsigned int slots;
  277. DdLocalCacheItem *item;
  278. DdNodePtr *key;
  279. unsigned int i, j;
  280. while (cache != NULL) {
  281. keysize = cache->keysize;
  282. itemsize = cache->itemsize;
  283. slots = cache->slots;
  284. item = cache->item;
  285. for (i = 0; i < slots; i++) {
  286. if (item->value != NULL) {
  287. if (Cudd_Regular(item->value)->ref == 0) {
  288. item->value = NULL;
  289. } else {
  290. key = item->key;
  291. for (j = 0; j < keysize; j++) {
  292. if (Cudd_Regular(key[j])->ref == 0) {
  293. item->value = NULL;
  294. break;
  295. }
  296. }
  297. }
  298. }
  299. item = (DdLocalCacheItem *) ((char *) item + itemsize);
  300. }
  301. cache = cache->next;
  302. }
  303. return;
  304. } /* end of cuddLocalCacheClearDead */
  305. /**Function********************************************************************
  306. Synopsis [Clears the local caches of a manager.]
  307. Description [Clears the local caches of a manager.
  308. Used before reordering.]
  309. SideEffects [None]
  310. SeeAlso []
  311. ******************************************************************************/
  312. void
  313. cuddLocalCacheClearAll(
  314. DdManager * manager)
  315. {
  316. DdLocalCache *cache = manager->localCaches;
  317. while (cache != NULL) {
  318. memset(cache->item, 0, cache->slots * cache->itemsize);
  319. cache = cache->next;
  320. }
  321. return;
  322. } /* end of cuddLocalCacheClearAll */
  323. #ifdef DD_CACHE_PROFILE
  324. #define DD_HYSTO_BINS 8
  325. /**Function********************************************************************
  326. Synopsis [Computes and prints a profile of a local cache usage.]
  327. Description [Computes and prints a profile of a local cache usage.
  328. Returns 1 if successful; 0 otherwise.]
  329. SideEffects [None]
  330. SeeAlso []
  331. ******************************************************************************/
  332. int
  333. cuddLocalCacheProfile(
  334. DdLocalCache * cache)
  335. {
  336. double count, mean, meansq, stddev, expected;
  337. long max, min;
  338. int imax, imin;
  339. int i, retval, slots;
  340. long *hystogram;
  341. int nbins = DD_HYSTO_BINS;
  342. int bin;
  343. long thiscount;
  344. double totalcount;
  345. int nzeroes;
  346. DdLocalCacheItem *entry;
  347. FILE *fp = cache->manager->out;
  348. slots = cache->slots;
  349. meansq = mean = expected = 0.0;
  350. max = min = (long) cache->item[0].count;
  351. imax = imin = nzeroes = 0;
  352. totalcount = 0.0;
  353. hystogram = ALLOC(long, nbins);
  354. if (hystogram == NULL) {
  355. return(0);
  356. }
  357. for (i = 0; i < nbins; i++) {
  358. hystogram[i] = 0;
  359. }
  360. for (i = 0; i < slots; i++) {
  361. entry = (DdLocalCacheItem *) ((char *) cache->item +
  362. i * cache->itemsize);
  363. thiscount = (long) entry->count;
  364. if (thiscount > max) {
  365. max = thiscount;
  366. imax = i;
  367. }
  368. if (thiscount < min) {
  369. min = thiscount;
  370. imin = i;
  371. }
  372. if (thiscount == 0) {
  373. nzeroes++;
  374. }
  375. count = (double) thiscount;
  376. mean += count;
  377. meansq += count * count;
  378. totalcount += count;
  379. expected += count * (double) i;
  380. bin = (i * nbins) / slots;
  381. hystogram[bin] += thiscount;
  382. }
  383. mean /= (double) slots;
  384. meansq /= (double) slots;
  385. stddev = sqrt(meansq - mean*mean);
  386. retval = fprintf(fp,"Cache stats: slots = %d average = %g ", slots, mean);
  387. if (retval == EOF) return(0);
  388. retval = fprintf(fp,"standard deviation = %g\n", stddev);
  389. if (retval == EOF) return(0);
  390. retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
  391. if (retval == EOF) return(0);
  392. retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
  393. if (retval == EOF) return(0);
  394. retval = fprintf(fp,"Cache unused slots = %d\n", nzeroes);
  395. if (retval == EOF) return(0);
  396. if (totalcount) {
  397. expected /= totalcount;
  398. retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
  399. if (retval == EOF) return(0);
  400. retval = fprintf(fp," (expected bin value = %g)\n# ", expected);
  401. if (retval == EOF) return(0);
  402. for (i = nbins - 1; i>=0; i--) {
  403. retval = fprintf(fp,"%ld ", hystogram[i]);
  404. if (retval == EOF) return(0);
  405. }
  406. retval = fprintf(fp,"\n");
  407. if (retval == EOF) return(0);
  408. }
  409. FREE(hystogram);
  410. return(1);
  411. } /* end of cuddLocalCacheProfile */
  412. #endif
  413. /**Function********************************************************************
  414. Synopsis [Initializes a hash table.]
  415. Description [Initializes a hash table. Returns a pointer to the new
  416. table if successful; NULL otherwise.]
  417. SideEffects [None]
  418. SeeAlso [cuddHashTableQuit]
  419. ******************************************************************************/
  420. DdHashTable *
  421. cuddHashTableInit(
  422. DdManager * manager,
  423. unsigned int keySize,
  424. unsigned int initSize)
  425. {
  426. DdHashTable *hash;
  427. int logSize;
  428. hash = ALLOC(DdHashTable, 1);
  429. if (hash == NULL) {
  430. manager->errorCode = CUDD_MEMORY_OUT;
  431. return(NULL);
  432. }
  433. hash->keysize = keySize;
  434. hash->manager = manager;
  435. hash->memoryList = NULL;
  436. hash->nextFree = NULL;
  437. hash->itemsize = (keySize + 1) * sizeof(DdNode *) +
  438. sizeof(ptrint) + sizeof(DdHashItem *);
  439. /* We have to guarantee that the shift be < 32. */
  440. if (initSize < 2) initSize = 2;
  441. logSize = cuddComputeFloorLog2(initSize);
  442. hash->numBuckets = 1 << logSize;
  443. hash->shift = sizeof(int) * 8 - logSize;
  444. hash->bucket = ALLOC(DdHashItem *, hash->numBuckets);
  445. if (hash->bucket == NULL) {
  446. manager->errorCode = CUDD_MEMORY_OUT;
  447. FREE(hash);
  448. return(NULL);
  449. }
  450. memset(hash->bucket, 0, hash->numBuckets * sizeof(DdHashItem *));
  451. hash->size = 0;
  452. hash->maxsize = hash->numBuckets * DD_MAX_HASHTABLE_DENSITY;
  453. return(hash);
  454. } /* end of cuddHashTableInit */
  455. /**Function********************************************************************
  456. Synopsis [Shuts down a hash table.]
  457. Description [Shuts down a hash table, dereferencing all the values.]
  458. SideEffects [None]
  459. SeeAlso [cuddHashTableInit]
  460. ******************************************************************************/
  461. void
  462. cuddHashTableQuit(
  463. DdHashTable * hash)
  464. {
  465. unsigned int i;
  466. DdManager *dd = hash->manager;
  467. DdHashItem *bucket;
  468. DdHashItem **memlist, **nextmem;
  469. unsigned int numBuckets = hash->numBuckets;
  470. for (i = 0; i < numBuckets; i++) {
  471. bucket = hash->bucket[i];
  472. while (bucket != NULL) {
  473. Cudd_RecursiveDeref(dd, bucket->value);
  474. bucket = bucket->next;
  475. }
  476. }
  477. memlist = hash->memoryList;
  478. while (memlist != NULL) {
  479. nextmem = (DdHashItem **) memlist[0];
  480. FREE(memlist);
  481. memlist = nextmem;
  482. }
  483. FREE(hash->bucket);
  484. FREE(hash);
  485. return;
  486. } /* end of cuddHashTableQuit */
  487. /**Function********************************************************************
  488. Synopsis [Shuts down a hash table.]
  489. Description [Shuts down a hash table, when the values are not DdNode
  490. pointers.]
  491. SideEffects [None]
  492. SeeAlso [cuddHashTableInit]
  493. ******************************************************************************/
  494. void
  495. cuddHashTableGenericQuit(
  496. DdHashTable * hash)
  497. {
  498. #ifdef __osf__
  499. #pragma pointer_size save
  500. #pragma pointer_size short
  501. #endif
  502. DdHashItem **memlist, **nextmem;
  503. memlist = hash->memoryList;
  504. while (memlist != NULL) {
  505. nextmem = (DdHashItem **) memlist[0];
  506. FREE(memlist);
  507. memlist = nextmem;
  508. }
  509. FREE(hash->bucket);
  510. FREE(hash);
  511. #ifdef __osf__
  512. #pragma pointer_size restore
  513. #endif
  514. return;
  515. } /* end of cuddHashTableGenericQuit */
  516. /**Function********************************************************************
  517. Synopsis [Inserts an item in a hash table.]
  518. Description [Inserts an item in a hash table when the key has more than
  519. three pointers. Returns 1 if successful; 0 otherwise.]
  520. SideEffects [None]
  521. SeeAlso [[cuddHashTableInsert1 cuddHashTableInsert2 cuddHashTableInsert3
  522. cuddHashTableLookup]
  523. ******************************************************************************/
  524. int
  525. cuddHashTableInsert(
  526. DdHashTable * hash,
  527. DdNodePtr * key,
  528. DdNode * value,
  529. ptrint count)
  530. {
  531. int result;
  532. unsigned int posn;
  533. DdHashItem *item;
  534. unsigned int i;
  535. #ifdef DD_DEBUG
  536. assert(hash->keysize > 3);
  537. #endif
  538. if (hash->size > hash->maxsize) {
  539. result = cuddHashTableResize(hash);
  540. if (result == 0) return(0);
  541. }
  542. item = cuddHashTableAlloc(hash);
  543. if (item == NULL) return(0);
  544. hash->size++;
  545. item->value = value;
  546. cuddRef(value);
  547. item->count = count;
  548. for (i = 0; i < hash->keysize; i++) {
  549. item->key[i] = key[i];
  550. }
  551. posn = ddLCHash(key,hash->keysize,hash->shift);
  552. item->next = hash->bucket[posn];
  553. hash->bucket[posn] = item;
  554. return(1);
  555. } /* end of cuddHashTableInsert */
  556. /**Function********************************************************************
  557. Synopsis [Looks up a key in a hash table.]
  558. Description [Looks up a key consisting of more than three pointers
  559. in a hash table. Returns the value associated to the key if there
  560. is an entry for the given key in the table; NULL otherwise. If the
  561. entry is present, its reference counter is decremented if not
  562. saturated. If the counter reaches 0, the value of the entry is
  563. dereferenced, and the entry is returned to the free list.]
  564. SideEffects [None]
  565. SeeAlso [cuddHashTableLookup1 cuddHashTableLookup2 cuddHashTableLookup3
  566. cuddHashTableInsert]
  567. ******************************************************************************/
  568. DdNode *
  569. cuddHashTableLookup(
  570. DdHashTable * hash,
  571. DdNodePtr * key)
  572. {
  573. unsigned int posn;
  574. DdHashItem *item, *prev;
  575. unsigned int i, keysize;
  576. #ifdef DD_DEBUG
  577. assert(hash->keysize > 3);
  578. #endif
  579. posn = ddLCHash(key,hash->keysize,hash->shift);
  580. item = hash->bucket[posn];
  581. prev = NULL;
  582. keysize = hash->keysize;
  583. while (item != NULL) {
  584. DdNodePtr *key2 = item->key;
  585. int equal = 1;
  586. for (i = 0; i < keysize; i++) {
  587. if (key[i] != key2[i]) {
  588. equal = 0;
  589. break;
  590. }
  591. }
  592. if (equal) {
  593. DdNode *value = item->value;
  594. cuddSatDec(item->count);
  595. if (item->count == 0) {
  596. cuddDeref(value);
  597. if (prev == NULL) {
  598. hash->bucket[posn] = item->next;
  599. } else {
  600. prev->next = item->next;
  601. }
  602. item->next = hash->nextFree;
  603. hash->nextFree = item;
  604. hash->size--;
  605. }
  606. return(value);
  607. }
  608. prev = item;
  609. item = item->next;
  610. }
  611. return(NULL);
  612. } /* end of cuddHashTableLookup */
  613. /**Function********************************************************************
  614. Synopsis [Inserts an item in a hash table.]
  615. Description [Inserts an item in a hash table when the key is one pointer.
  616. Returns 1 if successful; 0 otherwise.]
  617. SideEffects [None]
  618. SeeAlso [cuddHashTableInsert cuddHashTableInsert2 cuddHashTableInsert3
  619. cuddHashTableLookup1]
  620. ******************************************************************************/
  621. int
  622. cuddHashTableInsert1(
  623. DdHashTable * hash,
  624. DdNode * f,
  625. DdNode * value,
  626. ptrint count)
  627. {
  628. int result;
  629. unsigned int posn;
  630. DdHashItem *item;
  631. #ifdef DD_DEBUG
  632. assert(hash->keysize == 1);
  633. #endif
  634. if (hash->size > hash->maxsize) {
  635. result = cuddHashTableResize(hash);
  636. if (result == 0) return(0);
  637. }
  638. item = cuddHashTableAlloc(hash);
  639. if (item == NULL) return(0);
  640. hash->size++;
  641. item->value = value;
  642. cuddRef(value);
  643. item->count = count;
  644. item->key[0] = f;
  645. posn = ddLCHash1(f,hash->shift);
  646. item->next = hash->bucket[posn];
  647. hash->bucket[posn] = item;
  648. return(1);
  649. } /* end of cuddHashTableInsert1 */
  650. /**Function********************************************************************
  651. Synopsis [Looks up a key consisting of one pointer in a hash table.]
  652. Description [Looks up a key consisting of one pointer in a hash table.
  653. Returns the value associated to the key if there is an entry for the given
  654. key in the table; NULL otherwise. If the entry is present, its reference
  655. counter is decremented if not saturated. If the counter reaches 0, the
  656. value of the entry is dereferenced, and the entry is returned to the free
  657. list.]
  658. SideEffects [None]
  659. SeeAlso [cuddHashTableLookup cuddHashTableLookup2 cuddHashTableLookup3
  660. cuddHashTableInsert1]
  661. ******************************************************************************/
  662. DdNode *
  663. cuddHashTableLookup1(
  664. DdHashTable * hash,
  665. DdNode * f)
  666. {
  667. unsigned int posn;
  668. DdHashItem *item, *prev;
  669. #ifdef DD_DEBUG
  670. assert(hash->keysize == 1);
  671. #endif
  672. posn = ddLCHash1(f,hash->shift);
  673. item = hash->bucket[posn];
  674. prev = NULL;
  675. while (item != NULL) {
  676. DdNodePtr *key = item->key;
  677. if (f == key[0]) {
  678. DdNode *value = item->value;
  679. cuddSatDec(item->count);
  680. if (item->count == 0) {
  681. cuddDeref(value);
  682. if (prev == NULL) {
  683. hash->bucket[posn] = item->next;
  684. } else {
  685. prev->next = item->next;
  686. }
  687. item->next = hash->nextFree;
  688. hash->nextFree = item;
  689. hash->size--;
  690. }
  691. return(value);
  692. }
  693. prev = item;
  694. item = item->next;
  695. }
  696. return(NULL);
  697. } /* end of cuddHashTableLookup1 */
  698. /**Function********************************************************************
  699. Synopsis [Inserts an item in a hash table.]
  700. Description [Inserts an item in a hash table when the key is one
  701. pointer and the value is not a DdNode pointer. Returns 1 if
  702. successful; 0 otherwise.]
  703. SideEffects [None]
  704. SeeAlso [cuddHashTableInsert1 cuddHashTableGenericLookup]
  705. ******************************************************************************/
  706. int
  707. cuddHashTableGenericInsert(
  708. DdHashTable * hash,
  709. DdNode * f,
  710. void * value)
  711. {
  712. int result;
  713. unsigned int posn;
  714. DdHashItem *item;
  715. #ifdef DD_DEBUG
  716. assert(hash->keysize == 1);
  717. #endif
  718. if (hash->size > hash->maxsize) {
  719. result = cuddHashTableResize(hash);
  720. if (result == 0) return(0);
  721. }
  722. item = cuddHashTableAlloc(hash);
  723. if (item == NULL) return(0);
  724. hash->size++;
  725. item->value = (DdNode *) value;
  726. item->count = 0;
  727. item->key[0] = f;
  728. posn = ddLCHash1(f,hash->shift);
  729. item->next = hash->bucket[posn];
  730. hash->bucket[posn] = item;
  731. return(1);
  732. } /* end of cuddHashTableGenericInsert */
  733. /**Function********************************************************************
  734. Synopsis [Looks up a key consisting of one pointer in a hash table.]
  735. Description [Looks up a key consisting of one pointer in a hash
  736. table when the value is not a DdNode pointer. Returns the value
  737. associated to the key if there is an entry for the given key in the
  738. table; NULL otherwise.]
  739. SideEffects [None]
  740. SeeAlso [cuddHashTableLookup1 cuddHashTableGenericInsert]
  741. ******************************************************************************/
  742. void *
  743. cuddHashTableGenericLookup(
  744. DdHashTable * hash,
  745. DdNode * f)
  746. {
  747. unsigned int posn;
  748. DdHashItem *item;
  749. #ifdef DD_DEBUG
  750. assert(hash->keysize == 1);
  751. #endif
  752. posn = ddLCHash1(f,hash->shift);
  753. item = hash->bucket[posn];
  754. while (item != NULL) {
  755. if (f == item->key[0]) {
  756. return ((void *) item->value);
  757. }
  758. item = item->next;
  759. }
  760. return(NULL);
  761. } /* end of cuddHashTableGenericLookup */
  762. /**Function********************************************************************
  763. Synopsis [Inserts an item in a hash table.]
  764. Description [Inserts an item in a hash table when the key is
  765. composed of two pointers. Returns 1 if successful; 0 otherwise.]
  766. SideEffects [None]
  767. SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert3
  768. cuddHashTableLookup2]
  769. ******************************************************************************/
  770. int
  771. cuddHashTableInsert2(
  772. DdHashTable * hash,
  773. DdNode * f,
  774. DdNode * g,
  775. DdNode * value,
  776. ptrint count)
  777. {
  778. int result;
  779. unsigned int posn;
  780. DdHashItem *item;
  781. #ifdef DD_DEBUG
  782. assert(hash->keysize == 2);
  783. #endif
  784. if (hash->size > hash->maxsize) {
  785. result = cuddHashTableResize(hash);
  786. if (result == 0) return(0);
  787. }
  788. item = cuddHashTableAlloc(hash);
  789. if (item == NULL) return(0);
  790. hash->size++;
  791. item->value = value;
  792. cuddRef(value);
  793. item->count = count;
  794. item->key[0] = f;
  795. item->key[1] = g;
  796. posn = ddLCHash2(f,g,hash->shift);
  797. item->next = hash->bucket[posn];
  798. hash->bucket[posn] = item;
  799. return(1);
  800. } /* end of cuddHashTableInsert2 */
  801. /**Function********************************************************************
  802. Synopsis [Looks up a key consisting of two pointers in a hash table.]
  803. Description [Looks up a key consisting of two pointer in a hash table.
  804. Returns the value associated to the key if there is an entry for the given
  805. key in the table; NULL otherwise. If the entry is present, its reference
  806. counter is decremented if not saturated. If the counter reaches 0, the
  807. value of the entry is dereferenced, and the entry is returned to the free
  808. list.]
  809. SideEffects [None]
  810. SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup3
  811. cuddHashTableInsert2]
  812. ******************************************************************************/
  813. DdNode *
  814. cuddHashTableLookup2(
  815. DdHashTable * hash,
  816. DdNode * f,
  817. DdNode * g)
  818. {
  819. unsigned int posn;
  820. DdHashItem *item, *prev;
  821. #ifdef DD_DEBUG
  822. assert(hash->keysize == 2);
  823. #endif
  824. posn = ddLCHash2(f,g,hash->shift);
  825. item = hash->bucket[posn];
  826. prev = NULL;
  827. while (item != NULL) {
  828. DdNodePtr *key = item->key;
  829. if ((f == key[0]) && (g == key[1])) {
  830. DdNode *value = item->value;
  831. cuddSatDec(item->count);
  832. if (item->count == 0) {
  833. cuddDeref(value);
  834. if (prev == NULL) {
  835. hash->bucket[posn] = item->next;
  836. } else {
  837. prev->next = item->next;
  838. }
  839. item->next = hash->nextFree;
  840. hash->nextFree = item;
  841. hash->size--;
  842. }
  843. return(value);
  844. }
  845. prev = item;
  846. item = item->next;
  847. }
  848. return(NULL);
  849. } /* end of cuddHashTableLookup2 */
  850. /**Function********************************************************************
  851. Synopsis [Inserts an item in a hash table.]
  852. Description [Inserts an item in a hash table when the key is
  853. composed of three pointers. Returns 1 if successful; 0 otherwise.]
  854. SideEffects [None]
  855. SeeAlso [cuddHashTableInsert cuddHashTableInsert1 cuddHashTableInsert2
  856. cuddHashTableLookup3]
  857. ******************************************************************************/
  858. int
  859. cuddHashTableInsert3(
  860. DdHashTable * hash,
  861. DdNode * f,
  862. DdNode * g,
  863. DdNode * h,
  864. DdNode * value,
  865. ptrint count)
  866. {
  867. int result;
  868. unsigned int posn;
  869. DdHashItem *item;
  870. #ifdef DD_DEBUG
  871. assert(hash->keysize == 3);
  872. #endif
  873. if (hash->size > hash->maxsize) {
  874. result = cuddHashTableResize(hash);
  875. if (result == 0) return(0);
  876. }
  877. item = cuddHashTableAlloc(hash);
  878. if (item == NULL) return(0);
  879. hash->size++;
  880. item->value = value;
  881. cuddRef(value);
  882. item->count = count;
  883. item->key[0] = f;
  884. item->key[1] = g;
  885. item->key[2] = h;
  886. posn = ddLCHash3(f,g,h,hash->shift);
  887. item->next = hash->bucket[posn];
  888. hash->bucket[posn] = item;
  889. return(1);
  890. } /* end of cuddHashTableInsert3 */
  891. /**Function********************************************************************
  892. Synopsis [Looks up a key consisting of three pointers in a hash table.]
  893. Description [Looks up a key consisting of three pointers in a hash table.
  894. Returns the value associated to the key if there is an entry for the given
  895. key in the table; NULL otherwise. If the entry is present, its reference
  896. counter is decremented if not saturated. If the counter reaches 0, the
  897. value of the entry is dereferenced, and the entry is returned to the free
  898. list.]
  899. SideEffects [None]
  900. SeeAlso [cuddHashTableLookup cuddHashTableLookup1 cuddHashTableLookup2
  901. cuddHashTableInsert3]
  902. ******************************************************************************/
  903. DdNode *
  904. cuddHashTableLookup3(
  905. DdHashTable * hash,
  906. DdNode * f,
  907. DdNode * g,
  908. DdNode * h)
  909. {
  910. unsigned int posn;
  911. DdHashItem *item, *prev;
  912. #ifdef DD_DEBUG
  913. assert(hash->keysize == 3);
  914. #endif
  915. posn = ddLCHash3(f,g,h,hash->shift);
  916. item = hash->bucket[posn];
  917. prev = NULL;
  918. while (item != NULL) {
  919. DdNodePtr *key = item->key;
  920. if ((f == key[0]) && (g == key[1]) && (h == key[2])) {
  921. DdNode *value = item->value;
  922. cuddSatDec(item->count);
  923. if (item->count == 0) {
  924. cuddDeref(value);
  925. if (prev == NULL) {
  926. hash->bucket[posn] = item->next;
  927. } else {
  928. prev->next = item->next;
  929. }
  930. item->next = hash->nextFree;
  931. hash->nextFree = item;
  932. hash->size--;
  933. }
  934. return(value);
  935. }
  936. prev = item;
  937. item = item->next;
  938. }
  939. return(NULL);
  940. } /* end of cuddHashTableLookup3 */
  941. /*---------------------------------------------------------------------------*/
  942. /* Definition of static functions */
  943. /*---------------------------------------------------------------------------*/
  944. /**Function********************************************************************
  945. Synopsis [Resizes a local cache.]
  946. Description []
  947. SideEffects [None]
  948. SeeAlso []
  949. ******************************************************************************/
  950. static void
  951. cuddLocalCacheResize(
  952. DdLocalCache * cache)
  953. {
  954. DdLocalCacheItem *item, *olditem, *entry, *old;
  955. int i, shift;
  956. unsigned int posn;
  957. unsigned int slots, oldslots;
  958. extern DD_OOMFP MMoutOfMemory;
  959. DD_OOMFP saveHandler;
  960. olditem = cache->item;
  961. oldslots = cache->slots;
  962. slots = cache->slots = oldslots << 1;
  963. #ifdef DD_VERBOSE
  964. (void) fprintf(cache->manager->err,
  965. "Resizing local cache from %d to %d entries\n",
  966. oldslots, slots);
  967. (void) fprintf(cache->manager->err,
  968. "\thits = %.0f\tlookups = %.0f\thit ratio = %5.3f\n",
  969. cache->hits, cache->lookUps, cache->hits / cache->lookUps);
  970. #endif
  971. saveHandler = MMoutOfMemory;
  972. MMoutOfMemory = Cudd_OutOfMem;
  973. cache->item = item =
  974. (DdLocalCacheItem *) ALLOC(char, slots * cache->itemsize);
  975. MMoutOfMemory = saveHandler;
  976. /* If we fail to allocate the new table we just give up. */
  977. if (item == NULL) {
  978. #ifdef DD_VERBOSE
  979. (void) fprintf(cache->manager->err,"Resizing failed. Giving up.\n");
  980. #endif
  981. cache->slots = oldslots;
  982. cache->item = olditem;
  983. /* Do not try to resize again. */
  984. cache->maxslots = oldslots - 1;
  985. return;
  986. }
  987. shift = --(cache->shift);
  988. cache->manager->memused += (slots - oldslots) * cache->itemsize;
  989. /* Clear new cache. */
  990. memset(item, 0, slots * cache->itemsize);
  991. /* Copy from old cache to new one. */
  992. for (i = 0; (unsigned) i < oldslots; i++) {
  993. old = (DdLocalCacheItem *) ((char *) olditem + i * cache->itemsize);
  994. if (old->value != NULL) {
  995. posn = ddLCHash(old->key,cache->keysize,shift);
  996. entry = (DdLocalCacheItem *) ((char *) item +
  997. posn * cache->itemsize);
  998. memcpy(entry->key,old->key,cache->keysize*sizeof(DdNode *));
  999. entry->value = old->value;
  1000. }
  1001. }
  1002. FREE(olditem);
  1003. /* Reinitialize measurements so as to avoid division by 0 and
  1004. ** immediate resizing.
  1005. */
  1006. cache->lookUps = (double) (int) (slots * cache->minHit + 1);
  1007. cache->hits = 0;
  1008. } /* end of cuddLocalCacheResize */
  1009. /**Function********************************************************************
  1010. Synopsis [Computes the hash value for a local cache.]
  1011. Description [Computes the hash value for a local cache. Returns the
  1012. bucket index.]
  1013. SideEffects [None]
  1014. SeeAlso []
  1015. ******************************************************************************/
  1016. DD_INLINE
  1017. static unsigned int
  1018. ddLCHash(
  1019. DdNodePtr * key,
  1020. unsigned int keysize,
  1021. int shift)
  1022. {
  1023. unsigned int val = (unsigned int) (ptrint) key[0] * DD_P2;
  1024. unsigned int i;
  1025. for (i = 1; i < keysize; i++) {
  1026. val = val * DD_P1 + (int) (ptrint) key[i];
  1027. }
  1028. return(val >> shift);
  1029. } /* end of ddLCHash */
  1030. /**Function********************************************************************
  1031. Synopsis [Inserts a local cache in the manager list.]
  1032. Description []
  1033. SideEffects [None]
  1034. SeeAlso []
  1035. ******************************************************************************/
  1036. static void
  1037. cuddLocalCacheAddToList(
  1038. DdLocalCache * cache)
  1039. {
  1040. DdManager *manager = cache->manager;
  1041. cache->next = manager->localCaches;
  1042. manager->localCaches = cache;
  1043. return;
  1044. } /* end of cuddLocalCacheAddToList */
  1045. /**Function********************************************************************
  1046. Synopsis [Removes a local cache from the manager list.]
  1047. Description []
  1048. SideEffects [None]
  1049. SeeAlso []
  1050. ******************************************************************************/
  1051. static void
  1052. cuddLocalCacheRemoveFromList(
  1053. DdLocalCache * cache)
  1054. {
  1055. DdManager *manager = cache->manager;
  1056. DdLocalCache **prevCache, *nextCache;
  1057. prevCache = &(manager->localCaches);
  1058. nextCache = manager->localCaches;
  1059. while (nextCache != NULL) {
  1060. if (nextCache == cache) {
  1061. *prevCache = nextCache->next;
  1062. return;
  1063. }
  1064. prevCache = &(nextCache->next);
  1065. nextCache = nextCache->next;
  1066. }
  1067. return; /* should never get here */
  1068. } /* end of cuddLocalCacheRemoveFromList */
  1069. /**Function********************************************************************
  1070. Synopsis [Resizes a hash table.]
  1071. Description [Resizes a hash table. Returns 1 if successful; 0
  1072. otherwise.]
  1073. SideEffects [None]
  1074. SeeAlso [cuddHashTableInsert]
  1075. ******************************************************************************/
  1076. static int
  1077. cuddHashTableResize(
  1078. DdHashTable * hash)
  1079. {
  1080. int j;
  1081. unsigned int posn;
  1082. DdHashItem *item;
  1083. DdHashItem *next;
  1084. DdNode **key;
  1085. int numBuckets;
  1086. DdHashItem **buckets;
  1087. DdHashItem **oldBuckets = hash->bucket;
  1088. int shift;
  1089. int oldNumBuckets = hash->numBuckets;
  1090. extern DD_OOMFP MMoutOfMemory;
  1091. DD_OOMFP saveHandler;
  1092. /* Compute the new size of the table. */
  1093. numBuckets = oldNumBuckets << 1;
  1094. saveHandler = MMoutOfMemory;
  1095. MMoutOfMemory = Cudd_OutOfMem;
  1096. buckets = ALLOC(DdHashItem *, numBuckets);
  1097. MMoutOfMemory = saveHandler;
  1098. if (buckets == NULL) {
  1099. hash->maxsize <<= 1;
  1100. return(1);
  1101. }
  1102. hash->bucket = buckets;
  1103. hash->numBuckets = numBuckets;
  1104. shift = --(hash->shift);
  1105. hash->maxsize <<= 1;
  1106. memset(buckets, 0, numBuckets * sizeof(DdHashItem *));
  1107. if (hash->keysize == 1) {
  1108. for (j = 0; j < oldNumBuckets; j++) {
  1109. item = oldBuckets[j];
  1110. while (item != NULL) {
  1111. next = item->next;
  1112. key = item->key;
  1113. posn = ddLCHash2(key[0], key[0], shift);
  1114. item->next = buckets[posn];
  1115. buckets[posn] = item;
  1116. item = next;
  1117. }
  1118. }
  1119. } else if (hash->keysize == 2) {
  1120. for (j = 0; j < oldNumBuckets; j++) {
  1121. item = oldBuckets[j];
  1122. while (item != NULL) {
  1123. next = item->next;
  1124. key = item->key;
  1125. posn = ddLCHash2(key[0], key[1], shift);
  1126. item->next = buckets[posn];
  1127. buckets[posn] = item;
  1128. item = next;
  1129. }
  1130. }
  1131. } else if (hash->keysize == 3) {
  1132. for (j = 0; j < oldNumBuckets; j++) {
  1133. item = oldBuckets[j];
  1134. while (item != NULL) {
  1135. next = item->next;
  1136. key = item->key;
  1137. posn = ddLCHash3(key[0], key[1], key[2], shift);
  1138. item->next = buckets[posn];
  1139. buckets[posn] = item;
  1140. item = next;
  1141. }
  1142. }
  1143. } else {
  1144. for (j = 0; j < oldNumBuckets; j++) {
  1145. item = oldBuckets[j];
  1146. while (item != NULL) {
  1147. next = item->next;
  1148. posn = ddLCHash(item->key, hash->keysize, shift);
  1149. item->next = buckets[posn];
  1150. buckets[posn] = item;
  1151. item = next;
  1152. }
  1153. }
  1154. }
  1155. FREE(oldBuckets);
  1156. return(1);
  1157. } /* end of cuddHashTableResize */
  1158. /**Function********************************************************************
  1159. Synopsis [Fast storage allocation for items in a hash table.]
  1160. Description [Fast storage allocation for items in a hash table. The
  1161. first 4 bytes of a chunk contain a pointer to the next block; the
  1162. rest contains DD_MEM_CHUNK spaces for hash items. Returns a pointer to
  1163. a new item if successful; NULL is memory is full.]
  1164. SideEffects [None]
  1165. SeeAlso [cuddAllocNode cuddDynamicAllocNode]
  1166. ******************************************************************************/
  1167. DD_INLINE
  1168. static DdHashItem *
  1169. cuddHashTableAlloc(
  1170. DdHashTable * hash)
  1171. {
  1172. int i;
  1173. unsigned int itemsize = hash->itemsize;
  1174. extern DD_OOMFP MMoutOfMemory;
  1175. DD_OOMFP saveHandler;
  1176. DdHashItem **mem, *thisOne, *next, *item;
  1177. if (hash->nextFree == NULL) {
  1178. saveHandler = MMoutOfMemory;
  1179. MMoutOfMemory = Cudd_OutOfMem;
  1180. mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
  1181. MMoutOfMemory = saveHandler;
  1182. if (mem == NULL) {
  1183. if (hash->manager->stash != NULL) {
  1184. FREE(hash->manager->stash);
  1185. hash->manager->stash = NULL;
  1186. /* Inhibit resizing of tables. */
  1187. hash->manager->maxCacheHard = hash->manager->cacheSlots - 1;
  1188. hash->manager->cacheSlack = - (int) (hash->manager->cacheSlots + 1);
  1189. for (i = 0; i < hash->manager->size; i++) {
  1190. hash->manager->subtables[i].maxKeys <<= 2;
  1191. }
  1192. hash->manager->gcFrac = 0.2;
  1193. hash->manager->minDead =
  1194. (unsigned) (0.2 * (double) hash->manager->slots);
  1195. mem = (DdHashItem **) ALLOC(char,(DD_MEM_CHUNK+1) * itemsize);
  1196. }
  1197. if (mem == NULL) {
  1198. (*MMoutOfMemory)((long)((DD_MEM_CHUNK + 1) * itemsize));
  1199. hash->manager->errorCode = CUDD_MEMORY_OUT;
  1200. return(NULL);
  1201. }
  1202. }
  1203. mem[0] = (DdHashItem *) hash->memoryList;
  1204. hash->memoryList = mem;
  1205. thisOne = (DdHashItem *) ((char *) mem + itemsize);
  1206. hash->nextFree = thisOne;
  1207. for (i = 1; i < DD_MEM_CHUNK; i++) {
  1208. next = (DdHashItem *) ((char *) thisOne + itemsize);
  1209. thisOne->next = next;
  1210. thisOne = next;
  1211. }
  1212. thisOne->next = NULL;
  1213. }
  1214. item = hash->nextFree;
  1215. hash->nextFree = item->next;
  1216. return(item);
  1217. } /* end of cuddHashTableAlloc */