0024510: Remove unused local variables
[occt.git] / src / NCollection / NCollection_BaseAllocator.cxx
1 // Created on: 2002-04-12
2 // Created by: Alexander KARTOMIN (akm)
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 // Purpose:     Implementation of the BaseAllocator class
17
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>
23 #include <fstream>
24 #include <iomanip>
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
46   if (anAddress) Standard::Free(anAddress); 
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 //=======================================================================
67 /**
68  * Structure for collecting statistics about blocks of one size
69  */
70 //=======================================================================
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
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 namespace {
173   // dummy function for break point
174   inline void place_for_break_point () {}
175 };
176
177 //=======================================================================
178 //function : StandardCallBack
179 //purpose  : Callback function to register alloc/free calls
180 //=======================================================================
181
182 void NCollection_BaseAllocator::StandardCallBack
183                     (const Standard_Boolean theIsAlloc,
184                      const Standard_Address theStorage,
185                      const Standard_Size theRoundSize,
186                      const Standard_Size /*theSize*/)
187 {
188   static Standard_Mutex aMutex;
189   aMutex.Lock();
190   // statistics by storage size
191   NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap();
192   if (!aStMap.IsBound(theRoundSize))
193   {
194     StorageInfo aEmpty(theRoundSize);
195     aStMap.Bind(theRoundSize, aEmpty);
196   }
197   StorageInfo& aInfo = aStMap(theRoundSize);
198   if (theIsAlloc)
199     aInfo.nbAlloc++;
200   else
201     aInfo.nbFree++;
202
203   if (theRoundSize == StandardCallBack_CatchSize())
204   {
205     // statistics by alive objects
206     NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap();
207     NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet();
208     if (theIsAlloc)
209     {
210       aStIDMap.Bind(theStorage, ++CurrentID);
211       aStIDSet.Add(CurrentID);
212       if (CurrentID == StandardCallBack_CatchID())
213       {
214         // Place for break point for allocation of investigated ID
215         place_for_break_point();
216       }
217     }
218     else
219     {
220       if (aStIDMap.IsBound(theStorage))
221       {
222         Standard_Size anID = aStIDMap(theStorage);
223         aStIDSet.Remove(anID);
224         if (anID == StandardCallBack_CatchID())
225         {
226           // Place for break point for freeing of investigated ID
227           place_for_break_point();
228         }
229       }
230     }
231   }
232
233   aMutex.Unlock();
234 }
235
236 //=======================================================================
237 //function : PrintMemUsageStatistics
238 //purpose  : Prints memory usage statistics cumulated by StandardCallBack
239 //=======================================================================
240
241 void NCollection_BaseAllocator::PrintMemUsageStatistics()
242 {
243   // sort by roundsize
244   NCollection_List<StorageInfo> aColl;
245   NCollection_List<StorageInfo>::Iterator itLst;
246   NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap());
247   for (; itMap.More(); itMap.Next())
248   {
249     for (itLst.Init(aColl); itLst.More(); itLst.Next())
250       if (itMap.Value().roundSize < itLst.Value().roundSize)
251         break;
252     if (itLst.More())
253       aColl.InsertBefore(itMap.Value(), itLst);
254     else
255       aColl.Append(itMap.Value());
256   }
257   Standard_Size aTotAlloc = 0;
258   Standard_Size aTotLeft = 0;
259
260   // print
261   std::ofstream aFileOut ("memstat.d", std::ios_base::trunc | std::ios_base::out);
262   if (!aFileOut.is_open())
263   {
264     std::cout << "failure writing file memstat.d" << std::endl;
265     return;
266   }
267   aFileOut.imbue (std::locale ("C"));
268
269   // header
270   aFileOut << std::setw(20) << "BlockSize"   << ' '
271            << std::setw(12) << "NbAllocated" << ' '
272            << std::setw(12) << "NbLeft"      << ' '
273            << std::setw(20) << "Allocated"   << ' '
274            << std::setw(20) << "Left"        << '\n';
275
276   // body
277   for (itLst.Init(aColl); itLst.More(); itLst.Next())
278   {
279     const StorageInfo& aInfo = itLst.Value();
280     Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
281     Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.roundSize;
282     Standard_Size aSizeLeft = nbLeft * aInfo.roundSize;
283
284     aFileOut << std::setw(20) << aInfo.roundSize << ' '
285              << std::setw(12) << aInfo.nbAlloc   << ' '
286              << std::setw(12) << nbLeft          << ' '
287              << std::setw(20) << aSizeAlloc      << ' '
288              << std::setw(20) << aSizeLeft       << '\n';
289
290     aTotAlloc += aSizeAlloc;
291     aTotLeft  += aSizeLeft;
292   }
293
294   // footer
295   aFileOut << std::setw(20) << "Total:"  << ' '
296            << std::setw(12) << ""        << ' '
297            << std::setw(12) << ""        << ' '
298            << std::setw(20) << aTotAlloc << ' '
299            << std::setw(20) << aTotLeft  << '\n';
300
301   if (!StorageIDSet().IsEmpty())
302   {
303     aFileOut << "Alive allocation numbers of size=" << StandardCallBack_CatchSize() << '\n';
304     for (NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet()); itMap1.More(); itMap1.Next())
305     {
306       aFileOut << itMap1.Key() << '\n';
307     }
308   }
309   aFileOut.close();
310 }