0024489: Avoid type casts in call to Standard::Free()
[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//
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
26IMPLEMENT_STANDARD_HANDLE(NCollection_BaseAllocator,MMgt_TShared)
27IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,MMgt_TShared)
28
29//=======================================================================
30//function : Allocate
31//purpose : Standard allocation
32//=======================================================================
33
34void* 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
44void 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
54const 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
63static 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 71struct 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//=======================================================================
87static 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//=======================================================================
100static 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//=======================================================================
113static 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//=======================================================================
128Standard_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//=======================================================================
143Standard_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//=======================================================================
155static Standard_Size CurrentID = 0;
156
157//=======================================================================
158/**
159 * Exported function to reset the callback system to the initial state
160 */
161//=======================================================================
162Standard_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
177void 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
237void 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 // print
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}