macCarbCPUInfo.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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. #include <sys/types.h>
  23. #include <sys/sysctl.h>
  24. #include <mach/machine.h>
  25. #include <math.h>
  26. #include <CoreServices/CoreServices.h>
  27. #include "platformMac/platformMacCarb.h"
  28. #include "platform/platformAssert.h"
  29. #include "console/console.h"
  30. #include "core/stringTable.h"
  31. // Original code by Sean O'Brien (http://www.garagegames.com/community/forums/viewthread/81815).
  32. // Reads sysctl() string value into buffer at DEST with maximum length MAXLEN
  33. // Return: 0 on success, non-zero is error in accordance with stdlib and <errno.h>
  34. int _getSysCTLstring(const char key[], char * dest, size_t maxlen) {
  35. size_t len = 0;
  36. int err;
  37. // Call with NULL for 'dest' to have the required size stored in 'len'. If the 'key'
  38. // doesn't exist, 'err' will be -1 and if all goes well, it will be 0.
  39. err = sysctlbyname(key, NULL, &len, NULL, 0);
  40. if (err == 0) {
  41. AssertWarn((len <= maxlen), ("Insufficient buffer length for SYSCTL() read. Truncating.\n"));
  42. if (len > maxlen)
  43. len = maxlen;
  44. // Call with actual pointers to 'dest' and clamped 'len' fields to perform the read.
  45. err = sysctlbyname(key, dest, &len, NULL, 0);
  46. }
  47. return err;
  48. }
  49. // TEMPLATED Reads sysctl() integer value into variable DEST of type T
  50. // The two predominant types used are unsigned longs and unsiged long longs
  51. // and the size of the argument is on a case-by-case value. As a "guide" the
  52. // resources at Apple claim that any "byte count" or "frequency" values will
  53. // be returned as ULL's and most everything else will be UL's.
  54. // Return: 0 on success, non-zero is error in accordance with stdlib and <errno.h>
  55. template <typename T>
  56. int _getSysCTLvalue(const char key[], T * dest) {
  57. size_t len = 0;
  58. int err;
  59. // Call with NULL for 'dest' to get the size. If the 'key' doesn't exist, the
  60. // 'err' returned will be -1, so 0 indicates success.
  61. err = sysctlbyname(key, NULL, &len, NULL, 0);
  62. if (err == 0) {
  63. AssertFatal((len == sizeof(T)), "Mis-matched destination type for SYSCTL() read.\n");
  64. // We're just double-checking that we're being called with the correct type of
  65. // pointer for 'dest' so we don't clobber anything nearby when writing back.
  66. err = sysctlbyname(key, dest, &len, NULL, 0);
  67. }
  68. return err;
  69. }
  70. Platform::SystemInfo_struct Platform::SystemInfo;
  71. #define BASE_MHZ_SPEED 0
  72. void Processor::init()
  73. {
  74. U32 procflags;
  75. int err, cpufam, cputype, cpusub;
  76. char buf[20];
  77. unsigned long lraw;
  78. unsigned long long llraw;
  79. Con::printf( "System & Processor Information:" );
  80. SInt32 MacVersion;
  81. if( Gestalt( gestaltSystemVersion, &MacVersion ) == noErr )
  82. {
  83. U32 revision = MacVersion & 0xf;
  84. U32 minorVersion = ( MacVersion & 0xf0 ) >> 4;
  85. U32 majorVersion = ( MacVersion & 0xff00 ) >> 8;
  86. Con::printf( " OSX Version: %x.%x.%x", majorVersion, minorVersion, revision );
  87. }
  88. err = _getSysCTLstring("kern.ostype", buf, sizeof(buf));
  89. if (err)
  90. Con::printf( " Unable to determine OS type\n" );
  91. else
  92. Con::printf( " Mac OS Kernel name: %s", buf);
  93. err = _getSysCTLstring("kern.osrelease", buf, sizeof(buf));
  94. if (err)
  95. Con::printf( " Unable to determine OS release number\n" );
  96. else
  97. Con::printf( " Mac OS Kernel version: %s", buf );
  98. err = _getSysCTLvalue<unsigned long long>("hw.memsize", &llraw);
  99. if (err)
  100. Con::printf( " Unable to determine amount of physical RAM\n" );
  101. else
  102. Con::printf( " Physical memory installed: %d MB", (llraw >> 20));
  103. err = _getSysCTLvalue<unsigned long>("hw.usermem", &lraw);
  104. if (err)
  105. Con::printf( " Unable to determine available user address space\n");
  106. else
  107. Con::printf( " Addressable user memory: %d MB", (lraw >> 20));
  108. ////////////////////////////////
  109. // Values for the Family Type, CPU Type and CPU Subtype are defined in the
  110. // SDK files for the Mach Kernel ==> mach/machine.h
  111. ////////////////////////////////
  112. // CPU Family, Type, and Subtype
  113. cpufam = 0;
  114. cputype = 0;
  115. cpusub = 0;
  116. err = _getSysCTLvalue<unsigned long>("hw.cpufamily", &lraw);
  117. if (err)
  118. Con::printf( " Unable to determine 'family' of CPU\n");
  119. else {
  120. cpufam = (int) lraw;
  121. err = _getSysCTLvalue<unsigned long>("hw.cputype", &lraw);
  122. if (err)
  123. Con::printf( " Unable to determine CPU type\n");
  124. else {
  125. cputype = (int) lraw;
  126. err = _getSysCTLvalue<unsigned long>("hw.cpusubtype", &lraw);
  127. if (err)
  128. Con::printf( " Unable to determine CPU subtype\n");
  129. else
  130. cpusub = (int) lraw;
  131. // If we've made it this far,
  132. Con::printf( " Installed processor ID: Family 0x%08x Type %d Subtype %d",cpufam, cputype,cpusub);
  133. }
  134. }
  135. // The Gestalt version was known to have issues with some Processor Upgrade cards
  136. // but it is uncertain whether this version has similar issues.
  137. err = _getSysCTLvalue<unsigned long long>("hw.cpufrequency", &llraw);
  138. if (err) {
  139. llraw = BASE_MHZ_SPEED;
  140. Con::printf( " Unable to determine CPU Frequency. Defaulting to %d MHz\n", llraw);
  141. } else {
  142. llraw /= 1000000;
  143. Con::printf( " Installed processor clock frequency: %d MHz", llraw);
  144. }
  145. Platform::SystemInfo.processor.mhz = (unsigned int)llraw;
  146. // Here's one that the original version of this routine couldn't do -- number
  147. // of processors (cores)
  148. U32 ncpu = 1;
  149. err = _getSysCTLvalue<unsigned long>("hw.ncpu", &lraw);
  150. if (err)
  151. Con::printf( " Unable to determine number of processor cores\n");
  152. else
  153. {
  154. ncpu = lraw;
  155. Con::printf( " Installed/available processor cores: %d", lraw);
  156. }
  157. // Now use CPUFAM to determine and then store the processor type
  158. // and 'friendly name' in GG-accessible structure. Note that since
  159. // we have access to the Family code, the Type and Subtypes are useless.
  160. //
  161. // NOTE: Even this level of detail is almost assuredly not needed anymore
  162. // and the Optional Capability flags (further down) should be more than enough.
  163. switch(cpufam)
  164. {
  165. case CPUFAMILY_POWERPC_G3:
  166. Platform::SystemInfo.processor.type = CPU_PowerPC_G3;
  167. Platform::SystemInfo.processor.name = StringTable->insert("PowerPC G3");
  168. break;
  169. case CPUFAMILY_POWERPC_G4:
  170. Platform::SystemInfo.processor.type = CPU_PowerPC_G3;
  171. Platform::SystemInfo.processor.name = StringTable->insert("PowerPC G4");
  172. break;
  173. case CPUFAMILY_POWERPC_G5:
  174. Platform::SystemInfo.processor.type = CPU_PowerPC_G3;
  175. Platform::SystemInfo.processor.name = StringTable->insert("PowerPC G5");
  176. break;
  177. case CPUFAMILY_INTEL_6_14:
  178. Platform::SystemInfo.processor.type = CPU_Intel_Core;
  179. if( ncpu == 2 )
  180. Platform::SystemInfo.processor.name = StringTable->insert("Intel Core Duo");
  181. else
  182. Platform::SystemInfo.processor.name = StringTable->insert("Intel Core");
  183. break;
  184. #ifdef CPUFAMILY_INTEL_6_23
  185. case CPUFAMILY_INTEL_6_23:
  186. #endif
  187. case CPUFAMILY_INTEL_6_15:
  188. Platform::SystemInfo.processor.type = CPU_Intel_Core2;
  189. if( ncpu == 4 )
  190. Platform::SystemInfo.processor.name = StringTable->insert("Intel Core 2 Quad");
  191. else
  192. Platform::SystemInfo.processor.name = StringTable->insert("Intel Core 2 Duo");
  193. break;
  194. #ifdef CPUFAMILY_INTEL_6_26
  195. case CPUFAMILY_INTEL_6_26:
  196. Platform::SystemInfo.processor.type = CPU_Intel_Core2;
  197. Platform::SystemInfo.processor.name = StringTable->insert( "Intel 'Nehalem' Core Processor" );
  198. break;
  199. #endif
  200. default:
  201. // explain why we can't get the processor type.
  202. Con::warnf( " Unknown Processor (family, type, subtype): 0x%x\t%d %d", cpufam, cputype, cpusub);
  203. // for now, identify it as an x86 processor, because Apple is moving to Intel chips...
  204. Platform::SystemInfo.processor.type = CPU_X86Compatible;
  205. Platform::SystemInfo.processor.name = StringTable->insert("Unknown Processor, assuming x86 Compatible");
  206. break;
  207. }
  208. // Now we can directly query the system about a litany of "Optional" processor capabilities
  209. // and determine the status by using BOTH the 'err' value and the 'lraw' value. If we request
  210. // a non-existant feature from SYSCTL(), the 'err' result will be -1; 0 denotes it exists
  211. // >>>> BUT <<<<<
  212. // it may not be supported, only defined. Thus we need to check 'lraw' to determine if it's
  213. // actually supported/implemented by the processor: 0 = no, 1 = yes, others are undefined.
  214. procflags = 0;
  215. // Seriously this one should be an Assert()
  216. err = _getSysCTLvalue<unsigned long>("hw.optional.floatingpoint", &lraw);
  217. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_FPU;
  218. // List of chip-specific features
  219. err = _getSysCTLvalue<unsigned long>("hw.optional.mmx", &lraw);
  220. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_MMX;
  221. err = _getSysCTLvalue<unsigned long>("hw.optional.sse", &lraw);
  222. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE;
  223. err = _getSysCTLvalue<unsigned long>("hw.optional.sse2", &lraw);
  224. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE2;
  225. err = _getSysCTLvalue<unsigned long>("hw.optional.sse3", &lraw);
  226. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE3;
  227. err = _getSysCTLvalue<unsigned long>("hw.optional.supplementalsse3", &lraw);
  228. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE3xt;
  229. err = _getSysCTLvalue<unsigned long>("hw.optional.sse4_1", &lraw);
  230. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE4_1;
  231. err = _getSysCTLvalue<unsigned long>("hw.optional.sse4_2", &lraw);
  232. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE4_2;
  233. err = _getSysCTLvalue<unsigned long>("hw.optional.altivec", &lraw);
  234. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_ALTIVEC;
  235. // Finally some architecture-wide settings
  236. err = _getSysCTLvalue<unsigned long>("hw.ncpu", &lraw);
  237. if ((err==0)&&(lraw>1)) procflags |= CPU_PROP_MP;
  238. err = _getSysCTLvalue<unsigned long>("hw.cpu64bit_capable", &lraw);
  239. if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_64bit;
  240. err = _getSysCTLvalue<unsigned long>("hw.byteorder", &lraw);
  241. if ((err==0)&&(lraw==1234)) procflags |= CPU_PROP_LE;
  242. Platform::SystemInfo.processor.properties = procflags;
  243. Con::printf( "%s, %2.2f GHz", Platform::SystemInfo.processor.name, F32( Platform::SystemInfo.processor.mhz ) / 1000.0 );
  244. if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX)
  245. Con::printf( " MMX detected");
  246. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE)
  247. Con::printf( " SSE detected");
  248. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE2)
  249. Con::printf( " SSE2 detected");
  250. if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE3)
  251. Con::printf( " SSE3 detected");
  252. if (Platform::SystemInfo.processor.properties & CPU_PROP_ALTIVEC)
  253. Con::printf( " AltiVec detected");
  254. Con::printf( "" );
  255. // Trigger the signal
  256. Platform::SystemInfoReady.trigger();
  257. }