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 | // |
973c2be1 | 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. | |
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> | |
19 | #include <NCollection_DataMap.hxx> | |
23be7421 | 20 | #include <NCollection_Map.hxx> |
7fd59977 | 21 | #include <NCollection_List.hxx> |
22 | #include <Standard_Mutex.hxx> | |
64531d9c | 23 | #include <fstream> |
24 | #include <iomanip> | |
7fd59977 | 25 | |
26 | IMPLEMENT_STANDARD_HANDLE(NCollection_BaseAllocator,MMgt_TShared) | |
27 | IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,MMgt_TShared) | |
28 | ||
29 | //======================================================================= | |
30 | //function : Allocate | |
31 | //purpose : Standard allocation | |
32 | //======================================================================= | |
33 | ||
34 | void* NCollection_BaseAllocator::Allocate(const size_t size) | |
35 | { | |
36 | return Standard::Allocate(size); | |
37 | } | |
38 | ||
39 | //======================================================================= | |
40 | //function : Free | |
41 | //purpose : Standard deallocation | |
42 | //======================================================================= | |
43 | ||
44 | void NCollection_BaseAllocator::Free(void *anAddress) | |
45 | { | |
547702a1 | 46 | if (anAddress) Standard::Free(anAddress); |
7fd59977 | 47 | } |
48 | ||
49 | //======================================================================= | |
50 | //function : CommonBaseAllocator | |
51 | //purpose : Creates the only one BaseAllocator | |
52 | //======================================================================= | |
53 | ||
54 | const Handle(NCollection_BaseAllocator)& | |
55 | NCollection_BaseAllocator::CommonBaseAllocator(void) | |
56 | { | |
57 | static Handle(NCollection_BaseAllocator) pAllocator = | |
58 | new NCollection_BaseAllocator; | |
59 | return pAllocator; | |
60 | } | |
61 | ||
62 | // global variable to ensure that allocator will be created during loading the library | |
63 | static Handle(NCollection_BaseAllocator) theAllocInit = | |
64 | NCollection_BaseAllocator::CommonBaseAllocator(); | |
65 | ||
66 | //======================================================================= | |
23be7421 M |
67 | /** |
68 | * Structure for collecting statistics about blocks of one size | |
69 | */ | |
7fd59977 | 70 | //======================================================================= |
7fd59977 | 71 | struct StorageInfo |
72 | { | |
73 | Standard_Size roundSize; | |
74 | int nbAlloc; | |
75 | int nbFree; | |
76 | StorageInfo() | |
77 | : roundSize(0), nbAlloc(0), nbFree(0) {} | |
78 | StorageInfo(Standard_Size theSize) | |
79 | : roundSize(theSize), nbAlloc(0), nbFree(0) {} | |
80 | }; | |
81 | ||
23be7421 M |
82 | //======================================================================= |
83 | /** | |
84 | * Static data map (block_size -> StorageInfo) | |
85 | */ | |
86 | //======================================================================= | |
87 | static NCollection_DataMap<Standard_Size, StorageInfo>& StorageMap() | |
88 | { | |
89 | static NCollection_IncAllocator TheAlloc; | |
90 | static NCollection_DataMap<Standard_Size, StorageInfo> | |
91 | TheMap (1, & TheAlloc); | |
92 | return TheMap; | |
93 | } | |
94 | ||
95 | //======================================================================= | |
96 | /** | |
97 | * Static data map (address -> AllocationID) | |
98 | */ | |
99 | //======================================================================= | |
100 | static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap() | |
101 | { | |
102 | static NCollection_IncAllocator TheAlloc; | |
103 | static NCollection_DataMap<Standard_Address, Standard_Size> | |
104 | TheMap (1, & TheAlloc); | |
105 | return TheMap; | |
106 | } | |
107 | ||
108 | //======================================================================= | |
109 | /** | |
110 | * Static map (AllocationID) | |
111 | */ | |
112 | //======================================================================= | |
113 | static NCollection_Map<Standard_Size>& StorageIDSet() | |
114 | { | |
115 | static NCollection_IncAllocator TheAlloc; | |
116 | static NCollection_Map<Standard_Size> TheMap (1, & TheAlloc); | |
117 | return TheMap; | |
118 | } | |
119 | ||
120 | //======================================================================= | |
121 | /** | |
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. | |
126 | */ | |
127 | //======================================================================= | |
128 | Standard_EXPORT Standard_Size& StandardCallBack_CatchSize() | |
129 | { | |
130 | static Standard_Size Value = 0; | |
131 | return Value; | |
132 | } | |
133 | ||
134 | //======================================================================= | |
135 | /** | |
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 =". | |
141 | */ | |
142 | //======================================================================= | |
143 | Standard_EXPORT Standard_Size& StandardCallBack_CatchID() | |
144 | { | |
145 | static Standard_Size Value = 0; | |
146 | return Value; | |
147 | } | |
148 | ||
149 | //======================================================================= | |
150 | /** | |
151 | * Static value of the current allocation ID. It provides unique | |
152 | * numbering of allocation events. | |
153 | */ | |
154 | //======================================================================= | |
155 | static Standard_Size CurrentID = 0; | |
156 | ||
157 | //======================================================================= | |
158 | /** | |
159 | * Exported function to reset the callback system to the initial state | |
160 | */ | |
161 | //======================================================================= | |
162 | Standard_EXPORT void StandardCallBack_Reset() | |
163 | { | |
164 | StorageMap().Clear(); | |
165 | StorageIDMap().Clear(); | |
166 | StorageIDSet().Clear(); | |
167 | CurrentID = 0; | |
168 | StandardCallBack_CatchSize() = 0; | |
169 | StandardCallBack_CatchID() = 0; | |
170 | } | |
171 | ||
172 | //======================================================================= | |
173 | //function : StandardCallBack | |
174 | //purpose : Callback function to register alloc/free calls | |
175 | //======================================================================= | |
7fd59977 | 176 | |
177 | void NCollection_BaseAllocator::StandardCallBack | |
178 | (const Standard_Boolean theIsAlloc, | |
23be7421 | 179 | const Standard_Address theStorage, |
7fd59977 | 180 | const Standard_Size theRoundSize, |
181 | const Standard_Size /*theSize*/) | |
182 | { | |
23be7421 | 183 | static Standard_Mutex aMutex; |
bd0c22ce | 184 | aMutex.Lock(); |
23be7421 M |
185 | // statistics by storage size |
186 | NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap(); | |
187 | if (!aStMap.IsBound(theRoundSize)) | |
7fd59977 | 188 | { |
189 | StorageInfo aEmpty(theRoundSize); | |
23be7421 | 190 | aStMap.Bind(theRoundSize, aEmpty); |
7fd59977 | 191 | } |
23be7421 | 192 | StorageInfo& aInfo = aStMap(theRoundSize); |
7fd59977 | 193 | if (theIsAlloc) |
194 | aInfo.nbAlloc++; | |
195 | else | |
196 | aInfo.nbFree++; | |
23be7421 M |
197 | |
198 | if (theRoundSize == StandardCallBack_CatchSize()) | |
199 | { | |
200 | // statistics by alive objects | |
201 | NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap(); | |
202 | NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet(); | |
203 | int a; | |
204 | if (theIsAlloc) | |
205 | { | |
206 | aStIDMap.Bind(theStorage, ++CurrentID); | |
207 | aStIDSet.Add(CurrentID); | |
208 | if (CurrentID == StandardCallBack_CatchID()) | |
209 | { | |
210 | // Place for break point for allocation of investigated ID | |
211 | a = 1; | |
212 | } | |
213 | } | |
214 | else | |
215 | { | |
216 | if (aStIDMap.IsBound(theStorage)) | |
217 | { | |
218 | Standard_Size anID = aStIDMap(theStorage); | |
219 | aStIDSet.Remove(anID); | |
220 | if (anID == StandardCallBack_CatchID()) | |
221 | { | |
222 | // Place for break point for freeing of investigated ID | |
223 | a = 0; | |
224 | } | |
225 | } | |
226 | } | |
227 | } | |
228 | ||
bd0c22ce | 229 | aMutex.Unlock(); |
7fd59977 | 230 | } |
231 | ||
232 | //======================================================================= | |
233 | //function : PrintMemUsageStatistics | |
234 | //purpose : Prints memory usage statistics cumulated by StandardCallBack | |
235 | //======================================================================= | |
236 | ||
237 | void NCollection_BaseAllocator::PrintMemUsageStatistics() | |
238 | { | |
239 | // sort by roundsize | |
240 | NCollection_List<StorageInfo> aColl; | |
241 | NCollection_List<StorageInfo>::Iterator itLst; | |
23be7421 | 242 | NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap()); |
7fd59977 | 243 | for (; itMap.More(); itMap.Next()) |
244 | { | |
245 | for (itLst.Init(aColl); itLst.More(); itLst.Next()) | |
246 | if (itMap.Value().roundSize < itLst.Value().roundSize) | |
247 | break; | |
248 | if (itLst.More()) | |
249 | aColl.InsertBefore(itMap.Value(), itLst); | |
250 | else | |
251 | aColl.Append(itMap.Value()); | |
252 | } | |
253 | Standard_Size aTotAlloc = 0; | |
254 | Standard_Size aTotLeft = 0; | |
64531d9c | 255 | |
7fd59977 | 256 | |
64531d9c | 257 | std::ofstream aFileOut ("memstat.d", std::ios_base::trunc | std::ios_base::out); |
258 | if (!aFileOut.is_open()) | |
23be7421 | 259 | { |
64531d9c | 260 | std::cout << "failure writing file memstat.d" << std::endl; |
23be7421 M |
261 | return; |
262 | } | |
64531d9c | 263 | aFileOut.imbue (std::locale ("C")); |
264 | ||
265 | // header | |
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'; | |
271 | ||
272 | // body | |
7fd59977 | 273 | for (itLst.Init(aColl); itLst.More(); itLst.Next()) |
274 | { | |
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; | |
64531d9c | 279 | |
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'; | |
285 | ||
7fd59977 | 286 | aTotAlloc += aSizeAlloc; |
64531d9c | 287 | aTotLeft += aSizeLeft; |
7fd59977 | 288 | } |
64531d9c | 289 | |
290 | // footer | |
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'; | |
23be7421 M |
296 | |
297 | if (!StorageIDSet().IsEmpty()) | |
298 | { | |
64531d9c | 299 | aFileOut << "Alive allocation numbers of size=" << StandardCallBack_CatchSize() << '\n'; |
300 | for (NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet()); itMap1.More(); itMap1.Next()) | |
301 | { | |
302 | aFileOut << itMap1.Key() << '\n'; | |
303 | } | |
23be7421 | 304 | } |
64531d9c | 305 | aFileOut.close(); |
7fd59977 | 306 | } |