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