0024030: Undefined reference to `NCollection_IncAllocator::DefaultBlockSize'.
[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;
bd0c22ce 101 aMutex.Lock();
23be7421
M
102 StorageIDMap().Bind(theAlloc, ++CurrentID);
103 StorageIDSet().Add(CurrentID);
bd0c22ce 104 aMutex.Unlock();
23be7421
M
105 if (CurrentID == CATCH_ID)
106 {
107 // Place for break point for creation of investigated allocator
108 int a = 1;
109 }
110}
111
112//=======================================================================
113//function : Debug_Destroy
114//purpose : Forget the allocator address from the internal maps
115//=======================================================================
116
117static void Debug_Destroy(Standard_Address theAlloc)
118{
119 static Standard_Mutex aMutex;
bd0c22ce 120 aMutex.Lock();
23be7421
M
121 if (StorageIDMap().IsBound(theAlloc))
122 {
123 Standard_Size anID = StorageIDMap()(theAlloc);
124 StorageIDSet().Remove(anID);
125 StorageIDMap().UnBind(theAlloc);
126 }
bd0c22ce 127 aMutex.Unlock();
23be7421
M
128}
129
130//=======================================================================
131//function : IncAllocator_PrintAlive
132//purpose : Outputs the alive numbers to the file inc_alive.d
133//=======================================================================
134
135Standard_EXPORT void IncAllocator_PrintAlive()
136{
137 if (!StorageIDSet().IsEmpty())
138 {
139 FILE * ff = fopen("inc_alive.d", "wt");
140 if (ff == NULL)
141 {
142 cout << "failure writing file inc_alive.d" << endl;
143 }
144 else
145 {
146 fprintf(ff, "Alive IncAllocators (number, size in Kb)\n");
147 NCollection_DataMap<Standard_Address, Standard_Size>::Iterator
148 itMap(StorageIDMap());
149 Standard_Size aTotSize = 0;
150 Standard_Integer nbAlloc = 0;
151 for (; itMap.More(); itMap.Next())
152 {
153 NCollection_IncAllocator* anAlloc =
154 static_cast<NCollection_IncAllocator*>(itMap.Key());
155 Standard_Size anID = itMap.Value();
156 Standard_Size aSize = anAlloc->GetMemSize();
157 aTotSize += aSize;
158 nbAlloc++;
159 fprintf(ff, "%-8d %8.1f\n", anID, double(aSize)/1024);
160 }
161 fprintf(ff, "Total:\n%-8d %8.1f\n", nbAlloc, double(aTotSize)/1024);
162 fclose(ff);
163 }
164 }
165}
166
7fd59977 167//=======================================================================
168//function : NCollection_IncAllocator()
169//purpose : Constructor
170//=======================================================================
171
172NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
173{
174#ifdef ALLOC_TRACK_USAGE
175 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
23be7421
M
176#endif
177#ifdef DEB
178 if (IS_DEBUG)
179 Debug_Create(this);
7fd59977 180#endif
8ba3c5e0 181 const size_t aDefault = DefaultBlockSize;
7fd59977 182 const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
8ba3c5e0 183 IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : aDefault);
7fd59977 184 IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
185 myFirstBlock = aBlock;
db56cc2d 186 mySize = aSize - IMEM_SIZE(sizeof(IBlock));
23be7421 187 myMemSize = aSize * sizeof(aligned_t);
7fd59977 188 if (aBlock == NULL)
189 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
190 aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]);
191 aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize;
192 aBlock -> p_next = NULL;
193}
194
195//=======================================================================
196//function : ~NCollection_IncAllocator
197//purpose : Destructor
198//=======================================================================
199
200NCollection_IncAllocator::~NCollection_IncAllocator ()
201{
23be7421
M
202#ifdef DEB
203 if (IS_DEBUG)
204 Debug_Destroy(this);
205#endif
7fd59977 206 Clean();
207 free (myFirstBlock);
208}
209
210//=======================================================================
211//function : Allocate
212//purpose : allocate a memory
213//remark : returns NULL if allocation fails
214//=======================================================================
215
216void * NCollection_IncAllocator::Allocate (const size_t aSize)
217{
218 aligned_t * aResult = NULL;
219 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
220
221 if (cSize > mySize) {
222 /* If the requested size exceeds normal allocation size, allocate
223 a separate block and place it as the head of the list */
224 aResult = (aligned_t *) allocateNewBlock (cSize+1);
225 if (aResult)
226 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
db56cc2d 227 else
228 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
7fd59977 229 } else
230 if (cSize <= IMEM_FREE(myFirstBlock)) {
231 /* If the requested size fits into the free space in the 1st block */
232 aResult = myFirstBlock -> allocateInBlock (cSize);
233 } else {
234 /* Search for a block in the list with enough free space */
235 int aMaxLookup = MaxLookup; /* limit the number of blocks to query */
236 IBlock * aCurrentBlock = myFirstBlock -> p_next;
237 while (aCurrentBlock && aMaxLookup--) {
238 if (cSize <= IMEM_FREE(aCurrentBlock)) {
239 aResult = aCurrentBlock -> allocateInBlock (cSize);
240 break;
241 }
242 aCurrentBlock = aCurrentBlock -> p_next;
243 }
244 if (aResult == NULL) {
245 /* There is no available block with enough free space. Create a new
246 one and place it in the head of the list */
247 aResult = (aligned_t *) allocateNewBlock (mySize);
248 if (aResult)
249 myFirstBlock -> p_free_space = aResult + cSize;
db56cc2d 250 else
251 {
252 const size_t aDefault = IMEM_SIZE(DefaultBlockSize);
253 if (cSize > aDefault)
254 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
255 else
256 {
257 aResult = (aligned_t *) allocateNewBlock (aDefault);
258 if (aResult)
259 myFirstBlock -> p_free_space = aResult + cSize;
260 else
261 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
262 }
263 }
7fd59977 264 }
265 }
266 return aResult;
267}
268
269//=======================================================================
270//function : Reallocate
271//purpose :
272//=======================================================================
273
274void * NCollection_IncAllocator::Reallocate (void * theAddress,
275 const size_t oldSize,
276 const size_t newSize)
277{
278// Check that the dummy parameters are OK
279 if (theAddress == NULL || oldSize == 0)
280 return Allocate (newSize);
281 const size_t cOldSize = IMEM_SIZE(oldSize);
282 const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0;
283 aligned_t * anAddress = (aligned_t *) theAddress;
284
285// We check only the LAST allocation to do the real extension/contraction
286 if (anAddress + cOldSize == myFirstBlock -> p_free_space) {
287 myFirstBlock -> p_free_space = anAddress;
288// If the new size fits into the memory block => OK
289// This also includes any case of contraction
290 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
291 myFirstBlock -> p_free_space += cNewSize;
292 return anAddress;
293 }
294 }
295// In case of contraction of non-terminating allocation, do nothing
296 else if (cOldSize >= cNewSize)
297 return anAddress;
298// Extension of non-terminated allocation if there is enough room in the
299// current memory block
300 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
301 aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize);
302 if (aResult)
303 for (unsigned i = 0; i < cOldSize; i++)
304 aResult[i] = anAddress[i];
305 return aResult;
306 }
307
308// This is either of the cases:
309// - extension of non-terminating allocation, or
310// - extension of terminating allocation when the new size is too big
311// In both cases create a new memory block, allocate memory and copy there
312// the reallocated memory.
db56cc2d 313 size_t cMaxSize = mySize > cNewSize ? mySize : cNewSize;
314 aligned_t * aResult = (aligned_t *) allocateNewBlock (cMaxSize);
7fd59977 315 if (aResult) {
316 myFirstBlock -> p_free_space = aResult + cNewSize;
317 for (unsigned i = 0; i < cOldSize; i++)
318 aResult[i] = anAddress[i];
319 }
db56cc2d 320 else
321 {
322 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
323 }
7fd59977 324 return aResult;
325}
326
327//=======================================================================
328//function : Free
329//purpose :
330//=======================================================================
331
332void NCollection_IncAllocator::Free (void *)
333{}
334
335//=======================================================================
336//function : Clean
337//purpose :
338//=======================================================================
339
340void NCollection_IncAllocator::Clean ()
341{
342#ifdef ALLOC_TRACK_USAGE
343 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
344 double(GetMemSize())/1024, this);
345#endif
346 IBlock * aBlock = myFirstBlock;
347 if (aBlock) {
348 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
349 aBlock = aBlock -> p_next;
350 while (aBlock) {
351 IBlock * aNext = aBlock -> p_next;
352 free (aBlock);
353 aBlock = aNext;
354 }
355 myFirstBlock -> p_next = NULL;
356 }
23be7421 357 myMemSize = 0;
7fd59977 358}
359
360//=======================================================================
361//function : Reset
362//purpose :
363//=======================================================================
364
365void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
366{
367 if (doReleaseMem)
368 Clean();
369 else {
370 Standard_Integer aBlockCount(0);
371 IBlock * aBlock = myFirstBlock;
372 while (aBlock)
373 if (aBlockCount++ < MaxLookup) {
374 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
375 if (aBlockCount < MaxLookup)
376 aBlock = aBlock -> p_next;
377 else {
378 IBlock * aNext = aBlock -> p_next;
379 aBlock -> p_next = NULL;
380 aBlock = aNext;
381 }
382 } else {
383 IBlock * aNext = aBlock -> p_next;
23be7421 384 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
7fd59977 385 free (aBlock);
386 aBlock = aNext;
387 }
388 }
389}
390
391//=======================================================================
392//function : GetMemSize
393//purpose : diagnostic utility
394//=======================================================================
395
396size_t NCollection_IncAllocator::GetMemSize () const
397{
23be7421
M
398// size_t aResult = 0;
399// IBlock * aBlock = myFirstBlock;
400// while (aBlock) {
401// aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
402// aBlock = aBlock -> p_next;
403// }
404// return aResult * sizeof (aligned_t);
405 return myMemSize;
7fd59977 406}
407
408//=======================================================================
409//function : allocateNewBlock
410//purpose :
411//=======================================================================
412
413void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
414{
415 aligned_t * aResult = 0L;
416 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
417 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
418 if (aBlock) {
419 aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz;
420 aBlock -> p_next = myFirstBlock;
421 myFirstBlock = aBlock;
422 aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]);
23be7421 423 myMemSize += aSz * sizeof(aligned_t);
7fd59977 424 }
7fd59977 425 return aResult;
426}