1 // Created on: 2014-08-19
2 // Created by: Alexander Zaikin
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 2013-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 <OSD_Parallel.hxx>
18
19 #ifdef _WIN32
20 #include <windows.h>
21 #include <process.h>
22 #else
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #ifdef __sun
27 #include <sys/processor.h>
28 #include <sys/procset.h>
29 #else
30 #include <sched.h>
31 #endif
32 #endif
33
34 #include <Standard_WarningDisableFunctionCast.hxx>
35
36 namespace {
37
38 #if defined(_WIN32) && !defined(OCCT_UWP)
39 //! For a 64-bit app running under 64-bit Windows, this is FALSE.
isWow64()40 static bool isWow64()
41 {
42 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE , PBOOL);
43 BOOL bIsWow64 = FALSE;
44
45 HMODULE aKern32Module = GetModuleHandleW(L"kernel32");
46 LPFN_ISWOW64PROCESS aFunIsWow64 = (aKern32Module == NULL) ? (LPFN_ISWOW64PROCESS )NULL
47 : (LPFN_ISWOW64PROCESS)GetProcAddress(aKern32Module, "IsWow64Process");
48
49 return aFunIsWow64 != NULL &&
50 aFunIsWow64(GetCurrentProcess(), &bIsWow64) &&
51 bIsWow64 != FALSE;
52 }
53
54 #elif defined(__ANDROID__)
55
56 //! Simple number parser.
57 static const char* parseNumber (int& theResult,
58 const char* theInput,
59 const char* theLimit,
60 const int theBase = 10)
61 {
62 const char* aCharIter = theInput;
63 int aValue = 0;
64 while (aCharIter < theLimit)
65 {
66 int aDigit = (*aCharIter - '0');
67 if ((unsigned int )aDigit >= 10U)
68 {
69 aDigit = (*aCharIter - 'a');
70 if ((unsigned int )aDigit >= 6U)
71 {
72 aDigit = (*aCharIter - 'A');
73 }
74 if ((unsigned int )aDigit >= 6U)
75 {
76 break;
77 }
78 aDigit += 10;
79 }
80 if (aDigit >= theBase)
81 {
82 break;
83 }
84 aValue = aValue * theBase + aDigit;
85 ++aCharIter;
86 }
87 if (aCharIter == theInput)
88 {
89 return NULL;
90 }
91
92 theResult = aValue;
93 return aCharIter;
94 }
95
96 //! Read CPUs mask from sysfs.
97 static uint32_t readCpuMask (const char* thePath)
98 {
99 FILE* aFileHandle = fopen (thePath, "rb");
100 if (aFileHandle == NULL)
101 {
102 return 0;
103 }
104
105 fseek (aFileHandle, 0, SEEK_END);
106 long aFileLen = ftell (aFileHandle);
107 if (aFileLen <= 0L)
108 {
109 fclose (aFileHandle);
110 return 0;
111 }
112
113 char* aBuffer = (char* )Standard::Allocate (aFileLen);
114 if (aBuffer == NULL)
115 {
116 return 0;
117 }
118
119 fseek (aFileHandle, 0, SEEK_SET);
120 size_t aCountRead = fread (aBuffer, 1, aFileLen, aFileHandle);
121 (void )aCountRead;
122 fclose (aFileHandle);
123
124 uint32_t aCpuMask = 0;
125 const char* anEnd = aBuffer + aFileLen;
126 for (const char* aCharIter = aBuffer; aCharIter < anEnd && *aCharIter != '\n';)
127 {
128 const char* aChunkEnd = (const char* )::memchr (aCharIter, ',', anEnd - aCharIter);
129 if (aChunkEnd == NULL)
130 {
131 aChunkEnd = anEnd;
132 }
133
134 // get first value
135 int anIndexLower = 0;
136 aCharIter = parseNumber (anIndexLower, aCharIter, aChunkEnd);
137 if (aCharIter == NULL)
138 {
139 Standard::Free (aBuffer);
140 return aCpuMask;
141 }
142
143 // if we're not at the end of the item, expect a dash and integer; extract end value.
144 int anIndexUpper = anIndexLower;
145 if (aCharIter < aChunkEnd && *aCharIter == '-')
146 {
147 aCharIter = parseNumber (anIndexUpper, aCharIter + 1, aChunkEnd);
148 if (aCharIter == NULL)
149 {
150 Standard::Free (aBuffer);
151 return aCpuMask;
152 }
153 }
154
155 // set bits CPU list
156 for (int aCpuIndex = anIndexLower; aCpuIndex <= anIndexUpper; ++aCpuIndex)
157 {
158 if ((unsigned int )aCpuIndex < 32)
159 {
160 aCpuMask |= (uint32_t )(1U << aCpuIndex);
161 }
162 }
163
164 aCharIter = aChunkEnd;
165 if (aCharIter < anEnd)
166 {
167 ++aCharIter;
168 }
169 }
170
171 Standard::Free (aBuffer);
172 return aCpuMask;
173 }
174 #endif
175
176 static Standard_Boolean OSD_Parallel_ToUseOcctThreads =
177 #ifdef HAVE_TBB
178 Standard_False;
179 #else
180 Standard_True;
181 #endif
182 }
183
184 //=======================================================================
185 //function : ToUseOcctThreads
186 //purpose :
187 //=======================================================================
ToUseOcctThreads()188 Standard_Boolean OSD_Parallel::ToUseOcctThreads()
189 {
190 return OSD_Parallel_ToUseOcctThreads;
191 }
192
193 //=======================================================================
194 //function : SetUseOcctThreads
195 //purpose :
196 //=======================================================================
SetUseOcctThreads(Standard_Boolean theToUseOcct)197 void OSD_Parallel::SetUseOcctThreads (Standard_Boolean theToUseOcct)
198 {
199 #ifdef HAVE_TBB
200 OSD_Parallel_ToUseOcctThreads = theToUseOcct;
201 #else
202 (void )theToUseOcct;
203 #endif
204 }
205
206 //=======================================================================
207 //function : NbLogicalProcessors
208 //purpose : Returns number of logical processors.
209 //=======================================================================
NbLogicalProcessors()210 Standard_Integer OSD_Parallel::NbLogicalProcessors()
211 {
212 static Standard_Integer aNumLogicalProcessors = 0;
213 if ( aNumLogicalProcessors != 0 )
214 {
215 return aNumLogicalProcessors;
216 }
217 #ifdef _WIN32
218 // GetSystemInfo() will return the number of processors in a data field in a SYSTEM_INFO structure.
219 SYSTEM_INFO aSysInfo;
220 #ifndef OCCT_UWP
221 if ( isWow64() )
222 {
223 typedef BOOL (WINAPI *LPFN_GSI)(LPSYSTEM_INFO );
224
225 HMODULE aKern32 = GetModuleHandleW(L"kernel32");
226 LPFN_GSI aFuncSysInfo = (LPFN_GSI )GetProcAddress(aKern32, "GetNativeSystemInfo");
227
228 // So, they suggest 32-bit apps should call this instead of the other in WOW64
229 if ( aFuncSysInfo != NULL )
230 {
231 aFuncSysInfo(&aSysInfo);
232 }
233 else
234 {
235 GetSystemInfo(&aSysInfo);
236 }
237 }
238 else
239 {
240 GetSystemInfo(&aSysInfo);
241 }
242 #else
243 GetNativeSystemInfo(&aSysInfo);
244 #endif
245 aNumLogicalProcessors = aSysInfo.dwNumberOfProcessors;
246 #else
247
248 #if defined(__ANDROID__)
249 uint32_t aCpuMaskPresent = readCpuMask ("/sys/devices/system/cpu/present");
250 uint32_t aCpuMaskPossible = readCpuMask ("/sys/devices/system/cpu/possible");
251 aCpuMaskPresent &= aCpuMaskPossible;
252 aNumLogicalProcessors = __builtin_popcount (aCpuMaskPresent);
253 if (aNumLogicalProcessors >= 1)
254 {
255 return aNumLogicalProcessors;
256 }
257 #endif
258
259 // These are the choices. We'll check number of processors online.
260 // _SC_NPROCESSORS_CONF Number of processors configured
261 // _SC_NPROCESSORS_MAX Max number of processors supported by platform
262 // _SC_NPROCESSORS_ONLN Number of processors online
263 aNumLogicalProcessors = (Standard_Integer)sysconf(_SC_NPROCESSORS_ONLN);
264 #endif
265 return aNumLogicalProcessors;
266 }
267