1 // File: NCollection_IncAllocator.cxx
2 // Created: 12.04.02 21:16:26
3 // Author: Alexander GRIGORIEV
4 // Copyright: Open Cascade 2002
6 #include <NCollection_IncAllocator.hxx>
7 #include <NCollection_DataMap.hxx>
8 #include <NCollection_Map.hxx>
9 #include <Standard_Mutex.hxx>
10 #include <Standard_OutOfMemory.hxx>
13 IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
14 IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
16 #define IMEM_SIZE(_size) ((((_size) - 1)/sizeof(aligned_t)) + 1)
17 #define IMEM_FREE(p_bl) ((unsigned int)(p_bl->p_end_block - p_bl->p_free_space))
18 #define IMEM_ALIGN(_addr) (sizeof(aligned_t)* IMEM_SIZE((unsigned long)(_addr)))
22 static Standard_Boolean IS_DEBUG = Standard_False;
24 //=======================================================================
26 * Static data map (address -> AllocatorID)
28 //=======================================================================
29 static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
31 static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
35 //=======================================================================
37 * Static map (AllocatorID)
39 //=======================================================================
40 static NCollection_Map<Standard_Size>& StorageIDSet()
42 static NCollection_Map<Standard_Size> TheMap;
46 //=======================================================================
47 //function : IncAllocator_SetDebugFlag
48 //purpose : Turn on/off debugging of memory allocation
49 //=======================================================================
51 Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
56 //=======================================================================
58 * Static value of the current allocation ID. It provides unique
59 * numbering of allocators.
61 //=======================================================================
62 static Standard_Size CurrentID = 0;
63 static Standard_Size CATCH_ID = 0;
65 //=======================================================================
66 //function : Debug_Create
67 //purpose : Store the allocator address in the internal maps
68 //=======================================================================
70 static void Debug_Create(Standard_Address theAlloc)
72 static Standard_Mutex aMutex;
73 Standard_Boolean isReentrant = Standard::IsReentrant();
76 StorageIDMap().Bind(theAlloc, ++CurrentID);
77 StorageIDSet().Add(CurrentID);
80 if (CurrentID == CATCH_ID)
82 // Place for break point for creation of investigated allocator
87 //=======================================================================
88 //function : Debug_Destroy
89 //purpose : Forget the allocator address from the internal maps
90 //=======================================================================
92 static void Debug_Destroy(Standard_Address theAlloc)
94 static Standard_Mutex aMutex;
95 Standard_Boolean isReentrant = Standard::IsReentrant();
98 if (StorageIDMap().IsBound(theAlloc))
100 Standard_Size anID = StorageIDMap()(theAlloc);
101 StorageIDSet().Remove(anID);
102 StorageIDMap().UnBind(theAlloc);
108 //=======================================================================
109 //function : IncAllocator_PrintAlive
110 //purpose : Outputs the alive numbers to the file inc_alive.d
111 //=======================================================================
113 Standard_EXPORT void IncAllocator_PrintAlive()
115 if (!StorageIDSet().IsEmpty())
117 FILE * ff = fopen("inc_alive.d", "wt");
120 cout << "failure writing file inc_alive.d" << endl;
124 fprintf(ff, "Alive IncAllocators (number, size in Kb)\n");
125 NCollection_DataMap<Standard_Address, Standard_Size>::Iterator
126 itMap(StorageIDMap());
127 Standard_Size aTotSize = 0;
128 Standard_Integer nbAlloc = 0;
129 for (; itMap.More(); itMap.Next())
131 NCollection_IncAllocator* anAlloc =
132 static_cast<NCollection_IncAllocator*>(itMap.Key());
133 Standard_Size anID = itMap.Value();
134 Standard_Size aSize = anAlloc->GetMemSize();
137 fprintf(ff, "%-8d %8.1f\n", anID, double(aSize)/1024);
139 fprintf(ff, "Total:\n%-8d %8.1f\n", nbAlloc, double(aTotSize)/1024);
145 //=======================================================================
146 //function : NCollection_IncAllocator()
147 //purpose : Constructor
148 //=======================================================================
150 NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
152 #ifdef ALLOC_TRACK_USAGE
153 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
159 const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
160 IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : 24600);
161 IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
162 myFirstBlock = aBlock;
164 myMemSize = aSize * sizeof(aligned_t);
166 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
167 aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]);
168 aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize;
169 aBlock -> p_next = NULL;
172 //=======================================================================
173 //function : ~NCollection_IncAllocator
174 //purpose : Destructor
175 //=======================================================================
177 NCollection_IncAllocator::~NCollection_IncAllocator ()
187 //=======================================================================
188 //function : Allocate
189 //purpose : allocate a memory
190 //remark : returns NULL if allocation fails
191 //=======================================================================
193 void * NCollection_IncAllocator::Allocate (const size_t aSize)
195 aligned_t * aResult = NULL;
196 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
198 if (cSize > mySize) {
199 /* If the requested size exceeds normal allocation size, allocate
200 a separate block and place it as the head of the list */
201 aResult = (aligned_t *) allocateNewBlock (cSize+1);
203 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
205 if (cSize <= IMEM_FREE(myFirstBlock)) {
206 /* If the requested size fits into the free space in the 1st block */
207 aResult = myFirstBlock -> allocateInBlock (cSize);
209 /* Search for a block in the list with enough free space */
210 int aMaxLookup = MaxLookup; /* limit the number of blocks to query */
211 IBlock * aCurrentBlock = myFirstBlock -> p_next;
212 while (aCurrentBlock && aMaxLookup--) {
213 if (cSize <= IMEM_FREE(aCurrentBlock)) {
214 aResult = aCurrentBlock -> allocateInBlock (cSize);
217 aCurrentBlock = aCurrentBlock -> p_next;
219 if (aResult == NULL) {
220 /* There is no available block with enough free space. Create a new
221 one and place it in the head of the list */
222 aResult = (aligned_t *) allocateNewBlock (mySize);
224 myFirstBlock -> p_free_space = aResult + cSize;
230 //=======================================================================
231 //function : Reallocate
233 //=======================================================================
235 void * NCollection_IncAllocator::Reallocate (void * theAddress,
236 const size_t oldSize,
237 const size_t newSize)
239 // Check that the dummy parameters are OK
240 if (theAddress == NULL || oldSize == 0)
241 return Allocate (newSize);
242 const size_t cOldSize = IMEM_SIZE(oldSize);
243 const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0;
244 aligned_t * anAddress = (aligned_t *) theAddress;
246 // We check only the LAST allocation to do the real extension/contraction
247 if (anAddress + cOldSize == myFirstBlock -> p_free_space) {
248 myFirstBlock -> p_free_space = anAddress;
249 // If the new size fits into the memory block => OK
250 // This also includes any case of contraction
251 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
252 myFirstBlock -> p_free_space += cNewSize;
256 // In case of contraction of non-terminating allocation, do nothing
257 else if (cOldSize >= cNewSize)
259 // Extension of non-terminated allocation if there is enough room in the
260 // current memory block
261 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
262 aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize);
264 for (unsigned i = 0; i < cOldSize; i++)
265 aResult[i] = anAddress[i];
269 // This is either of the cases:
270 // - extension of non-terminating allocation, or
271 // - extension of terminating allocation when the new size is too big
272 // In both cases create a new memory block, allocate memory and copy there
273 // the reallocated memory.
274 aligned_t * aResult = (aligned_t *) allocateNewBlock (mySize);
276 myFirstBlock -> p_free_space = aResult + cNewSize;
277 for (unsigned i = 0; i < cOldSize; i++)
278 aResult[i] = anAddress[i];
283 //=======================================================================
286 //=======================================================================
288 void NCollection_IncAllocator::Free (void *)
291 //=======================================================================
294 //=======================================================================
296 void NCollection_IncAllocator::Clean ()
298 #ifdef ALLOC_TRACK_USAGE
299 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
300 double(GetMemSize())/1024, this);
302 IBlock * aBlock = myFirstBlock;
304 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
305 aBlock = aBlock -> p_next;
307 IBlock * aNext = aBlock -> p_next;
311 myFirstBlock -> p_next = NULL;
316 //=======================================================================
319 //=======================================================================
321 void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
326 Standard_Integer aBlockCount(0);
327 IBlock * aBlock = myFirstBlock;
329 if (aBlockCount++ < MaxLookup) {
330 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
331 if (aBlockCount < MaxLookup)
332 aBlock = aBlock -> p_next;
334 IBlock * aNext = aBlock -> p_next;
335 aBlock -> p_next = NULL;
339 IBlock * aNext = aBlock -> p_next;
340 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
347 //=======================================================================
348 //function : GetMemSize
349 //purpose : diagnostic utility
350 //=======================================================================
352 size_t NCollection_IncAllocator::GetMemSize () const
354 // size_t aResult = 0;
355 // IBlock * aBlock = myFirstBlock;
357 // aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
358 // aBlock = aBlock -> p_next;
360 // return aResult * sizeof (aligned_t);
364 //=======================================================================
365 //function : allocateNewBlock
367 //=======================================================================
369 void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
371 aligned_t * aResult = 0L;
372 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
373 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
375 aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz;
376 aBlock -> p_next = myFirstBlock;
377 myFirstBlock = aBlock;
378 aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]);
379 myMemSize += aSz * sizeof(aligned_t);
382 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");