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