Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 2002-04-12 |
2 | // Created by: Alexander KARTOMIN (akm) | |
973c2be1 | 3 | // Copyright (c) 2002-2014 OPEN CASCADE SAS |
b311480e | 4 | // |
973c2be1 | 5 | // This file is part of Open CASCADE Technology software library. |
b311480e | 6 | // |
d5f74e42 | 7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published | |
973c2be1 | 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. | |
b311480e | 12 | // |
973c2be1 | 13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. | |
b311480e | 15 | |
7fd59977 | 16 | // Purpose: Implementation of the BaseAllocator class |
17 | ||
18 | #include <NCollection_BaseAllocator.hxx> | |
ddf2fe8e | 19 | #include <NCollection_IncAllocator.hxx> |
7fd59977 | 20 | #include <NCollection_DataMap.hxx> |
23be7421 | 21 | #include <NCollection_Map.hxx> |
7fd59977 | 22 | #include <NCollection_List.hxx> |
23 | #include <Standard_Mutex.hxx> | |
64531d9c | 24 | #include <fstream> |
25 | #include <iomanip> | |
7fd59977 | 26 | |
7fd59977 | 27 | |
25e59720 | 28 | IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,Standard_Transient) |
92efcf78 | 29 | |
7fd59977 | 30 | //======================================================================= |
31 | //function : Allocate | |
32 | //purpose : Standard allocation | |
33 | //======================================================================= | |
34 | ||
35 | void* NCollection_BaseAllocator::Allocate(const size_t size) | |
36 | { | |
37 | return Standard::Allocate(size); | |
38 | } | |
39 | ||
40 | //======================================================================= | |
41 | //function : Free | |
42 | //purpose : Standard deallocation | |
43 | //======================================================================= | |
44 | ||
45 | void NCollection_BaseAllocator::Free(void *anAddress) | |
46 | { | |
547702a1 | 47 | if (anAddress) Standard::Free(anAddress); |
7fd59977 | 48 | } |
49 | ||
50 | //======================================================================= | |
51 | //function : CommonBaseAllocator | |
52 | //purpose : Creates the only one BaseAllocator | |
53 | //======================================================================= | |
54 | ||
55 | const Handle(NCollection_BaseAllocator)& | |
56 | NCollection_BaseAllocator::CommonBaseAllocator(void) | |
57 | { | |
58 | static Handle(NCollection_BaseAllocator) pAllocator = | |
59 | new NCollection_BaseAllocator; | |
60 | return pAllocator; | |
61 | } | |
62 | ||
63 | // global variable to ensure that allocator will be created during loading the library | |
64 | static Handle(NCollection_BaseAllocator) theAllocInit = | |
65 | NCollection_BaseAllocator::CommonBaseAllocator(); | |
66 | ||
67 | //======================================================================= | |
23be7421 M |
68 | /** |
69 | * Structure for collecting statistics about blocks of one size | |
70 | */ | |
7fd59977 | 71 | //======================================================================= |
7fd59977 | 72 | struct StorageInfo |
73 | { | |
74 | Standard_Size roundSize; | |
75 | int nbAlloc; | |
76 | int nbFree; | |
77 | StorageInfo() | |
78 | : roundSize(0), nbAlloc(0), nbFree(0) {} | |
79 | StorageInfo(Standard_Size theSize) | |
80 | : roundSize(theSize), nbAlloc(0), nbFree(0) {} | |
81 | }; | |
82 | ||
23be7421 M |
83 | //======================================================================= |
84 | /** | |
85 | * Static data map (block_size -> StorageInfo) | |
86 | */ | |
87 | //======================================================================= | |
88 | static NCollection_DataMap<Standard_Size, StorageInfo>& StorageMap() | |
89 | { | |
90 | static NCollection_IncAllocator TheAlloc; | |
91 | static NCollection_DataMap<Standard_Size, StorageInfo> | |
92 | TheMap (1, & TheAlloc); | |
93 | return TheMap; | |
94 | } | |
95 | ||
96 | //======================================================================= | |
97 | /** | |
98 | * Static data map (address -> AllocationID) | |
99 | */ | |
100 | //======================================================================= | |
101 | static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap() | |
102 | { | |
103 | static NCollection_IncAllocator TheAlloc; | |
104 | static NCollection_DataMap<Standard_Address, Standard_Size> | |
105 | TheMap (1, & TheAlloc); | |
106 | return TheMap; | |
107 | } | |
108 | ||
109 | //======================================================================= | |
110 | /** | |
111 | * Static map (AllocationID) | |
112 | */ | |
113 | //======================================================================= | |
114 | static NCollection_Map<Standard_Size>& StorageIDSet() | |
115 | { | |
116 | static NCollection_IncAllocator TheAlloc; | |
117 | static NCollection_Map<Standard_Size> TheMap (1, & TheAlloc); | |
118 | return TheMap; | |
119 | } | |
120 | ||
121 | //======================================================================= | |
122 | /** | |
123 | * Exported value to set the block size for which it is required | |
124 | * collecting alive allocation IDs. | |
125 | * The method NCollection_BaseAllocator::PrintMemUsageStatistics | |
126 | * dumps all alive IDs into the file alive.d in the current directory. | |
127 | */ | |
128 | //======================================================================= | |
129 | Standard_EXPORT Standard_Size& StandardCallBack_CatchSize() | |
130 | { | |
131 | static Standard_Size Value = 0; | |
132 | return Value; | |
133 | } | |
134 | ||
135 | //======================================================================= | |
136 | /** | |
137 | * Exported value to set the allocation ID for which it is required | |
138 | * to set a breakpoint on the moment of allocation or freeing. | |
139 | * See the method NCollection_BaseAllocator::StandardCallBack | |
140 | * where the value StandardCallBack_CatchID() is compared to the current ID. | |
141 | * There you can place a break point at the stub assignment statement "a =". | |
142 | */ | |
143 | //======================================================================= | |
144 | Standard_EXPORT Standard_Size& StandardCallBack_CatchID() | |
145 | { | |
146 | static Standard_Size Value = 0; | |
147 | return Value; | |
148 | } | |
149 | ||
150 | //======================================================================= | |
151 | /** | |
152 | * Static value of the current allocation ID. It provides unique | |
153 | * numbering of allocation events. | |
154 | */ | |
155 | //======================================================================= | |
156 | static Standard_Size CurrentID = 0; | |
157 | ||
158 | //======================================================================= | |
159 | /** | |
160 | * Exported function to reset the callback system to the initial state | |
161 | */ | |
162 | //======================================================================= | |
163 | Standard_EXPORT void StandardCallBack_Reset() | |
164 | { | |
165 | StorageMap().Clear(); | |
166 | StorageIDMap().Clear(); | |
167 | StorageIDSet().Clear(); | |
168 | CurrentID = 0; | |
169 | StandardCallBack_CatchSize() = 0; | |
170 | StandardCallBack_CatchID() = 0; | |
171 | } | |
172 | ||
96a95605 DB |
173 | namespace { |
174 | // dummy function for break point | |
175 | inline void place_for_break_point () {} | |
a3f6f591 | 176 | } |
96a95605 | 177 | |
23be7421 M |
178 | //======================================================================= |
179 | //function : StandardCallBack | |
180 | //purpose : Callback function to register alloc/free calls | |
181 | //======================================================================= | |
7fd59977 | 182 | |
183 | void NCollection_BaseAllocator::StandardCallBack | |
184 | (const Standard_Boolean theIsAlloc, | |
23be7421 | 185 | const Standard_Address theStorage, |
7fd59977 | 186 | const Standard_Size theRoundSize, |
187 | const Standard_Size /*theSize*/) | |
188 | { | |
23be7421 | 189 | static Standard_Mutex aMutex; |
bd0c22ce | 190 | aMutex.Lock(); |
23be7421 M |
191 | // statistics by storage size |
192 | NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap(); | |
193 | if (!aStMap.IsBound(theRoundSize)) | |
7fd59977 | 194 | { |
195 | StorageInfo aEmpty(theRoundSize); | |
23be7421 | 196 | aStMap.Bind(theRoundSize, aEmpty); |
7fd59977 | 197 | } |
23be7421 | 198 | StorageInfo& aInfo = aStMap(theRoundSize); |
7fd59977 | 199 | if (theIsAlloc) |
200 | aInfo.nbAlloc++; | |
201 | else | |
202 | aInfo.nbFree++; | |
23be7421 M |
203 | |
204 | if (theRoundSize == StandardCallBack_CatchSize()) | |
205 | { | |
206 | // statistics by alive objects | |
207 | NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap(); | |
208 | NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet(); | |
23be7421 M |
209 | if (theIsAlloc) |
210 | { | |
211 | aStIDMap.Bind(theStorage, ++CurrentID); | |
212 | aStIDSet.Add(CurrentID); | |
213 | if (CurrentID == StandardCallBack_CatchID()) | |
214 | { | |
215 | // Place for break point for allocation of investigated ID | |
96a95605 | 216 | place_for_break_point(); |
23be7421 M |
217 | } |
218 | } | |
219 | else | |
220 | { | |
221 | if (aStIDMap.IsBound(theStorage)) | |
222 | { | |
223 | Standard_Size anID = aStIDMap(theStorage); | |
224 | aStIDSet.Remove(anID); | |
225 | if (anID == StandardCallBack_CatchID()) | |
226 | { | |
227 | // Place for break point for freeing of investigated ID | |
96a95605 | 228 | place_for_break_point(); |
23be7421 M |
229 | } |
230 | } | |
231 | } | |
232 | } | |
233 | ||
bd0c22ce | 234 | aMutex.Unlock(); |
7fd59977 | 235 | } |
236 | ||
237 | //======================================================================= | |
238 | //function : PrintMemUsageStatistics | |
239 | //purpose : Prints memory usage statistics cumulated by StandardCallBack | |
240 | //======================================================================= | |
241 | ||
242 | void NCollection_BaseAllocator::PrintMemUsageStatistics() | |
243 | { | |
244 | // sort by roundsize | |
245 | NCollection_List<StorageInfo> aColl; | |
246 | NCollection_List<StorageInfo>::Iterator itLst; | |
23be7421 | 247 | NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap()); |
7fd59977 | 248 | for (; itMap.More(); itMap.Next()) |
249 | { | |
250 | for (itLst.Init(aColl); itLst.More(); itLst.Next()) | |
251 | if (itMap.Value().roundSize < itLst.Value().roundSize) | |
252 | break; | |
253 | if (itLst.More()) | |
254 | aColl.InsertBefore(itMap.Value(), itLst); | |
255 | else | |
256 | aColl.Append(itMap.Value()); | |
257 | } | |
258 | Standard_Size aTotAlloc = 0; | |
259 | Standard_Size aTotLeft = 0; | |
64531d9c | 260 | |
7fd59977 | 261 | |
64531d9c | 262 | std::ofstream aFileOut ("memstat.d", std::ios_base::trunc | std::ios_base::out); |
263 | if (!aFileOut.is_open()) | |
23be7421 | 264 | { |
64531d9c | 265 | std::cout << "failure writing file memstat.d" << std::endl; |
23be7421 M |
266 | return; |
267 | } | |
64531d9c | 268 | aFileOut.imbue (std::locale ("C")); |
269 | ||
270 | // header | |
271 | aFileOut << std::setw(20) << "BlockSize" << ' ' | |
272 | << std::setw(12) << "NbAllocated" << ' ' | |
273 | << std::setw(12) << "NbLeft" << ' ' | |
274 | << std::setw(20) << "Allocated" << ' ' | |
275 | << std::setw(20) << "Left" << '\n'; | |
276 | ||
277 | // body | |
7fd59977 | 278 | for (itLst.Init(aColl); itLst.More(); itLst.Next()) |
279 | { | |
280 | const StorageInfo& aInfo = itLst.Value(); | |
281 | Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree; | |
282 | Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.roundSize; | |
283 | Standard_Size aSizeLeft = nbLeft * aInfo.roundSize; | |
64531d9c | 284 | |
285 | aFileOut << std::setw(20) << aInfo.roundSize << ' ' | |
286 | << std::setw(12) << aInfo.nbAlloc << ' ' | |
287 | << std::setw(12) << nbLeft << ' ' | |
288 | << std::setw(20) << aSizeAlloc << ' ' | |
289 | << std::setw(20) << aSizeLeft << '\n'; | |
290 | ||
7fd59977 | 291 | aTotAlloc += aSizeAlloc; |
64531d9c | 292 | aTotLeft += aSizeLeft; |
7fd59977 | 293 | } |
64531d9c | 294 | |
295 | // footer | |
296 | aFileOut << std::setw(20) << "Total:" << ' ' | |
297 | << std::setw(12) << "" << ' ' | |
298 | << std::setw(12) << "" << ' ' | |
299 | << std::setw(20) << aTotAlloc << ' ' | |
300 | << std::setw(20) << aTotLeft << '\n'; | |
23be7421 M |
301 | |
302 | if (!StorageIDSet().IsEmpty()) | |
303 | { | |
64531d9c | 304 | aFileOut << "Alive allocation numbers of size=" << StandardCallBack_CatchSize() << '\n'; |
305 | for (NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet()); itMap1.More(); itMap1.Next()) | |
306 | { | |
307 | aFileOut << itMap1.Key() << '\n'; | |
308 | } | |
23be7421 | 309 | } |
64531d9c | 310 | aFileOut.close(); |
7fd59977 | 311 | } |