/**CFile**************************************************************** FileName [cloudCore.c] PackageName [Fast application-specific BDD package.] Synopsis [The package core.] Author [Alan Mishchenko ] Affiliation [ECE Department. Portland State University, Portland, Oregon.] Date [Ver. 1.0. Started - June 10, 2002.] Revision [$Id: cloudCore.c,v 1.0 2002/06/10 03:00:00 alanmi Exp $] ***********************************************************************/ #include #include "cloud.h" ABC_NAMESPACE_IMPL_START // the number of operators using cache static int CacheOperNum = 4; // the ratio of cache size to the unique table size for each operator static int CacheLogRatioDefault[4] = { 2, // CLOUD_OPER_AND, 8, // CLOUD_OPER_XOR, 8, // CLOUD_OPER_BDIFF, 8 // CLOUD_OPER_LEQ }; // the ratio of cache size to the unique table size for each operator static int CacheSize[4] = { 2, // CLOUD_OPER_AND, 2, // CLOUD_OPER_XOR, 2, // CLOUD_OPER_BDIFF, 2 // CLOUD_OPER_LEQ }; //////////////////////////////////////////////////////////////////////// /// FUNCTION DECLARATIONS /// //////////////////////////////////////////////////////////////////////// // static functions static CloudNode * cloudMakeNode( CloudManager * dd, CloudVar v, CloudNode * t, CloudNode * e ); static void cloudCacheAllocate( CloudManager * dd, CloudOper oper ); //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function******************************************************************** Synopsis [Starts the cloud manager.] Description [The first arguments is the number of elementary variables used. The second arguments is the number of bits of the unsigned integer used to represent nodes in the unique table. If the second argument is 0, the package assumes 23 to represent nodes, which is equivalent to 2^23 = 8,388,608 nodes.] SideEffects [] SeeAlso [] ******************************************************************************/ CloudManager * Cloud_Init( int nVars, int nBits ) { CloudManager * dd; int i; abctime clk1, clk2; assert( nVars <= 100000 ); assert( nBits < 32 ); // assign the defaults if ( nBits == 0 ) nBits = CLOUD_NODE_BITS; // start the manager dd = ABC_CALLOC( CloudManager, 1 ); dd->nMemUsed += sizeof(CloudManager); // variables dd->nVars = nVars; // the number of variables allocated // bits dd->bitsNode = nBits; // the number of bits used for the node for ( i = 0; i < CacheOperNum; i++ ) dd->bitsCache[i] = nBits - CacheLogRatioDefault[i]; // shifts dd->shiftUnique = 8*sizeof(unsigned) - (nBits + 1); // gets node index in the hash table for ( i = 0; i < CacheOperNum; i++ ) dd->shiftCache[i] = 8*sizeof(unsigned) - dd->bitsCache[i]; // nodes dd->nNodesAlloc = (1 << (nBits + 1)); // 2 ^ (nBits + 1) dd->nNodesLimit = (1 << nBits); // 2 ^ nBits // unique table clk1 = Abc_Clock(); dd->tUnique = ABC_CALLOC( CloudNode, dd->nNodesAlloc ); dd->nMemUsed += sizeof(CloudNode) * dd->nNodesAlloc; clk2 = Abc_Clock(); //ABC_PRT( "calloc() time", clk2 - clk1 ); // set up the constant node (the only node that is not in the hash table) dd->nSignCur = 1; dd->tUnique[0].s = dd->nSignCur; dd->tUnique[0].v = CLOUD_CONST_INDEX; dd->tUnique[0].e = NULL; dd->tUnique[0].t = NULL; dd->one = dd->tUnique; dd->zero = Cloud_Not(dd->one); dd->nNodesCur = 1; // special nodes dd->pNodeStart = dd->tUnique + 1; dd->pNodeEnd = dd->tUnique + dd->nNodesAlloc; // set up the elementary variables dd->vars = ABC_ALLOC( CloudNode *, dd->nVars ); dd->nMemUsed += sizeof(CloudNode *) * dd->nVars; for ( i = 0; i < dd->nVars; i++ ) dd->vars[i] = cloudMakeNode( dd, i, dd->one, dd->zero ); return dd; }; /**Function******************************************************************** Synopsis [Stops the cloud manager.] Description [The first arguments tells show many elementary variables are used. The second arguments tells how many bits of the unsigned integer are used to represent regular nodes in the unique table.] SideEffects [] SeeAlso [] ******************************************************************************/ void Cloud_Quit( CloudManager * dd ) { int i; ABC_FREE( dd->ppNodes ); ABC_FREE( dd->tUnique ); ABC_FREE( dd->vars ); for ( i = 0; i < 4; i++ ) ABC_FREE( dd->tCaches[i] ); ABC_FREE( dd ); } /**Function******************************************************************** Synopsis [Prepares the manager for another run.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ void Cloud_Restart( CloudManager * dd ) { int i; assert( dd->one->s == dd->nSignCur ); dd->nSignCur++; dd->one->s++; for ( i = 0; i < dd->nVars; i++ ) dd->vars[i]->s++; dd->nNodesCur = 1 + dd->nVars; } /**Function******************************************************************** Synopsis [This optional function allocates operation cache of the given size.] Description [Cache for each operation is allocated independently when the first operation of the given type is performed. The user can allocate cache of his/her preferred size by calling Cloud_CacheAllocate before the first operation of the given type is performed, but this call is optional. Argument "logratio" gives the binary logarithm of the ratio of the size of the unique table to that of cache. For example, if "logratio" is equal to 3, and the unique table will be 2^3=8 times larger than cache; so, if unique table is 2^23 = 8,388,608 nodes, the cache size will be 2^3=8 times smaller and equal to 2^20 = 1,048,576 entries.] SideEffects [] SeeAlso [] ******************************************************************************/ void Cloud_CacheAllocate( CloudManager * dd, CloudOper oper, int logratio ) { assert( logratio > 0 ); // cache cannot be larger than the unique table assert( logratio < dd->bitsNode ); // cache cannot be smaller than 2 entries if ( logratio ) { dd->bitsCache[oper] = dd->bitsNode - logratio; dd->shiftCache[oper] = 8*sizeof(unsigned) - dd->bitsCache[oper]; } cloudCacheAllocate( dd, oper ); } /**Function******************************************************************** Synopsis [Internal cache allocation.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ void cloudCacheAllocate( CloudManager * dd, CloudOper oper ) { int nCacheEntries = (1 << dd->bitsCache[oper]); if ( CacheSize[oper] == 1 ) { dd->tCaches[oper] = (CloudCacheEntry2 *)ABC_CALLOC( CloudCacheEntry1, nCacheEntries ); dd->nMemUsed += sizeof(CloudCacheEntry1) * nCacheEntries; } else if ( CacheSize[oper] == 2 ) { dd->tCaches[oper] = (CloudCacheEntry2 *)ABC_CALLOC( CloudCacheEntry2, nCacheEntries ); dd->nMemUsed += sizeof(CloudCacheEntry2) * nCacheEntries; } else if ( CacheSize[oper] == 3 ) { dd->tCaches[oper] = (CloudCacheEntry2 *)ABC_CALLOC( CloudCacheEntry3, nCacheEntries ); dd->nMemUsed += sizeof(CloudCacheEntry3) * nCacheEntries; } } /**Function******************************************************************** Synopsis [Returns or creates a new node] Description [Checks the unique table for the existance of the node. If the node is present, returns the node. If the node is absent, creates a new node.] SideEffects [] SeeAlso [] ******************************************************************************/ CloudNode * Cloud_MakeNode( CloudManager * dd, CloudVar v, CloudNode * t, CloudNode * e ) { CloudNode * pRes; CLOUD_ASSERT(t); CLOUD_ASSERT(e); assert( v < Cloud_V(t) && v < Cloud_V(e) ); // variable should be above in the order if ( Cloud_IsComplement(t) ) { pRes = cloudMakeNode( dd, v, Cloud_Not(t), Cloud_Not(e) ); if ( pRes != NULL ) pRes = Cloud_Not(pRes); } else pRes = cloudMakeNode( dd, v, t, e ); return pRes; } /**Function******************************************************************** Synopsis [Returns or creates a new node] Description [Checks the unique table for the existance of the node. If the node is present, returns the node. If the node is absent, creates a new node.] SideEffects [] SeeAlso [] ******************************************************************************/ CloudNode * cloudMakeNode( CloudManager * dd, CloudVar v, CloudNode * t, CloudNode * e ) { CloudNode * entryUnique; CLOUD_ASSERT(t); CLOUD_ASSERT(e); assert( ((int)v) >= 0 && ((int)v) < dd->nVars ); // the variable must be in the range assert( v < Cloud_V(t) && v < Cloud_V(e) ); // variable should be above in the order assert( !Cloud_IsComplement(t) ); // the THEN edge must not be complemented // make sure we are not searching for the constant node assert( t && e ); // get the unique entry entryUnique = dd->tUnique + cloudHashCudd3(v, t, e, dd->shiftUnique); while ( entryUnique->s == dd->nSignCur ) { // compare the node if ( entryUnique->v == v && entryUnique->t == t && entryUnique->e == e ) { // the node is found dd->nUniqueHits++; return entryUnique; // returns the node } // increment the hash value modulus the hash table size if ( ++entryUnique - dd->tUnique == dd->nNodesAlloc ) entryUnique = dd->tUnique + 1; // increment the number of steps through the table dd->nUniqueSteps++; } dd->nUniqueMisses++; // check if the new node can be created if ( ++dd->nNodesCur == dd->nNodesLimit ) { // initiate the restart printf( "Cloud needs restart!\n" ); // fflush( stdout ); // exit(1); return NULL; } // create the node entryUnique->s = dd->nSignCur; entryUnique->v = v; entryUnique->t = t; entryUnique->e = e; return entryUnique; // returns the node } /**Function******************************************************************** Synopsis [Performs the AND or two BDDs] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ CloudNode * cloudBddAnd( CloudManager * dd, CloudNode * f, CloudNode * g ) { CloudNode * F, * G, * r; CloudCacheEntry2 * cacheEntry; CloudNode * fv, * fnv, * gv, * gnv, * t, * e; CloudVar var; assert( f <= g ); // terminal cases F = Cloud_Regular(f); G = Cloud_Regular(g); if ( F == G ) { if ( f == g ) return f; else return dd->zero; } if ( F == dd->one ) { if ( f == dd->one ) return g; else return f; } // check cache cacheEntry = dd->tCaches[CLOUD_OPER_AND] + cloudHashCudd2(f, g, dd->shiftCache[CLOUD_OPER_AND]); // cacheEntry = dd->tCaches[CLOUD_OPER_AND] + cloudHashBuddy2(f, g, dd->shiftCache[CLOUD_OPER_AND]); r = cloudCacheLookup2( cacheEntry, dd->nSignCur, f, g ); if ( r != NULL ) { dd->nCacheHits++; return r; } dd->nCacheMisses++; // compute cofactors if ( cloudV(F) <= cloudV(G) ) { var = cloudV(F); if ( Cloud_IsComplement(f) ) { fnv = Cloud_Not(cloudE(F)); fv = Cloud_Not(cloudT(F)); } else { fnv = cloudE(F); fv = cloudT(F); } } else { var = cloudV(G); fv = fnv = f; } if ( cloudV(G) <= cloudV(F) ) { if ( Cloud_IsComplement(g) ) { gnv = Cloud_Not(cloudE(G)); gv = Cloud_Not(cloudT(G)); } else { gnv = cloudE(G); gv = cloudT(G); } } else { gv = gnv = g; } if ( fv <= gv ) t = cloudBddAnd( dd, fv, gv ); else t = cloudBddAnd( dd, gv, fv ); if ( t == NULL ) return NULL; if ( fnv <= gnv ) e = cloudBddAnd( dd, fnv, gnv ); else e = cloudBddAnd( dd, gnv, fnv ); if ( e == NULL ) return NULL; if ( t == e ) r = t; else { if ( Cloud_IsComplement(t) ) { r = cloudMakeNode( dd, var, Cloud_Not(t), Cloud_Not(e) ); if ( r == NULL ) return NULL; r = Cloud_Not(r); } else { r = cloudMakeNode( dd, var, t, e ); if ( r == NULL ) return NULL; } } cloudCacheInsert2( cacheEntry, dd->nSignCur, f, g, r ); return r; } /**Function******************************************************************** Synopsis [Performs the AND or two BDDs] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ static inline CloudNode * cloudBddAnd_gate( CloudManager * dd, CloudNode * f, CloudNode * g ) { if ( f <= g ) return cloudBddAnd(dd,f,g); else return cloudBddAnd(dd,g,f); } /**Function******************************************************************** Synopsis [Performs the AND or two BDDs] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ CloudNode * Cloud_bddAnd( CloudManager * dd, CloudNode * f, CloudNode * g ) { if ( Cloud_Regular(f) == NULL || Cloud_Regular(g) == NULL ) return NULL; CLOUD_ASSERT(f); CLOUD_ASSERT(g); if ( dd->tCaches[CLOUD_OPER_AND] == NULL ) cloudCacheAllocate( dd, CLOUD_OPER_AND ); return cloudBddAnd_gate( dd, f, g ); } /**Function******************************************************************** Synopsis [Performs the OR or two BDDs] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ CloudNode * Cloud_bddOr( CloudManager * dd, CloudNode * f, CloudNode * g ) { CloudNode * res; if ( Cloud_Regular(f) == NULL || Cloud_Regular(g) == NULL ) return NULL; CLOUD_ASSERT(f); CLOUD_ASSERT(g); if ( dd->tCaches[CLOUD_OPER_AND] == NULL ) cloudCacheAllocate( dd, CLOUD_OPER_AND ); res = cloudBddAnd_gate( dd, Cloud_Not(f), Cloud_Not(g) ); res = Cloud_NotCond( res, res != NULL ); return res; } /**Function******************************************************************** Synopsis [Performs the XOR or two BDDs] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ CloudNode * Cloud_bddXor( CloudManager * dd, CloudNode * f, CloudNode * g ) { CloudNode * t0, * t1, * r; if ( Cloud_Regular(f) == NULL || Cloud_Regular(g) == NULL ) return NULL; CLOUD_ASSERT(f); CLOUD_ASSERT(g); if ( dd->tCaches[CLOUD_OPER_AND] == NULL ) cloudCacheAllocate( dd, CLOUD_OPER_AND ); t0 = cloudBddAnd_gate( dd, f, Cloud_Not(g) ); if ( t0 == NULL ) return NULL; t1 = cloudBddAnd_gate( dd, Cloud_Not(f), g ); if ( t1 == NULL ) return NULL; r = Cloud_bddOr( dd, t0, t1 ); return r; } /**Function******************************************************************** Synopsis [Performs a DFS from f, clearing the LSB of the next pointers.] Description [] SideEffects [None] SeeAlso [cloudSupport cloudDagSize] ******************************************************************************/ static void cloudClearMark( CloudManager * dd, CloudNode * n ) { if ( !cloudNodeIsMarked(n) ) return; // clear visited flag cloudNodeUnmark(n); if ( cloudIsConstant(n) ) return; cloudClearMark( dd, cloudT(n) ); cloudClearMark( dd, Cloud_Regular(cloudE(n)) ); } /**Function******************************************************************** Synopsis [Performs the recursive step of Cloud_Support.] Description [Performs the recursive step of Cloud_Support. Performs a DFS from f. The support is accumulated in supp as a side effect. Uses the LSB of the then pointer as visited flag.] SideEffects [None] SeeAlso [] ******************************************************************************/ static void cloudSupport( CloudManager * dd, CloudNode * n, int * support ) { if ( cloudIsConstant(n) || cloudNodeIsMarked(n) ) return; // set visited flag cloudNodeMark(n); support[cloudV(n)] = 1; cloudSupport( dd, cloudT(n), support ); cloudSupport( dd, Cloud_Regular(cloudE(n)), support ); } /**Function******************************************************************** Synopsis [Finds the variables on which a DD depends.] Description [Finds the variables on which a DD depends. Returns a BDD consisting of the product of the variables if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ CloudNode * Cloud_Support( CloudManager * dd, CloudNode * n ) { CloudNode * res; int * support, i; CLOUD_ASSERT(n); // allocate and initialize support array for cloudSupport support = ABC_CALLOC( int, dd->nVars ); // compute support and clean up markers cloudSupport( dd, Cloud_Regular(n), support ); cloudClearMark( dd, Cloud_Regular(n) ); // transform support from array to cube res = dd->one; for ( i = dd->nVars - 1; i >= 0; i-- ) // for each level bottom-up if ( support[i] == 1 ) { res = Cloud_bddAnd( dd, res, dd->vars[i] ); if ( res == NULL ) break; } ABC_FREE( support ); return res; } /**Function******************************************************************** Synopsis [Counts the variables on which a DD depends.] Description [Counts the variables on which a DD depends. Returns the number of the variables if successful; Cloud_OUT_OF_MEM otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int Cloud_SupportSize( CloudManager * dd, CloudNode * n ) { int * support, i, count; CLOUD_ASSERT(n); // allocate and initialize support array for cloudSupport support = ABC_CALLOC( int, dd->nVars ); // compute support and clean up markers cloudSupport( dd, Cloud_Regular(n), support ); cloudClearMark( dd, Cloud_Regular(n) ); // count support variables count = 0; for ( i = 0; i < dd->nVars; i++ ) { if ( support[i] == 1 ) count++; } ABC_FREE( support ); return count; } /**Function******************************************************************** Synopsis [Performs the recursive step of Cloud_DagSize.] Description [Performs the recursive step of Cloud_DagSize. Returns the number of nodes in the graph rooted at n.] SideEffects [None] ******************************************************************************/ static int cloudDagSize( CloudManager * dd, CloudNode * n ) { int tval, eval; if ( cloudNodeIsMarked(n) ) return 0; // set visited flag cloudNodeMark(n); if ( cloudIsConstant(n) ) return 1; tval = cloudDagSize( dd, cloudT(n) ); eval = cloudDagSize( dd, Cloud_Regular(cloudE(n)) ); return tval + eval + 1; } /**Function******************************************************************** Synopsis [Counts the number of nodes in a DD.] Description [Counts the number of nodes in a DD. Returns the number of nodes in the graph rooted at node.] SideEffects [] SeeAlso [] ******************************************************************************/ int Cloud_DagSize( CloudManager * dd, CloudNode * n ) { int res; res = cloudDagSize( dd, Cloud_Regular( n ) ); cloudClearMark( dd, Cloud_Regular( n ) ); return res; } /**Function******************************************************************** Synopsis [Performs the recursive step of Cloud_DagSize.] Description [Performs the recursive step of Cloud_DagSize. Returns the number of nodes in the graph rooted at n.] SideEffects [None] ******************************************************************************/ static int Cloud_DagCollect_rec( CloudManager * dd, CloudNode * n, int * pCounter ) { int tval, eval; if ( cloudNodeIsMarked(n) ) return 0; // set visited flag cloudNodeMark(n); if ( cloudIsConstant(n) ) { dd->ppNodes[(*pCounter)++] = n; return 1; } tval = Cloud_DagCollect_rec( dd, cloudT(n), pCounter ); eval = Cloud_DagCollect_rec( dd, Cloud_Regular(cloudE(n)), pCounter ); dd->ppNodes[(*pCounter)++] = n; return tval + eval + 1; } /**Function******************************************************************** Synopsis [Counts the number of nodes in a DD.] Description [Counts the number of nodes in a DD. Returns the number of nodes in the graph rooted at node.] SideEffects [] SeeAlso [] ******************************************************************************/ int Cloud_DagCollect( CloudManager * dd, CloudNode * n ) { int res, Counter = 0; if ( dd->ppNodes == NULL ) dd->ppNodes = ABC_ALLOC( CloudNode *, dd->nNodesLimit ); res = Cloud_DagCollect_rec( dd, Cloud_Regular( n ), &Counter ); cloudClearMark( dd, Cloud_Regular( n ) ); assert( res == Counter ); return res; } /**Function******************************************************************** Synopsis [Counts the number of nodes in an array of DDs.] Description [Counts the number of nodes in a DD. Returns the number of nodes in the graph rooted at node.] SideEffects [] SeeAlso [] ******************************************************************************/ int Cloud_SharingSize( CloudManager * dd, CloudNode ** pn, int nn ) { int res, i; res = 0; for ( i = 0; i < nn; i++ ) res += cloudDagSize( dd, Cloud_Regular( pn[i] ) ); for ( i = 0; i < nn; i++ ) cloudClearMark( dd, Cloud_Regular( pn[i] ) ); return res; } /**Function******************************************************************** Synopsis [Returns one cube contained in the given BDD.] Description [] SideEffects [] ******************************************************************************/ CloudNode * Cloud_GetOneCube( CloudManager * dd, CloudNode * bFunc ) { CloudNode * bFunc0, * bFunc1, * res; if ( Cloud_IsConstant(bFunc) ) return bFunc; // cofactor if ( Cloud_IsComplement(bFunc) ) { bFunc0 = Cloud_Not( cloudE(bFunc) ); bFunc1 = Cloud_Not( cloudT(bFunc) ); } else { bFunc0 = cloudE(bFunc); bFunc1 = cloudT(bFunc); } // try to find the cube with the negative literal res = Cloud_GetOneCube( dd, bFunc0 ); if ( res == NULL ) return NULL; if ( res != dd->zero ) { res = Cloud_bddAnd( dd, res, Cloud_Not(dd->vars[Cloud_V(bFunc)]) ); } else { // try to find the cube with the positive literal res = Cloud_GetOneCube( dd, bFunc1 ); if ( res == NULL ) return NULL; assert( res != dd->zero ); res = Cloud_bddAnd( dd, res, dd->vars[Cloud_V(bFunc)] ); } return res; } /**Function******************************************************************** Synopsis [Prints the BDD as a set of disjoint cubes to the standard output.] Description [] SideEffects [] ******************************************************************************/ void Cloud_bddPrint( CloudManager * dd, CloudNode * Func ) { CloudNode * Cube; int fFirst = 1; if ( Func == dd->zero ) printf( "Constant 0." ); else if ( Func == dd->one ) printf( "Constant 1." ); else { while ( 1 ) { Cube = Cloud_GetOneCube( dd, Func ); if ( Cube == NULL || Cube == dd->zero ) break; if ( fFirst ) fFirst = 0; else printf( " + " ); Cloud_bddPrintCube( dd, Cube ); Func = Cloud_bddAnd( dd, Func, Cloud_Not(Cube) ); } } printf( "\n" ); } /**Function******************************************************************** Synopsis [Prints one cube.] Description [] SideEffects [] ******************************************************************************/ void Cloud_bddPrintCube( CloudManager * dd, CloudNode * bCube ) { CloudNode * bCube0, * bCube1; assert( !Cloud_IsConstant(bCube) ); while ( 1 ) { // get the node structure if ( Cloud_IsConstant(bCube) ) break; // cofactor the cube if ( Cloud_IsComplement(bCube) ) { bCube0 = Cloud_Not( cloudE(bCube) ); bCube1 = Cloud_Not( cloudT(bCube) ); } else { bCube0 = cloudE(bCube); bCube1 = cloudT(bCube); } if ( bCube0 != dd->zero ) { assert( bCube1 == dd->zero ); printf( "[%d]'", cloudV(bCube) ); bCube = bCube0; } else { assert( bCube1 != dd->zero ); printf( "[%d]", cloudV(bCube) ); bCube = bCube1; } } } /**Function******************************************************************** Synopsis [Prints info.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ void Cloud_PrintInfo( CloudManager * dd ) { if ( dd == NULL ) return; printf( "The number of unique table nodes allocated = %12d.\n", dd->nNodesAlloc ); printf( "The number of unique table nodes present = %12d.\n", dd->nNodesCur ); printf( "The number of unique table hits = %12d.\n", dd->nUniqueHits ); printf( "The number of unique table misses = %12d.\n", dd->nUniqueMisses ); printf( "The number of unique table steps = %12d.\n", dd->nUniqueSteps ); printf( "The number of cache hits = %12d.\n", dd->nCacheHits ); printf( "The number of cache misses = %12d.\n", dd->nCacheMisses ); printf( "The current signature = %12d.\n", dd->nSignCur ); printf( "The total memory in use = %12d.\n", dd->nMemUsed ); } /**Function******************************************************************** Synopsis [Prints the state of the hash table.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ void Cloud_PrintHashTable( CloudManager * dd ) { int i; for ( i = 0; i < dd->nNodesAlloc; i++ ) if ( dd->tUnique[i].v == CLOUD_CONST_INDEX ) printf( "-" ); else printf( "+" ); printf( "\n" ); } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END