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.

990 lines
23 KiB

2 months ago
  1. /**
  2. @file
  3. @ingroup cudd
  4. @brief Functions for cache insertion and lookup.
  5. @author Fabio Somenzi
  6. @copyright@parblock
  7. Copyright (c) 1995-2015, Regents of the University of Colorado
  8. All rights reserved.
  9. Redistribution and use in source and binary forms, with or without
  10. modification, are permitted provided that the following conditions
  11. are met:
  12. Redistributions of source code must retain the above copyright
  13. notice, this list of conditions and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright
  15. notice, this list of conditions and the following disclaimer in the
  16. documentation and/or other materials provided with the distribution.
  17. Neither the name of the University of Colorado nor the names of its
  18. contributors may be used to endorse or promote products derived from
  19. this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  27. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  30. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. POSSIBILITY OF SUCH DAMAGE.
  32. @endparblock
  33. */
  34. #include "util.h"
  35. #include "cuddInt.h"
  36. /*---------------------------------------------------------------------------*/
  37. /* Constant declarations */
  38. /*---------------------------------------------------------------------------*/
  39. #ifdef DD_CACHE_PROFILE
  40. #define DD_HYSTO_BINS 8
  41. #endif
  42. /*---------------------------------------------------------------------------*/
  43. /* Stucture declarations */
  44. /*---------------------------------------------------------------------------*/
  45. /*---------------------------------------------------------------------------*/
  46. /* Type declarations */
  47. /*---------------------------------------------------------------------------*/
  48. /*---------------------------------------------------------------------------*/
  49. /* Variable declarations */
  50. /*---------------------------------------------------------------------------*/
  51. /*---------------------------------------------------------------------------*/
  52. /* Macro declarations */
  53. /*---------------------------------------------------------------------------*/
  54. /** \cond */
  55. /*---------------------------------------------------------------------------*/
  56. /* Static function prototypes */
  57. /*---------------------------------------------------------------------------*/
  58. /** \endcond */
  59. /*---------------------------------------------------------------------------*/
  60. /* Definition of exported functions */
  61. /*---------------------------------------------------------------------------*/
  62. /*---------------------------------------------------------------------------*/
  63. /* Definition of internal functions */
  64. /*---------------------------------------------------------------------------*/
  65. /**
  66. @brief Initializes the computed table.
  67. @details It is called by Cudd_Init.
  68. @return 1 in case of success; 0 otherwise.
  69. @sideeffect None
  70. @see Cudd_Init
  71. */
  72. int
  73. cuddInitCache(
  74. DdManager * unique /**< unique table */,
  75. unsigned int cacheSize /**< initial size of the cache */,
  76. unsigned int maxCacheSize /**< cache size beyond which no resizing occurs */)
  77. {
  78. int i;
  79. unsigned int logSize;
  80. #ifndef DD_CACHE_PROFILE
  81. DdNodePtr *mem;
  82. ptruint offset;
  83. #endif
  84. /* Round cacheSize to largest power of 2 not greater than the requested
  85. ** initial cache size. */
  86. logSize = cuddComputeFloorLog2(ddMax(cacheSize,unique->slots/2));
  87. cacheSize = 1U << logSize;
  88. unique->acache = ALLOC(DdCache,cacheSize+1);
  89. if (unique->acache == NULL) {
  90. unique->errorCode = CUDD_MEMORY_OUT;
  91. return(0);
  92. }
  93. /* If the size of the cache entry is a power of 2, we want to
  94. ** enforce alignment to that power of two. This happens when
  95. ** DD_CACHE_PROFILE is not defined. */
  96. #ifdef DD_CACHE_PROFILE
  97. unique->cache = unique->acache;
  98. unique->memused += (cacheSize) * sizeof(DdCache);
  99. #else
  100. mem = (DdNodePtr *) unique->acache;
  101. offset = (ptruint) mem & (sizeof(DdCache) - 1);
  102. mem += (sizeof(DdCache) - offset) / sizeof(DdNodePtr);
  103. unique->cache = (DdCache *) mem;
  104. assert(((ptruint) unique->cache & (sizeof(DdCache) - 1)) == 0);
  105. unique->memused += (cacheSize+1) * sizeof(DdCache);
  106. #endif
  107. unique->cacheSlots = cacheSize;
  108. unique->cacheShift = sizeof(int) * 8 - logSize;
  109. unique->maxCacheHard = maxCacheSize;
  110. /* If cacheSlack is non-negative, we can resize. */
  111. unique->cacheSlack = (int) ddMin(maxCacheSize,
  112. DD_MAX_CACHE_TO_SLOTS_RATIO*unique->slots) -
  113. 2 * (int) cacheSize;
  114. Cudd_SetMinHit(unique,DD_MIN_HIT);
  115. /* Initialize to avoid division by 0 and immediate resizing. */
  116. unique->cacheMisses = (double) (int) (cacheSize * unique->minHit + 1);
  117. unique->cacheHits = 0;
  118. unique->totCachehits = 0;
  119. /* The sum of cacheMisses and totCacheMisses is always correct,
  120. ** even though cacheMisses is larger than it should for the reasons
  121. ** explained above. */
  122. unique->totCacheMisses = -unique->cacheMisses;
  123. unique->cachecollisions = 0;
  124. unique->cacheinserts = 0;
  125. unique->cacheLastInserts = 0;
  126. unique->cachedeletions = 0;
  127. /* Initialize the cache */
  128. for (i = 0; (unsigned) i < cacheSize; i++) {
  129. unique->cache[i].h = 0; /* unused slots */
  130. unique->cache[i].data = NULL; /* invalid entry */
  131. #ifdef DD_CACHE_PROFILE
  132. unique->cache[i].count = 0;
  133. #endif
  134. }
  135. return(1);
  136. } /* end of cuddInitCache */
  137. /**
  138. @brief Inserts a result in the cache for a function with three
  139. operands.
  140. @details The operator tag (see cuddInt.h for details) is split and
  141. stored into unused bits of the first two pointers.
  142. @sideeffect None
  143. @see cuddCacheInsert2 cuddCacheInsert1
  144. */
  145. void
  146. cuddCacheInsert(
  147. DdManager * table,
  148. ptruint op,
  149. DdNode * f,
  150. DdNode * g,
  151. DdNode * h,
  152. DdNode * data)
  153. {
  154. int posn;
  155. DdCache *entry;
  156. ptruint uf, ug, uh;
  157. uf = (ptruint) f | (op & 0xe);
  158. ug = (ptruint) g | (op >> 4);
  159. uh = (ptruint) h;
  160. posn = ddCHash2(uh,uf,ug,table->cacheShift);
  161. entry = &table->cache[posn];
  162. table->cachecollisions += entry->data != NULL;
  163. table->cacheinserts++;
  164. entry->f = (DdNode *) uf;
  165. entry->g = (DdNode *) ug;
  166. entry->h = uh;
  167. entry->data = data;
  168. #ifdef DD_CACHE_PROFILE
  169. entry->count++;
  170. #endif
  171. } /* end of cuddCacheInsert */
  172. /**
  173. @brief Inserts a result in the cache for a function with two
  174. operands.
  175. @sideeffect None
  176. @see cuddCacheInsert cuddCacheInsert1
  177. */
  178. void
  179. cuddCacheInsert2(
  180. DdManager * table,
  181. DD_CTFP op,
  182. DdNode * f,
  183. DdNode * g,
  184. DdNode * data)
  185. {
  186. int posn;
  187. DdCache *entry;
  188. posn = ddCHash2(op,f,g,table->cacheShift);
  189. entry = &table->cache[posn];
  190. if (entry->data != NULL) {
  191. table->cachecollisions++;
  192. }
  193. table->cacheinserts++;
  194. entry->f = f;
  195. entry->g = g;
  196. entry->h = (ptruint) op;
  197. entry->data = data;
  198. #ifdef DD_CACHE_PROFILE
  199. entry->count++;
  200. #endif
  201. } /* end of cuddCacheInsert2 */
  202. /**
  203. @brief Inserts a result in the cache for a function with two
  204. operands.
  205. @sideeffect None
  206. @see cuddCacheInsert cuddCacheInsert2
  207. */
  208. void
  209. cuddCacheInsert1(
  210. DdManager * table,
  211. DD_CTFP1 op,
  212. DdNode * f,
  213. DdNode * data)
  214. {
  215. int posn;
  216. DdCache *entry;
  217. posn = ddCHash2(op,f,f,table->cacheShift);
  218. entry = &table->cache[posn];
  219. if (entry->data != NULL) {
  220. table->cachecollisions++;
  221. }
  222. table->cacheinserts++;
  223. entry->f = f;
  224. entry->g = f;
  225. entry->h = (ptruint) op;
  226. entry->data = data;
  227. #ifdef DD_CACHE_PROFILE
  228. entry->count++;
  229. #endif
  230. } /* end of cuddCacheInsert1 */
  231. /**
  232. @brief Looks up in the cache for the result of op applied to f,
  233. g, and h.
  234. @return the result if found; it returns NULL if no result is found.
  235. @sideeffect None
  236. @see cuddCacheLookup2 cuddCacheLookup1
  237. */
  238. DdNode *
  239. cuddCacheLookup(
  240. DdManager * table,
  241. ptruint op,
  242. DdNode * f,
  243. DdNode * g,
  244. DdNode * h)
  245. {
  246. int posn;
  247. DdCache *en,*cache;
  248. DdNode *data;
  249. ptruint uf, ug, uh;
  250. uf = (ptruint) f | (op & 0xe);
  251. ug = (ptruint) g | (op >> 4);
  252. uh = (ptruint) h;
  253. cache = table->cache;
  254. #ifdef DD_DEBUG
  255. if (cache == NULL) {
  256. return(NULL);
  257. }
  258. #endif
  259. posn = ddCHash2(uh,uf,ug,table->cacheShift);
  260. en = &cache[posn];
  261. if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
  262. en->h==uh) {
  263. data = Cudd_Regular(en->data);
  264. table->cacheHits++;
  265. if (data->ref == 0) {
  266. cuddReclaim(table,data);
  267. }
  268. return(en->data);
  269. }
  270. /* Cache miss: decide whether to resize. */
  271. table->cacheMisses++;
  272. if (table->cacheSlack >= 0 &&
  273. table->cacheHits > table->cacheMisses * table->minHit) {
  274. cuddCacheResize(table);
  275. }
  276. return(NULL);
  277. } /* end of cuddCacheLookup */
  278. /**
  279. @brief Looks up in the cache for the result of op applied to f,
  280. g, and h.
  281. @return the result if found; it returns NULL if no result is found.
  282. @sideeffect None
  283. @see cuddCacheLookup2Zdd cuddCacheLookup1Zdd
  284. */
  285. DdNode *
  286. cuddCacheLookupZdd(
  287. DdManager * table,
  288. ptruint op,
  289. DdNode * f,
  290. DdNode * g,
  291. DdNode * h)
  292. {
  293. int posn;
  294. DdCache *en,*cache;
  295. DdNode *data;
  296. ptruint uf, ug, uh;
  297. uf = (ptruint) f | (op & 0xe);
  298. ug = (ptruint) g | (op >> 4);
  299. uh = (ptruint) h;
  300. cache = table->cache;
  301. #ifdef DD_DEBUG
  302. if (cache == NULL) {
  303. return(NULL);
  304. }
  305. #endif
  306. posn = ddCHash2(uh,uf,ug,table->cacheShift);
  307. en = &cache[posn];
  308. if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
  309. en->h==uh) {
  310. data = Cudd_Regular(en->data);
  311. table->cacheHits++;
  312. if (data->ref == 0) {
  313. cuddReclaimZdd(table,data);
  314. }
  315. return(en->data);
  316. }
  317. /* Cache miss: decide whether to resize. */
  318. table->cacheMisses++;
  319. if (table->cacheSlack >= 0 &&
  320. table->cacheHits > table->cacheMisses * table->minHit) {
  321. cuddCacheResize(table);
  322. }
  323. return(NULL);
  324. } /* end of cuddCacheLookupZdd */
  325. /**
  326. @brief Looks up in the cache for the result of op applied to f
  327. and g.
  328. @return the result if found; it returns NULL if no result is found.
  329. @sideeffect None
  330. @see cuddCacheLookup cuddCacheLookup1
  331. */
  332. DdNode *
  333. cuddCacheLookup2(
  334. DdManager * table,
  335. DD_CTFP op,
  336. DdNode * f,
  337. DdNode * g)
  338. {
  339. int posn;
  340. DdCache *en,*cache;
  341. DdNode *data;
  342. cache = table->cache;
  343. #ifdef DD_DEBUG
  344. if (cache == NULL) {
  345. return(NULL);
  346. }
  347. #endif
  348. posn = ddCHash2(op,f,g,table->cacheShift);
  349. en = &cache[posn];
  350. if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
  351. data = Cudd_Regular(en->data);
  352. table->cacheHits++;
  353. if (data->ref == 0) {
  354. cuddReclaim(table,data);
  355. }
  356. return(en->data);
  357. }
  358. /* Cache miss: decide whether to resize. */
  359. table->cacheMisses++;
  360. if (table->cacheSlack >= 0 &&
  361. table->cacheHits > table->cacheMisses * table->minHit) {
  362. cuddCacheResize(table);
  363. }
  364. return(NULL);
  365. } /* end of cuddCacheLookup2 */
  366. /**
  367. @brief Looks up in the cache for the result of op applied to f.
  368. @return the result if found; it returns NULL if no result is found.
  369. @sideeffect None
  370. @see cuddCacheLookup cuddCacheLookup2
  371. */
  372. DdNode *
  373. cuddCacheLookup1(
  374. DdManager * table,
  375. DD_CTFP1 op,
  376. DdNode * f)
  377. {
  378. int posn;
  379. DdCache *en,*cache;
  380. DdNode *data;
  381. cache = table->cache;
  382. #ifdef DD_DEBUG
  383. if (cache == NULL) {
  384. return(NULL);
  385. }
  386. #endif
  387. posn = ddCHash2(op,f,f,table->cacheShift);
  388. en = &cache[posn];
  389. if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
  390. data = Cudd_Regular(en->data);
  391. table->cacheHits++;
  392. if (data->ref == 0) {
  393. cuddReclaim(table,data);
  394. }
  395. return(en->data);
  396. }
  397. /* Cache miss: decide whether to resize. */
  398. table->cacheMisses++;
  399. if (table->cacheSlack >= 0 &&
  400. table->cacheHits > table->cacheMisses * table->minHit) {
  401. cuddCacheResize(table);
  402. }
  403. return(NULL);
  404. } /* end of cuddCacheLookup1 */
  405. /**
  406. @brief Looks up in the cache for the result of op applied to f
  407. and g.
  408. @return the result if found; it returns NULL if no result is found.
  409. @sideeffect None
  410. @see cuddCacheLookupZdd cuddCacheLookup1Zdd
  411. */
  412. DdNode *
  413. cuddCacheLookup2Zdd(
  414. DdManager * table,
  415. DD_CTFP op,
  416. DdNode * f,
  417. DdNode * g)
  418. {
  419. int posn;
  420. DdCache *en,*cache;
  421. DdNode *data;
  422. cache = table->cache;
  423. #ifdef DD_DEBUG
  424. if (cache == NULL) {
  425. return(NULL);
  426. }
  427. #endif
  428. posn = ddCHash2(op,f,g,table->cacheShift);
  429. en = &cache[posn];
  430. if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
  431. data = Cudd_Regular(en->data);
  432. table->cacheHits++;
  433. if (data->ref == 0) {
  434. cuddReclaimZdd(table,data);
  435. }
  436. return(en->data);
  437. }
  438. /* Cache miss: decide whether to resize. */
  439. table->cacheMisses++;
  440. if (table->cacheSlack >= 0 &&
  441. table->cacheHits > table->cacheMisses * table->minHit) {
  442. cuddCacheResize(table);
  443. }
  444. return(NULL);
  445. } /* end of cuddCacheLookup2Zdd */
  446. /**
  447. @brief Looks up in the cache for the result of op applied to f.
  448. @return the result if found; it returns NULL if no result is found.
  449. @sideeffect None
  450. @see cuddCacheLookupZdd cuddCacheLookup2Zdd
  451. */
  452. DdNode *
  453. cuddCacheLookup1Zdd(
  454. DdManager * table,
  455. DD_CTFP1 op,
  456. DdNode * f)
  457. {
  458. int posn;
  459. DdCache *en,*cache;
  460. DdNode *data;
  461. cache = table->cache;
  462. #ifdef DD_DEBUG
  463. if (cache == NULL) {
  464. return(NULL);
  465. }
  466. #endif
  467. posn = ddCHash2(op,f,f,table->cacheShift);
  468. en = &cache[posn];
  469. if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
  470. data = Cudd_Regular(en->data);
  471. table->cacheHits++;
  472. if (data->ref == 0) {
  473. cuddReclaimZdd(table,data);
  474. }
  475. return(en->data);
  476. }
  477. /* Cache miss: decide whether to resize. */
  478. table->cacheMisses++;
  479. if (table->cacheSlack >= 0 &&
  480. table->cacheHits > table->cacheMisses * table->minHit) {
  481. cuddCacheResize(table);
  482. }
  483. return(NULL);
  484. } /* end of cuddCacheLookup1Zdd */
  485. /**
  486. @brief Looks up in the cache for the result of op applied to f,
  487. g, and h.
  488. @details Assumes that the calling procedure (e.g.,
  489. Cudd_bddIteConstant) is only interested in whether the result is
  490. constant or not.
  491. @return the result if found (possibly DD_NON_CONSTANT); otherwise it
  492. returns NULL.
  493. @sideeffect None
  494. @see cuddCacheLookup
  495. */
  496. DdNode *
  497. cuddConstantLookup(
  498. DdManager * table,
  499. ptruint op,
  500. DdNode * f,
  501. DdNode * g,
  502. DdNode * h)
  503. {
  504. int posn;
  505. DdCache *en,*cache;
  506. ptruint uf, ug, uh;
  507. uf = (ptruint) f | (op & 0xe);
  508. ug = (ptruint) g | (op >> 4);
  509. uh = (ptruint) h;
  510. cache = table->cache;
  511. #ifdef DD_DEBUG
  512. if (cache == NULL) {
  513. return(NULL);
  514. }
  515. #endif
  516. posn = ddCHash2(uh,uf,ug,table->cacheShift);
  517. en = &cache[posn];
  518. /* We do not reclaim here because the result should not be
  519. * referenced, but only tested for being a constant.
  520. */
  521. if (en->data != NULL &&
  522. en->f == (DdNodePtr)uf && en->g == (DdNodePtr)ug && en->h == uh) {
  523. table->cacheHits++;
  524. return(en->data);
  525. }
  526. /* Cache miss: decide whether to resize. */
  527. table->cacheMisses++;
  528. if (table->cacheSlack >= 0 &&
  529. table->cacheHits > table->cacheMisses * table->minHit) {
  530. cuddCacheResize(table);
  531. }
  532. return(NULL);
  533. } /* end of cuddConstantLookup */
  534. /**
  535. @brief Computes and prints a profile of the cache usage.
  536. @return 1 if successful; 0 otherwise.
  537. @sideeffect None
  538. */
  539. int
  540. cuddCacheProfile(
  541. DdManager * table,
  542. FILE * fp)
  543. {
  544. DdCache *cache = table->cache;
  545. int slots = table->cacheSlots;
  546. int nzeroes = 0;
  547. int i, retval;
  548. double exUsed;
  549. #ifdef DD_CACHE_PROFILE
  550. double count, mean, meansq, stddev, expected;
  551. long max, min;
  552. int imax, imin;
  553. double *hystogramQ, *hystogramR; /* histograms by quotient and remainder */
  554. int nbins = DD_HYSTO_BINS;
  555. int bin;
  556. long thiscount;
  557. double totalcount, exStddev;
  558. meansq = mean = expected = 0.0;
  559. max = min = (long) cache[0].count;
  560. imax = imin = 0;
  561. totalcount = 0.0;
  562. hystogramQ = ALLOC(double, nbins);
  563. if (hystogramQ == NULL) {
  564. table->errorCode = CUDD_MEMORY_OUT;
  565. return(0);
  566. }
  567. hystogramR = ALLOC(double, nbins);
  568. if (hystogramR == NULL) {
  569. FREE(hystogramQ);
  570. table->errorCode = CUDD_MEMORY_OUT;
  571. return(0);
  572. }
  573. for (i = 0; i < nbins; i++) {
  574. hystogramQ[i] = 0;
  575. hystogramR[i] = 0;
  576. }
  577. for (i = 0; i < slots; i++) {
  578. thiscount = (long) cache[i].count;
  579. if (thiscount > max) {
  580. max = thiscount;
  581. imax = i;
  582. }
  583. if (thiscount < min) {
  584. min = thiscount;
  585. imin = i;
  586. }
  587. if (thiscount == 0) {
  588. nzeroes++;
  589. }
  590. count = (double) thiscount;
  591. mean += count;
  592. meansq += count * count;
  593. totalcount += count;
  594. expected += count * (double) i;
  595. bin = (i * nbins) / slots;
  596. hystogramQ[bin] += (double) thiscount;
  597. bin = i % nbins;
  598. hystogramR[bin] += (double) thiscount;
  599. }
  600. mean /= (double) slots;
  601. meansq /= (double) slots;
  602. /* Compute the standard deviation from both the data and the
  603. ** theoretical model for a random distribution. */
  604. stddev = sqrt(meansq - mean*mean);
  605. exStddev = sqrt((1 - 1/(double) slots) * totalcount / (double) slots);
  606. retval = fprintf(fp,"Cache average accesses = %g\n", mean);
  607. if (retval == EOF) return(0);
  608. retval = fprintf(fp,"Cache access standard deviation = %g ", stddev);
  609. if (retval == EOF) return(0);
  610. retval = fprintf(fp,"(expected = %g)\n", exStddev);
  611. if (retval == EOF) return(0);
  612. retval = fprintf(fp,"Cache max accesses = %ld for slot %d\n", max, imax);
  613. if (retval == EOF) return(0);
  614. retval = fprintf(fp,"Cache min accesses = %ld for slot %d\n", min, imin);
  615. if (retval == EOF) return(0);
  616. exUsed = 100.0 * (1.0 - exp(-totalcount / (double) slots));
  617. retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
  618. 100.0 - (double) nzeroes * 100.0 / (double) slots,
  619. exUsed);
  620. if (retval == EOF) return(0);
  621. if (totalcount > 0) {
  622. expected /= totalcount;
  623. retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
  624. if (retval == EOF) return(0);
  625. retval = fprintf(fp," (expected bin value = %g)\nBy quotient:",
  626. expected);
  627. if (retval == EOF) return(0);
  628. for (i = nbins - 1; i>=0; i--) {
  629. retval = fprintf(fp," %.0f", hystogramQ[i]);
  630. if (retval == EOF) return(0);
  631. }
  632. retval = fprintf(fp,"\nBy residue: ");
  633. if (retval == EOF) return(0);
  634. for (i = nbins - 1; i>=0; i--) {
  635. retval = fprintf(fp," %.0f", hystogramR[i]);
  636. if (retval == EOF) return(0);
  637. }
  638. retval = fprintf(fp,"\n");
  639. if (retval == EOF) return(0);
  640. }
  641. FREE(hystogramQ);
  642. FREE(hystogramR);
  643. #else
  644. for (i = 0; i < slots; i++) {
  645. nzeroes += cache[i].h == 0;
  646. }
  647. exUsed = 100.0 *
  648. (1.0 - exp(-(table->cacheinserts - table->cacheLastInserts) /
  649. (double) slots));
  650. retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
  651. 100.0 - (double) nzeroes * 100.0 / (double) slots,
  652. exUsed);
  653. if (retval == EOF) return(0);
  654. #endif
  655. return(1);
  656. } /* end of cuddCacheProfile */
  657. /**
  658. @brief Resizes the cache.
  659. @sideeffect None
  660. */
  661. void
  662. cuddCacheResize(
  663. DdManager * table)
  664. {
  665. DdCache *cache, *oldcache, *oldacache, *entry, *old;
  666. int i;
  667. int posn, shift;
  668. unsigned int slots, oldslots;
  669. double offset;
  670. int moved = 0;
  671. extern DD_OOMFP MMoutOfMemory;
  672. DD_OOMFP saveHandler;
  673. #ifndef DD_CACHE_PROFILE
  674. ptruint misalignment;
  675. DdNodePtr *mem;
  676. #endif
  677. oldcache = table->cache;
  678. oldacache = table->acache;
  679. oldslots = table->cacheSlots;
  680. slots = table->cacheSlots = oldslots << 1;
  681. #ifdef DD_VERBOSE
  682. (void) fprintf(table->err,"Resizing the cache from %d to %d entries\n",
  683. oldslots, slots);
  684. (void) fprintf(table->err,
  685. "\thits = %g\tmisses = %g\thit ratio = %5.3f\n",
  686. table->cacheHits, table->cacheMisses,
  687. table->cacheHits / (table->cacheHits + table->cacheMisses));
  688. #endif
  689. saveHandler = MMoutOfMemory;
  690. MMoutOfMemory = table->outOfMemCallback;
  691. table->acache = cache = ALLOC(DdCache,slots+1);
  692. MMoutOfMemory = saveHandler;
  693. /* If we fail to allocate the new table we just give up. */
  694. if (cache == NULL) {
  695. #ifdef DD_VERBOSE
  696. (void) fprintf(table->err,"Resizing failed. Giving up.\n");
  697. #endif
  698. table->cacheSlots = oldslots;
  699. table->acache = oldacache;
  700. /* Do not try to resize again. */
  701. table->maxCacheHard = oldslots - 1;
  702. table->cacheSlack = - (int) (oldslots + 1);
  703. return;
  704. }
  705. /* If the size of the cache entry is a power of 2, we want to
  706. ** enforce alignment to that power of two. This happens when
  707. ** DD_CACHE_PROFILE is not defined. */
  708. #ifdef DD_CACHE_PROFILE
  709. table->cache = cache;
  710. #else
  711. mem = (DdNodePtr *) cache;
  712. misalignment = (ptruint) mem & (sizeof(DdCache) - 1);
  713. mem += (sizeof(DdCache) - misalignment) / sizeof(DdNodePtr);
  714. table->cache = cache = (DdCache *) mem;
  715. assert(((ptruint) table->cache & (sizeof(DdCache) - 1)) == 0);
  716. #endif
  717. shift = --(table->cacheShift);
  718. table->memused += (slots - oldslots) * sizeof(DdCache);
  719. table->cacheSlack -= slots; /* need these many slots to double again */
  720. /* Clear new cache. */
  721. for (i = 0; (unsigned) i < slots; i++) {
  722. cache[i].data = NULL;
  723. cache[i].h = 0;
  724. #ifdef DD_CACHE_PROFILE
  725. cache[i].count = 0;
  726. #endif
  727. }
  728. /* Copy from old cache to new one. */
  729. for (i = 0; (unsigned) i < oldslots; i++) {
  730. old = &oldcache[i];
  731. if (old->data != NULL) {
  732. posn = ddCHash2(old->h,old->f,old->g,shift);
  733. entry = &cache[posn];
  734. entry->f = old->f;
  735. entry->g = old->g;
  736. entry->h = old->h;
  737. entry->data = old->data;
  738. #ifdef DD_CACHE_PROFILE
  739. entry->count = 1;
  740. #endif
  741. moved++;
  742. }
  743. }
  744. FREE(oldacache);
  745. /* Reinitialize measurements so as to avoid division by 0 and
  746. ** immediate resizing.
  747. */
  748. offset = (double) (int) (slots * table->minHit + 1);
  749. table->totCacheMisses += table->cacheMisses - offset;
  750. table->cacheMisses = offset;
  751. table->totCachehits += table->cacheHits;
  752. table->cacheHits = 0;
  753. table->cacheLastInserts = table->cacheinserts - (double) moved;
  754. } /* end of cuddCacheResize */
  755. /**
  756. @brief Flushes the cache.
  757. @sideeffect None
  758. */
  759. void
  760. cuddCacheFlush(
  761. DdManager * table)
  762. {
  763. int i, slots;
  764. DdCache *cache;
  765. slots = table->cacheSlots;
  766. cache = table->cache;
  767. for (i = 0; i < slots; i++) {
  768. table->cachedeletions += cache[i].data != NULL;
  769. cache[i].data = NULL;
  770. }
  771. table->cacheLastInserts = table->cacheinserts;
  772. return;
  773. } /* end of cuddCacheFlush */
  774. /**
  775. @brief Returns the floor of the logarithm to the base 2.
  776. @details The input value is assumed to be greater than 0.
  777. @sideeffect None
  778. */
  779. int
  780. cuddComputeFloorLog2(
  781. unsigned int value)
  782. {
  783. int floorLog = 0;
  784. #ifdef DD_DEBUG
  785. assert(value > 0);
  786. #endif
  787. while (value > 1) {
  788. floorLog++;
  789. value >>= 1;
  790. }
  791. return(floorLog);
  792. } /* end of cuddComputeFloorLog2 */
  793. /*---------------------------------------------------------------------------*/
  794. /* Definition of static functions */
  795. /*---------------------------------------------------------------------------*/