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