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.
20 #include <NCollection_IncAllocator.hxx>
21 #include <NCollection_DataMap.hxx>
22 #include <NCollection_Map.hxx>
23 #include <Standard_Mutex.hxx>
24 #include <Standard_OutOfMemory.hxx>
29 IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
30 IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
35 inline size_t IMEM_SIZE (const size_t theSize)
37 return (theSize - 1) / sizeof(NCollection_IncAllocator::aligned_t) + 1;
40 inline size_t IMEM_ALIGN (const void* theAddress)
42 return sizeof(NCollection_IncAllocator::aligned_t) * IMEM_SIZE (size_t(theAddress));
45 #define IMEM_FREE(p_bl) (size_t(p_bl->p_end_block - p_bl->p_free_space))
51 static Standard_Boolean IS_DEBUG = Standard_False;
53 //=======================================================================
55 * Static data map (address -> AllocatorID)
57 //=======================================================================
58 static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
60 static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
64 //=======================================================================
66 * Static map (AllocatorID)
68 //=======================================================================
69 static NCollection_Map<Standard_Size>& StorageIDSet()
71 static NCollection_Map<Standard_Size> TheMap;
75 //=======================================================================
76 //function : IncAllocator_SetDebugFlag
77 //purpose : Turn on/off debugging of memory allocation
78 //=======================================================================
80 Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
85 //=======================================================================
87 * Static value of the current allocation ID. It provides unique
88 * numbering of allocators.
90 //=======================================================================
91 static Standard_Size CurrentID = 0;
92 static Standard_Size CATCH_ID = 0;
94 //=======================================================================
95 //function : Debug_Create
96 //purpose : Store the allocator address in the internal maps
97 //=======================================================================
99 static void Debug_Create(Standard_Address theAlloc)
101 static Standard_Mutex aMutex;
103 StorageIDMap().Bind(theAlloc, ++CurrentID);
104 StorageIDSet().Add(CurrentID);
106 if (CurrentID == CATCH_ID)
108 // Place for break point for creation of investigated allocator
113 //=======================================================================
114 //function : Debug_Destroy
115 //purpose : Forget the allocator address from the internal maps
116 //=======================================================================
118 static void Debug_Destroy(Standard_Address theAlloc)
120 static Standard_Mutex aMutex;
122 if (StorageIDMap().IsBound(theAlloc))
124 Standard_Size anID = StorageIDMap()(theAlloc);
125 StorageIDSet().Remove(anID);
126 StorageIDMap().UnBind(theAlloc);
131 //=======================================================================
132 //function : IncAllocator_PrintAlive
133 //purpose : Outputs the alive numbers to the file inc_alive.d
134 //=======================================================================
136 Standard_EXPORT void IncAllocator_PrintAlive()
138 if (StorageIDSet().IsEmpty())
143 std::ofstream aFileOut ("inc_alive.d", std::ios_base::trunc | std::ios_base::out);
144 if (!aFileOut.is_open())
146 std::cout << "failure writing file inc_alive.d" << std::endl;
149 aFileOut.imbue (std::locale ("C"));
150 aFileOut << std::fixed << std::setprecision(1);
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())
158 const NCollection_IncAllocator* anAlloc = static_cast<NCollection_IncAllocator*>(itMap.Key());
159 Standard_Size anID = itMap.Value();
160 Standard_Size aSize = anAlloc->GetMemSize();
163 aFileOut << std::setw(20) << anID << ' '
164 << std::setw(20) << (double(aSize) / 1024.0)
167 aFileOut << "Total:\n"
168 << std::setw(20) << nbAlloc << ' '
169 << std::setw(20) << (double(aTotSize) / 1024.0)
174 //=======================================================================
175 //function : NCollection_IncAllocator()
176 //purpose : Constructor
177 //=======================================================================
179 NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
181 #ifdef ALLOC_TRACK_USAGE
182 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
188 const size_t aDefault = DefaultBlockSize;
189 const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
190 IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : aDefault);
191 IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
192 myFirstBlock = aBlock;
193 mySize = aSize - IMEM_SIZE(sizeof(IBlock));
194 myMemSize = aSize * sizeof(aligned_t);
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;
202 //=======================================================================
203 //function : ~NCollection_IncAllocator
204 //purpose : Destructor
205 //=======================================================================
207 NCollection_IncAllocator::~NCollection_IncAllocator ()
217 //=======================================================================
218 //function : Allocate
219 //purpose : allocate a memory
220 //remark : returns NULL if allocation fails
221 //=======================================================================
223 void * NCollection_IncAllocator::Allocate (const size_t aSize)
225 aligned_t * aResult = NULL;
226 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
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);
233 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
235 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
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);
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);
249 aCurrentBlock = aCurrentBlock -> p_next;
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);
256 myFirstBlock -> p_free_space = aResult + cSize;
259 const size_t aDefault = IMEM_SIZE(DefaultBlockSize);
260 if (cSize > aDefault)
261 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
264 aResult = (aligned_t *) allocateNewBlock (aDefault);
266 myFirstBlock -> p_free_space = aResult + cSize;
268 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
276 //=======================================================================
277 //function : Reallocate
279 //=======================================================================
281 void * NCollection_IncAllocator::Reallocate (void * theAddress,
282 const size_t oldSize,
283 const size_t newSize)
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;
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;
302 // In case of contraction of non-terminating allocation, do nothing
303 else if (cOldSize >= cNewSize)
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);
310 for (unsigned i = 0; i < cOldSize; i++)
311 aResult[i] = anAddress[i];
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.
320 size_t cMaxSize = mySize > cNewSize ? mySize : cNewSize;
321 aligned_t * aResult = (aligned_t *) allocateNewBlock (cMaxSize);
323 myFirstBlock -> p_free_space = aResult + cNewSize;
324 for (unsigned i = 0; i < cOldSize; i++)
325 aResult[i] = anAddress[i];
329 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
334 //=======================================================================
337 //=======================================================================
339 void NCollection_IncAllocator::Free (void *)
342 //=======================================================================
345 //=======================================================================
347 void NCollection_IncAllocator::Clean ()
349 #ifdef ALLOC_TRACK_USAGE
350 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
351 double(GetMemSize())/1024, this);
353 IBlock * aBlock = myFirstBlock;
355 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
356 aBlock = aBlock -> p_next;
358 IBlock * aNext = aBlock -> p_next;
362 myFirstBlock -> p_next = NULL;
367 //=======================================================================
370 //=======================================================================
372 void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
377 Standard_Integer aBlockCount(0);
378 IBlock * aBlock = myFirstBlock;
380 if (aBlockCount++ < MaxLookup) {
381 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
382 if (aBlockCount < MaxLookup)
383 aBlock = aBlock -> p_next;
385 IBlock * aNext = aBlock -> p_next;
386 aBlock -> p_next = NULL;
390 IBlock * aNext = aBlock -> p_next;
391 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
398 //=======================================================================
399 //function : GetMemSize
400 //purpose : diagnostic utility
401 //=======================================================================
403 size_t NCollection_IncAllocator::GetMemSize () const
405 // size_t aResult = 0;
406 // IBlock * aBlock = myFirstBlock;
408 // aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
409 // aBlock = aBlock -> p_next;
411 // return aResult * sizeof (aligned_t);
415 //=======================================================================
416 //function : allocateNewBlock
418 //=======================================================================
420 void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
422 aligned_t * aResult = 0L;
423 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
424 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
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]);
430 myMemSize += aSz * sizeof(aligned_t);