0030945: JT Import, JtProperty_LateLoaded - expose type of Deferred object
[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 under
8 // the terms of the GNU Lesser General Public License 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 #include <NCollection_BaseAllocator.hxx>
17
18 #include <NCollection_IncAllocator.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
27 IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,Standard_Transient)
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 namespace
63 {
64   // global variable to ensure that allocator will be created during loading the library
65   static Handle(NCollection_BaseAllocator) theAllocInit = NCollection_BaseAllocator::CommonBaseAllocator();
66
67   //! Structure for collecting statistics about blocks of one size
68   struct StorageInfo
69   {
70     Standard_Size roundSize;
71     int nbAlloc;
72     int nbFree;
73     StorageInfo() : roundSize(0), nbAlloc(0), nbFree(0) {}
74     StorageInfo(Standard_Size theSize) : roundSize(theSize), nbAlloc(0), nbFree(0) {}
75   };
76
77   //! Static data map (block_size -> StorageInfo)
78   static NCollection_DataMap<Standard_Size, StorageInfo>& StorageMap()
79   {
80     static NCollection_IncAllocator TheAlloc;
81     static NCollection_DataMap<Standard_Size, StorageInfo> TheMap (1, & TheAlloc);
82     return TheMap;
83   }
84
85   //! Static data map (address -> AllocationID)
86   static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
87   {
88     static NCollection_IncAllocator TheAlloc;
89     static NCollection_DataMap<Standard_Address, Standard_Size> TheMap (1, & TheAlloc);
90     return TheMap;
91   }
92
93   //! Static map (AllocationID)
94   static NCollection_Map<Standard_Size>& StorageIDSet()
95   {
96     static NCollection_IncAllocator TheAlloc;
97     static NCollection_Map<Standard_Size> TheMap (1, & TheAlloc);
98     return TheMap;
99   }
100
101   // dummy function for break point
102   inline void place_for_break_point () {}
103
104   //! Static value of the current allocation ID. It provides unique numbering of allocation events.
105   static Standard_Size CurrentID = 0;
106 }
107
108 //=======================================================================
109 /**
110  * Exported value to set the block size for which it is required 
111  * collecting alive allocation IDs.
112  * The method NCollection_BaseAllocator::PrintMemUsageStatistics
113  * dumps all alive IDs into the file alive.d in the current directory.
114  */
115 //=======================================================================
116 Standard_EXPORT Standard_Size& StandardCallBack_CatchSize()
117 {
118   static Standard_Size Value = 0;
119   return Value;
120 }
121
122 //=======================================================================
123 /**
124  * Exported value to set the allocation ID for which it is required 
125  * to set a breakpoint on the moment of allocation or freeing.
126  * See the method NCollection_BaseAllocator::StandardCallBack
127  * where the value StandardCallBack_CatchID() is compared to the current ID.
128  * There you can place a break point at the stub assignment statement "a =".
129  */
130 //=======================================================================
131 Standard_EXPORT Standard_Size& StandardCallBack_CatchID()
132 {
133   static Standard_Size Value = 0;
134   return Value;
135 }
136
137 //=======================================================================
138 /**
139  * Exported function to reset the callback system to the initial state
140  */
141 //=======================================================================
142 Standard_EXPORT void StandardCallBack_Reset()
143 {
144   StorageMap().Clear();
145   StorageIDMap().Clear();
146   StorageIDSet().Clear();
147   CurrentID = 0;
148   StandardCallBack_CatchSize() = 0;
149   StandardCallBack_CatchID() = 0;
150 }
151
152 //=======================================================================
153 //function : StandardCallBack
154 //purpose  : Callback function to register alloc/free calls
155 //=======================================================================
156
157 void NCollection_BaseAllocator::StandardCallBack
158                     (const Standard_Boolean theIsAlloc,
159                      const Standard_Address theStorage,
160                      const Standard_Size theRoundSize,
161                      const Standard_Size /*theSize*/)
162 {
163   static Standard_Mutex aMutex;
164   aMutex.Lock();
165   // statistics by storage size
166   NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap();
167   if (!aStMap.IsBound(theRoundSize))
168   {
169     StorageInfo aEmpty(theRoundSize);
170     aStMap.Bind(theRoundSize, aEmpty);
171   }
172   StorageInfo& aInfo = aStMap(theRoundSize);
173   if (theIsAlloc)
174     aInfo.nbAlloc++;
175   else
176     aInfo.nbFree++;
177
178   if (theRoundSize == StandardCallBack_CatchSize())
179   {
180     // statistics by alive objects
181     NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap();
182     NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet();
183     if (theIsAlloc)
184     {
185       aStIDMap.Bind(theStorage, ++CurrentID);
186       aStIDSet.Add(CurrentID);
187       if (CurrentID == StandardCallBack_CatchID())
188       {
189         // Place for break point for allocation of investigated ID
190         place_for_break_point();
191       }
192     }
193     else
194     {
195       if (aStIDMap.IsBound(theStorage))
196       {
197         Standard_Size anID = aStIDMap(theStorage);
198         aStIDSet.Remove(anID);
199         if (anID == StandardCallBack_CatchID())
200         {
201           // Place for break point for freeing of investigated ID
202           place_for_break_point();
203         }
204       }
205     }
206   }
207
208   aMutex.Unlock();
209 }
210
211 //=======================================================================
212 //function : PrintMemUsageStatistics
213 //purpose  : Prints memory usage statistics cumulated by StandardCallBack
214 //=======================================================================
215
216 void NCollection_BaseAllocator::PrintMemUsageStatistics()
217 {
218   // sort by roundsize
219   NCollection_List<StorageInfo> aColl;
220   NCollection_List<StorageInfo>::Iterator itLst;
221   NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap());
222   for (; itMap.More(); itMap.Next())
223   {
224     for (itLst.Init(aColl); itLst.More(); itLst.Next())
225       if (itMap.Value().roundSize < itLst.Value().roundSize)
226         break;
227     if (itLst.More())
228       aColl.InsertBefore(itMap.Value(), itLst);
229     else
230       aColl.Append(itMap.Value());
231   }
232   Standard_Size aTotAlloc = 0;
233   Standard_Size aTotLeft = 0;
234
235   // print
236   std::ofstream aFileOut ("memstat.d", std::ios_base::trunc | std::ios_base::out);
237   if (!aFileOut.is_open())
238   {
239     std::cout << "failure writing file memstat.d" << std::endl;
240     return;
241   }
242   aFileOut.imbue (std::locale ("C"));
243
244   // header
245   aFileOut << std::setw(20) << "BlockSize"   << ' '
246            << std::setw(12) << "NbAllocated" << ' '
247            << std::setw(12) << "NbLeft"      << ' '
248            << std::setw(20) << "Allocated"   << ' '
249            << std::setw(20) << "Left"        << '\n';
250
251   // body
252   for (itLst.Init(aColl); itLst.More(); itLst.Next())
253   {
254     const StorageInfo& aInfo = itLst.Value();
255     Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
256     Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.roundSize;
257     Standard_Size aSizeLeft = nbLeft * aInfo.roundSize;
258
259     aFileOut << std::setw(20) << aInfo.roundSize << ' '
260              << std::setw(12) << aInfo.nbAlloc   << ' '
261              << std::setw(12) << nbLeft          << ' '
262              << std::setw(20) << aSizeAlloc      << ' '
263              << std::setw(20) << aSizeLeft       << '\n';
264
265     aTotAlloc += aSizeAlloc;
266     aTotLeft  += aSizeLeft;
267   }
268
269   // footer
270   aFileOut << std::setw(20) << "Total:"  << ' '
271            << std::setw(12) << ""        << ' '
272            << std::setw(12) << ""        << ' '
273            << std::setw(20) << aTotAlloc << ' '
274            << std::setw(20) << aTotLeft  << '\n';
275
276   if (!StorageIDSet().IsEmpty())
277   {
278     aFileOut << "Alive allocation numbers of size=" << StandardCallBack_CatchSize() << '\n';
279     for (NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet()); itMap1.More(); itMap1.Next())
280     {
281       aFileOut << itMap1.Key() << '\n';
282     }
283   }
284   aFileOut.close();
285 }