diff options
Diffstat (limited to '')
-rw-r--r-- | CPP/Windows/System.cpp | 169 |
1 files changed, 138 insertions, 31 deletions
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp index 03c8988..4745785 100644 --- a/CPP/Windows/System.cpp +++ b/CPP/Windows/System.cpp | |||
@@ -25,6 +25,69 @@ namespace NSystem { | |||
25 | 25 | ||
26 | #ifdef _WIN32 | 26 | #ifdef _WIN32 |
27 | 27 | ||
28 | /* | ||
29 | note: returned value in 32-bit version can be limited by value 32. | ||
30 | while 64-bit version returns full value. | ||
31 | GetMaximumProcessorCount(groupNumber) can return higher value than | ||
32 | GetActiveProcessorCount(groupNumber) in some cases, because CPUs can be added. | ||
33 | */ | ||
34 | // typedef DWORD (WINAPI *Func_GetMaximumProcessorCount)(WORD GroupNumber); | ||
35 | typedef DWORD (WINAPI *Func_GetActiveProcessorCount)(WORD GroupNumber); | ||
36 | typedef WORD (WINAPI *Func_GetActiveProcessorGroupCount)(VOID); | ||
37 | /* | ||
38 | #if 0 && defined(ALL_PROCESSOR_GROUPS) | ||
39 | #define MY_ALL_PROCESSOR_GROUPS ALL_PROCESSOR_GROUPS | ||
40 | #else | ||
41 | #define MY_ALL_PROCESSOR_GROUPS 0xffff | ||
42 | #endif | ||
43 | */ | ||
44 | |||
45 | Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | ||
46 | |||
47 | bool CCpuGroups::Load() | ||
48 | { | ||
49 | NumThreadsTotal = 0; | ||
50 | GroupSizes.Clear(); | ||
51 | const HMODULE hmodule = ::GetModuleHandleA("kernel32.dll"); | ||
52 | // Is_Win11_Groups = GetProcAddress(hmodule, "SetThreadSelectedCpuSetMasks") != NULL; | ||
53 | const | ||
54 | Func_GetActiveProcessorGroupCount | ||
55 | fn_GetActiveProcessorGroupCount = Z7_GET_PROC_ADDRESS( | ||
56 | Func_GetActiveProcessorGroupCount, hmodule, | ||
57 | "GetActiveProcessorGroupCount"); | ||
58 | const | ||
59 | Func_GetActiveProcessorCount | ||
60 | fn_GetActiveProcessorCount = Z7_GET_PROC_ADDRESS( | ||
61 | Func_GetActiveProcessorCount, hmodule, | ||
62 | "GetActiveProcessorCount"); | ||
63 | if (!fn_GetActiveProcessorGroupCount || | ||
64 | !fn_GetActiveProcessorCount) | ||
65 | return false; | ||
66 | |||
67 | const unsigned numGroups = fn_GetActiveProcessorGroupCount(); | ||
68 | if (numGroups == 0) | ||
69 | return false; | ||
70 | UInt32 sum = 0; | ||
71 | for (unsigned i = 0; i < numGroups; i++) | ||
72 | { | ||
73 | const UInt32 num = fn_GetActiveProcessorCount((WORD)i); | ||
74 | /* | ||
75 | if (num == 0) | ||
76 | { | ||
77 | // it means error | ||
78 | // but is it possible that some group is empty by some reason? | ||
79 | // GroupSizes.Clear(); | ||
80 | // return false; | ||
81 | } | ||
82 | */ | ||
83 | sum += num; | ||
84 | GroupSizes.Add(num); | ||
85 | } | ||
86 | NumThreadsTotal = sum; | ||
87 | // NumThreadsTotal = fn_GetActiveProcessorCount(MY_ALL_PROCESSOR_GROUPS); | ||
88 | return true; | ||
89 | } | ||
90 | |||
28 | UInt32 CountAffinity(DWORD_PTR mask) | 91 | UInt32 CountAffinity(DWORD_PTR mask) |
29 | { | 92 | { |
30 | UInt32 num = 0; | 93 | UInt32 num = 0; |
@@ -38,31 +101,62 @@ UInt32 CountAffinity(DWORD_PTR mask) | |||
38 | 101 | ||
39 | BOOL CProcessAffinity::Get() | 102 | BOOL CProcessAffinity::Get() |
40 | { | 103 | { |
41 | #ifndef UNDER_CE | 104 | IsGroupMode = false; |
42 | return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); | 105 | Groups.Load(); |
43 | #else | 106 | // SetThreadAffinityMask(GetCurrentThread(), 1); |
44 | return FALSE; | 107 | // SetProcessAffinityMask(GetCurrentProcess(), 1); |
45 | #endif | 108 | BOOL res = GetProcessAffinityMask(GetCurrentProcess(), |
109 | &processAffinityMask, &systemAffinityMask); | ||
110 | /* DOCs: On a system with more than 64 processors, if the threads | ||
111 | of the calling process are in a single processor group, the | ||
112 | function sets the variables pointed to by lpProcessAffinityMask | ||
113 | and lpSystemAffinityMask to the process affinity mask and the | ||
114 | processor mask of active logical processors for that group. | ||
115 | If the calling process contains threads in multiple groups, | ||
116 | the function returns zero for both affinity masks | ||
117 | |||
118 | note: tested in Win10: GetProcessAffinityMask() doesn't return 0 | ||
119 | in (processAffinityMask) and (systemAffinityMask) masks. | ||
120 | We need to test it in Win11: how to get mask==0 from GetProcessAffinityMask()? | ||
121 | */ | ||
122 | if (!res) | ||
123 | { | ||
124 | processAffinityMask = 0; | ||
125 | systemAffinityMask = 0; | ||
126 | } | ||
127 | if (Groups.GroupSizes.Size() > 1 && Groups.NumThreadsTotal) | ||
128 | if (// !res || | ||
129 | processAffinityMask == 0 || // to support case described in DOCs and for (!res) case | ||
130 | processAffinityMask == systemAffinityMask) // for default nonchanged affinity | ||
131 | { | ||
132 | // we set IsGroupMode only if processAffinity is default (not changed). | ||
133 | res = TRUE; | ||
134 | IsGroupMode = true; | ||
135 | } | ||
136 | return res; | ||
46 | } | 137 | } |
47 | 138 | ||
48 | 139 | ||
140 | UInt32 CProcessAffinity::Load_and_GetNumberOfThreads() | ||
141 | { | ||
142 | if (Get()) | ||
143 | { | ||
144 | const UInt32 numProcessors = GetNumProcessThreads(); | ||
145 | if (numProcessors) | ||
146 | return numProcessors; | ||
147 | } | ||
148 | SYSTEM_INFO systemInfo; | ||
149 | GetSystemInfo(&systemInfo); | ||
150 | // the number of logical processors in the current group | ||
151 | return systemInfo.dwNumberOfProcessors; | ||
152 | } | ||
153 | |||
49 | UInt32 GetNumberOfProcessors() | 154 | UInt32 GetNumberOfProcessors() |
50 | { | 155 | { |
51 | // We need to know how many threads we can use. | 156 | // We need to know how many threads we can use. |
52 | // By default the process is assigned to one group. | 157 | // By default the process is assigned to one group. |
53 | // So we get the number of logical processors (threads) | ||
54 | // assigned to current process in the current group. | ||
55 | // Group size can be smaller than total number logical processors, for exammple, 2x36 | ||
56 | |||
57 | CProcessAffinity pa; | 158 | CProcessAffinity pa; |
58 | 159 | return pa.Load_and_GetNumberOfThreads(); | |
59 | if (pa.Get() && pa.processAffinityMask != 0) | ||
60 | return pa.GetNumProcessThreads(); | ||
61 | |||
62 | SYSTEM_INFO systemInfo; | ||
63 | GetSystemInfo(&systemInfo); | ||
64 | // the number of logical processors in the current group | ||
65 | return (UInt32)systemInfo.dwNumberOfProcessors; | ||
66 | } | 160 | } |
67 | 161 | ||
68 | #else | 162 | #else |
@@ -142,9 +236,9 @@ typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer); | |||
142 | #endif // !UNDER_CE | 236 | #endif // !UNDER_CE |
143 | 237 | ||
144 | 238 | ||
145 | bool GetRamSize(UInt64 &size) | 239 | bool GetRamSize(size_t &size) |
146 | { | 240 | { |
147 | size = (UInt64)(sizeof(size_t)) << 29; | 241 | size = (size_t)sizeof(size_t) << 29; |
148 | 242 | ||
149 | #ifndef UNDER_CE | 243 | #ifndef UNDER_CE |
150 | MY_MEMORYSTATUSEX stat; | 244 | MY_MEMORYSTATUSEX stat; |
@@ -167,11 +261,23 @@ bool GetRamSize(UInt64 &size) | |||
167 | "GlobalMemoryStatusEx"); | 261 | "GlobalMemoryStatusEx"); |
168 | if (fn && fn(&stat)) | 262 | if (fn && fn(&stat)) |
169 | { | 263 | { |
170 | size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); | 264 | // (MY_MEMORYSTATUSEX::ullTotalVirtual) < 4 GiB in 32-bit mode |
265 | size_t size2 = (size_t)0 - 1; | ||
266 | if (size2 > stat.ullTotalPhys) | ||
267 | size2 = (size_t)stat.ullTotalPhys; | ||
268 | if (size2 > stat.ullTotalVirtual) | ||
269 | size2 = (size_t)stat.ullTotalVirtual; | ||
270 | size = size2; | ||
171 | return true; | 271 | return true; |
172 | } | 272 | } |
173 | #endif | 273 | #endif |
174 | 274 | ||
275 | // On computers with more than 4 GB of memory: | ||
276 | // new docs : GlobalMemoryStatus can report (-1) value to indicate an overflow. | ||
277 | // some old docs : GlobalMemoryStatus can report (modulo 4 GiB) value. | ||
278 | // (for example, if 5 GB total memory, it could report 1 GB). | ||
279 | // We don't want to get (modulo 4 GiB) value. | ||
280 | // So we use GlobalMemoryStatusEx() instead. | ||
175 | { | 281 | { |
176 | MEMORYSTATUS stat2; | 282 | MEMORYSTATUS stat2; |
177 | stat2.dwLength = sizeof(stat2); | 283 | stat2.dwLength = sizeof(stat2); |
@@ -187,9 +293,11 @@ bool GetRamSize(UInt64 &size) | |||
187 | // POSIX | 293 | // POSIX |
188 | // #include <stdio.h> | 294 | // #include <stdio.h> |
189 | 295 | ||
190 | bool GetRamSize(UInt64 &size) | 296 | bool GetRamSize(size_t &size) |
191 | { | 297 | { |
192 | size = (UInt64)(sizeof(size_t)) << 29; | 298 | UInt64 size64; |
299 | size = (size_t)sizeof(size_t) << 29; | ||
300 | size64 = size; | ||
193 | 301 | ||
194 | #if defined(__APPLE__) || defined(__DragonFly__) || \ | 302 | #if defined(__APPLE__) || defined(__DragonFly__) || \ |
195 | defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) | 303 | defined(BSD) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) |
@@ -215,7 +323,7 @@ bool GetRamSize(UInt64 &size) | |||
215 | // we use strict check (size_sys == sizeof(val)) for returned value | 323 | // we use strict check (size_sys == sizeof(val)) for returned value |
216 | // because big-endian encoding is possible: | 324 | // because big-endian encoding is possible: |
217 | if (res == 0 && size_sys == sizeof(val) && val) | 325 | if (res == 0 && size_sys == sizeof(val) && val) |
218 | size = val; | 326 | size64 = val; |
219 | else | 327 | else |
220 | { | 328 | { |
221 | uint32_t val32 = 0; | 329 | uint32_t val32 = 0; |
@@ -223,12 +331,12 @@ bool GetRamSize(UInt64 &size) | |||
223 | res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); | 331 | res = sysctl(mib, 2, &val32, &size_sys, NULL, 0); |
224 | // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); | 332 | // printf("\n sysctl res=%d val=%llx size_sys = %d, %d\n", res, (long long int)val32, (int)size_sys, errno); |
225 | if (res == 0 && size_sys == sizeof(val32) && val32) | 333 | if (res == 0 && size_sys == sizeof(val32) && val32) |
226 | size = val32; | 334 | size64 = val32; |
227 | } | 335 | } |
228 | 336 | ||
229 | #elif defined(_AIX) | 337 | #elif defined(_AIX) |
230 | #if defined(_SC_AIX_REALMEM) // AIX | 338 | #if defined(_SC_AIX_REALMEM) // AIX |
231 | size = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; | 339 | size64 = (UInt64)sysconf(_SC_AIX_REALMEM) * 1024; |
232 | #endif | 340 | #endif |
233 | #elif 0 || defined(__sun) | 341 | #elif 0 || defined(__sun) |
234 | #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) | 342 | #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) |
@@ -240,7 +348,7 @@ bool GetRamSize(UInt64 &size) | |||
240 | // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); | 348 | // printf("\n_SC_PHYS_PAGES (hex) = %lx", (unsigned long)phys_pages); |
241 | // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); | 349 | // printf("\n_SC_PAGESIZE = %lu\n", (unsigned long)page_size); |
242 | if (phys_pages != -1 && page_size != -1) | 350 | if (phys_pages != -1 && page_size != -1) |
243 | size = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; | 351 | size64 = (UInt64)(Int64)phys_pages * (UInt64)(Int64)page_size; |
244 | } | 352 | } |
245 | #endif | 353 | #endif |
246 | #elif defined(__gnu_hurd__) | 354 | #elif defined(__gnu_hurd__) |
@@ -253,7 +361,7 @@ bool GetRamSize(UInt64 &size) | |||
253 | struct sysinfo info; | 361 | struct sysinfo info; |
254 | if (::sysinfo(&info) != 0) | 362 | if (::sysinfo(&info) != 0) |
255 | return false; | 363 | return false; |
256 | size = (UInt64)info.mem_unit * info.totalram; | 364 | size64 = (UInt64)info.mem_unit * info.totalram; |
257 | /* | 365 | /* |
258 | printf("\n mem_unit = %lld", (UInt64)info.mem_unit); | 366 | printf("\n mem_unit = %lld", (UInt64)info.mem_unit); |
259 | printf("\n totalram = %lld", (UInt64)info.totalram); | 367 | printf("\n totalram = %lld", (UInt64)info.totalram); |
@@ -262,10 +370,9 @@ bool GetRamSize(UInt64 &size) | |||
262 | 370 | ||
263 | #endif | 371 | #endif |
264 | 372 | ||
265 | const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1); | 373 | size = (size_t)1 << (sizeof(size_t) * 8 - 1); |
266 | if (size > kLimit) | 374 | if (size > size64) |
267 | size = kLimit; | 375 | size = (size_t)size64; |
268 | |||
269 | return true; | 376 | return true; |
270 | } | 377 | } |
271 | 378 | ||