macCPU.mm
Engine/source/platformMac/macCPU.mm
Namespaces:
namespace
Public Defines
define
BASE_MHZ_SPEED() 0
define
CPUFAMILY_INTEL_MEROM() 0x426f69ef
define
CPUFAMILY_INTEL_YONAH() 0x73d67300
Public Functions
int
_getSysCTLstring(const char key, char * dest, size_t maxlen)
int
_getSysCTLvalue(const char key, T * dest)
Detailed Description
Public Defines
BASE_MHZ_SPEED() 0
CPUFAMILY_INTEL_MEROM() 0x426f69ef
CPUFAMILY_INTEL_YONAH() 0x73d67300
Public Functions
_getSysCTLstring(const char key, char * dest, size_t maxlen)
_getSysCTLvalue(const char key, T * dest)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#import <sys/types.h> 25#import <sys/sysctl.h> 26#import <mach/machine.h> 27#import <math.h> 28#import <CoreServices/CoreServices.h> 29 30#import "platform/platformAssert.h" 31#import "console/console.h" 32#import "core/stringTable.h" 33#import "platform/platformCPUCount.h" 34 35// Gestalt has been deprecated 36// we now have to use NSProcessInfo 37#import <Foundation/Foundation.h> 38 39//recently removed in Xcode 8 - most likely don't need these anymore 40#ifndef CPUFAMILY_INTEL_YONAH 41#define CPUFAMILY_INTEL_YONAH 0x73d67300 42#endif 43 44#ifndef CPUFAMILY_INTEL_MEROM 45#define CPUFAMILY_INTEL_MEROM 0x426f69ef 46#endif 47 48// Original code by Sean O'Brien (http://www.garagegames.com/community/forums/viewthread/81815). 49 50 51// Reads sysctl() string value into buffer at DEST with maximum length MAXLEN 52// Return: 0 on success, non-zero is error in accordance with stdlib and <errno.h> 53int _getSysCTLstring(const char key[], char * dest, size_t maxlen) { 54 size_t len = 0; 55 int err; 56 // Call with NULL for 'dest' to have the required size stored in 'len'. If the 'key' 57 // doesn't exist, 'err' will be -1 and if all goes well, it will be 0. 58 err = sysctlbyname(key, NULL, &len, NULL, 0); 59 if (err == 0) { 60 AssertWarn((len <= maxlen), ("Insufficient buffer length for SYSCTL() read. Truncating.\n")); 61 if (len > maxlen) 62 len = maxlen; 63 // Call with actual pointers to 'dest' and clamped 'len' fields to perform the read. 64 err = sysctlbyname(key, dest, &len, NULL, 0); 65 } 66 return err; 67} 68 69// TEMPLATED Reads sysctl() integer value into variable DEST of type T 70// The two predominant types used are unsigned longs and unsiged long longs 71// and the size of the argument is on a case-by-case value. As a "guide" the 72// resources at Apple claim that any "byte count" or "frequency" values will 73// be returned as ULL's and most everything else will be UL's. 74// Return: 0 on success, non-zero is error in accordance with stdlib and <errno.h> 75template <typename T> 76int _getSysCTLvalue(const char key[], T * dest) { 77 size_t len = 0; 78 int err; 79 // Call with NULL for 'dest' to get the size. If the 'key' doesn't exist, the 80 // 'err' returned will be -1, so 0 indicates success. 81 err = sysctlbyname(key, NULL, &len, NULL, 0); 82 if (err == 0) { 83 AssertFatal((len == sizeof(T)), "Mis-matched destination type for SYSCTL() read.\n"); 84 // We're just double-checking that we're being called with the correct type of 85 // pointer for 'dest' so we don't clobber anything nearby when writing back. 86 err = sysctlbyname(key, dest, &len, NULL, 0); 87 } 88 return err; 89} 90 91Platform::SystemInfo_struct Platform::SystemInfo; 92 93#define BASE_MHZ_SPEED 0 94//TODO update cpu list 95void Processor::init() 96{ 97 U32 procflags; 98 int err, cpufam, cputype, cpusub; 99 char buf[255]; 100 U32 lraw; 101 U64 llraw; 102 103 Con::printf( "System & Processor Information:" ); 104 105 // Gestalt has been deprecated since Mac OSX Mountain Lion and has stopped working on 106 // Mac OSX Yosemite. we have to use NSProcessInfo now. 107 // Availability: Mac OS 10.2 or greater. 108 NSString *osVersionStr = [[NSProcessInfo processInfo] operatingSystemVersionString]; 109 Con::printf( " OSX Version: %s", [osVersionStr UTF8String]); 110 111 err = _getSysCTLstring("kern.ostype", buf, sizeof(buf)); 112 if (err) 113 Con::printf( " Unable to determine OS type\n" ); 114 else 115 Con::printf( " Mac OS Kernel name: %s", buf); 116 117 err = _getSysCTLstring("kern.osrelease", buf, sizeof(buf)); 118 if (err) 119 Con::printf( " Unable to determine OS release number\n" ); 120 else 121 Con::printf( " Mac OS Kernel version: %s", buf ); 122 123 err = _getSysCTLvalue<U64>("hw.memsize", &llraw); 124 if (err) 125 Con::printf( " Unable to determine amount of physical RAM\n" ); 126 else 127 Con::printf( " Physical memory installed: %d MB", (llraw >> 20)); 128 129 err = _getSysCTLvalue<U32>("hw.usermem", &lraw); 130 if (err) 131 Con::printf( " Unable to determine available user address space\n"); 132 else 133 Con::printf( " Addressable user memory: %d MB", (lraw >> 20)); 134 135 //////////////////////////////// 136 // Values for the Family Type, CPU Type and CPU Subtype are defined in the 137 // SDK files for the Mach Kernel ==> mach/machine.h 138 //////////////////////////////// 139 140 // CPU Family, Type, and Subtype 141 cpufam = 0; 142 cputype = 0; 143 cpusub = 0; 144 err = _getSysCTLvalue<U32>("hw.cpufamily", &lraw); 145 if (err) 146 Con::printf( " Unable to determine 'family' of CPU\n"); 147 else { 148 cpufam = (int) lraw; 149 err = _getSysCTLvalue<U32>("hw.cputype", &lraw); 150 if (err) 151 Con::printf( " Unable to determine CPU type\n"); 152 else { 153 cputype = (int) lraw; 154 err = _getSysCTLvalue<U32>("hw.cpusubtype", &lraw); 155 if (err) 156 Con::printf( " Unable to determine CPU subtype\n"); 157 else 158 cpusub = (int) lraw; 159 // If we've made it this far, 160 Con::printf( " Installed processor ID: Family 0x%08x Type %d Subtype %d",cpufam, cputype,cpusub); 161 } 162 } 163 164 // The Gestalt version was known to have issues with some Processor Upgrade cards 165 // but it is uncertain whether this version has similar issues. 166 err = _getSysCTLvalue<U64>("hw.cpufrequency", &llraw); 167 if (err) { 168 llraw = BASE_MHZ_SPEED; 169 Con::printf( " Unable to determine CPU Frequency. Defaulting to %d MHz\n", llraw); 170 } else { 171 llraw /= 1000000; 172 Con::printf( " Installed processor clock frequency: %d MHz", llraw); 173 } 174 Platform::SystemInfo.processor.mhz = (unsigned int)llraw; 175 176 // Here's one that the original version of this routine couldn't do -- number 177 // of processors (cores) 178 U32 ncpu = 1; 179 err = _getSysCTLvalue<U32>("hw.ncpu", &lraw); 180 if (err) 181 Con::printf( " Unable to determine number of processor cores\n"); 182 else 183 { 184 ncpu = lraw; 185 Con::printf( " Installed/available processor cores: %d", lraw); 186 } 187 188 // Now use CPUFAM to determine and then store the processor type 189 // and 'friendly name' in GG-accessible structure. Note that since 190 // we have access to the Family code, the Type and Subtypes are useless. 191 // 192 // NOTE: Even this level of detail is almost assuredly not needed anymore 193 // and the Optional Capability flags (further down) should be more than enough. 194 switch(cpufam) 195 { 196 case CPUFAMILY_INTEL_YONAH: 197 Platform::SystemInfo.processor.type = CPU_Intel_Core; 198 if( ncpu == 2 ) 199 Platform::SystemInfo.processor.name = StringTable->insert("Intel Core Duo"); 200 else 201 Platform::SystemInfo.processor.name = StringTable->insert("Intel Core"); 202 break; 203 case CPUFAMILY_INTEL_PENRYN: 204 case CPUFAMILY_INTEL_MEROM: 205 Platform::SystemInfo.processor.type = CPU_Intel_Core2; 206 if( ncpu == 4 ) 207 Platform::SystemInfo.processor.name = StringTable->insert("Intel Core 2 Quad"); 208 else 209 Platform::SystemInfo.processor.name = StringTable->insert("Intel Core 2 Duo"); 210 break; 211 212 case CPUFAMILY_INTEL_NEHALEM: 213 Platform::SystemInfo.processor.type = CPU_Intel_Core2; 214 Platform::SystemInfo.processor.name = StringTable->insert( "Intel 'Nehalem' Core Processor" ); 215 break; 216 217 default: 218 // explain why we can't get the processor type. 219 Con::warnf( " Unknown Processor (family, type, subtype): 0x%x\t%d %d", cpufam, cputype, cpusub); 220 // for now, identify it as an x86 processor, because Apple is moving to Intel chips... 221 Platform::SystemInfo.processor.type = CPU_X86Compatible; 222 Platform::SystemInfo.processor.name = StringTable->insert("Unknown Processor, assuming x86 Compatible"); 223 break; 224 } 225 // Now we can directly query the system about a litany of "Optional" processor capabilities 226 // and determine the status by using BOTH the 'err' value and the 'lraw' value. If we request 227 // a non-existant feature from SYSCTL(), the 'err' result will be -1; 0 denotes it exists 228 // >>>> BUT <<<<< 229 // it may not be supported, only defined. Thus we need to check 'lraw' to determine if it's 230 // actually supported/implemented by the processor: 0 = no, 1 = yes, others are undefined. 231 procflags = 0; 232 // Seriously this one should be an Assert() 233 err = _getSysCTLvalue<U32>("hw.optional.floatingpoint", &lraw); 234 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_FPU; 235 // List of chip-specific features 236 err = _getSysCTLvalue<U32>("hw.optional.mmx", &lraw); 237 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_MMX; 238 err = _getSysCTLvalue<U32>("hw.optional.sse", &lraw); 239 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE; 240 err = _getSysCTLvalue<U32>("hw.optional.sse2", &lraw); 241 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE2; 242 err = _getSysCTLvalue<U32>("hw.optional.sse3", &lraw); 243 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE3; 244 err = _getSysCTLvalue<U32>("hw.optional.supplementalsse3", &lraw); 245 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE3xt; 246 err = _getSysCTLvalue<U32>("hw.optional.sse4_1", &lraw); 247 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE4_1; 248 err = _getSysCTLvalue<U32>("hw.optional.sse4_2", &lraw); 249 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_SSE4_2; 250 251 // Finally some architecture-wide settings 252 err = _getSysCTLvalue<U32>("hw.ncpu", &lraw); 253 if ((err==0)&&(lraw>1)) procflags |= CPU_PROP_MP; 254 err = _getSysCTLvalue<U32>("hw.cpu64bit_capable", &lraw); 255 if ((err==0)&&(lraw==1)) procflags |= CPU_PROP_64bit; 256 err = _getSysCTLvalue<U32>("hw.byteorder", &lraw); 257 if ((err==0)&&(lraw==1234)) procflags |= CPU_PROP_LE; 258 259 Platform::SystemInfo.processor.properties = procflags; 260 261 Con::printf( "%s, %2.2f GHz", Platform::SystemInfo.processor.name, F32( Platform::SystemInfo.processor.mhz ) / 1000.0 ); 262 if (Platform::SystemInfo.processor.properties & CPU_PROP_MMX) 263 Con::printf( " MMX detected"); 264 if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE) 265 Con::printf( " SSE detected"); 266 if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE2) 267 Con::printf( " SSE2 detected"); 268 if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE3) 269 Con::printf( " SSE3 detected"); 270 if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_1) 271 Con::printf( " SSE4.1 detected"); 272 if (Platform::SystemInfo.processor.properties & CPU_PROP_SSE4_2) 273 Con::printf( " SSE4.2 detected"); 274 275 Con::printf( "" ); 276 277 // Trigger the signal 278 Platform::SystemInfoReady.trigger(); 279} 280 281namespace CPUInfo { 282 EConfig CPUCount(U32 &logical, U32 &numCores, U32 &numPhysical) { 283 // todo properly implement this 284 logical = [[NSProcessInfo processInfo] activeProcessorCount]; 285 numCores = [[NSProcessInfo processInfo] activeProcessorCount]; 286 numPhysical = [[NSProcessInfo processInfo] processorCount]; 287 288 // todo check for hyperthreading 289 if (numCores > 1) 290 return CONFIG_MultiCoreAndHTNotCapable; 291 return CONFIG_SingleCoreAndHTNotCapable; 292 } 293} 294