macCPU.mm 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #import <sys/types.h>
  23. #import <sys/sysctl.h>
  24. #import <mach/machine.h>
  25. #import <math.h>
  26. #import <CoreServices/CoreServices.h>
  27. #import "platform/platformAssert.h"
  28. #import "console/console.h"
  29. #import "core/stringTable.h"
  30. #import "platform/platformCPUCount.h"
  31. // Gestalt has been deprecated
  32. // we now have to use NSProcessInfo
  33. #import <Foundation/Foundation.h>
  34. // Original code by Sean O'Brien (http://www.garagegames.com/community/forums/viewthread/81815).
  35. // Reads sysctl() string value into buffer at DEST with maximum length MAXLEN
  36. // Return: 0 on success, non-zero is error in accordance with stdlib and <errno.h>
  37. int _getSysCTLstring(const char key[], char * dest, size_t maxlen) {
  38. size_t len = 0;
  39. int err;
  40. // Call with NULL for 'dest' to have the required size stored in 'len'. If the 'key'
  41. // doesn't exist, 'err' will be -1 and if all goes well, it will be 0.
  42. err = sysctlbyname(key, NULL, &len, NULL, 0);
  43. if (err == 0) {
  44. AssertWarn((len <= maxlen), ("Insufficient buffer length for SYSCTL() read. Truncating.\n"));
  45. if (len > maxlen)
  46. len = maxlen;
  47. // Call with actual pointers to 'dest' and clamped 'len' fields to perform the read.
  48. err = sysctlbyname(key, dest, &len, NULL, 0);
  49. }
  50. return err;
  51. }
  52. // TEMPLATED Reads sysctl() integer value into variable DEST of type T
  53. // The two predominant types used are unsigned longs and unsiged long longs
  54. // and the size of the argument is on a case-by-case value. As a "guide" the
  55. // resources at Apple claim that any "byte count" or "frequency" values will
  56. // be returned as ULL's and most everything else will be UL's.
  57. // Return: 0 on success, non-zero is error in accordance with stdlib and <errno.h>
  58. template <typename T>
  59. int _getSysCTLvalue(const char key[], T * dest) {
  60. size_t len = 0;
  61. int err;
  62. // Call with NULL for 'dest' to get the size. If the 'key' doesn't exist, the
  63. // 'err' returned will be -1, so 0 indicates success.
  64. err = sysctlbyname(key, NULL, &len, NULL, 0);
  65. if (err == 0) {
  66. AssertFatal((len == sizeof(T)), "Mis-matched destination type for SYSCTL() read.\n");
  67. // We're just double-checking that we're being called with the correct type of
  68. // pointer for 'dest' so we don't clobber anything nearby when writing back.
  69. err = sysctlbyname(key, dest, &len, NULL, 0);
  70. }
  71. return err;
  72. }
  73. Platform::SystemInfo_struct Platform::SystemInfo;
  74. #define BASE_MHZ_SPEED 1000
  75. #define BASE_APPLE_SILICON_MHZ_SPEED 3200
  76. static void detectCpuFeatures(U32 &procflags)
  77. {
  78. // Now we can directly query the system about a litany of "Optional" processor capabilities
  79. // and determine the status by using BOTH the 'err' value and the 'lraw' value. If we request
  80. // a non-existant feature from SYSCTL(), the 'err' result will be -1; 0 denotes it exists
  81. // >>>> BUT <<<<<
  82. // it may not be supported, only defined. Thus we need to check 'lraw' to determine if it's
  83. // actually supported/implemented by the processor: 0 = no, 1 = yes, others are undefined.
  84. int err;
  85. U32 lraw;
  86. // All Cpus have fpu
  87. procflags = CPU_PROP_C | CPU_PROP_FPU;
  88. #if defined(TORQUE_CPU_X86) || defined(TORQUE_CPU_X64)
  89. // List of chip-specific features
  90. err = _getSysCTLvalue<U32>("hw.optional.mmx", &lraw);
  91. if ((err==0)&&(lraw==1))
  92. procflags |= CPU_PROP_MMX;
  93. err = _getSysCTLvalue<U32>("hw.optional.sse", &lraw);
  94. if ((err==0)&&(lraw==1))
  95. procflags |= CPU_PROP_SSE;
  96. err = _getSysCTLvalue<U32>("hw.optional.sse2", &lraw);
  97. if ((err==0)&&(lraw==1))
  98. procflags |= CPU_PROP_SSE2;
  99. err = _getSysCTLvalue<U32>("hw.optional.sse3", &lraw);
  100. if ((err==0)&&(lraw==1))
  101. procflags |= CPU_PROP_SSE3;
  102. err = _getSysCTLvalue<U32>("hw.optional.supplementalsse3", &lraw);
  103. if ((err==0)&&(lraw==1))
  104. procflags |= CPU_PROP_SSE3ex;
  105. err = _getSysCTLvalue<U32>("hw.optional.sse4_1", &lraw);
  106. if ((err==0)&&(lraw==1))
  107. procflags |= CPU_PROP_SSE4_1;
  108. err = _getSysCTLvalue<U32>("hw.optional.sse4_2", &lraw);
  109. if ((err==0)&&(lraw==1))
  110. procflags |= CPU_PROP_SSE4_2;
  111. err = _getSysCTLvalue<U32>("hw.optional.avx1_0", &lraw);
  112. if ((err==0)&&(lraw==1))
  113. procflags |= CPU_PROP_AVX;
  114. #elif defined(TORQUE_CPU_ARM64)
  115. err = _getSysCTLvalue<U32>("hw.optional.neon", &lraw);
  116. if ((err==0)&&(lraw==1))
  117. procflags |= CPU_PROP_NEON;
  118. #endif
  119. err = _getSysCTLvalue<U32>("hw.ncpu", &lraw);
  120. if ((err==0)&&(lraw>1))
  121. procflags |= CPU_PROP_MP;
  122. err = _getSysCTLvalue<U32>("hw.cpu64bit_capable", &lraw);
  123. if ((err==0)&&(lraw==1))
  124. procflags |= CPU_PROP_64bit;
  125. err = _getSysCTLvalue<U32>("hw.byteorder", &lraw);
  126. if ((err==0)&&(lraw==1234))
  127. procflags |= CPU_PROP_LE;
  128. }
  129. void Processor::init()
  130. {
  131. U32 procflags = 0;
  132. int err, cpufam, cputype, cpusub;
  133. char buf[255];
  134. U32 lraw;
  135. U64 llraw;
  136. // Availability: Mac OS 10.2 or greater.
  137. NSString *osVersionStr = [[NSProcessInfo processInfo] operatingSystemVersionString];
  138. S32 ramMB;
  139. err = _getSysCTLvalue<U64>("hw.memsize", &llraw);
  140. if (err)
  141. ramMB = 512;
  142. else
  143. ramMB = llraw >> 20;
  144. char brandString[256];
  145. err = _getSysCTLstring("machdep.cpu.brand_string", brandString, sizeof(brandString));
  146. if (err)
  147. brandString[0] = '\0';
  148. char vendor[256];
  149. err = _getSysCTLstring("machdep.cpu.vendor", vendor, sizeof(vendor));
  150. if (err)
  151. vendor[0] = '\0';
  152. // Note: hw.cpufrequency seems to be missing on the M1. For Apple Silicon,
  153. // we will assume the base frequency of the M1 which is 3.2ghz
  154. err = _getSysCTLvalue<U64>("hw.cpufrequency", &llraw);
  155. if (err) {
  156. #if defined(TORQUE_CPU_ARM64)
  157. llraw = BASE_APPLE_SILICON_MHZ_SPEED;
  158. #else
  159. llraw = BASE_MHZ_SPEED;
  160. #endif
  161. } else {
  162. llraw /= 1000000;
  163. }
  164. Platform::SystemInfo.processor.mhz = (unsigned int)llraw;
  165. detectCpuFeatures(procflags);
  166. Platform::SystemInfo.processor.properties = procflags;
  167. SetProcessorInfo(Platform::SystemInfo.processor, vendor, brandString);
  168. Con::printf("System & Processor Information:");
  169. Con::printf(" MacOS Version: %s", [osVersionStr UTF8String]);
  170. Con::printf(" Physical memory installed: %d MB", ramMB);
  171. Con::printf(" Processor: %s", Platform::SystemInfo.processor.name);
  172. if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
  173. Con::printf(" MMX detected");
  174. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE)
  175. Con::printf(" SSE detected");
  176. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE2)
  177. Con::printf(" SSE2 detected");
  178. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE3)
  179. Con::printf(" SSE3 detected");
  180. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE3ex)
  181. Con::printf(" SSE3ex detected");
  182. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_1)
  183. Con::printf(" SSE4.1 detected");
  184. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_2)
  185. Con::printf(" SSE4.2 detected");
  186. if (Platform::SystemInfo.processor.properties & CPU_PROP_AVX)
  187. Con::printf(" AVX detected");
  188. if (Platform::SystemInfo.processor.properties & CPU_PROP_NEON)
  189. Con::printf(" Neon detected");
  190. if (Platform::SystemInfo.processor.properties & CPU_PROP_MP)
  191. Con::printf(" MultiCore CPU detected [%i cores, %i logical]", Platform::SystemInfo.processor.numPhysicalProcessors, Platform::SystemInfo.processor.numLogicalProcessors);
  192. Con::printf( "" );
  193. // Trigger the signal
  194. Platform::SystemInfoReady.trigger();
  195. }
  196. namespace CPUInfo {
  197. EConfig CPUCount(U32 &logical, U32 &physical) {
  198. U32 lraw;
  199. int err;
  200. err = _getSysCTLvalue<U32>("hw.physicalcpu", &lraw);
  201. if (err == 0)
  202. physical = lraw;
  203. else
  204. physical = 1;
  205. err = _getSysCTLvalue<U32>("hw.logicalcpu", &lraw);
  206. if (err == 0)
  207. {
  208. logical = lraw;
  209. }
  210. else
  211. {
  212. // fallback to querying the number of cpus. If that fails, then assume same as number of cores
  213. err = _getSysCTLvalue<U32>("hw.ncpu", &lraw);
  214. if (err == 0)
  215. logical = lraw;
  216. else
  217. logical = physical;
  218. }
  219. const bool smtEnabled = logical > physical;
  220. if (physical == 1)
  221. return smtEnabled ? CONFIG_SingleCoreHTEnabled : CONFIG_SingleCoreAndHTNotCapable;
  222. return smtEnabled ? CONFIG_MultiCoreAndHTEnabled : CONFIG_MultiCoreAndHTNotCapable;
  223. }
  224. }