1 // Created on: 2002-04-12
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2002-2012 OPEN CASCADE SAS
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.
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.
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.
21 #include <NCollection_IncAllocator.hxx>
22 #include <NCollection_DataMap.hxx>
23 #include <NCollection_Map.hxx>
24 #include <Standard_Mutex.hxx>
25 #include <Standard_OutOfMemory.hxx>
28 IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
29 IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
34 inline size_t IMEM_SIZE (const size_t theSize)
36 return (theSize - 1) / sizeof(NCollection_IncAllocator::aligned_t) + 1;
39 inline size_t IMEM_ALIGN (const void* theAddress)
41 return sizeof(NCollection_IncAllocator::aligned_t) * IMEM_SIZE (size_t(theAddress));
44 #define IMEM_FREE(p_bl) (size_t(p_bl->p_end_block - p_bl->p_free_space))
50 static Standard_Boolean IS_DEBUG = Standard_False;
52 //=======================================================================
54 * Static data map (address -> AllocatorID)
56 //=======================================================================
57 static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
59 static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
63 //=======================================================================
65 * Static map (AllocatorID)
67 //=======================================================================
68 static NCollection_Map<Standard_Size>& StorageIDSet()
70 static NCollection_Map<Standard_Size> TheMap;
74 //=======================================================================
75 //function : IncAllocator_SetDebugFlag
76 //purpose : Turn on/off debugging of memory allocation
77 //=======================================================================
79 Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
84 //=======================================================================
86 * Static value of the current allocation ID. It provides unique
87 * numbering of allocators.
89 //=======================================================================
90 static Standard_Size CurrentID = 0;
91 static Standard_Size CATCH_ID = 0;
93 //=======================================================================
94 //function : Debug_Create
95 //purpose : Store the allocator address in the internal maps
96 //=======================================================================
98 static void Debug_Create(Standard_Address theAlloc)
100 static Standard_Mutex aMutex;
101 Standard_Boolean isReentrant = Standard::IsReentrant();
104 StorageIDMap().Bind(theAlloc, ++CurrentID);
105 StorageIDSet().Add(CurrentID);
108 if (CurrentID == CATCH_ID)
110 // Place for break point for creation of investigated allocator
115 //=======================================================================
116 //function : Debug_Destroy
117 //purpose : Forget the allocator address from the internal maps
118 //=======================================================================
120 static void Debug_Destroy(Standard_Address theAlloc)
122 static Standard_Mutex aMutex;
123 Standard_Boolean isReentrant = Standard::IsReentrant();
126 if (StorageIDMap().IsBound(theAlloc))
128 Standard_Size anID = StorageIDMap()(theAlloc);
129 StorageIDSet().Remove(anID);
130 StorageIDMap().UnBind(theAlloc);
136 //=======================================================================
137 //function : IncAllocator_PrintAlive
138 //purpose : Outputs the alive numbers to the file inc_alive.d
139 //=======================================================================
141 Standard_EXPORT void IncAllocator_PrintAlive()
143 if (!StorageIDSet().IsEmpty())
145 FILE * ff = fopen("inc_alive.d", "wt");
148 cout << "failure writing file inc_alive.d" << endl;
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())
159 NCollection_IncAllocator* anAlloc =
160 static_cast<NCollection_IncAllocator*>(itMap.Key());
161 Standard_Size anID = itMap.Value();
162 Standard_Size aSize = anAlloc->GetMemSize();
165 fprintf(ff, "%-8d %8.1f\n", anID, double(aSize)/1024);
167 fprintf(ff, "Total:\n%-8d %8.1f\n", nbAlloc, double(aTotSize)/1024);
173 //=======================================================================
174 //function : NCollection_IncAllocator()
175 //purpose : Constructor
176 //=======================================================================
178 NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
180 #ifdef ALLOC_TRACK_USAGE
181 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
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;
192 myMemSize = aSize * sizeof(aligned_t);
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;
200 //=======================================================================
201 //function : ~NCollection_IncAllocator
202 //purpose : Destructor
203 //=======================================================================
205 NCollection_IncAllocator::~NCollection_IncAllocator ()
215 //=======================================================================
216 //function : Allocate
217 //purpose : allocate a memory
218 //remark : returns NULL if allocation fails
219 //=======================================================================
221 void * NCollection_IncAllocator::Allocate (const size_t aSize)
223 aligned_t * aResult = NULL;
224 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
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);
231 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
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);
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);
245 aCurrentBlock = aCurrentBlock -> p_next;
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);
252 myFirstBlock -> p_free_space = aResult + cSize;
258 //=======================================================================
259 //function : Reallocate
261 //=======================================================================
263 void * NCollection_IncAllocator::Reallocate (void * theAddress,
264 const size_t oldSize,
265 const size_t newSize)
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;
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;
284 // In case of contraction of non-terminating allocation, do nothing
285 else if (cOldSize >= cNewSize)
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);
292 for (unsigned i = 0; i < cOldSize; i++)
293 aResult[i] = anAddress[i];
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);
304 myFirstBlock -> p_free_space = aResult + cNewSize;
305 for (unsigned i = 0; i < cOldSize; i++)
306 aResult[i] = anAddress[i];
311 //=======================================================================
314 //=======================================================================
316 void NCollection_IncAllocator::Free (void *)
319 //=======================================================================
322 //=======================================================================
324 void NCollection_IncAllocator::Clean ()
326 #ifdef ALLOC_TRACK_USAGE
327 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
328 double(GetMemSize())/1024, this);
330 IBlock * aBlock = myFirstBlock;
332 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
333 aBlock = aBlock -> p_next;
335 IBlock * aNext = aBlock -> p_next;
339 myFirstBlock -> p_next = NULL;
344 //=======================================================================
347 //=======================================================================
349 void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
354 Standard_Integer aBlockCount(0);
355 IBlock * aBlock = myFirstBlock;
357 if (aBlockCount++ < MaxLookup) {
358 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
359 if (aBlockCount < MaxLookup)
360 aBlock = aBlock -> p_next;
362 IBlock * aNext = aBlock -> p_next;
363 aBlock -> p_next = NULL;
367 IBlock * aNext = aBlock -> p_next;
368 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
375 //=======================================================================
376 //function : GetMemSize
377 //purpose : diagnostic utility
378 //=======================================================================
380 size_t NCollection_IncAllocator::GetMemSize () const
382 // size_t aResult = 0;
383 // IBlock * aBlock = myFirstBlock;
385 // aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
386 // aBlock = aBlock -> p_next;
388 // return aResult * sizeof (aligned_t);
392 //=======================================================================
393 //function : allocateNewBlock
395 //=======================================================================
397 void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
399 aligned_t * aResult = 0L;
400 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
401 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
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]);
407 myMemSize += aSz * sizeof(aligned_t);
410 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");