4f79abb650924e6a29fc53058dafb5467c671e64
[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-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <Standard.ixx>
18
19 #include <stdlib.h>
20
21 #include <Standard_MMgrOpt.hxx>
22 #include <Standard_MMgrRaw.hxx>
23 #include <Standard_MMgrTBBalloc.hxx>
24
25 #if(defined(_WIN32) || defined(__WIN32__))
26   #include <windows.h>
27   #include <malloc.h>
28   #include <locale.h>
29 #endif
30
31 #if defined(_MSC_VER) || defined(__ANDROID__)
32   #include <malloc.h>
33 #elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
34   #include <mm_malloc.h>
35 #else
36   extern "C" int posix_memalign (void** thePtr, size_t theAlign, size_t theSize);
37 #endif
38
39 #ifndef OCCT_MMGT_OPT_DEFAULT
40 #define OCCT_MMGT_OPT_DEFAULT 0
41 #endif
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 /*#if defined(_MSC_VER) && (_MSC_VER > 1400)
67   // Turn ON thread-safe C locale globally to avoid side effects by setlocale() calls between threads.
68   // After this call all following _configthreadlocale() will be ignored assuming
69   // Notice that this is MSVCRT feature - on POSIX systems xlocale API (uselocale instead of setlocale)
70   // should be used explicitly to ensure thread-safety!
71
72   // This is not well documented call because _ENABLE_PER_THREAD_LOCALE_GLOBAL flag is defined but not implemented for some reason.
73   // -1 will set global locale flag to force _ENABLE_PER_THREAD_LOCALE_GLOBAL + _ENABLE_PER_THREAD_LOCALE_NEW behaviour
74   // although there NO way to turn it off again and following calls will have no effect (locale will be changed only for current thread).
75   _configthreadlocale (-1);
76 #endif*/
77
78   char* aVar;
79   aVar = getenv ("MMGT_OPT");
80   Standard_Integer anAllocId   = (aVar ?  atoi (aVar): OCCT_MMGT_OPT_DEFAULT);
81
82 #if defined(_WIN32) && !defined(_WIN64)
83   static const DWORD _SSE2_FEATURE_BIT(0x04000000);
84   if ( anAllocId == 2 )
85   {
86     // CR25396: Check if SSE2 instructions are supported, if not then use MMgrRaw
87     // instead of MMgrTBBalloc. It is to avoid runtime crash when running on a 
88     // CPU that supports SSE but does not support SSE2 (some modifications of
89     // AMD Sempron).
90     DWORD volatile dwFeature;
91     _asm
92     {
93       push eax
94       push ebx
95       push ecx
96       push edx
97
98       // get the CPU feature bits
99       mov eax, 1
100       cpuid
101       mov dwFeature, edx
102
103       pop edx
104       pop ecx
105       pop ebx
106       pop eax
107     }
108     if ((dwFeature & _SSE2_FEATURE_BIT) == 0)
109       anAllocId = 0;
110   }
111 #endif
112
113   aVar = getenv ("MMGT_CLEAR");
114   Standard_Boolean toClear     = (aVar ? (atoi (aVar) != 0) : Standard_True);
115
116   // on Windows (actual for XP and 2000) activate low fragmentation heap
117   // for CRT heap in order to get best performance.
118   // Environment variable MMGT_LFH can be used to switch off this action (if set to 0)
119 #if defined(_MSC_VER)
120   aVar = getenv ("MMGT_LFH");
121   if ( aVar == NULL || atoi (aVar) != 0 )
122   {
123     ULONG aHeapInfo = 2;
124     HANDLE aCRTHeap = (HANDLE)_get_heap_handle();
125     HeapSetInformation (aCRTHeap, HeapCompatibilityInformation, &aHeapInfo, sizeof(aHeapInfo));
126   }
127 #endif
128
129   switch (anAllocId)
130   {
131     case 1:  // OCCT optimized memory allocator
132     {
133       aVar = getenv ("MMGT_MMAP");
134       Standard_Boolean bMMap       = (aVar ? (atoi (aVar) != 0) : Standard_True);
135       aVar = getenv ("MMGT_CELLSIZE");
136       Standard_Integer aCellSize   = (aVar ?  atoi (aVar) : 200);
137       aVar = getenv ("MMGT_NBPAGES");
138       Standard_Integer aNbPages    = (aVar ?  atoi (aVar) : 1000);
139       aVar = getenv ("MMGT_THRESHOLD");
140       Standard_Integer aThreshold  = (aVar ?  atoi (aVar) : 40000);
141       myFMMgr = new Standard_MMgrOpt (toClear, bMMap, aCellSize, aNbPages, aThreshold);
142       break;
143     }
144     case 2:  // TBB memory allocator
145       myFMMgr = new Standard_MMgrTBBalloc (toClear);
146       break;
147     case 0:
148     default: // system default memory allocator
149       myFMMgr = new Standard_MMgrRaw (toClear);
150   }
151 }
152
153 //=======================================================================
154 //function : ~Standard_MMgrFactory
155 //purpose  : 
156 //=======================================================================
157
158 Standard_MMgrFactory::~Standard_MMgrFactory()
159 {
160   if (  myFMMgr ) {
161     myFMMgr->Purge(Standard_True);
162 //  delete myFMMgr;
163 //  myFMMgr = 0;  
164   }
165 }
166
167 //=======================================================================
168 // function: GetMMgr
169 //
170 // This static function has a purpose to wrap static holder for memory 
171 // manager instance. 
172 //
173 // Wrapping holder inside a function is needed to ensure that it will
174 // be initialized not later than the first call to memory manager (that
175 // would be impossible to guarantee if holder was static variable on 
176 // global or file scope, because memory manager may be called from 
177 // constructors of other static objects).
178 //
179 // Note that at the same time we could not guarantee that the holder 
180 // object is destroyed after last call to memory manager, since that 
181 // last call may be from static Handle() object which has been initialized
182 // dynamically during program execution rather than in its constructor.
183 //
184 // Therefore holder currently does not call destructor of the memory manager 
185 // but only its method Purge() with Standard_True.
186 //
187 // To free the memory completely, we probably could use compiler-specific 
188 // pragmas (such as '#pragma fini' on SUN Solaris and '#pragma init_seg' on 
189 // WNT MSVC++) to put destructing function in code segment that is called
190 // after destructors of other (even static) objects. However, this is not 
191 // done by the moment since it is compiler-dependent and there is no guarantee 
192 // thatsome other object calling memory manager is not placed also in that segment...
193 //
194 // Note that C runtime function atexit() could not help in this problem 
195 // since its behaviour is the same as for destructors of static objects 
196 // (see ISO 14882:1998 "Programming languages -- C++" 3.6.3)
197 //
198 // The correct approach to deal with the problem would be to have memory manager 
199 // to properly control its memory allocation and caching free blocks so 
200 // as to release all memory as soon as it is returned to it, and probably
201 // even delete itself if all memory it manages has been released and 
202 // last call to method Purge() was with True.
203 //
204 // Note that one possible method to control memory allocations could
205 // be counting calls to Allocate() and Free()...
206 //
207 //=======================================================================
208
209 static Standard_MMgrRoot* GetMMgr()
210 {
211   static Standard_MMgrFactory aFactory;
212   return aFactory.myFMMgr;
213 }
214
215 //=======================================================================
216 //function : Allocate
217 //purpose  : 
218 //=======================================================================
219
220 Standard_Address Standard::Allocate(const Standard_Size size)
221 {
222   return GetMMgr()->Allocate(size);
223 }
224
225 //=======================================================================
226 //function : Free
227 //purpose  : 
228 //=======================================================================
229
230 void Standard::Free (Standard_Address theStorage)
231 {
232   GetMMgr()->Free(theStorage);
233 }
234
235 //=======================================================================
236 //function : Reallocate
237 //purpose  : 
238 //=======================================================================
239
240 Standard_Address Standard::Reallocate (Standard_Address theStorage,
241                                        const Standard_Size theSize)
242 {
243   return GetMMgr()->Reallocate (theStorage, theSize);
244 }
245
246 //=======================================================================
247 //function : Purge
248 //purpose  : 
249 //=======================================================================
250
251 Standard_Integer Standard::Purge()
252 {
253   return GetMMgr()->Purge();
254 }
255
256 //=======================================================================
257 //function : AllocateAligned
258 //purpose  :
259 //=======================================================================
260
261 Standard_Address Standard::AllocateAligned (const Standard_Size theSize,
262                                             const Standard_Size theAlign)
263 {
264 #if defined(_MSC_VER)
265   return _aligned_malloc (theSize, theAlign);
266 #elif defined(__ANDROID__)
267   return memalign (theAlign, theSize);
268 #elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
269   return _mm_malloc (theSize, theAlign);
270 #else
271   void* aPtr;
272   if (posix_memalign (&aPtr, theAlign, theSize))
273   {
274     return NULL;
275   }
276   return aPtr;
277 #endif
278 }
279
280 //=======================================================================
281 //function : FreeAligned
282 //purpose  :
283 //=======================================================================
284
285 void Standard::FreeAligned (Standard_Address thePtrAligned)
286 {
287 #if defined(_MSC_VER)
288   _aligned_free (thePtrAligned);
289 #elif defined(__ANDROID__)
290   free (thePtrAligned);
291 #elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1)
292   _mm_free (thePtrAligned);
293 #else
294   free (thePtrAligned);
295 #endif
296 }