cuddCache.c 30.1 KB
Newer Older
Alan Mishchenko committed
1 2 3 4 5 6 7 8 9
/**CFile***********************************************************************

  FileName    [cuddCache.c]

  PackageName [cudd]

  Synopsis    [Functions for cache insertion and lookup.]

  Description [Internal procedures included in this module:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
                <ul>
                <li> cuddInitCache()
                <li> cuddCacheInsert()
                <li> cuddCacheInsert2()
                <li> cuddCacheLookup()
                <li> cuddCacheLookupZdd()
                <li> cuddCacheLookup2()
                <li> cuddCacheLookup2Zdd()
                <li> cuddConstantLookup()
                <li> cuddCacheProfile()
                <li> cuddCacheResize()
                <li> cuddCacheFlush()
                <li> cuddComputeFloorLog2()
                </ul>
            Static procedures included in this module:
                <ul>
                </ul> ]
Alan Mishchenko committed
27 28 29 30 31

  SeeAlso     []

  Author      [Fabio Somenzi]

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
  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.]
Alan Mishchenko committed
63 64 65

******************************************************************************/

66
#include "misc/util/util_hack.h"
67
#include "cuddInt.h"
Alan Mishchenko committed
68

69 70 71
ABC_NAMESPACE_IMPL_START


72

Alan Mishchenko committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/*---------------------------------------------------------------------------*/
/* Constant declarations                                                     */
/*---------------------------------------------------------------------------*/

#ifdef DD_CACHE_PROFILE
#define DD_HYSTO_BINS 8
#endif

/*---------------------------------------------------------------------------*/
/* Stucture declarations                                                     */
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
/* Type declarations                                                         */
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
/* Variable declarations                                                     */
/*---------------------------------------------------------------------------*/

#ifndef lint
96
static char rcsid[] DD_UNUSED = "$Id: cuddCache.c,v 1.34 2009/02/19 16:17:50 fabio Exp $";
Alan Mishchenko committed
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
#endif

/*---------------------------------------------------------------------------*/
/* Macro declarations                                                        */
/*---------------------------------------------------------------------------*/


/**AutomaticStart*************************************************************/

/*---------------------------------------------------------------------------*/
/* Static function prototypes                                                */
/*---------------------------------------------------------------------------*/


/**AutomaticEnd***************************************************************/


/*---------------------------------------------------------------------------*/
/* Definition of exported functions                                          */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Definition of internal functions                                          */
/*---------------------------------------------------------------------------*/


/**Function********************************************************************

  Synopsis    [Initializes the computed table.]

  Description [Initializes the computed table. It is called by
  Cudd_Init. Returns 1 in case of success; 0 otherwise.]

  SideEffects [None]

  SeeAlso     [Cudd_Init]

******************************************************************************/
int
cuddInitCache(
  DdManager * unique /* unique table */,
  unsigned int cacheSize /* initial size of the cache */,
  unsigned int maxCacheSize /* cache size beyond which no resizing occurs */)
{
    int i;
    unsigned int logSize;
#ifndef DD_CACHE_PROFILE
    DdNodePtr *mem;
    ptruint offset;
#endif

    /* Round cacheSize to largest power of 2 not greater than the requested
    ** initial cache size. */
    logSize = cuddComputeFloorLog2(ddMax(cacheSize,unique->slots/2));
    cacheSize = 1 << logSize;
152 153
//    unique->acache = ABC_ALLOC(DdCache,cacheSize+1);
    unique->acache = ABC_ALLOC(DdCache,cacheSize+2);
Alan Mishchenko committed
154
    if (unique->acache == NULL) {
155 156
        unique->errorCode = CUDD_MEMORY_OUT;
        return(0);
Alan Mishchenko committed
157 158 159 160 161 162 163 164 165
    }
    /* If the size of the cache entry is a power of 2, we want to
    ** enforce alignment to that power of two. This happens when
    ** DD_CACHE_PROFILE is not defined. */
#ifdef DD_CACHE_PROFILE
    unique->cache = unique->acache;
    unique->memused += (cacheSize) * sizeof(DdCache);
#else
    mem = (DdNodePtr *) unique->acache;
166 167 168 169
//    offset = (ptruint) mem & (sizeof(DdCache) - 1);
//    mem += (sizeof(DdCache) - offset) / sizeof(DdNodePtr);
    offset = (ptruint) mem & (32 - 1);
    mem += (32 - offset) / sizeof(DdNodePtr);
Alan Mishchenko committed
170
    unique->cache = (DdCache *) mem;
171 172
//    assert(((ptruint) unique->cache & (sizeof(DdCache) - 1)) == 0);
    assert(((ptruint) unique->cache & (32 - 1)) == 0);
Alan Mishchenko committed
173 174 175 176 177 178 179
    unique->memused += (cacheSize+1) * sizeof(DdCache);
#endif
    unique->cacheSlots = cacheSize;
    unique->cacheShift = sizeof(int) * 8 - logSize;
    unique->maxCacheHard = maxCacheSize;
    /* If cacheSlack is non-negative, we can resize. */
    unique->cacheSlack = (int) ddMin(maxCacheSize,
180 181
        DD_MAX_CACHE_TO_SLOTS_RATIO*unique->slots) -
        2 * (int) cacheSize;
Alan Mishchenko committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    Cudd_SetMinHit(unique,DD_MIN_HIT);
    /* Initialize to avoid division by 0 and immediate resizing. */
    unique->cacheMisses = (double) (int) (cacheSize * unique->minHit + 1);
    unique->cacheHits = 0;
    unique->totCachehits = 0;
    /* The sum of cacheMisses and totCacheMisses is always correct,
    ** even though cacheMisses is larger than it should for the reasons
    ** explained above. */
    unique->totCacheMisses = -unique->cacheMisses;
    unique->cachecollisions = 0;
    unique->cacheinserts = 0;
    unique->cacheLastInserts = 0;
    unique->cachedeletions = 0;

    /* Initialize the cache */
    for (i = 0; (unsigned) i < cacheSize; i++) {
198 199
        unique->cache[i].h = 0; /* unused slots */
        unique->cache[i].data = NULL; /* invalid entry */
Alan Mishchenko committed
200
#ifdef DD_CACHE_PROFILE
201
        unique->cache[i].count = 0;
Alan Mishchenko committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
#endif
    }

    return(1);

} /* end of cuddInitCache */


/**Function********************************************************************

  Synopsis    [Inserts a result in the cache.]

  Description []

  SideEffects [None]

  SeeAlso     [cuddCacheInsert2 cuddCacheInsert1]

******************************************************************************/
void
cuddCacheInsert(
  DdManager * table,
  ptruint op,
  DdNode * f,
  DdNode * g,
  DdNode * h,
  DdNode * data)
{
    int posn;
231
    unsigned hash;
Alan Mishchenko committed
232 233
    register DdCache *entry;
    ptruint uf, ug, uh;
234
    ptruint ufc, ugc, uhc;
Alan Mishchenko committed
235 236 237 238 239

    uf = (ptruint) f | (op & 0xe);
    ug = (ptruint) g | (op >> 4);
    uh = (ptruint) h;

240 241 242 243 244 245 246
    ufc = (ptruint) cuddF2L(f) | (op & 0xe);
    ugc = (ptruint) cuddF2L(g) | (op >> 4);
    uhc = (ptruint) cuddF2L(h);

    hash = ddCHash2_(uhc,ufc,ugc);
//    posn = ddCHash2(uhc,ufc,ugc,table->cacheShift);
    posn = hash >> table->cacheShift;
Alan Mishchenko committed
247 248 249 250 251 252 253 254 255 256 257 258
    entry = &table->cache[posn];

    table->cachecollisions += entry->data != NULL;
    table->cacheinserts++;

    entry->f    = (DdNode *) uf;
    entry->g    = (DdNode *) ug;
    entry->h    = uh;
    entry->data = data;
#ifdef DD_CACHE_PROFILE
    entry->count++;
#endif
259
    entry->hash = hash;
Alan Mishchenko committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

} /* end of cuddCacheInsert */


/**Function********************************************************************

  Synopsis    [Inserts a result in the cache for a function with two
  operands.]

  Description []

  SideEffects [None]

  SeeAlso     [cuddCacheInsert cuddCacheInsert1]

******************************************************************************/
void
cuddCacheInsert2(
  DdManager * table,
279
  DD_CTFP op,
Alan Mishchenko committed
280 281 282 283 284
  DdNode * f,
  DdNode * g,
  DdNode * data)
{
    int posn;
285
    unsigned hash;
Alan Mishchenko committed
286 287
    register DdCache *entry;

288 289 290
    hash = ddCHash2_(op,cuddF2L(f),cuddF2L(g));
//    posn = ddCHash2(op,cuddF2L(f),cuddF2L(g),table->cacheShift);
    posn = hash >> table->cacheShift;
Alan Mishchenko committed
291 292 293 294 295 296 297 298 299 300 301 302 303 304
    entry = &table->cache[posn];

    if (entry->data != NULL) {
        table->cachecollisions++;
    }
    table->cacheinserts++;

    entry->f = f;
    entry->g = g;
    entry->h = (ptruint) op;
    entry->data = data;
#ifdef DD_CACHE_PROFILE
    entry->count++;
#endif
305
    entry->hash = hash;
Alan Mishchenko committed
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

} /* end of cuddCacheInsert2 */


/**Function********************************************************************

  Synopsis    [Inserts a result in the cache for a function with two
  operands.]

  Description []

  SideEffects [None]

  SeeAlso     [cuddCacheInsert cuddCacheInsert2]

******************************************************************************/
void
cuddCacheInsert1(
  DdManager * table,
325
  DD_CTFP1 op,
Alan Mishchenko committed
326 327 328 329
  DdNode * f,
  DdNode * data)
{
    int posn;
330
    unsigned hash;
Alan Mishchenko committed
331 332
    register DdCache *entry;

333 334 335
    hash = ddCHash2_(op,cuddF2L(f),cuddF2L(f));
//    posn = ddCHash2(op,cuddF2L(f),cuddF2L(f),table->cacheShift);
    posn = hash >> table->cacheShift;
Alan Mishchenko committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349
    entry = &table->cache[posn];

    if (entry->data != NULL) {
        table->cachecollisions++;
    }
    table->cacheinserts++;

    entry->f = f;
    entry->g = f;
    entry->h = (ptruint) op;
    entry->data = data;
#ifdef DD_CACHE_PROFILE
    entry->count++;
#endif
350
    entry->hash = hash;
Alan Mishchenko committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

} /* end of cuddCacheInsert1 */


/**Function********************************************************************

  Synopsis    [Looks up in the cache for the result of op applied to f,
  g, and h.]

  Description [Returns the result if found; it returns NULL if no
  result is found.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookup2 cuddCacheLookup1]

******************************************************************************/
DdNode *
cuddCacheLookup(
  DdManager * table,
  ptruint op,
  DdNode * f,
  DdNode * g,
  DdNode * h)
{
    int posn;
    DdCache *en,*cache;
    DdNode *data;
    ptruint uf, ug, uh;
380
    ptruint ufc, ugc, uhc;
Alan Mishchenko committed
381 382 383 384 385

    uf = (ptruint) f | (op & 0xe);
    ug = (ptruint) g | (op >> 4);
    uh = (ptruint) h;

386 387 388 389
    ufc = (ptruint) cuddF2L(f) | (op & 0xe);
    ugc = (ptruint) cuddF2L(g) | (op >> 4);
    uhc = (ptruint) cuddF2L(h);

Alan Mishchenko committed
390 391 392 393 394 395 396
    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif

397
    posn = ddCHash2(uhc,ufc,ugc,table->cacheShift);
Alan Mishchenko committed
398
    en = &cache[posn];
399
    if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug && en->h==uh) {
400 401 402 403 404 405
        data = Cudd_Regular(en->data);
        table->cacheHits++;
        if (data->ref == 0) {
            cuddReclaim(table,data);
        }
        return(en->data);
Alan Mishchenko committed
406 407 408 409 410 411
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0 &&
412 413
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
    }

    return(NULL);

} /* end of cuddCacheLookup */


/**Function********************************************************************

  Synopsis    [Looks up in the cache for the result of op applied to f,
  g, and h.]

  Description [Returns the result if found; it returns NULL if no
  result is found.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookup2Zdd cuddCacheLookup1Zdd]

******************************************************************************/
DdNode *
cuddCacheLookupZdd(
  DdManager * table,
  ptruint op,
  DdNode * f,
  DdNode * g,
  DdNode * h)
{
    int posn;
    DdCache *en,*cache;
    DdNode *data;
    ptruint uf, ug, uh;
446
    ptruint ufc, ugc, uhc;
Alan Mishchenko committed
447 448 449 450 451

    uf = (ptruint) f | (op & 0xe);
    ug = (ptruint) g | (op >> 4);
    uh = (ptruint) h;

452 453 454 455
    ufc = (ptruint) cuddF2L(f) | (op & 0xe);
    ugc = (ptruint) cuddF2L(g) | (op >> 4);
    uhc = (ptruint) cuddF2L(h);

Alan Mishchenko committed
456 457 458 459 460 461 462
    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif

463
    posn = ddCHash2(uhc,ufc,ugc,table->cacheShift);
Alan Mishchenko committed
464 465
    en = &cache[posn];
    if (en->data != NULL && en->f==(DdNodePtr)uf && en->g==(DdNodePtr)ug &&
466 467 468 469 470 471 472
        en->h==uh) {
        data = Cudd_Regular(en->data);
        table->cacheHits++;
        if (data->ref == 0) {
            cuddReclaimZdd(table,data);
        }
        return(en->data);
Alan Mishchenko committed
473 474 475 476 477 478
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0 &&
479 480
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
    }

    return(NULL);

} /* end of cuddCacheLookupZdd */


/**Function********************************************************************

  Synopsis    [Looks up in the cache for the result of op applied to f
  and g.]

  Description [Returns the result if found; it returns NULL if no
  result is found.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookup cuddCacheLookup1]

******************************************************************************/
DdNode *
cuddCacheLookup2(
  DdManager * table,
504
  DD_CTFP op,
Alan Mishchenko committed
505 506 507 508 509 510 511 512 513 514 515 516 517 518
  DdNode * f,
  DdNode * g)
{
    int posn;
    DdCache *en,*cache;
    DdNode *data;

    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif

519
    posn = ddCHash2(op,cuddF2L(f),cuddF2L(g),table->cacheShift);
Alan Mishchenko committed
520 521
    en = &cache[posn];
    if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
522 523 524 525 526 527
        data = Cudd_Regular(en->data);
        table->cacheHits++;
        if (data->ref == 0) {
            cuddReclaim(table,data);
        }
        return(en->data);
Alan Mishchenko committed
528 529 530 531 532 533
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0 &&
534 535
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
    }

    return(NULL);

} /* end of cuddCacheLookup2 */


/**Function********************************************************************

  Synopsis [Looks up in the cache for the result of op applied to f.]

  Description [Returns the result if found; it returns NULL if no
  result is found.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookup cuddCacheLookup2]

******************************************************************************/
DdNode *
cuddCacheLookup1(
  DdManager * table,
558
  DD_CTFP1 op,
Alan Mishchenko committed
559 560 561 562 563 564 565 566 567 568 569 570 571
  DdNode * f)
{
    int posn;
    DdCache *en,*cache;
    DdNode *data;

    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif

572
    posn = ddCHash2(op,cuddF2L(f),cuddF2L(f),table->cacheShift);
Alan Mishchenko committed
573 574
    en = &cache[posn];
    if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
575 576 577 578 579 580
        data = Cudd_Regular(en->data);
        table->cacheHits++;
        if (data->ref == 0) {
            cuddReclaim(table,data);
        }
        return(en->data);
Alan Mishchenko committed
581 582 583 584 585 586
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0 &&
587 588
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
    }

    return(NULL);

} /* end of cuddCacheLookup1 */


/**Function********************************************************************

  Synopsis [Looks up in the cache for the result of op applied to f
  and g.]

  Description [Returns the result if found; it returns NULL if no
  result is found.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookupZdd cuddCacheLookup1Zdd]

******************************************************************************/
DdNode *
cuddCacheLookup2Zdd(
  DdManager * table,
612
  DD_CTFP op,
Alan Mishchenko committed
613 614 615 616 617 618 619 620 621 622 623 624 625 626
  DdNode * f,
  DdNode * g)
{
    int posn;
    DdCache *en,*cache;
    DdNode *data;

    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif

627
    posn = ddCHash2(op,cuddF2L(f),cuddF2L(g),table->cacheShift);
Alan Mishchenko committed
628 629
    en = &cache[posn];
    if (en->data != NULL && en->f==f && en->g==g && en->h==(ptruint)op) {
630 631 632 633 634 635
        data = Cudd_Regular(en->data);
        table->cacheHits++;
        if (data->ref == 0) {
            cuddReclaimZdd(table,data);
        }
        return(en->data);
Alan Mishchenko committed
636 637 638 639 640 641
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0 &&
642 643
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
    }

    return(NULL);

} /* end of cuddCacheLookup2Zdd */


/**Function********************************************************************

  Synopsis [Looks up in the cache for the result of op applied to f.]

  Description [Returns the result if found; it returns NULL if no
  result is found.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookupZdd cuddCacheLookup2Zdd]

******************************************************************************/
DdNode *
cuddCacheLookup1Zdd(
  DdManager * table,
666
  DD_CTFP1 op,
Alan Mishchenko committed
667 668 669 670 671 672 673 674 675 676 677 678 679
  DdNode * f)
{
    int posn;
    DdCache *en,*cache;
    DdNode *data;

    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif

680
    posn = ddCHash2(op,cuddF2L(f),cuddF2L(f),table->cacheShift);
Alan Mishchenko committed
681 682
    en = &cache[posn];
    if (en->data != NULL && en->f==f && en->h==(ptruint)op) {
683 684 685 686 687 688
        data = Cudd_Regular(en->data);
        table->cacheHits++;
        if (data->ref == 0) {
            cuddReclaimZdd(table,data);
        }
        return(en->data);
Alan Mishchenko committed
689 690 691 692 693 694
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0  &&
695 696
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
    }

    return(NULL);

} /* end of cuddCacheLookup1Zdd */


/**Function********************************************************************

  Synopsis [Looks up in the cache for the result of op applied to f,
  g, and h.]

  Description [Looks up in the cache for the result of op applied to f,
  g, and h. Assumes that the calling procedure (e.g.,
  Cudd_bddIteConstant) is only interested in whether the result is
  constant or not. Returns the result if found (possibly
  DD_NON_CONSTANT); otherwise it returns NULL.]

  SideEffects [None]

  SeeAlso     [cuddCacheLookup]

******************************************************************************/
DdNode *
cuddConstantLookup(
  DdManager * table,
  ptruint op,
  DdNode * f,
  DdNode * g,
  DdNode * h)
{
    int posn;
    DdCache *en,*cache;
    ptruint uf, ug, uh;
731
    ptruint ufc, ugc, uhc;
Alan Mishchenko committed
732 733 734 735 736

    uf = (ptruint) f | (op & 0xe);
    ug = (ptruint) g | (op >> 4);
    uh = (ptruint) h;

737 738 739 740
    ufc = (ptruint) cuddF2L(f) | (op & 0xe);
    ugc = (ptruint) cuddF2L(g) | (op >> 4);
    uhc = (ptruint) cuddF2L(h);

Alan Mishchenko committed
741 742 743 744 745 746
    cache = table->cache;
#ifdef DD_DEBUG
    if (cache == NULL) {
        return(NULL);
    }
#endif
747
    posn = ddCHash2(uhc,ufc,ugc,table->cacheShift);
Alan Mishchenko committed
748 749 750 751 752 753
    en = &cache[posn];

    /* We do not reclaim here because the result should not be
     * referenced, but only tested for being a constant.
     */
    if (en->data != NULL &&
754 755
        en->f == (DdNodePtr)uf && en->g == (DdNodePtr)ug && en->h == uh) {
        table->cacheHits++;
Alan Mishchenko committed
756 757 758 759 760 761 762
        return(en->data);
    }

    /* Cache miss: decide whether to resize. */
    table->cacheMisses++;

    if (table->cacheSlack >= 0 &&
763 764
        table->cacheHits > table->cacheMisses * table->minHit) {
        cuddCacheResize(table);
Alan Mishchenko committed
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
    }

    return(NULL);

} /* end of cuddConstantLookup */


/**Function********************************************************************

  Synopsis    [Computes and prints a profile of the cache usage.]

  Description [Computes and prints a profile of the cache usage.
  Returns 1 if successful; 0 otherwise.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
int
cuddCacheProfile(
  DdManager * table,
  FILE * fp)
{
    DdCache *cache = table->cache;
    int slots = table->cacheSlots;
    int nzeroes = 0;
    int i, retval;
    double exUsed;

#ifdef DD_CACHE_PROFILE
    double count, mean, meansq, stddev, expected;
    long max, min;
    int imax, imin;
    double *hystogramQ, *hystogramR; /* histograms by quotient and remainder */
    int nbins = DD_HYSTO_BINS;
    int bin;
    long thiscount;
    double totalcount, exStddev;

    meansq = mean = expected = 0.0;
    max = min = (long) cache[0].count;
    imax = imin = 0;
    totalcount = 0.0;

Alan Mishchenko committed
810
    hystogramQ = ABC_ALLOC(double, nbins);
Alan Mishchenko committed
811
    if (hystogramQ == NULL) {
812 813
        table->errorCode = CUDD_MEMORY_OUT;
        return(0);
Alan Mishchenko committed
814
    }
Alan Mishchenko committed
815
    hystogramR = ABC_ALLOC(double, nbins);
Alan Mishchenko committed
816
    if (hystogramR == NULL) {
817 818 819
        ABC_FREE(hystogramQ);
        table->errorCode = CUDD_MEMORY_OUT;
        return(0);
Alan Mishchenko committed
820 821
    }
    for (i = 0; i < nbins; i++) {
822 823
        hystogramQ[i] = 0;
        hystogramR[i] = 0;
Alan Mishchenko committed
824 825 826
    }

    for (i = 0; i < slots; i++) {
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
        thiscount = (long) cache[i].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;
        hystogramQ[bin] += (double) thiscount;
        bin = i % nbins;
        hystogramR[bin] += (double) thiscount;
Alan Mishchenko committed
848 849 850
    }
    mean /= (double) slots;
    meansq /= (double) slots;
851

Alan Mishchenko committed
852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
    /* Compute the standard deviation from both the data and the
    ** theoretical model for a random distribution. */
    stddev = sqrt(meansq - mean*mean);
    exStddev = sqrt((1 - 1/(double) slots) * totalcount / (double) slots);

    retval = fprintf(fp,"Cache average accesses = %g\n",  mean);
    if (retval == EOF) return(0);
    retval = fprintf(fp,"Cache access standard deviation = %g ", stddev);
    if (retval == EOF) return(0);
    retval = fprintf(fp,"(expected = %g)\n", exStddev);
    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);
    exUsed = 100.0 * (1.0 - exp(-totalcount / (double) slots));
    retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
869 870
                     100.0 - (double) nzeroes * 100.0 / (double) slots,
                     exUsed);
Alan Mishchenko committed
871 872 873
    if (retval == EOF) return(0);

    if (totalcount > 0) {
874 875
        expected /= totalcount;
        retval = fprintf(fp,"Cache access hystogram for %d bins", nbins);
Alan Mishchenko committed
876
        if (retval == EOF) return(0);
877 878 879 880 881 882 883 884 885 886 887 888 889 890
        retval = fprintf(fp," (expected bin value = %g)\nBy quotient:",
                         expected);
        if (retval == EOF) return(0);
        for (i = nbins - 1; i>=0; i--) {
            retval = fprintf(fp," %.0f", hystogramQ[i]);
            if (retval == EOF) return(0);
        }
        retval = fprintf(fp,"\nBy residue: ");
        if (retval == EOF) return(0);
        for (i = nbins - 1; i>=0; i--) {
            retval = fprintf(fp," %.0f", hystogramR[i]);
            if (retval == EOF) return(0);
        }
        retval = fprintf(fp,"\n");
Alan Mishchenko committed
891 892 893
        if (retval == EOF) return(0);
    }

Alan Mishchenko committed
894 895
    ABC_FREE(hystogramQ);
    ABC_FREE(hystogramR);
Alan Mishchenko committed
896 897
#else
    for (i = 0; i < slots; i++) {
898
        nzeroes += cache[i].h == 0;
Alan Mishchenko committed
899 900
    }
    exUsed = 100.0 *
901 902
        (1.0 - exp(-(table->cacheinserts - table->cacheLastInserts) /
                   (double) slots));
Alan Mishchenko committed
903
    retval = fprintf(fp,"Cache used slots = %.2f%% (expected %.2f%%)\n",
904 905
                     100.0 - (double) nzeroes * 100.0 / (double) slots,
                     exUsed);
Alan Mishchenko committed
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
    if (retval == EOF) return(0);
#endif
    return(1);

} /* end of cuddCacheProfile */


/**Function********************************************************************

  Synopsis    [Resizes the cache.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
void
cuddCacheResize(
  DdManager * table)
{
    DdCache *cache, *oldcache, *oldacache, *entry, *old;
    int i;
    int posn, shift;
    unsigned int slots, oldslots;
    double offset;
    int moved = 0;
934 935
    extern DD_OOMFP MMoutOfMemory;
    DD_OOMFP saveHandler;
Alan Mishchenko committed
936 937 938 939 940 941 942 943 944 945 946 947
#ifndef DD_CACHE_PROFILE
    ptruint misalignment;
    DdNodePtr *mem;
#endif

    oldcache = table->cache;
    oldacache = table->acache;
    oldslots = table->cacheSlots;
    slots = table->cacheSlots = oldslots << 1;

#ifdef DD_VERBOSE
    (void) fprintf(table->err,"Resizing the cache from %d to %d entries\n",
948
                   oldslots, slots);
Alan Mishchenko committed
949
    (void) fprintf(table->err,
950 951 952
                   "\thits = %g\tmisses = %g\thit ratio = %5.3f\n",
                   table->cacheHits, table->cacheMisses,
                   table->cacheHits / (table->cacheHits + table->cacheMisses));
Alan Mishchenko committed
953 954 955 956
#endif

    saveHandler = MMoutOfMemory;
    MMoutOfMemory = Cudd_OutOfMem;
957 958
//    table->acache = cache = ABC_ALLOC(DdCache,slots+1);
    table->acache = cache = ABC_ALLOC(DdCache,slots+2);
Alan Mishchenko committed
959 960 961 962
    MMoutOfMemory = saveHandler;
    /* If we fail to allocate the new table we just give up. */
    if (cache == NULL) {
#ifdef DD_VERBOSE
963
        (void) fprintf(table->err,"Resizing failed. Giving up.\n");
Alan Mishchenko committed
964
#endif
965 966 967 968 969 970
        table->cacheSlots = oldslots;
        table->acache = oldacache;
        /* Do not try to resize again. */
        table->maxCacheHard = oldslots - 1;
        table->cacheSlack = - (int) (oldslots + 1);
        return;
Alan Mishchenko committed
971 972 973 974 975 976 977 978
    }
    /* If the size of the cache entry is a power of 2, we want to
    ** enforce alignment to that power of two. This happens when
    ** DD_CACHE_PROFILE is not defined. */
#ifdef DD_CACHE_PROFILE
    table->cache = cache;
#else
    mem = (DdNodePtr *) cache;
979 980 981 982 983 984
//    misalignment = (ptruint) mem & (sizeof(DdCache) - 1);
//    mem += (sizeof(DdCache) - misalignment) / sizeof(DdNodePtr);
//    table->cache = cache = (DdCache *) mem;
//    assert(((ptruint) table->cache & (sizeof(DdCache) - 1)) == 0);
    misalignment = (ptruint) mem & (32 - 1);
    mem += (32 - misalignment) / sizeof(DdNodePtr);
Alan Mishchenko committed
985
    table->cache = cache = (DdCache *) mem;
986
    assert(((ptruint) table->cache & (32 - 1)) == 0);
Alan Mishchenko committed
987 988 989 990 991 992 993
#endif
    shift = --(table->cacheShift);
    table->memused += (slots - oldslots) * sizeof(DdCache);
    table->cacheSlack -= slots; /* need these many slots to double again */

    /* Clear new cache. */
    for (i = 0; (unsigned) i < slots; i++) {
994 995
        cache[i].data = NULL;
        cache[i].h = 0;
Alan Mishchenko committed
996
#ifdef DD_CACHE_PROFILE
997
        cache[i].count = 0;
Alan Mishchenko committed
998 999 1000 1001 1002
#endif
    }

    /* Copy from old cache to new one. */
    for (i = 0; (unsigned) i < oldslots; i++) {
1003 1004
        old = &oldcache[i];
        if (old->data != NULL) {
1005 1006
//            posn = ddCHash2(old->h,old->f,old->g,shift);
            posn = old->hash >> shift;
1007 1008 1009 1010 1011
            entry = &cache[posn];
            entry->f = old->f;
            entry->g = old->g;
            entry->h = old->h;
            entry->data = old->data;
Alan Mishchenko committed
1012
#ifdef DD_CACHE_PROFILE
1013
            entry->count = 1;
Alan Mishchenko committed
1014
#endif
1015
            entry->hash = old->hash;
1016 1017
            moved++;
        }
Alan Mishchenko committed
1018 1019
    }

Alan Mishchenko committed
1020
    ABC_FREE(oldacache);
Alan Mishchenko committed
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055

    /* Reinitialize measurements so as to avoid division by 0 and
    ** immediate resizing.
    */
    offset = (double) (int) (slots * table->minHit + 1);
    table->totCacheMisses += table->cacheMisses - offset;
    table->cacheMisses = offset;
    table->totCachehits += table->cacheHits;
    table->cacheHits = 0;
    table->cacheLastInserts = table->cacheinserts - (double) moved;

} /* end of cuddCacheResize */


/**Function********************************************************************

  Synopsis    [Flushes the cache.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
void
cuddCacheFlush(
  DdManager * table)
{
    int i, slots;
    DdCache *cache;

    slots = table->cacheSlots;
    cache = table->cache;
    for (i = 0; i < slots; i++) {
1056 1057
        table->cachedeletions += cache[i].data != NULL;
        cache[i].data = NULL;
Alan Mishchenko committed
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
    }
    table->cacheLastInserts = table->cacheinserts;

    return;

} /* end of cuddCacheFlush */


/**Function********************************************************************

  Synopsis    [Returns the floor of the logarithm to the base 2.]

  Description [Returns the floor of the logarithm to the base 2.
  The input value is assumed to be greater than 0.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
int
cuddComputeFloorLog2(
  unsigned int value)
{
    int floorLog = 0;
#ifdef DD_DEBUG
    assert(value > 0);
#endif
    while (value > 1) {
1087 1088
        floorLog++;
        value >>= 1;
Alan Mishchenko committed
1089 1090 1091 1092 1093 1094 1095 1096
    }
    return(floorLog);

} /* end of cuddComputeFloorLog2 */

/*---------------------------------------------------------------------------*/
/* Definition of static functions                                            */
/*---------------------------------------------------------------------------*/
1097 1098


1099 1100
ABC_NAMESPACE_IMPL_END