0022627: Change OCCT memory management defaults
[occt.git] / src / NCollection / NCollection_IncAllocator.cxx
CommitLineData
7fd59977 1// File: NCollection_IncAllocator.cxx
2// Created: 12.04.02 21:16:26
3// Author: Alexander GRIGORIEV
4// Copyright: Open Cascade 2002
5
6#include <NCollection_IncAllocator.hxx>
23be7421
M
7#include <NCollection_DataMap.hxx>
8#include <NCollection_Map.hxx>
9#include <Standard_Mutex.hxx>
7fd59977 10#include <Standard_OutOfMemory.hxx>
11#include <stdio.h>
12
13IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
14IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
15
c99551fa
K
16namespace
17{
18
19 inline size_t IMEM_SIZE (const size_t theSize)
20 {
21 return (theSize - 1) / sizeof(NCollection_IncAllocator::aligned_t) + 1;
22 }
23
24 inline size_t IMEM_ALIGN (const void* theAddress)
25 {
26 return sizeof(NCollection_IncAllocator::aligned_t) * IMEM_SIZE (size_t(theAddress));
27 }
28
29 #define IMEM_FREE(p_bl) (size_t(p_bl->p_end_block - p_bl->p_free_space))
30
31};
7fd59977 32
33#define MaxLookup 16
34
23be7421
M
35static Standard_Boolean IS_DEBUG = Standard_False;
36
37//=======================================================================
38/**
39 * Static data map (address -> AllocatorID)
40 */
41//=======================================================================
42static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
43{
44 static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
45 return TheMap;
46}
47
48//=======================================================================
49/**
50 * Static map (AllocatorID)
51 */
52//=======================================================================
53static NCollection_Map<Standard_Size>& StorageIDSet()
54{
55 static NCollection_Map<Standard_Size> TheMap;
56 return TheMap;
57}
58
59//=======================================================================
60//function : IncAllocator_SetDebugFlag
61//purpose : Turn on/off debugging of memory allocation
62//=======================================================================
63
64Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
65{
66 IS_DEBUG = theDebug;
67}
68
69//=======================================================================
70/**
71 * Static value of the current allocation ID. It provides unique
72 * numbering of allocators.
73 */
74//=======================================================================
75static Standard_Size CurrentID = 0;
76static Standard_Size CATCH_ID = 0;
77
78//=======================================================================
79//function : Debug_Create
80//purpose : Store the allocator address in the internal maps
81//=======================================================================
82
83static void Debug_Create(Standard_Address theAlloc)
84{
85 static Standard_Mutex aMutex;
86 Standard_Boolean isReentrant = Standard::IsReentrant();
87 if (isReentrant)
88 aMutex.Lock();
89 StorageIDMap().Bind(theAlloc, ++CurrentID);
90 StorageIDSet().Add(CurrentID);
91 if (isReentrant)
92 aMutex.Unlock();
93 if (CurrentID == CATCH_ID)
94 {
95 // Place for break point for creation of investigated allocator
96 int a = 1;
97 }
98}
99
100//=======================================================================
101//function : Debug_Destroy
102//purpose : Forget the allocator address from the internal maps
103//=======================================================================
104
105static void Debug_Destroy(Standard_Address theAlloc)
106{
107 static Standard_Mutex aMutex;
108 Standard_Boolean isReentrant = Standard::IsReentrant();
109 if (isReentrant)
110 aMutex.Lock();
111 if (StorageIDMap().IsBound(theAlloc))
112 {
113 Standard_Size anID = StorageIDMap()(theAlloc);
114 StorageIDSet().Remove(anID);
115 StorageIDMap().UnBind(theAlloc);
116 }
117 if (isReentrant)
118 aMutex.Unlock();
119}
120
121//=======================================================================
122//function : IncAllocator_PrintAlive
123//purpose : Outputs the alive numbers to the file inc_alive.d
124//=======================================================================
125
126Standard_EXPORT void IncAllocator_PrintAlive()
127{
128 if (!StorageIDSet().IsEmpty())
129 {
130 FILE * ff = fopen("inc_alive.d", "wt");
131 if (ff == NULL)
132 {
133 cout << "failure writing file inc_alive.d" << endl;
134 }
135 else
136 {
137 fprintf(ff, "Alive IncAllocators (number, size in Kb)\n");
138 NCollection_DataMap<Standard_Address, Standard_Size>::Iterator
139 itMap(StorageIDMap());
140 Standard_Size aTotSize = 0;
141 Standard_Integer nbAlloc = 0;
142 for (; itMap.More(); itMap.Next())
143 {
144 NCollection_IncAllocator* anAlloc =
145 static_cast<NCollection_IncAllocator*>(itMap.Key());
146 Standard_Size anID = itMap.Value();
147 Standard_Size aSize = anAlloc->GetMemSize();
148 aTotSize += aSize;
149 nbAlloc++;
150 fprintf(ff, "%-8d %8.1f\n", anID, double(aSize)/1024);
151 }
152 fprintf(ff, "Total:\n%-8d %8.1f\n", nbAlloc, double(aTotSize)/1024);
153 fclose(ff);
154 }
155 }
156}
157
7fd59977 158//=======================================================================
159//function : NCollection_IncAllocator()
160//purpose : Constructor
161//=======================================================================
162
163NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
164{
165#ifdef ALLOC_TRACK_USAGE
166 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
23be7421
M
167#endif
168#ifdef DEB
169 if (IS_DEBUG)
170 Debug_Create(this);
7fd59977 171#endif
172 const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
173 IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : 24600);
174 IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
175 myFirstBlock = aBlock;
176 mySize = aSize;
23be7421 177 myMemSize = aSize * sizeof(aligned_t);
7fd59977 178 if (aBlock == NULL)
179 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
180 aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]);
181 aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize;
182 aBlock -> p_next = NULL;
183}
184
185//=======================================================================
186//function : ~NCollection_IncAllocator
187//purpose : Destructor
188//=======================================================================
189
190NCollection_IncAllocator::~NCollection_IncAllocator ()
191{
23be7421
M
192#ifdef DEB
193 if (IS_DEBUG)
194 Debug_Destroy(this);
195#endif
7fd59977 196 Clean();
197 free (myFirstBlock);
198}
199
200//=======================================================================
201//function : Allocate
202//purpose : allocate a memory
203//remark : returns NULL if allocation fails
204//=======================================================================
205
206void * NCollection_IncAllocator::Allocate (const size_t aSize)
207{
208 aligned_t * aResult = NULL;
209 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
210
211 if (cSize > mySize) {
212 /* If the requested size exceeds normal allocation size, allocate
213 a separate block and place it as the head of the list */
214 aResult = (aligned_t *) allocateNewBlock (cSize+1);
215 if (aResult)
216 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
217 } else
218 if (cSize <= IMEM_FREE(myFirstBlock)) {
219 /* If the requested size fits into the free space in the 1st block */
220 aResult = myFirstBlock -> allocateInBlock (cSize);
221 } else {
222 /* Search for a block in the list with enough free space */
223 int aMaxLookup = MaxLookup; /* limit the number of blocks to query */
224 IBlock * aCurrentBlock = myFirstBlock -> p_next;
225 while (aCurrentBlock && aMaxLookup--) {
226 if (cSize <= IMEM_FREE(aCurrentBlock)) {
227 aResult = aCurrentBlock -> allocateInBlock (cSize);
228 break;
229 }
230 aCurrentBlock = aCurrentBlock -> p_next;
231 }
232 if (aResult == NULL) {
233 /* There is no available block with enough free space. Create a new
234 one and place it in the head of the list */
235 aResult = (aligned_t *) allocateNewBlock (mySize);
236 if (aResult)
237 myFirstBlock -> p_free_space = aResult + cSize;
238 }
239 }
240 return aResult;
241}
242
243//=======================================================================
244//function : Reallocate
245//purpose :
246//=======================================================================
247
248void * NCollection_IncAllocator::Reallocate (void * theAddress,
249 const size_t oldSize,
250 const size_t newSize)
251{
252// Check that the dummy parameters are OK
253 if (theAddress == NULL || oldSize == 0)
254 return Allocate (newSize);
255 const size_t cOldSize = IMEM_SIZE(oldSize);
256 const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0;
257 aligned_t * anAddress = (aligned_t *) theAddress;
258
259// We check only the LAST allocation to do the real extension/contraction
260 if (anAddress + cOldSize == myFirstBlock -> p_free_space) {
261 myFirstBlock -> p_free_space = anAddress;
262// If the new size fits into the memory block => OK
263// This also includes any case of contraction
264 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
265 myFirstBlock -> p_free_space += cNewSize;
266 return anAddress;
267 }
268 }
269// In case of contraction of non-terminating allocation, do nothing
270 else if (cOldSize >= cNewSize)
271 return anAddress;
272// Extension of non-terminated allocation if there is enough room in the
273// current memory block
274 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
275 aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize);
276 if (aResult)
277 for (unsigned i = 0; i < cOldSize; i++)
278 aResult[i] = anAddress[i];
279 return aResult;
280 }
281
282// This is either of the cases:
283// - extension of non-terminating allocation, or
284// - extension of terminating allocation when the new size is too big
285// In both cases create a new memory block, allocate memory and copy there
286// the reallocated memory.
287 aligned_t * aResult = (aligned_t *) allocateNewBlock (mySize);
288 if (aResult) {
289 myFirstBlock -> p_free_space = aResult + cNewSize;
290 for (unsigned i = 0; i < cOldSize; i++)
291 aResult[i] = anAddress[i];
292 }
293 return aResult;
294}
295
296//=======================================================================
297//function : Free
298//purpose :
299//=======================================================================
300
301void NCollection_IncAllocator::Free (void *)
302{}
303
304//=======================================================================
305//function : Clean
306//purpose :
307//=======================================================================
308
309void NCollection_IncAllocator::Clean ()
310{
311#ifdef ALLOC_TRACK_USAGE
312 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
313 double(GetMemSize())/1024, this);
314#endif
315 IBlock * aBlock = myFirstBlock;
316 if (aBlock) {
317 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
318 aBlock = aBlock -> p_next;
319 while (aBlock) {
320 IBlock * aNext = aBlock -> p_next;
321 free (aBlock);
322 aBlock = aNext;
323 }
324 myFirstBlock -> p_next = NULL;
325 }
23be7421 326 myMemSize = 0;
7fd59977 327}
328
329//=======================================================================
330//function : Reset
331//purpose :
332//=======================================================================
333
334void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
335{
336 if (doReleaseMem)
337 Clean();
338 else {
339 Standard_Integer aBlockCount(0);
340 IBlock * aBlock = myFirstBlock;
341 while (aBlock)
342 if (aBlockCount++ < MaxLookup) {
343 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
344 if (aBlockCount < MaxLookup)
345 aBlock = aBlock -> p_next;
346 else {
347 IBlock * aNext = aBlock -> p_next;
348 aBlock -> p_next = NULL;
349 aBlock = aNext;
350 }
351 } else {
352 IBlock * aNext = aBlock -> p_next;
23be7421 353 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
7fd59977 354 free (aBlock);
355 aBlock = aNext;
356 }
357 }
358}
359
360//=======================================================================
361//function : GetMemSize
362//purpose : diagnostic utility
363//=======================================================================
364
365size_t NCollection_IncAllocator::GetMemSize () const
366{
23be7421
M
367// size_t aResult = 0;
368// IBlock * aBlock = myFirstBlock;
369// while (aBlock) {
370// aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
371// aBlock = aBlock -> p_next;
372// }
373// return aResult * sizeof (aligned_t);
374 return myMemSize;
7fd59977 375}
376
377//=======================================================================
378//function : allocateNewBlock
379//purpose :
380//=======================================================================
381
382void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
383{
384 aligned_t * aResult = 0L;
385 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
386 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
387 if (aBlock) {
388 aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz;
389 aBlock -> p_next = myFirstBlock;
390 myFirstBlock = aBlock;
391 aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]);
23be7421 392 myMemSize += aSz * sizeof(aligned_t);
7fd59977 393 }
394 else
395 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
396 return aResult;
397}