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