macCPU.mm

Engine/source/platformMac/macCPU.mm

More...

Namespaces:

namespace

Public Defines

define
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