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