Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_cholmod_l_memory.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === Core/cholmod_memory ================================================== */
3 /* ========================================================================== */
4 
5 /* -----------------------------------------------------------------------------
6  * CHOLMOD/Core Module. Copyright (C) 2005-2006,
7  * Univ. of Florida. Author: Timothy A. Davis
8  * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
9  * Lesser General Public License. See lesser.txt for a text of the license.
10  * CHOLMOD is also available under other licenses; contact authors for details.
11  * http://www.cise.ufl.edu/research/sparse
12  * -------------------------------------------------------------------------- */
13 
14 /* Core memory management routines:
15  *
16  * Primary routines:
17  * -----------------
18  * cholmod_malloc malloc wrapper
19  * cholmod_free free wrapper
20  *
21  * Secondary routines:
22  * -------------------
23  * cholmod_calloc calloc wrapper
24  * cholmod_realloc realloc wrapper
25  * cholmod_realloc_multiple realloc wrapper for multiple objects
26  *
27  * The user may make use of these, just like malloc and free. You can even
28  * malloc an object and safely free it with cholmod_free, and visa versa
29  * (except that the memory usage statistics will be corrupted). These routines
30  * do differ from malloc and free. If cholmod_free is given a NULL pointer,
31  * for example, it does nothing (unlike the ANSI free). cholmod_realloc does
32  * not return NULL if given a non-NULL pointer and a nonzero size, even if it
33  * fails (it sets an error code in Common->status instead).
34  *
35  * CHOLMOD keeps track of the amount of memory it has allocated, and so the
36  * cholmod_free routine includes as a parameter the size of the object being
37  * freed. This is only used for memory usage statistics, which are very useful
38  * in finding memory leaks in your program. If you, the user of CHOLMOD, pass
39  * the wrong size, the only consequence is that the memory usage statistics
40  * will be invalid. This will causes assertions to fail if CHOLMOD is
41  * compiled with debugging enabled, but otherwise it will cause no errors.
42  *
43  * The cholmod_free_* routines for each CHOLMOD object keep track of the size
44  * of the blocks they free, so they do not require you to pass their sizes
45  * as a parameter.
46  *
47  * If a block of size zero is requested, these routines allocate a block of
48  * size one instead.
49  */
50 
51 /* This file should make the long int version of CHOLMOD */
52 #define DLONG 1
53 
55 #include "amesos_cholmod_core.h"
56 
57 /* ========================================================================== */
58 /* === cholmod_add_size_t =================================================== */
59 /* ========================================================================== */
60 
61 /* Safely compute a+b, and check for integer overflow. If overflow occurs,
62  * return 0 and set OK to FALSE. Also return 0 if OK is FALSE on input. */
63 
64 size_t CHOLMOD(add_size_t) (size_t a, size_t b, int *ok)
65 {
66  size_t s = a + b ;
67  (*ok) = (*ok) && (s >= a) ;
68  return ((*ok) ? s : 0) ;
69 }
70 
71 /* ========================================================================== */
72 /* === cholmod_mult_size_t ================================================== */
73 /* ========================================================================== */
74 
75 /* Safely compute a*k, where k should be small, and check for integer overflow.
76  * If overflow occurs, return 0 and set OK to FALSE. Also return 0 if OK is
77  * FALSE on input. */
78 
79 size_t CHOLMOD(mult_size_t) (size_t a, size_t k, int *ok)
80 {
81  size_t p = 0, s ;
82  while (*ok)
83  {
84  if (k % 2)
85  {
86  p = p + a ;
87  (*ok) = (*ok) && (p >= a) ;
88  }
89  k = k / 2 ;
90  if (!k) return (p) ;
91  s = a + a ;
92  (*ok) = (*ok) && (s >= a) ;
93  a = s ;
94  }
95  return (0) ;
96 }
97 
98 
99 /* ========================================================================== */
100 /* === cholmod_malloc ======================================================= */
101 /* ========================================================================== */
102 
103 /* Wrapper around malloc routine. Allocates space of size MAX(1,n)*size, where
104  * size is normally a sizeof (...).
105  *
106  * This routine, cholmod_calloc, and cholmod_realloc do not set Common->status
107  * to CHOLMOD_OK on success, so that a sequence of cholmod_malloc's, _calloc's,
108  * or _realloc's can be used. If any of them fails, the Common->status will
109  * hold the most recent error status.
110  *
111  * Usage, for a pointer to int:
112  *
113  * p = cholmod_malloc (n, sizeof (int), Common)
114  *
115  * Uses a pointer to the malloc routine (or its equivalent) defined in Common.
116  */
117 
118 void *CHOLMOD(malloc) /* returns pointer to the newly malloc'd block */
119 (
120  /* ---- input ---- */
121  size_t n, /* number of items */
122  size_t size, /* size of each item */
123  /* --------------- */
124  cholmod_common *Common
125 )
126 {
127  void *p ;
128  size_t s ;
129  int ok = TRUE ;
130 
132  if (size == 0)
133  {
134  ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
135  p = NULL ;
136  }
137  else if (n >= (Size_max / size) || n >= Int_max)
138  {
139  /* object is too big to allocate without causing integer overflow */
140  ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
141  p = NULL ;
142  }
143  else
144  {
145  /* call malloc, or its equivalent */
146  s = CHOLMOD(mult_size_t) (MAX (1,n), size, &ok) ;
147  p = ok ? ((Common->malloc_memory) (s)) : NULL ;
148  if (p == NULL)
149  {
150  /* failure: out of memory */
151  ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
152  }
153  else
154  {
155  /* success: increment the count of objects allocated */
156  Common->malloc_count++ ;
157  Common->memory_inuse += (n * size) ;
158  Common->memory_usage =
159  MAX (Common->memory_usage, Common->memory_inuse) ;
160  PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n",
161  p, n*size, Common->malloc_count, Common->memory_inuse)) ;
162  }
163  }
164  return (p) ;
165 }
166 
167 
168 /* ========================================================================== */
169 /* === cholmod_free ========================================================= */
170 /* ========================================================================== */
171 
172 /* Wrapper around free routine. Returns NULL, which can be assigned to the
173  * pointer being freed, as in:
174  *
175  * p = cholmod_free (n, sizeof (int), p, Common) ;
176  *
177  * In CHOLMOD, the syntax:
178  *
179  * cholmod_free (n, sizeof (int), p, Common) ;
180  *
181  * is used if p is a local pointer and the routine is returning shortly.
182  * Uses a pointer to the free routine (or its equivalent) defined in Common.
183  * Nothing is freed if the pointer is NULL.
184  */
185 
186 void *CHOLMOD(free) /* always returns NULL */
187 (
188  /* ---- input ---- */
189  size_t n, /* number of items */
190  size_t size, /* size of each item */
191  /* ---- in/out --- */
192  void *p, /* block of memory to free */
193  /* --------------- */
194  cholmod_common *Common
195 )
196 {
198  if (p != NULL)
199  {
200  /* only free the object if the pointer is not NULL */
201  /* call free, or its equivalent */
202  (Common->free_memory) (p) ;
203  Common->malloc_count-- ;
204  Common->memory_inuse -= (n * size) ;
205  PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n",
206  p, n*size, Common->malloc_count, Common->memory_inuse)) ;
207  /* This assertion will fail if the user calls cholmod_malloc and
208  * cholmod_free with mismatched memory sizes. It shouldn't fail
209  * otherwise. */
210  DEBUG (if (Common->malloc_count == 0 && Common->memory_inuse != 0)
211  PRINT0 (("inuse: %d\n", Common->memory_inuse))) ;
212  ASSERT (IMPLIES (Common->malloc_count == 0, Common->memory_inuse == 0));
213  }
214  /* return NULL, and the caller should assign this to p. This avoids
215  * freeing the same pointer twice. */
216  return (NULL) ;
217 }
218 
219 
220 /* ========================================================================== */
221 /* === cholmod_calloc ======================================================= */
222 /* ========================================================================== */
223 
224 /* Wrapper around calloc routine.
225  *
226  * Uses a pointer to the calloc routine (or its equivalent) defined in Common.
227  * This routine is identical to malloc, except that it zeros the newly allocated
228  * block to zero.
229  */
230 
231 void *CHOLMOD(calloc) /* returns pointer to the newly calloc'd block */
232 (
233  /* ---- input ---- */
234  size_t n, /* number of items */
235  size_t size, /* size of each item */
236  /* --------------- */
237  cholmod_common *Common
238 )
239 {
240  void *p ;
241 
243  if (size == 0)
244  {
245  ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
246  p = NULL ;
247  }
248  else if (n >= (Size_max / size) || n >= Int_max)
249  {
250  /* object is too big to allocate without causing integer overflow */
251  ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
252  p = NULL ;
253  }
254  else
255  {
256  /* call calloc, or its equivalent */
257  p = (Common->calloc_memory) (MAX (1,n), size) ;
258  if (p == NULL)
259  {
260  /* failure: out of memory */
261  ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
262  }
263  else
264  {
265  /* success: increment the count of objects allocated */
266  Common->malloc_count++ ;
267  Common->memory_inuse += (n * size) ;
268  Common->memory_usage =
269  MAX (Common->memory_usage, Common->memory_inuse) ;
270  PRINTM (("cholmod_calloc %p %d cnt: %d inuse %d\n",
271  p, n*size, Common->malloc_count, Common->memory_inuse)) ;
272  }
273  }
274  return (p) ;
275 }
276 
277 
278 /* ========================================================================== */
279 /* === cholmod_realloc ====================================================== */
280 /* ========================================================================== */
281 
282 /* Wrapper around realloc routine. Given a pointer p to a block of size
283  * (*n)*size memory, it changes the size of the block pointed to by p to be
284  * MAX(1,nnew)*size in size. It may return a pointer different than p. This
285  * should be used as (for a pointer to int):
286  *
287  * p = cholmod_realloc (nnew, sizeof (int), p, *n, Common) ;
288  *
289  * If p is NULL, this is the same as p = cholmod_malloc (...).
290  * A size of nnew=0 is treated as nnew=1.
291  *
292  * If the realloc fails, p is returned unchanged and Common->status is set
293  * to CHOLMOD_OUT_OF_MEMORY. If successful, Common->status is not modified,
294  * and p is returned (possibly changed) and pointing to a large block of memory.
295  *
296  * Uses a pointer to the realloc routine (or its equivalent) defined in Common.
297  */
298 
299 void *CHOLMOD(realloc) /* returns pointer to reallocated block */
300 (
301  /* ---- input ---- */
302  size_t nnew, /* requested # of items in reallocated block */
303  size_t size, /* size of each item */
304  /* ---- in/out --- */
305  void *p, /* block of memory to realloc */
306  size_t *n, /* current size on input, nnew on output if successful*/
307  /* --------------- */
308  cholmod_common *Common
309 )
310 {
311  size_t nold = (*n) ;
312  void *pnew ;
313  size_t s ;
314  int ok = TRUE ;
315 
317  if (size == 0)
318  {
319  ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
320  p = NULL ;
321  }
322  else if (p == NULL)
323  {
324  /* A fresh object is being allocated. */
325  PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ;
326  p = CHOLMOD(malloc) (nnew, size, Common) ;
327  *n = (p == NULL) ? 0 : nnew ;
328  }
329  else if (nold == nnew)
330  {
331  /* Nothing to do. Do not change p or n. */
332  PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ;
333  }
334  else if (nnew >= (Size_max / size) || nnew >= Int_max)
335  {
336  /* failure: nnew is too big. Do not change p or n. */
337  ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
338  }
339  else
340  {
341  /* The object exists, and is changing to some other nonzero size. */
342  /* call realloc, or its equivalent */
343  PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ;
344  pnew = NULL ;
345 
346  s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ;
347  pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ;
348 
349  if (pnew == NULL)
350  {
351  /* Do not change p, since it still points to allocated memory */
352  if (nnew <= nold)
353  {
354  /* The attempt to reduce the size of the block from n to
355  * nnew has failed. The current block is not modified, so
356  * pretend to succeed, but do not change p. Do change
357  * CHOLMOD's notion of the size of the block, however. */
358  *n = nnew ;
359  PRINTM (("nnew <= nold failed, pretend to succeed\n")) ;
360  PRINTM (("cholmod_realloc_old: %p %d cnt: %d inuse %d\n"
361  "cholmod_realloc_new: %p %d cnt: %d inuse %d\n",
362  p, nold*size, Common->malloc_count-1,
363  Common->memory_inuse - nold*size,
364  p, nnew*size, Common->malloc_count,
365  Common->memory_inuse + (nnew-nold)*size)) ;
366  Common->memory_inuse += ((nnew-nold) * size) ;
367  }
368  else
369  {
370  /* Increasing the size of the block has failed.
371  * Do not change n. */
372  ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
373  }
374  }
375  else
376  {
377  /* success: return revised p and change the size of the block */
378  PRINTM (("cholmod_realloc_old: %p %d cnt: %d inuse %d\n"
379  "cholmod_realloc_new: %p %d cnt: %d inuse %d\n",
380  p, nold*size, Common->malloc_count-1,
381  Common->memory_inuse - nold*size,
382  pnew, nnew*size, Common->malloc_count,
383  Common->memory_inuse + (nnew-nold)*size)) ;
384  p = pnew ;
385  *n = nnew ;
386  Common->memory_inuse += ((nnew-nold) * size) ;
387  }
388  Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse);
389  }
390 
391  return (p) ;
392 }
393 
394 
395 /* ========================================================================== */
396 /* === cholmod_realloc_multiple ============================================= */
397 /* ========================================================================== */
398 
399 /* reallocate multiple blocks of memory, all of the same size (up to two integer
400  * and two real blocks). Either reallocations all succeed, or all are returned
401  * in the original size (they are freed if the original size is zero). The nnew
402  * blocks are of size 1 or more.
403  */
404 
406 (
407  /* ---- input ---- */
408  size_t nnew, /* requested # of items in reallocated blocks */
409  int nint, /* number of int/UF_long blocks */
410  int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
411  /* ---- in/out --- */
412  void **I, /* int or UF_long block */
413  void **J, /* int or UF_long block */
414  void **X, /* complex or double block */
415  void **Z, /* zomplex case only: double block */
416  size_t *nold_p, /* current size of the I,J,X,Z blocks on input,
417  * nnew on output if successful */
418  /* --------------- */
419  cholmod_common *Common
420 )
421 {
422  double *xx, *zz ;
423  size_t i, j, x, z, nold ;
424 
426 
427  if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
428  {
429  ERROR (CHOLMOD_INVALID, "invalid xtype") ;
430  return (FALSE) ;
431  }
432 
433  nold = *nold_p ;
434 
435  if (nint < 1 && xtype == CHOLMOD_PATTERN)
436  {
437  /* nothing to do */
438  return (TRUE) ;
439  }
440 
441  i = nold ;
442  j = nold ;
443  x = nold ;
444  z = nold ;
445 
446  if (nint > 0)
447  {
448  *I = CHOLMOD(realloc) (nnew, sizeof (Int), *I, &i, Common) ;
449  }
450  if (nint > 1)
451  {
452  *J = CHOLMOD(realloc) (nnew, sizeof (Int), *J, &j, Common) ;
453  }
454 
455  switch (xtype)
456  {
457  case CHOLMOD_REAL:
458  *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ;
459  break ;
460 
461  case CHOLMOD_COMPLEX:
462  *X = CHOLMOD(realloc) (nnew, 2*sizeof (double), *X, &x, Common) ;
463  break ;
464 
465  case CHOLMOD_ZOMPLEX:
466  *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ;
467  *Z = CHOLMOD(realloc) (nnew, sizeof (double), *Z, &z, Common) ;
468  break ;
469  }
470 
471  if (Common->status < CHOLMOD_OK)
472  {
473  /* one or more realloc's failed. Resize all back down to nold. */
474 
475  if (nold == 0)
476  {
477 
478  if (nint > 0)
479  {
480  *I = CHOLMOD(free) (i, sizeof (Int), *I, Common) ;
481  }
482  if (nint > 1)
483  {
484  *J = CHOLMOD(free) (j, sizeof (Int), *J, Common) ;
485  }
486 
487  switch (xtype)
488  {
489  case CHOLMOD_REAL:
490  *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ;
491  break ;
492 
493  case CHOLMOD_COMPLEX:
494  *X = CHOLMOD(free) (x, 2*sizeof (double), *X, Common) ;
495  break ;
496 
497  case CHOLMOD_ZOMPLEX:
498  *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ;
499  *Z = CHOLMOD(free) (x, sizeof (double), *Z, Common) ;
500  break ;
501  }
502 
503  }
504  else
505  {
506  if (nint > 0)
507  {
508  *I = CHOLMOD(realloc) (nold, sizeof (Int), *I, &i, Common) ;
509  }
510  if (nint > 1)
511  {
512  *J = CHOLMOD(realloc) (nold, sizeof (Int), *J, &j, Common) ;
513  }
514 
515  switch (xtype)
516  {
517  case CHOLMOD_REAL:
518  *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x,
519  Common) ;
520  break ;
521 
522  case CHOLMOD_COMPLEX:
523  *X = CHOLMOD(realloc) (nold, 2*sizeof (double), *X, &x,
524  Common) ;
525  break ;
526 
527  case CHOLMOD_ZOMPLEX:
528  *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x,
529  Common) ;
530  *Z = CHOLMOD(realloc) (nold, sizeof (double), *Z, &z,
531  Common) ;
532  break ;
533  }
534 
535  }
536 
537  return (FALSE) ;
538  }
539 
540  if (nold == 0)
541  {
542  /* New space was allocated. Clear the first entry so that valgrind
543  * doesn't complain about its access in change_complexity
544  * (Core/cholmod_complex.c). */
545  xx = *X ;
546  zz = *Z ;
547  switch (xtype)
548  {
549  case CHOLMOD_REAL:
550  xx [0] = 0 ;
551  break ;
552 
553  case CHOLMOD_COMPLEX:
554  xx [0] = 0 ;
555  xx [1] = 0 ;
556  break ;
557 
558  case CHOLMOD_ZOMPLEX:
559  xx [0] = 0 ;
560  zz [0] = 0 ;
561  break ;
562  }
563  }
564 
565  /* all realloc's succeeded, change size to reflect realloc'ed size. */
566  *nold_p = nnew ;
567  return (TRUE) ;
568 }
#define CHOLMOD_TOO_LARGE
void * CHOLMOD(malloc)
#define PRINTM(params)
int CHOLMOD() realloc_multiple(size_t nnew, int nint, int xtype, void **I, void **J, void **X, void **Z, size_t *nold_p, cholmod_common *Common)
#define Int
size_t CHOLMOD() add_size_t(size_t a, size_t b, int *ok)
#define CHOLMOD_COMPLEX
#define FALSE
#define PRINT1(params)
#define RETURN_IF_NULL_COMMON(result)
size_t CHOLMOD() mult_size_t(size_t a, size_t k, int *ok)
#define CHOLMOD_PATTERN
#define MAX(a, b)
#define CHOLMOD_REAL
#define NULL
#define Int_max
#define ASSERT(expression)
#define CHOLMOD_INVALID
#define CHOLMOD_OK
#define PRINT0(params)
#define CHOLMOD_OUT_OF_MEMORY
#define Size_max
#define DEBUG(statement)
#define IMPLIES(p, q)
int n
#define ERROR(status, msg)
#define TRUE
#define CHOLMOD_ZOMPLEX