0029915: Porting to VC 2017 : Regressions in Modeling Algorithms on VC 2017
[occt.git] / src / NCollection / NCollection_BaseAllocator.cxx
CommitLineData
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 28IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,Standard_Transient)
92efcf78 29
7fd59977 30//=======================================================================
31//function : Allocate
32//purpose : Standard allocation
33//=======================================================================
34
35void* 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
45void 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
55const 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
64static 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 72struct 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//=======================================================================
88static 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//=======================================================================
101static 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//=======================================================================
114static 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//=======================================================================
129Standard_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//=======================================================================
144Standard_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//=======================================================================
156static Standard_Size CurrentID = 0;
157
158//=======================================================================
159/**
160 * Exported function to reset the callback system to the initial state
161 */
162//=======================================================================
163Standard_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
173namespace {
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
183void 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
242void 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 // print
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}