0023592: Enabling TBB allocator by default for OCC built with -DHAVE_TBB
[occt.git] / src / Standard / Standard.cxx
1 // Created on: 2005-03-15
2 // Created by: Peter KURNEV
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22
23 #include <Standard.ixx>
24
25 #include <stdlib.h>
26
27 #include <Standard_MMgrOpt.hxx>
28 #include <Standard_MMgrRaw.hxx>
29 #include <Standard_MMgrTBBalloc.hxx>
30
31 #if(defined(_WIN32) || defined(__WIN32__))
32 #include <windows.h>
33 #include <malloc.h>
34 #endif
35
36 #ifndef OCCT_MMGT_OPT_DEFAULT
37 #define OCCT_MMGT_OPT_DEFAULT 0
38 #endif
39
40 // Global reentrant flag
41 static Standard_Boolean Standard_IsReentrant = Standard_True;
42
43 //=======================================================================
44 //class    : Standard_MMgrFactory 
45 //purpose  : Container for pointer to memory manager;
46 //           used to construct appropriate memory manager according
47 //           to environment settings, and to ensure destruction upon exit
48 //=======================================================================
49
50 class Standard_MMgrFactory {
51  public:
52   Standard_MMgrFactory();
53   ~Standard_MMgrFactory();
54  public:
55   Standard_MMgrRoot* myFMMgr;
56 };
57
58 //=======================================================================
59 //function : Standard_MMgrFactory
60 //purpose  : Check environment variables and create appropriate memory manager
61 //=======================================================================
62
63 Standard_MMgrFactory::Standard_MMgrFactory()
64 : myFMMgr (NULL)
65 {
66   char* aVar;
67   Standard_Integer anAllocId   = (aVar = getenv ("MMGT_OPT"      )) ?  atoi (aVar)       :
68     (OCCT_MMGT_OPT_DEFAULT);
69   Standard_Boolean toClear     = (aVar = getenv ("MMGT_CLEAR"    )) ? (atoi (aVar) != 0) : Standard_True;
70
71
72   // on Windows (actual for XP and 2000) activate low fragmentation heap
73   // for CRT heap in order to get best performance.
74   // Environment variable MMGT_LFH can be used to switch off this action (if set to 0)
75 #if defined(_MSC_VER)
76   aVar = getenv ("MMGT_LFH");
77   if ( aVar == NULL || atoi (aVar) != 0 )
78   {
79     ULONG aHeapInfo = 2;
80     HANDLE aCRTHeap = (HANDLE)_get_heap_handle();
81     HeapSetInformation (aCRTHeap, HeapCompatibilityInformation, &aHeapInfo, sizeof(aHeapInfo));
82   }
83 #endif
84
85   aVar = getenv ("MMGT_REENTRANT");
86   if ( aVar != NULL ) 
87     Standard_IsReentrant = (atoi (aVar) != 0);
88
89   switch (anAllocId)
90   {
91     case 1:  // OCCT optimized memory allocator
92     {
93       Standard_Boolean bMMap       = (aVar = getenv ("MMGT_MMAP"     )) ? (atoi (aVar) != 0) : Standard_True;
94       Standard_Integer aCellSize   = (aVar = getenv ("MMGT_CELLSIZE" )) ?  atoi (aVar) : 200;
95       Standard_Integer aNbPages    = (aVar = getenv ("MMGT_NBPAGES"  )) ?  atoi (aVar) : 1000;
96       Standard_Integer aThreshold  = (aVar = getenv ("MMGT_THRESHOLD")) ?  atoi (aVar) : 40000;
97       myFMMgr = new Standard_MMgrOpt (toClear, bMMap, aCellSize, aNbPages, aThreshold, Standard_IsReentrant);
98       break;
99     }
100     case 2:  // TBB memory allocator
101       myFMMgr = new Standard_MMgrTBBalloc (toClear);
102       break;
103     case 0:
104     default: // system default memory allocator
105       myFMMgr = new Standard_MMgrRaw (toClear);
106   }
107 }
108
109 //=======================================================================
110 //function : ~Standard_MMgrFactory
111 //purpose  : 
112 //=======================================================================
113
114 Standard_MMgrFactory::~Standard_MMgrFactory()
115 {
116   if (  myFMMgr ) {
117     myFMMgr->Purge(Standard_True);
118 //  delete myFMMgr;
119 //  myFMMgr = 0;  
120   }
121 }
122
123 //=======================================================================
124 // function: GetMMgr
125 //
126 // This static function has a purpose to wrap static holder for memory 
127 // manager instance. 
128 //
129 // Wrapping holder inside a function is needed to ensure that it will
130 // be initialized not later than the first call to memory manager (that
131 // would be impossible to guarantee if holder was static variable on 
132 // global or file scope, because memory manager may be called from 
133 // constructors of other static objects).
134 //
135 // Note that at the same time we could not guarantee that the holder 
136 // object is destroyed after last call to memory manager, since that 
137 // last call may be from static Handle() object which has been initialized
138 // dynamically during program execution rather than in its constructor.
139 //
140 // Therefore holder currently does not call destructor of the memory manager 
141 // but only its method Purge() with Standard_True.
142 //
143 // To free the memory completely, we probably could use compiler-specific 
144 // pragmas (such as '#pragma fini' on SUN Solaris and '#pragma init_seg' on 
145 // WNT MSVC++) to put destructing function in code segment that is called
146 // after destructors of other (even static) objects. However, this is not 
147 // done by the moment since it is compiler-dependent and there is no guarantee 
148 // thatsome other object calling memory manager is not placed also in that segment...
149 //
150 // Note that C runtime function atexit() could not help in this problem 
151 // since its behaviour is the same as for destructors of static objects 
152 // (see ISO 14882:1998 "Programming languages -- C++" 3.6.3)
153 //
154 // The correct approach to deal with the problem would be to have memory manager 
155 // to properly control its memory allocation and caching free blocks so 
156 // as to release all memory as soon as it is returned to it, and probably
157 // even delete itself if all memory it manages has been released and 
158 // last call to method Purge() was with True.
159 //
160 // Note that one possible method to control memory allocations could
161 // be counting calls to Allocate() and Free()...
162 //
163 //=======================================================================
164
165 static Standard_MMgrRoot* GetMMgr()
166 {
167   static Standard_MMgrFactory aFactory;
168   return aFactory.myFMMgr;
169 }
170
171 //=======================================================================
172 //function : Allocate
173 //purpose  : 
174 //=======================================================================
175
176 Standard_Address Standard::Allocate(const Standard_Size size)
177 {
178   return GetMMgr()->Allocate(size);
179 }
180
181 //=======================================================================
182 //function : Free
183 //purpose  : 
184 //=======================================================================
185
186 void Standard::Free(Standard_Address& aStorage)
187 {
188   GetMMgr()->Free(aStorage);
189 }
190
191 //=======================================================================
192 //function : Reallocate
193 //purpose  : 
194 //=======================================================================
195
196 Standard_Address Standard::Reallocate(Standard_Address& aStorage,
197                                       const Standard_Size newSize)
198 {
199   return GetMMgr()->Reallocate(aStorage, newSize);
200 }
201
202 //=======================================================================
203 //function : Purge
204 //purpose  : 
205 //=======================================================================
206
207 Standard_Integer Standard::Purge()
208 {
209   return GetMMgr()->Purge();
210 }
211
212 //=======================================================================
213 //function : IsReentrant
214 //purpose  : 
215 //=======================================================================
216
217 Standard_Boolean Standard::IsReentrant()
218 {
219   return Standard_IsReentrant;
220 }
221
222 //=======================================================================
223 //function : SetReentrant
224 //purpose  : 
225 //=======================================================================
226
227 void Standard::SetReentrant (const Standard_Boolean isReentrant)
228 {
229   Standard_IsReentrant = isReentrant;
230   GetMMgr()->SetReentrant (isReentrant);
231 }