Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

697 lines
20 KiB

  1. //===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "pch_tier0.h"
  8. #if defined(_WIN32) && !defined(_X360)
  9. #define WINDOWS_LEAN_AND_MEAN
  10. #include <windows.h>
  11. #include "cputopology.h"
  12. #elif defined( PLATFORM_OSX )
  13. #include <sys/sysctl.h>
  14. #endif
  15. #ifndef _PS3
  16. #include "tier0_strtools.h"
  17. #endif
  18. //#include "tier1/strtools.h" // this is included for the definition of V_isspace()
  19. #ifdef PLATFORM_WINDOWS_PC
  20. #include <intrin.h>
  21. #endif
  22. // NOTE: This has to be the last file included!
  23. #include "tier0/memdbgon.h"
  24. const tchar* GetProcessorVendorId();
  25. static bool cpuid(uint32 function, uint32& out_eax, uint32& out_ebx, uint32& out_ecx, uint32& out_edx)
  26. {
  27. #if defined( _X360 ) || defined( _PS3 )
  28. return false;
  29. #elif defined(GNUC)
  30. asm("mov %%ebx, %%esi\n\t"
  31. "cpuid\n\t"
  32. "xchg %%esi, %%ebx"
  33. : "=a" (out_eax),
  34. "=S" (out_ebx),
  35. "=c" (out_ecx),
  36. "=d" (out_edx)
  37. : "a" (function)
  38. );
  39. return true;
  40. #elif defined(_WIN64)
  41. int pCPUInfo[4];
  42. __cpuid( pCPUInfo, (int)function );
  43. out_eax = pCPUInfo[0];
  44. out_ebx = pCPUInfo[1];
  45. out_ecx = pCPUInfo[2];
  46. out_edx = pCPUInfo[3];
  47. return false;
  48. #else
  49. bool retval = true;
  50. uint32 local_eax, local_ebx, local_ecx, local_edx;
  51. _asm pushad;
  52. __try
  53. {
  54. _asm
  55. {
  56. xor edx, edx // Clue the compiler that EDX & others is about to be used.
  57. xor ecx, ecx
  58. xor ebx, ebx // <Sergiy> Note: if I don't zero these out, cpuid sometimes won't work, I didn't find out why yet
  59. mov eax, function // set up CPUID to return processor version and features
  60. // 0 = vendor string, 1 = version info, 2 = cache info
  61. cpuid // code bytes = 0fh, 0a2h
  62. mov local_eax, eax // features returned in eax
  63. mov local_ebx, ebx // features returned in ebx
  64. mov local_ecx, ecx // features returned in ecx
  65. mov local_edx, edx // features returned in edx
  66. }
  67. }
  68. __except(EXCEPTION_EXECUTE_HANDLER)
  69. {
  70. retval = false;
  71. }
  72. out_eax = local_eax;
  73. out_ebx = local_ebx;
  74. out_ecx = local_ecx;
  75. out_edx = local_edx;
  76. _asm popad
  77. return retval;
  78. #endif
  79. }
  80. static bool CheckMMXTechnology(void)
  81. {
  82. #if defined( _X360 ) || defined( _PS3 )
  83. return true;
  84. #else
  85. uint32 eax,ebx,edx,unused;
  86. if ( !cpuid(1,eax,ebx,unused,edx) )
  87. return false;
  88. return ( edx & 0x800000 ) != 0;
  89. #endif
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: This is a bit of a hack because it appears
  93. // Output : Returns true on success, false on failure.
  94. //-----------------------------------------------------------------------------
  95. static bool IsWin98OrOlder()
  96. {
  97. #if defined( _X360 ) || defined( _PS3 ) || defined( POSIX )
  98. return false;
  99. #else
  100. bool retval = false;
  101. OSVERSIONINFOEX osvi;
  102. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  103. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  104. BOOL bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi);
  105. if( !bOsVersionInfoEx )
  106. {
  107. // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO.
  108. osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  109. if ( !GetVersionEx ( (OSVERSIONINFO *) &osvi) )
  110. {
  111. Error( _T("IsWin98OrOlder: Unable to get OS version information") );
  112. }
  113. }
  114. switch (osvi.dwPlatformId)
  115. {
  116. case VER_PLATFORM_WIN32_NT:
  117. // NT, XP, Win2K, etc. all OK for SSE
  118. break;
  119. case VER_PLATFORM_WIN32_WINDOWS:
  120. // Win95, 98, Me can't do SSE
  121. retval = true;
  122. break;
  123. case VER_PLATFORM_WIN32s:
  124. // Can't really run this way I don't think...
  125. retval = true;
  126. break;
  127. default:
  128. break;
  129. }
  130. return retval;
  131. #endif
  132. }
  133. static bool CheckSSETechnology(void)
  134. {
  135. #if defined( _X360 ) || defined( _PS3 )
  136. return true;
  137. #else
  138. if ( IsWin98OrOlder() )
  139. {
  140. return false;
  141. }
  142. uint32 eax,ebx,edx,unused;
  143. if ( !cpuid(1,eax,ebx,unused,edx) )
  144. {
  145. return false;
  146. }
  147. return ( edx & 0x2000000L ) != 0;
  148. #endif
  149. }
  150. static bool CheckSSE2Technology(void)
  151. {
  152. #if defined( _X360 ) || defined( _PS3 )
  153. return false;
  154. #else
  155. uint32 eax,ebx,edx,unused;
  156. if ( !cpuid(1,eax,ebx,unused,edx) )
  157. return false;
  158. return ( edx & 0x04000000 ) != 0;
  159. #endif
  160. }
  161. bool CheckSSE3Technology(void)
  162. {
  163. #if defined( _X360 ) || defined( _PS3 )
  164. return false;
  165. #else
  166. uint32 eax,ebx,edx,ecx;
  167. if( !cpuid(1,eax,ebx,ecx,edx) )
  168. return false;
  169. return ( ecx & 0x00000001 ) != 0; // bit 1 of ECX
  170. #endif
  171. }
  172. bool CheckSSSE3Technology(void)
  173. {
  174. #if defined( _X360 ) || defined( _PS3 )
  175. return false;
  176. #else
  177. // SSSE 3 is implemented by both Intel and AMD
  178. // detection is done the same way for both vendors
  179. uint32 eax,ebx,edx,ecx;
  180. if( !cpuid(1,eax,ebx,ecx,edx) )
  181. return false;
  182. return ( ecx & ( 1 << 9 ) ) != 0; // bit 9 of ECX
  183. #endif
  184. }
  185. bool CheckSSE41Technology(void)
  186. {
  187. #if defined( _X360 ) || defined( _PS3 )
  188. return false;
  189. #else
  190. // SSE 4.1 is implemented by both Intel and AMD
  191. // detection is done the same way for both vendors
  192. uint32 eax,ebx,edx,ecx;
  193. if( !cpuid(1,eax,ebx,ecx,edx) )
  194. return false;
  195. return ( ecx & ( 1 << 19 ) ) != 0; // bit 19 of ECX
  196. #endif
  197. }
  198. bool CheckSSE42Technology(void)
  199. {
  200. #if defined( _X360 ) || defined( _PS3 )
  201. return false;
  202. #else
  203. // SSE4.2 is an Intel-only feature
  204. const char *pchVendor = GetProcessorVendorId();
  205. if ( 0 != V_tier0_stricmp( pchVendor, "GenuineIntel" ) )
  206. return false;
  207. uint32 eax,ebx,edx,ecx;
  208. if( !cpuid(1,eax,ebx,ecx,edx) )
  209. return false;
  210. return ( ecx & ( 1 << 20 ) ) != 0; // bit 20 of ECX
  211. #endif
  212. }
  213. bool CheckSSE4aTechnology( void )
  214. {
  215. #if defined( _X360 ) || defined( _PS3 )
  216. return false;
  217. #else
  218. // SSE 4a is an AMD-only feature
  219. const char *pchVendor = GetProcessorVendorId();
  220. if ( 0 != V_tier0_stricmp( pchVendor, "AuthenticAMD" ) )
  221. return false;
  222. uint32 eax,ebx,edx,ecx;
  223. if( !cpuid( 0x80000001,eax,ebx,ecx,edx) )
  224. return false;
  225. return ( ecx & ( 1 << 6 ) ) != 0; // bit 6 of ECX
  226. #endif
  227. }
  228. static bool Check3DNowTechnology(void)
  229. {
  230. #if defined( _X360 ) || defined( _PS3 )
  231. return false;
  232. #else
  233. uint32 eax, unused;
  234. if ( !cpuid(0x80000000,eax,unused,unused,unused) )
  235. return false;
  236. if ( eax > 0x80000000L )
  237. {
  238. if ( !cpuid(0x80000001,unused,unused,unused,eax) )
  239. return false;
  240. return ( eax & 1<<31 ) != 0;
  241. }
  242. return false;
  243. #endif
  244. }
  245. static bool CheckCMOVTechnology()
  246. {
  247. #if defined( _X360 ) || defined( _PS3 )
  248. return false;
  249. #else
  250. uint32 eax,ebx,edx,unused;
  251. if ( !cpuid(1,eax,ebx,unused,edx) )
  252. return false;
  253. return ( edx & (1<<15) ) != 0;
  254. #endif
  255. }
  256. static bool CheckFCMOVTechnology(void)
  257. {
  258. #if defined( _X360 ) || defined( _PS3 )
  259. return false;
  260. #else
  261. uint32 eax,ebx,edx,unused;
  262. if ( !cpuid(1,eax,ebx,unused,edx) )
  263. return false;
  264. return ( edx & (1<<16) ) != 0;
  265. #endif
  266. }
  267. static bool CheckRDTSCTechnology(void)
  268. {
  269. #if defined( _X360 ) || defined( _PS3 )
  270. return false;
  271. #else
  272. uint32 eax,ebx,edx,unused;
  273. if ( !cpuid(1,eax,ebx,unused,edx) )
  274. return false;
  275. return ( edx & 0x10 ) != 0;
  276. #endif
  277. }
  278. // Return the Processor's vendor identification string, or "Generic_x86" if it doesn't exist on this CPU
  279. const tchar* GetProcessorVendorId()
  280. {
  281. #if defined( _X360 ) || defined( _PS3 )
  282. return "PPC";
  283. #else
  284. uint32 unused, VendorIDRegisters[3];
  285. static tchar VendorID[13];
  286. memset( VendorID, 0, sizeof(VendorID) );
  287. if ( !cpuid(0,unused, VendorIDRegisters[0], VendorIDRegisters[2], VendorIDRegisters[1] ) )
  288. {
  289. if ( IsPC() )
  290. {
  291. _tcscpy( VendorID, _T( "Generic_x86" ) );
  292. }
  293. else if ( IsX360() )
  294. {
  295. _tcscpy( VendorID, _T( "PowerPC" ) );
  296. }
  297. }
  298. else
  299. {
  300. memcpy( VendorID+0, &(VendorIDRegisters[0]), sizeof( VendorIDRegisters[0] ) );
  301. memcpy( VendorID+4, &(VendorIDRegisters[1]), sizeof( VendorIDRegisters[1] ) );
  302. memcpy( VendorID+8, &(VendorIDRegisters[2]), sizeof( VendorIDRegisters[2] ) );
  303. }
  304. return VendorID;
  305. #endif
  306. }
  307. // Returns non-zero if Hyper-Threading Technology is supported on the processors and zero if not.
  308. // If it's supported, it does not mean that it's been enabled. So we test another flag to see if it's enabled
  309. // See Intel Processor Identification and the CPUID instruction Application Note 485
  310. // http://www.intel.com/Assets/PDF/appnote/241618.pdf
  311. static bool HTSupported(void)
  312. {
  313. #if ( defined( _X360 ) || defined( _PS3 ) )
  314. // not entirtely sure about the semantic of HT support, it being an intel name
  315. // are we asking about HW threads or HT?
  316. return true;
  317. #else
  318. enum {
  319. HT_BIT = 0x10000000, // EDX[28] - Bit 28 set indicates Hyper-Threading Technology is supported in hardware.
  320. FAMILY_ID = 0x0f00, // EAX[11:8] - Bit 11 thru 8 contains family processor id
  321. EXT_FAMILY_ID = 0x0f00000, // EAX[23:20] - Bit 23 thru 20 contains extended family processor id
  322. FAMILY_ID_386 = 0x0300,
  323. FAMILY_ID_486 = 0x0400, // EAX[8:12] - 486, 487 and overdrive
  324. FAMILY_ID_PENTIUM = 0x0500, // Pentium, Pentium OverDrive 60 - 200
  325. FAMILY_ID_PENTIUM_PRO = 0x0600,// P Pro, P II, P III, P M, Celeron M, Core Duo, Core Solo, Core2 Duo, Core2 Extreme, P D, Xeon model F,
  326. // also 45-nm : Intel Atom, Core i7, Xeon MP ; see Intel Processor Identification and the CPUID instruction pg 20,21
  327. FAMILY_ID_EXTENDED = 0x0F00 // P IV, Xeon, Celeron D, P D,
  328. };
  329. uint32 unused,
  330. reg_eax = 0,
  331. reg_ebx = 0,
  332. reg_edx = 0,
  333. vendor_id[3] = {0, 0, 0};
  334. // verify cpuid instruction is supported
  335. if( !cpuid(0,unused, vendor_id[0],vendor_id[2],vendor_id[1])
  336. || !cpuid(1,reg_eax,reg_ebx,unused,reg_edx) )
  337. return false;
  338. // <Sergiy> Previously, we detected P4 specifically; now, we detect GenuineIntel with HT enabled in general
  339. // if (((reg_eax & FAMILY_ID) == FAMILY_ID_EXTENDED) || (reg_eax & EXT_FAMILY_ID))
  340. // Check to see if this is an Intel Processor with HT or CMT capability , and if HT/CMT is enabled
  341. if (vendor_id[0] == 'uneG' && vendor_id[1] == 'Ieni' && vendor_id[2] == 'letn')
  342. return (reg_edx & HT_BIT) != 0 && // Genuine Intel Processor with Hyper-Threading Technology implemented
  343. ((reg_ebx >> 16) & 0xFF) > 1 ; // Hyper-Threading OR Core Multi-Processing has been enabled
  344. return false; // This is not a genuine Intel processor.
  345. #endif
  346. }
  347. // See Intel Processor Identification and the CPUID instruction Application Note 485
  348. // http://www.intel.com/Assets/PDF/appnote/241618.pdf
  349. int LogicalProcessorsPerCore()
  350. {
  351. #if defined( _X360 ) || defined( _PS3 ) || defined( LINUX )
  352. return 2; //
  353. #elif defined(_WIN32)
  354. uint32 nMaxStandardFnSupported, nVendorId[3];
  355. if( !cpuid( 0, nMaxStandardFnSupported,nVendorId[0],nVendorId[2],nVendorId[1] ) )
  356. {
  357. return 1;
  358. }
  359. uint32 nFn1_Eax, nFn1_Ebx, nFn1_Ecx, nFn1_Edx;
  360. if( !cpuid( 1, nFn1_Eax, nFn1_Ebx, nFn1_Ecx, nFn1_Edx) )
  361. {
  362. return 1;
  363. }
  364. enum CpuidFnMasks
  365. {
  366. HTT = 0x10000000, // Fn0000_0001 EDX[28]
  367. LogicalProcessorCount = 0x00FF0000, // Fn0000_0001 EBX[23:16]
  368. ApicId = 0xFF000000, // Fn0000_0001 EBX[31:24]
  369. NC_Intel = 0xFC000000, // Fn0000_0004 EAX[31:26]
  370. NC_Amd = 0x000000FF, // Fn8000_0008 ECX[7:0]
  371. CmpLegacy_Amd = 0x00000002, // Fn8000_0001 ECX[1]
  372. ApicIdCoreIdSize_Amd = 0x0000F000 // Fn8000_0008 ECX[15:12]
  373. };
  374. // Determine if hardware threading is enabled.
  375. if( nFn1_Edx & HTT )
  376. {
  377. // Determine the total number of logical processors per package.
  378. int nLogProcsPerPkg = ( nFn1_Ebx & LogicalProcessorCount ) >> 16;
  379. int nCoresPerPkg = 1;
  380. if( ( ( nFn1_Ebx >> 16 ) & 0xFF ) <= 1 ) // Has Hyper-Threading OR Core Multi-Processing not been enabled ?
  381. {
  382. // NOTE: This is only tested on Intel CPUs; I don't know if it's true on AMD, as I have no HT AMD to test on
  383. return 1; // HT was turned off, for all intents and purposes in our engine it means one logical CPU per core
  384. }
  385. // Determine the total number of cores per package. This info
  386. // is extracted differently dependending on the cpu vendor.
  387. if( nVendorId[0] == 'uneG' && nVendorId[1] == 'Ieni' && nVendorId[2] == 'letn' ) // GenuineIntel
  388. {
  389. if( nMaxStandardFnSupported >= 4 )
  390. {
  391. uint32 nFn4_Eax, nFn4_Ebx, nFn4_Ecx, nFn4_Edx ;
  392. if( cpuid( 4, nFn4_Eax, nFn4_Ebx, nFn4_Ecx, nFn4_Edx ) )
  393. {
  394. nCoresPerPkg = ( ( nFn4_Eax & NC_Intel ) >> 26 ) + 1;
  395. }
  396. }
  397. // <Sergiy> as the DirectX CoreDetection sample goes, the logic is that on old processors where
  398. // the functions aren't supported, we assume one core per package, multiple logical processors per package
  399. // I suspect this may be wrong, especially for AMD processors.
  400. return nLogProcsPerPkg / nCoresPerPkg;
  401. }
  402. #if 0 // <Sergiy> To make as concervative change as possible now, I'll skip AMD hyperthread detection
  403. else
  404. {
  405. if( nVendorId[0] == 'htuA' && nVendorId[1] == 'itne' && nVendorId[2] == 'DMAc' ) // AuthenticAMD
  406. {
  407. uint32 nFnx8_Eax, nFnx8_Ebx, nFnx8_Ecx, nFnx8_Edx ;
  408. if( cpuid( 0x80000008, nFnx8_Eax, nFnx8_Ebx, nFnx8_Ecx, nFnx8_Edx ) )
  409. {
  410. // AMD reports the msb width of the CORE_ID bit field of the APIC ID
  411. // in ApicIdCoreIdSize_Amd. The maximum value represented by the msb
  412. // width is the theoretical number of cores the processor can support
  413. // and not the actual number of current cores, which is how the msb width
  414. // of the CORE_ID bit field has been traditionally determined. If the
  415. // ApicIdCoreIdSize_Amd value is zero, then you use the traditional method
  416. // to determine the CORE_ID msb width.
  417. DWORD msbWidth = nFnx8_Ecx & ApicIdCoreIdSize_Amd;
  418. if( msbWidth )
  419. {
  420. // Set nCoresPerPkg to the maximum theortical number of cores
  421. // the processor package can support (2 ^ width) so the APIC
  422. // extractor object can be configured to extract the proper
  423. // values from an APIC.
  424. nCoresPerPkg = 1 << ( msbWidth >> 12 );
  425. }
  426. else
  427. {
  428. // Set nCoresPerPkg to the actual number of cores being reported
  429. // by the CPUID instruction.
  430. nCoresPerPkg = ( nFnx8_Ecx & NC_Amd ) + 1;
  431. }
  432. }
  433. }
  434. // <Sergiy> as the DirectX CoreDetection sample goes, the logic is that on old processors where
  435. // the functions aren't supported, we assume one core per package, multiple logical processors per package
  436. // I suspect this may be wrong, especially for AMD processors.
  437. return nLogProcsPerPkg / nCoresPerPkg;
  438. }
  439. #endif
  440. }
  441. return 1;
  442. #endif
  443. }
  444. // Measure the processor clock speed by sampling the cycle count, waiting
  445. // for some fraction of a second, then measuring the elapsed number of cycles.
  446. static int64 CalculateClockSpeed()
  447. {
  448. #if defined( _X360 ) || defined(_PS3)
  449. // Xbox360 and PS3 have the same clock speed and share a lot of characteristics on PPU
  450. return 3200000000LL;
  451. #else
  452. #if defined( _WIN32 )
  453. LARGE_INTEGER waitTime, startCount, curCount;
  454. CCycleCount start, end;
  455. // Take 1/32 of a second for the measurement.
  456. QueryPerformanceFrequency( &waitTime );
  457. int scale = 5;
  458. waitTime.QuadPart >>= scale;
  459. QueryPerformanceCounter( &startCount );
  460. start.Sample();
  461. do
  462. {
  463. QueryPerformanceCounter( &curCount );
  464. }
  465. while ( curCount.QuadPart - startCount.QuadPart < waitTime.QuadPart );
  466. end.Sample();
  467. return (end.m_Int64 - start.m_Int64) << scale;
  468. #elif defined(POSIX)
  469. uint64 CalculateCPUFreq(); // from cpu_linux.cpp
  470. int64 freq =(int64)CalculateCPUFreq();
  471. if ( freq == 0 ) // couldn't calculate clock speed
  472. {
  473. Error( "Unable to determine CPU Frequency\n" );
  474. }
  475. return freq;
  476. #else
  477. #error "Please implement Clock Speed function for this platform"
  478. #endif
  479. #endif
  480. }
  481. static CPUInformation s_cpuInformation;
  482. const CPUInformation& GetCPUInformation()
  483. {
  484. CPUInformation &pi = s_cpuInformation;
  485. // Has the structure already been initialized and filled out?
  486. if ( pi.m_Size == sizeof(pi) )
  487. return pi;
  488. // Redundant, but just in case the user somehow messes with the size.
  489. memset(&pi, 0x0, sizeof(pi));
  490. // Fill out the structure, and return it:
  491. pi.m_Size = sizeof(pi);
  492. // Grab the processor frequency:
  493. pi.m_Speed = CalculateClockSpeed();
  494. // Get the logical and physical processor counts:
  495. #if defined( _X360 )
  496. pi.m_nPhysicalProcessors = 3;
  497. pi.m_nLogicalProcessors = 6;
  498. #elif defined( _PS3 )
  499. pi.m_nPhysicalProcessors = 1;
  500. pi.m_nLogicalProcessors = 2;
  501. #elif defined(_WIN32) && !defined( _X360 )
  502. SYSTEM_INFO si;
  503. ZeroMemory( &si, sizeof(si) );
  504. GetSystemInfo( &si );
  505. // Sergiy: fixing: si.dwNumberOfProcessors is the number of logical processors according to experiments on i7, P4 and a DirectX sample (Aug'09)
  506. // this is contrary to MSDN documentation on GetSystemInfo()
  507. //
  508. pi.m_nLogicalProcessors = si.dwNumberOfProcessors;
  509. if ( 0 == V_tier0_stricmp( GetProcessorVendorId(), "AuthenticAMD" ) )
  510. {
  511. // quick fix for AMD Phenom: it reports 3 logical cores and 4 physical cores;
  512. // no AMD CPUs by the end of 2009 have HT, so we'll override HT detection here
  513. pi.m_nPhysicalProcessors = pi.m_nLogicalProcessors;
  514. }
  515. else
  516. {
  517. CpuTopology topo;
  518. pi.m_nPhysicalProcessors = topo.NumberOfSystemCores();
  519. }
  520. // Make sure I always report at least one, when running WinXP with the /ONECPU switch,
  521. // it likes to report 0 processors for some reason.
  522. if ( pi.m_nPhysicalProcessors == 0 && pi.m_nLogicalProcessors == 0 )
  523. {
  524. Assert( !"Sergiy: apparently I didn't fix some CPU detection code completely. Let me know and I'll do my best to fix it soon." );
  525. pi.m_nPhysicalProcessors = 1;
  526. pi.m_nLogicalProcessors = 1;
  527. }
  528. #elif defined(LINUX)
  529. pi.m_nLogicalProcessors = 0;
  530. pi.m_nPhysicalProcessors = 0;
  531. const int k_cMaxProcessors = 256;
  532. bool rgbProcessors[k_cMaxProcessors];
  533. memset( rgbProcessors, 0, sizeof( rgbProcessors ) );
  534. int cMaxCoreId = 0;
  535. FILE *fpCpuInfo = fopen( "/proc/cpuinfo", "r" );
  536. if ( fpCpuInfo )
  537. {
  538. char rgchLine[256];
  539. while ( fgets( rgchLine, sizeof( rgchLine ), fpCpuInfo ) )
  540. {
  541. if ( !strncasecmp( rgchLine, "processor", strlen( "processor" ) ) )
  542. {
  543. pi.m_nLogicalProcessors++;
  544. }
  545. if ( !strncasecmp( rgchLine, "core id", strlen( "core id" ) ) )
  546. {
  547. char *pchValue = strchr( rgchLine, ':' );
  548. cMaxCoreId = MAX( cMaxCoreId, atoi( pchValue + 1 ) );
  549. }
  550. if ( !strncasecmp( rgchLine, "physical id", strlen( "physical id" ) ) )
  551. {
  552. // it seems (based on survey data) that we can see
  553. // processor N (N > 0) when it's the only processor in
  554. // the system. so keep track of each processor
  555. char *pchValue = strchr( rgchLine, ':' );
  556. int cPhysicalId = atoi( pchValue + 1 );
  557. if ( cPhysicalId < k_cMaxProcessors )
  558. rgbProcessors[cPhysicalId] = true;
  559. }
  560. /* this code will tell us how many physical chips are in the machine, but we want
  561. core count, so for the moment, each processor counts as both logical and physical.
  562. if ( !strncasecmp( rgchLine, "physical id ", strlen( "physical id " ) ) )
  563. {
  564. char *pchValue = strchr( rgchLine, ':' );
  565. pi.m_nPhysicalProcessors = MAX( pi.m_nPhysicalProcessors, atol( pchValue ) );
  566. }
  567. */
  568. }
  569. fclose( fpCpuInfo );
  570. for ( int i = 0; i < k_cMaxProcessors; i++ )
  571. if ( rgbProcessors[i] )
  572. pi.m_nPhysicalProcessors++;
  573. pi.m_nPhysicalProcessors *= ( cMaxCoreId + 1 );
  574. }
  575. else
  576. {
  577. pi.m_nLogicalProcessors = 1;
  578. pi.m_nPhysicalProcessors = 1;
  579. Assert( !"couldn't read cpu information from /proc/cpuinfo" );
  580. }
  581. #elif defined(OSX)
  582. int mib[2], num_cpu = 1;
  583. size_t len;
  584. mib[0] = CTL_HW;
  585. mib[1] = HW_NCPU;
  586. len = sizeof(num_cpu);
  587. sysctl(mib, 2, &num_cpu, &len, NULL, 0);
  588. pi.m_nPhysicalProcessors = num_cpu;
  589. pi.m_nLogicalProcessors = num_cpu;
  590. #endif
  591. // Determine Processor Features:
  592. pi.m_bRDTSC = CheckRDTSCTechnology();
  593. pi.m_bCMOV = CheckCMOVTechnology();
  594. pi.m_bFCMOV = CheckFCMOVTechnology();
  595. pi.m_bMMX = CheckMMXTechnology();
  596. pi.m_bSSE = CheckSSETechnology();
  597. pi.m_bSSE2 = CheckSSE2Technology();
  598. pi.m_bSSE3 = CheckSSE3Technology();
  599. pi.m_bSSSE3 = CheckSSSE3Technology();
  600. pi.m_bSSE4a = CheckSSE4aTechnology();
  601. pi.m_bSSE41 = CheckSSE41Technology();
  602. pi.m_bSSE42 = CheckSSE42Technology();
  603. pi.m_b3DNow = Check3DNowTechnology();
  604. pi.m_szProcessorID = (tchar*)GetProcessorVendorId();
  605. pi.m_bHT = pi.m_nPhysicalProcessors < pi.m_nLogicalProcessors; //HTSupported();
  606. return pi;
  607. }