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