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