1 // Created on: 2002-04-12
2 // Created by: Alexander KARTOMIN (akm)
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and / or modify it
8 // under the terms of the GNU Lesser General Public version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 // Purpose: Implementation of the BaseAllocator class
18 #include <NCollection_BaseAllocator.hxx>
19 #include <NCollection_DataMap.hxx>
20 #include <NCollection_Map.hxx>
21 #include <NCollection_List.hxx>
22 #include <Standard_Mutex.hxx>
26 IMPLEMENT_STANDARD_HANDLE(NCollection_BaseAllocator,MMgt_TShared)
27 IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,MMgt_TShared)
29 //=======================================================================
31 //purpose : Standard allocation
32 //=======================================================================
34 void* NCollection_BaseAllocator::Allocate(const size_t size)
36 return Standard::Allocate(size);
39 //=======================================================================
41 //purpose : Standard deallocation
42 //=======================================================================
44 void NCollection_BaseAllocator::Free(void *anAddress)
46 if (anAddress) Standard::Free(anAddress);
49 //=======================================================================
50 //function : CommonBaseAllocator
51 //purpose : Creates the only one BaseAllocator
52 //=======================================================================
54 const Handle(NCollection_BaseAllocator)&
55 NCollection_BaseAllocator::CommonBaseAllocator(void)
57 static Handle(NCollection_BaseAllocator) pAllocator =
58 new NCollection_BaseAllocator;
62 // global variable to ensure that allocator will be created during loading the library
63 static Handle(NCollection_BaseAllocator) theAllocInit =
64 NCollection_BaseAllocator::CommonBaseAllocator();
66 //=======================================================================
68 * Structure for collecting statistics about blocks of one size
70 //=======================================================================
73 Standard_Size roundSize;
77 : roundSize(0), nbAlloc(0), nbFree(0) {}
78 StorageInfo(Standard_Size theSize)
79 : roundSize(theSize), nbAlloc(0), nbFree(0) {}
82 //=======================================================================
84 * Static data map (block_size -> StorageInfo)
86 //=======================================================================
87 static NCollection_DataMap<Standard_Size, StorageInfo>& StorageMap()
89 static NCollection_IncAllocator TheAlloc;
90 static NCollection_DataMap<Standard_Size, StorageInfo>
91 TheMap (1, & TheAlloc);
95 //=======================================================================
97 * Static data map (address -> AllocationID)
99 //=======================================================================
100 static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
102 static NCollection_IncAllocator TheAlloc;
103 static NCollection_DataMap<Standard_Address, Standard_Size>
104 TheMap (1, & TheAlloc);
108 //=======================================================================
110 * Static map (AllocationID)
112 //=======================================================================
113 static NCollection_Map<Standard_Size>& StorageIDSet()
115 static NCollection_IncAllocator TheAlloc;
116 static NCollection_Map<Standard_Size> TheMap (1, & TheAlloc);
120 //=======================================================================
122 * Exported value to set the block size for which it is required
123 * collecting alive allocation IDs.
124 * The method NCollection_BaseAllocator::PrintMemUsageStatistics
125 * dumps all alive IDs into the file alive.d in the current directory.
127 //=======================================================================
128 Standard_EXPORT Standard_Size& StandardCallBack_CatchSize()
130 static Standard_Size Value = 0;
134 //=======================================================================
136 * Exported value to set the allocation ID for which it is required
137 * to set a breakpoint on the moment of allocation or freeing.
138 * See the method NCollection_BaseAllocator::StandardCallBack
139 * where the value StandardCallBack_CatchID() is compared to the current ID.
140 * There you can place a break point at the stub assignment statement "a =".
142 //=======================================================================
143 Standard_EXPORT Standard_Size& StandardCallBack_CatchID()
145 static Standard_Size Value = 0;
149 //=======================================================================
151 * Static value of the current allocation ID. It provides unique
152 * numbering of allocation events.
154 //=======================================================================
155 static Standard_Size CurrentID = 0;
157 //=======================================================================
159 * Exported function to reset the callback system to the initial state
161 //=======================================================================
162 Standard_EXPORT void StandardCallBack_Reset()
164 StorageMap().Clear();
165 StorageIDMap().Clear();
166 StorageIDSet().Clear();
168 StandardCallBack_CatchSize() = 0;
169 StandardCallBack_CatchID() = 0;
172 //=======================================================================
173 //function : StandardCallBack
174 //purpose : Callback function to register alloc/free calls
175 //=======================================================================
177 void NCollection_BaseAllocator::StandardCallBack
178 (const Standard_Boolean theIsAlloc,
179 const Standard_Address theStorage,
180 const Standard_Size theRoundSize,
181 const Standard_Size /*theSize*/)
183 static Standard_Mutex aMutex;
185 // statistics by storage size
186 NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap();
187 if (!aStMap.IsBound(theRoundSize))
189 StorageInfo aEmpty(theRoundSize);
190 aStMap.Bind(theRoundSize, aEmpty);
192 StorageInfo& aInfo = aStMap(theRoundSize);
198 if (theRoundSize == StandardCallBack_CatchSize())
200 // statistics by alive objects
201 NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap();
202 NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet();
206 aStIDMap.Bind(theStorage, ++CurrentID);
207 aStIDSet.Add(CurrentID);
208 if (CurrentID == StandardCallBack_CatchID())
210 // Place for break point for allocation of investigated ID
216 if (aStIDMap.IsBound(theStorage))
218 Standard_Size anID = aStIDMap(theStorage);
219 aStIDSet.Remove(anID);
220 if (anID == StandardCallBack_CatchID())
222 // Place for break point for freeing of investigated ID
232 //=======================================================================
233 //function : PrintMemUsageStatistics
234 //purpose : Prints memory usage statistics cumulated by StandardCallBack
235 //=======================================================================
237 void NCollection_BaseAllocator::PrintMemUsageStatistics()
240 NCollection_List<StorageInfo> aColl;
241 NCollection_List<StorageInfo>::Iterator itLst;
242 NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap());
243 for (; itMap.More(); itMap.Next())
245 for (itLst.Init(aColl); itLst.More(); itLst.Next())
246 if (itMap.Value().roundSize < itLst.Value().roundSize)
249 aColl.InsertBefore(itMap.Value(), itLst);
251 aColl.Append(itMap.Value());
253 Standard_Size aTotAlloc = 0;
254 Standard_Size aTotLeft = 0;
257 std::ofstream aFileOut ("memstat.d", std::ios_base::trunc | std::ios_base::out);
258 if (!aFileOut.is_open())
260 std::cout << "failure writing file memstat.d" << std::endl;
263 aFileOut.imbue (std::locale ("C"));
266 aFileOut << std::setw(20) << "BlockSize" << ' '
267 << std::setw(12) << "NbAllocated" << ' '
268 << std::setw(12) << "NbLeft" << ' '
269 << std::setw(20) << "Allocated" << ' '
270 << std::setw(20) << "Left" << '\n';
273 for (itLst.Init(aColl); itLst.More(); itLst.Next())
275 const StorageInfo& aInfo = itLst.Value();
276 Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
277 Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.roundSize;
278 Standard_Size aSizeLeft = nbLeft * aInfo.roundSize;
280 aFileOut << std::setw(20) << aInfo.roundSize << ' '
281 << std::setw(12) << aInfo.nbAlloc << ' '
282 << std::setw(12) << nbLeft << ' '
283 << std::setw(20) << aSizeAlloc << ' '
284 << std::setw(20) << aSizeLeft << '\n';
286 aTotAlloc += aSizeAlloc;
287 aTotLeft += aSizeLeft;
291 aFileOut << std::setw(20) << "Total:" << ' '
292 << std::setw(12) << "" << ' '
293 << std::setw(12) << "" << ' '
294 << std::setw(20) << aTotAlloc << ' '
295 << std::setw(20) << aTotLeft << '\n';
297 if (!StorageIDSet().IsEmpty())
299 aFileOut << "Alive allocation numbers of size=" << StandardCallBack_CatchSize() << '\n';
300 for (NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet()); itMap1.More(); itMap1.Next())
302 aFileOut << itMap1.Key() << '\n';