Amesos Package Browser (Single Doxygen Collection) Development
amesos_cholmod_l_memory.c
Go to the documentation of this file.
00001 /* ========================================================================== */
00002 /* === Core/cholmod_memory ================================================== */
00003 /* ========================================================================== */
00004 
00005 /* -----------------------------------------------------------------------------
00006  * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
00007  * Univ. of Florida.  Author: Timothy A. Davis
00008  * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
00009  * Lesser General Public License.  See lesser.txt for a text of the license.
00010  * CHOLMOD is also available under other licenses; contact authors for details.
00011  * http://www.cise.ufl.edu/research/sparse
00012  * -------------------------------------------------------------------------- */
00013 
00014 /* Core memory management routines:
00015  *
00016  * Primary routines:
00017  * -----------------
00018  * cholmod_malloc   malloc wrapper
00019  * cholmod_free     free wrapper
00020  *
00021  * Secondary routines:
00022  * -------------------
00023  * cholmod_calloc   calloc wrapper
00024  * cholmod_realloc    realloc wrapper
00025  * cholmod_realloc_multiple realloc wrapper for multiple objects
00026  *
00027  * The user may make use of these, just like malloc and free.  You can even
00028  * malloc an object and safely free it with cholmod_free, and visa versa
00029  * (except that the memory usage statistics will be corrupted).  These routines
00030  * do differ from malloc and free.  If cholmod_free is given a NULL pointer,
00031  * for example, it does nothing (unlike the ANSI free).  cholmod_realloc does
00032  * not return NULL if given a non-NULL pointer and a nonzero size, even if it
00033  * fails (it sets an error code in Common->status instead).
00034  *
00035  * CHOLMOD keeps track of the amount of memory it has allocated, and so the
00036  * cholmod_free routine includes as a parameter the size of the object being
00037  * freed.  This is only used for memory usage statistics, which are very useful
00038  * in finding memory leaks in your program.  If you, the user of CHOLMOD, pass
00039  * the wrong size, the only consequence is that the memory usage statistics
00040  * will be invalid.  This will causes assertions to fail if CHOLMOD is
00041  * compiled with debugging enabled, but otherwise it will cause no errors.
00042  *
00043  * The cholmod_free_* routines for each CHOLMOD object keep track of the size
00044  * of the blocks they free, so they do not require you to pass their sizes
00045  * as a parameter.
00046  *
00047  * If a block of size zero is requested, these routines allocate a block of
00048  * size one instead.
00049  */
00050 
00051 /* This file should make the long int version of CHOLMOD */
00052 #define DLONG 1
00053 
00054 #include "amesos_cholmod_internal.h"
00055 #include "amesos_cholmod_core.h"
00056 
00057 /* ========================================================================== */
00058 /* === cholmod_add_size_t =================================================== */
00059 /* ========================================================================== */
00060 
00061 /* Safely compute a+b, and check for integer overflow.  If overflow occurs,
00062  * return 0 and set OK to FALSE.  Also return 0 if OK is FALSE on input. */
00063 
00064 size_t CHOLMOD(add_size_t) (size_t a, size_t b, int *ok)
00065 {
00066     size_t s = a + b ;
00067     (*ok) = (*ok) && (s >= a) ;
00068     return ((*ok) ? s : 0) ;
00069 }
00070 
00071 /* ========================================================================== */
00072 /* === cholmod_mult_size_t ================================================== */
00073 /* ========================================================================== */
00074 
00075 /* Safely compute a*k, where k should be small, and check for integer overflow.
00076  * If overflow occurs, return 0 and set OK to FALSE.  Also return 0 if OK is
00077  * FALSE on input. */
00078 
00079 size_t CHOLMOD(mult_size_t) (size_t a, size_t k, int *ok)
00080 {
00081     size_t p = 0, s ;
00082     while (*ok)
00083     {
00084   if (k % 2)
00085   {
00086       p = p + a ;
00087       (*ok) = (*ok) && (p >= a) ;
00088   }
00089   k = k / 2 ;
00090   if (!k) return (p) ;
00091   s = a + a ;
00092   (*ok) = (*ok) && (s >= a) ;
00093   a = s ;
00094     }
00095     return (0) ;
00096 }
00097 
00098 
00099 /* ========================================================================== */
00100 /* === cholmod_malloc ======================================================= */
00101 /* ========================================================================== */
00102 
00103 /* Wrapper around malloc routine.  Allocates space of size MAX(1,n)*size, where
00104  * size is normally a sizeof (...).
00105  *
00106  * This routine, cholmod_calloc, and cholmod_realloc do not set Common->status
00107  * to CHOLMOD_OK on success, so that a sequence of cholmod_malloc's, _calloc's,
00108  * or _realloc's can be used.  If any of them fails, the Common->status will
00109  * hold the most recent error status.
00110  *
00111  * Usage, for a pointer to int:
00112  *
00113  *  p = cholmod_malloc (n, sizeof (int), Common)
00114  *
00115  * Uses a pointer to the malloc routine (or its equivalent) defined in Common.
00116  */
00117 
00118 void *CHOLMOD(malloc) /* returns pointer to the newly malloc'd block */
00119 (
00120     /* ---- input ---- */
00121     size_t n,   /* number of items */
00122     size_t size,  /* size of each item */
00123     /* --------------- */
00124     cholmod_common *Common
00125 )
00126 {
00127     void *p ;
00128     size_t s ;
00129     int ok = TRUE ;
00130 
00131     RETURN_IF_NULL_COMMON (NULL) ;
00132     if (size == 0)
00133     {
00134   ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0")  ;
00135   p = NULL ;
00136     }
00137     else if (n >= (Size_max / size) || n >= Int_max)
00138     {
00139   /* object is too big to allocate without causing integer overflow */
00140   ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
00141   p = NULL ;
00142     }
00143     else
00144     {
00145   /* call malloc, or its equivalent */
00146   s = CHOLMOD(mult_size_t) (MAX (1,n), size, &ok) ;
00147   p = ok ? ((Common->malloc_memory) (s)) : NULL ;
00148   if (p == NULL)
00149   {
00150       /* failure: out of memory */
00151       ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
00152   }
00153   else
00154   {
00155       /* success: increment the count of objects allocated */
00156       Common->malloc_count++ ;
00157       Common->memory_inuse += (n * size) ;
00158       Common->memory_usage =
00159     MAX (Common->memory_usage, Common->memory_inuse) ;
00160       PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n",
00161         p, n*size, Common->malloc_count, Common->memory_inuse)) ;
00162   }
00163     }
00164     return (p) ;
00165 }
00166 
00167 
00168 /* ========================================================================== */
00169 /* === cholmod_free ========================================================= */
00170 /* ========================================================================== */
00171 
00172 /* Wrapper around free routine.  Returns NULL, which can be assigned to the
00173  * pointer being freed, as in:
00174  *
00175  *  p = cholmod_free (n, sizeof (int), p, Common) ;
00176  *
00177  * In CHOLMOD, the syntax:
00178  *
00179  *  cholmod_free (n, sizeof (int), p, Common) ;
00180  *
00181  * is used if p is a local pointer and the routine is returning shortly.
00182  * Uses a pointer to the free routine (or its equivalent) defined in Common.
00183  * Nothing is freed if the pointer is NULL.
00184  */
00185 
00186 void *CHOLMOD(free) /* always returns NULL */
00187 (
00188     /* ---- input ---- */
00189     size_t n,   /* number of items */
00190     size_t size,  /* size of each item */
00191     /* ---- in/out --- */
00192     void *p,    /* block of memory to free */
00193     /* --------------- */
00194     cholmod_common *Common
00195 )
00196 {
00197     RETURN_IF_NULL_COMMON (NULL) ;
00198     if (p != NULL)
00199     {
00200   /* only free the object if the pointer is not NULL */
00201   /* call free, or its equivalent */
00202   (Common->free_memory) (p) ;
00203   Common->malloc_count-- ;
00204   Common->memory_inuse -= (n * size) ;
00205   PRINTM (("cholmod_free   %p %d cnt: %d inuse %d\n",
00206     p, n*size, Common->malloc_count, Common->memory_inuse)) ;
00207   /* This assertion will fail if the user calls cholmod_malloc and
00208    * cholmod_free with mismatched memory sizes.  It shouldn't fail
00209    * otherwise. */
00210   DEBUG (if (Common->malloc_count == 0 && Common->memory_inuse != 0)
00211       PRINT0 (("inuse: %d\n", Common->memory_inuse))) ;
00212   ASSERT (IMPLIES (Common->malloc_count == 0, Common->memory_inuse == 0));
00213     }
00214     /* return NULL, and the caller should assign this to p.  This avoids
00215      * freeing the same pointer twice. */
00216     return (NULL) ;
00217 }
00218 
00219 
00220 /* ========================================================================== */
00221 /* === cholmod_calloc ======================================================= */
00222 /* ========================================================================== */
00223 
00224 /* Wrapper around calloc routine.
00225  *
00226  * Uses a pointer to the calloc routine (or its equivalent) defined in Common.
00227  * This routine is identical to malloc, except that it zeros the newly allocated
00228  * block to zero.
00229  */
00230 
00231 void *CHOLMOD(calloc) /* returns pointer to the newly calloc'd block */
00232 (
00233     /* ---- input ---- */
00234     size_t n,   /* number of items */
00235     size_t size,  /* size of each item */
00236     /* --------------- */
00237     cholmod_common *Common
00238 )
00239 {
00240     void *p ;
00241 
00242     RETURN_IF_NULL_COMMON (NULL) ;
00243     if (size == 0)
00244     {
00245   ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
00246   p = NULL ;
00247     }
00248     else if (n >= (Size_max / size) || n >= Int_max)
00249     {
00250   /* object is too big to allocate without causing integer overflow */
00251   ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
00252   p = NULL ;
00253     }
00254     else
00255     {
00256   /* call calloc, or its equivalent */
00257   p = (Common->calloc_memory) (MAX (1,n), size) ;
00258   if (p == NULL)
00259   {
00260       /* failure: out of memory */
00261       ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
00262   }
00263   else
00264   {
00265       /* success: increment the count of objects allocated */
00266       Common->malloc_count++ ;
00267       Common->memory_inuse += (n * size) ;
00268       Common->memory_usage =
00269     MAX (Common->memory_usage, Common->memory_inuse) ;
00270       PRINTM (("cholmod_calloc %p %d cnt: %d inuse %d\n",
00271         p, n*size, Common->malloc_count, Common->memory_inuse)) ;
00272   }
00273     }
00274     return (p) ;
00275 }
00276 
00277 
00278 /* ========================================================================== */
00279 /* === cholmod_realloc ====================================================== */
00280 /* ========================================================================== */
00281 
00282 /* Wrapper around realloc routine.  Given a pointer p to a block of size
00283  * (*n)*size memory, it changes the size of the block pointed to by p to be
00284  * MAX(1,nnew)*size in size.  It may return a pointer different than p.  This
00285  * should be used as (for a pointer to int):
00286  *
00287  *  p = cholmod_realloc (nnew, sizeof (int), p, *n, Common) ;
00288  *
00289  * If p is NULL, this is the same as p = cholmod_malloc (...).
00290  * A size of nnew=0 is treated as nnew=1.
00291  *
00292  * If the realloc fails, p is returned unchanged and Common->status is set
00293  * to CHOLMOD_OUT_OF_MEMORY.  If successful, Common->status is not modified,
00294  * and p is returned (possibly changed) and pointing to a large block of memory.
00295  *
00296  * Uses a pointer to the realloc routine (or its equivalent) defined in Common.
00297  */
00298 
00299 void *CHOLMOD(realloc)  /* returns pointer to reallocated block */
00300 (
00301     /* ---- input ---- */
00302     size_t nnew,  /* requested # of items in reallocated block */
00303     size_t size,  /* size of each item */
00304     /* ---- in/out --- */
00305     void *p,    /* block of memory to realloc */
00306     size_t *n,    /* current size on input, nnew on output if successful*/
00307     /* --------------- */
00308     cholmod_common *Common
00309 )
00310 {
00311     size_t nold = (*n) ;
00312     void *pnew ;
00313     size_t s ;
00314     int ok = TRUE ;
00315 
00316     RETURN_IF_NULL_COMMON (NULL) ;
00317     if (size == 0)
00318     {
00319   ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
00320   p = NULL ;
00321     }
00322     else if (p == NULL)
00323     {
00324   /* A fresh object is being allocated. */
00325   PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ;
00326   p = CHOLMOD(malloc) (nnew, size, Common) ;
00327   *n = (p == NULL) ? 0 : nnew ;
00328     }
00329     else if (nold == nnew)
00330     {
00331   /* Nothing to do.  Do not change p or n. */
00332   PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ;
00333     }
00334     else if (nnew >= (Size_max / size) || nnew >= Int_max)
00335     {
00336   /* failure: nnew is too big.  Do not change p or n. */
00337   ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
00338     }
00339     else
00340     {
00341   /* The object exists, and is changing to some other nonzero size. */
00342   /* call realloc, or its equivalent */
00343   PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ;
00344   pnew = NULL ;
00345 
00346   s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ;
00347   pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ;
00348 
00349   if (pnew == NULL)
00350   {
00351       /* Do not change p, since it still points to allocated memory */
00352       if (nnew <= nold)
00353       {
00354     /* The attempt to reduce the size of the block from n to
00355      * nnew has failed.  The current block is not modified, so
00356      * pretend to succeed, but do not change p.  Do change
00357      * CHOLMOD's notion of the size of the block, however. */
00358     *n = nnew ;
00359     PRINTM (("nnew <= nold failed, pretend to succeed\n")) ;
00360     PRINTM (("cholmod_realloc_old: %p %d cnt: %d inuse %d\n"
00361        "cholmod_realloc_new: %p %d cnt: %d inuse %d\n",
00362         p, nold*size, Common->malloc_count-1,
00363           Common->memory_inuse - nold*size,
00364         p, nnew*size, Common->malloc_count,
00365           Common->memory_inuse + (nnew-nold)*size)) ;
00366     Common->memory_inuse += ((nnew-nold) * size) ;
00367       }
00368       else
00369       {
00370     /* Increasing the size of the block has failed.
00371      * Do not change n. */
00372     ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
00373       }
00374   }
00375   else
00376   {
00377       /* success: return revised p and change the size of the block */
00378       PRINTM (("cholmod_realloc_old: %p %d cnt: %d inuse %d\n"
00379          "cholmod_realloc_new: %p %d cnt: %d inuse %d\n",
00380     p, nold*size,    Common->malloc_count-1,
00381          Common->memory_inuse - nold*size,
00382     pnew, nnew*size, Common->malloc_count,
00383          Common->memory_inuse + (nnew-nold)*size)) ;
00384       p = pnew ;
00385       *n = nnew ;
00386       Common->memory_inuse += ((nnew-nold) * size) ;
00387   }
00388   Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse);
00389     }
00390 
00391     return (p) ;
00392 }
00393 
00394 
00395 /* ========================================================================== */
00396 /* === cholmod_realloc_multiple ============================================= */
00397 /* ========================================================================== */
00398 
00399 /* reallocate multiple blocks of memory, all of the same size (up to two integer
00400  * and two real blocks).  Either reallocations all succeed, or all are returned
00401  * in the original size (they are freed if the original size is zero).  The nnew
00402  * blocks are of size 1 or more.
00403  */
00404 
00405 int CHOLMOD(realloc_multiple)
00406 (
00407     /* ---- input ---- */
00408     size_t nnew,  /* requested # of items in reallocated blocks */
00409     int nint,   /* number of int/UF_long blocks */
00410     int xtype,    /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
00411     /* ---- in/out --- */
00412     void **I,   /* int or UF_long block */
00413     void **J,   /* int or UF_long block */
00414     void **X,   /* complex or double block */
00415     void **Z,   /* zomplex case only: double block */
00416     size_t *nold_p, /* current size of the I,J,X,Z blocks on input,
00417        * nnew on output if successful */
00418     /* --------------- */
00419     cholmod_common *Common
00420 )
00421 {
00422     double *xx, *zz ;
00423     size_t i, j, x, z, nold ;
00424 
00425     RETURN_IF_NULL_COMMON (FALSE) ;
00426 
00427     if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
00428     {
00429   ERROR (CHOLMOD_INVALID, "invalid xtype") ;
00430   return (FALSE) ;
00431     }
00432 
00433     nold = *nold_p ;
00434 
00435     if (nint < 1 && xtype == CHOLMOD_PATTERN)
00436     {
00437   /* nothing to do */
00438   return (TRUE) ;
00439     }
00440 
00441     i = nold ;
00442     j = nold ;
00443     x = nold ;
00444     z = nold ;
00445 
00446     if (nint > 0)
00447     {
00448   *I = CHOLMOD(realloc) (nnew, sizeof (Int), *I, &i, Common) ;
00449     }
00450     if (nint > 1)
00451     {
00452   *J = CHOLMOD(realloc) (nnew, sizeof (Int), *J, &j, Common) ;
00453     }
00454 
00455     switch (xtype)
00456     {
00457   case CHOLMOD_REAL:
00458       *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ;
00459       break ;
00460 
00461   case CHOLMOD_COMPLEX:
00462       *X = CHOLMOD(realloc) (nnew, 2*sizeof (double), *X, &x, Common) ;
00463       break ;
00464 
00465   case CHOLMOD_ZOMPLEX:
00466       *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ;
00467       *Z = CHOLMOD(realloc) (nnew, sizeof (double), *Z, &z, Common) ;
00468       break ;
00469     }
00470 
00471     if (Common->status < CHOLMOD_OK)
00472     {
00473   /* one or more realloc's failed.  Resize all back down to nold. */
00474 
00475   if (nold == 0)
00476   {
00477 
00478       if (nint > 0)
00479       {
00480     *I = CHOLMOD(free) (i, sizeof (Int), *I, Common) ;
00481       }
00482       if (nint > 1)
00483       {
00484     *J = CHOLMOD(free) (j, sizeof (Int), *J, Common) ;
00485       }
00486 
00487       switch (xtype)
00488       {
00489     case CHOLMOD_REAL:
00490         *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ;
00491         break ;
00492 
00493     case CHOLMOD_COMPLEX:
00494         *X = CHOLMOD(free) (x, 2*sizeof (double), *X, Common) ;
00495         break ;
00496 
00497     case CHOLMOD_ZOMPLEX:
00498         *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ;
00499         *Z = CHOLMOD(free) (x, sizeof (double), *Z, Common) ;
00500         break ;
00501       }
00502 
00503   }
00504   else
00505   {
00506       if (nint > 0)
00507       {
00508     *I = CHOLMOD(realloc) (nold, sizeof (Int), *I, &i, Common) ;
00509       }
00510       if (nint > 1)
00511       {
00512     *J = CHOLMOD(realloc) (nold, sizeof (Int), *J, &j, Common) ;
00513       }
00514 
00515       switch (xtype)
00516       {
00517     case CHOLMOD_REAL:
00518         *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x,
00519           Common) ;
00520         break ;
00521 
00522     case CHOLMOD_COMPLEX:
00523         *X = CHOLMOD(realloc) (nold, 2*sizeof (double), *X, &x,
00524           Common) ;
00525         break ;
00526 
00527     case CHOLMOD_ZOMPLEX:
00528         *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x,
00529           Common) ;
00530         *Z = CHOLMOD(realloc) (nold, sizeof (double), *Z, &z,
00531           Common) ;
00532         break ;
00533       }
00534 
00535   }
00536 
00537   return (FALSE) ;
00538     }
00539 
00540     if (nold == 0)
00541     {
00542   /* New space was allocated.  Clear the first entry so that valgrind
00543    * doesn't complain about its access in change_complexity
00544    * (Core/cholmod_complex.c). */
00545   xx = *X ;
00546   zz = *Z ;
00547   switch (xtype)
00548   {
00549       case CHOLMOD_REAL:
00550     xx [0] = 0 ;
00551     break ;
00552 
00553       case CHOLMOD_COMPLEX:
00554     xx [0] = 0 ;
00555     xx [1] = 0 ;
00556     break ;
00557 
00558       case CHOLMOD_ZOMPLEX:
00559     xx [0] = 0 ;
00560     zz [0] = 0 ;
00561     break ;
00562   }
00563     }
00564 
00565     /* all realloc's succeeded, change size to reflect realloc'ed size. */
00566     *nold_p = nnew ;
00567     return (TRUE) ;
00568 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines