umf_get_memory.c
7.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
/* ========================================================================== */
/* === UMF_get_memory ======================================================= */
/* ========================================================================== */
/* -------------------------------------------------------------------------- */
/* UMFPACK Copyright (c) Timothy A. Davis, CISE, */
/* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */
/* web: http://www.cise.ufl.edu/research/sparse/umfpack */
/* -------------------------------------------------------------------------- */
/*
Reallocate the workspace (Numeric->Memory) and shift elements downwards.
needunits: increase in size so that the free space is at least this many
Units (to which the tuple lengths is added).
Return TRUE if successful, FALSE if out of memory.
*/
#include "umf_internal.h"
#include "umf_garbage_collection.h"
#include "umf_tuple_lengths.h"
#include "umf_build_tuples.h"
#include "umf_mem_free_tail_block.h"
#include "umf_realloc.h"
GLOBAL Int UMF_get_memory
(
NumericType *Numeric,
WorkType *Work,
Int needunits,
Int r2, /* compact current front to r2-by-c2 */
Int c2,
Int do_Fcpos
)
{
double nsize, bsize, tsize ;
Int i, minsize, newsize, newmem, costly, row, col, *Row_tlen, *Col_tlen,
n_row, n_col, *Row_degree, *Col_degree ;
Unit *mnew, *p ;
/* ---------------------------------------------------------------------- */
/* get and check parameters */
/* ---------------------------------------------------------------------- */
#ifndef NDEBUG
DEBUG1 (("::::GET MEMORY::::\n")) ;
UMF_dump_memory (Numeric) ;
#endif
n_row = Work->n_row ;
n_col = Work->n_col ;
Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */
Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */
Row_tlen = Numeric->Uilen ;
Col_tlen = Numeric->Lilen ;
/* ---------------------------------------------------------------------- */
/* initialize the tuple list lengths */
/* ---------------------------------------------------------------------- */
for (row = 0 ; row < n_row ; row++)
{
if (NON_PIVOTAL_ROW (row))
{
Row_tlen [row] = 0 ;
}
}
for (col = 0 ; col < n_col ; col++)
{
if (NON_PIVOTAL_COL (col))
{
Col_tlen [col] = 0 ;
}
}
/* ---------------------------------------------------------------------- */
/* determine how much memory is needed for the tuples */
/* ---------------------------------------------------------------------- */
nsize = (double) needunits + 2 ;
needunits += UMF_tuple_lengths (Numeric, Work, &tsize) ;
nsize += tsize ;
needunits += 2 ; /* add 2, so that newmem >= 2 is true if realloc'd */
/* note: Col_tlen and Row_tlen are updated, but the tuple lists */
/* themselves are not. Do not attempt to scan the tuple lists. */
/* They are now stale, and are about to be destroyed and recreated. */
/* ---------------------------------------------------------------------- */
/* determine the desired new size of memory */
/* ---------------------------------------------------------------------- */
DEBUG0 (("UMF_get_memory: needunits: "ID"\n", needunits)) ;
minsize = Numeric->size + needunits ;
nsize += (double) Numeric->size ;
bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ;
newsize = (Int) (UMF_REALLOC_INCREASE * ((double) minsize)) ;
nsize *= UMF_REALLOC_INCREASE ;
nsize += 1 ;
if (newsize < 0 || nsize > bsize)
{
/* :: realloc Numeric->Memory int overflow :: */
DEBUGm3 (("Realloc hit integer limit\n")) ;
newsize = (Int) bsize ; /* we cannot increase the size beyond bsize */
}
else
{
ASSERT (newsize <= nsize) ;
newsize = MAX (newsize, minsize) ;
}
newsize = MAX (newsize, Numeric->size) ;
DEBUG0 ((
"REALLOC MEMORY: needunits "ID" old size: "ID" new size: "ID" Units \n",
needunits, Numeric->size, newsize)) ;
/* Forget where the biggest free block is (we no longer need it) */
/* since garbage collection will occur shortly. */
Numeric->ibig = EMPTY ;
DEBUG0 (("Before realloc E [0] "ID"\n", Work->E [0])) ;
/* ---------------------------------------------------------------------- */
/* reallocate the memory, if possible, and make it bigger */
/* ---------------------------------------------------------------------- */
mnew = (Unit *) NULL ;
while (!mnew)
{
mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ;
if (!mnew)
{
if (newsize == minsize) /* last realloc attempt failed */
{
/* We failed to get the minimum. Just stick with the */
/* current allocation and hope that garbage collection */
/* can recover enough space. */
mnew = Numeric->Memory ; /* no new memory available */
newsize = Numeric->size ;
}
else
{
/* otherwise, reduce the request and keep trying */
newsize = (Int) (UMF_REALLOC_REDUCTION * ((double) newsize)) ;
newsize = MAX (minsize, newsize) ;
}
}
}
ASSERT (mnew != (Unit *) NULL) ;
/* see if realloc had to copy, rather than just extend memory */
costly = (mnew != Numeric->Memory) ;
/* ---------------------------------------------------------------------- */
/* extend the tail portion of memory downwards */
/* ---------------------------------------------------------------------- */
Numeric->Memory = mnew ;
if (Work->E [0])
{
Int nb, dr, dc ;
nb = Work->nb ;
dr = Work->fnr_curr ;
dc = Work->fnc_curr ;
Work->Flublock = (Entry *) (Numeric->Memory + Work->E [0]) ;
Work->Flblock = Work->Flublock + nb * nb ;
Work->Fublock = Work->Flblock + dr * nb ;
Work->Fcblock = Work->Fublock + nb * dc ;
DEBUG0 (("after realloc E [0] "ID"\n", Work->E [0])) ;
}
ASSERT (IMPLIES (!(Work->E [0]), Work->Flublock == (Entry *) NULL)) ;
newmem = newsize - Numeric->size ;
ASSERT (newmem == 0 || newmem >= 2) ;
if (newmem >= 2)
{
/* reallocation succeeded */
/* point to the old tail marker block of size 1 + header */
p = Numeric->Memory + Numeric->size - 2 ;
/* create a new block out of the newly extended memory */
p->header.size = newmem - 1 ;
i = Numeric->size - 1 ;
p += newmem ;
/* create a new tail marker block */
p->header.prevsize = newmem - 1 ;
p->header.size = 1 ;
Numeric->size = newsize ;
/* free the new block */
UMF_mem_free_tail_block (Numeric, i) ;
Numeric->nrealloc++ ;
if (costly)
{
Numeric->ncostly++ ;
}
}
DEBUG1 (("Done with realloc memory\n")) ;
/* ---------------------------------------------------------------------- */
/* garbage collection on the tail of Numeric->memory (destroys tuples) */
/* ---------------------------------------------------------------------- */
UMF_garbage_collection (Numeric, Work, r2, c2, do_Fcpos) ;
/* ---------------------------------------------------------------------- */
/* rebuild the tuples */
/* ---------------------------------------------------------------------- */
return (UMF_build_tuples (Numeric, Work)) ;
}