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.

1017 lines
42 KiB

  1. //-------------------------------------------------------------------------------------
  2. // CpuTopology.cpp
  3. //
  4. // CpuToplogy class implementation.
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //-------------------------------------------------------------------------------------
  8. #include "pch_tier0.h"
  9. #if defined(_WIN32) && !defined(_X360) && !defined( _PS3 )
  10. #include "cputopology.h"
  11. #include <stdlib.h>
  12. #include <crtdbg.h>
  13. #undef malloc
  14. #undef free
  15. #ifdef _WIN64
  16. // Inline assembly is not supported in 64-bit. Ideally, we would prefer to
  17. // use the __cpuid intrinsic to avoid having to drop to assembly altogether.
  18. // However, as of MSVC 9.0, the __cpuid intrinsic does not enable the
  19. // ability to set the ECX register, which is required for obtaining certain
  20. // extended CPU information. To overcome these issues, we must call the
  21. // Cpuid64() external function, which is written in assembly and located in
  22. // the cpuid64.asm file included in this project. This project contains a build
  23. // step that invokes 64-bit MASM on cpuid64.asm when building a 64-bit target.
  24. extern "C" void Cpuid64(void* argsPtr);
  25. #endif
  26. //---------------------------------------------------------------------------------
  27. // Name: ICpuToplogy
  28. // Desc: Specifies the interface that each class that provides an implementation
  29. // for extracting cpu topology must conform to. This is the Implementor
  30. // class in the traditional Bridge Pattern.
  31. //---------------------------------------------------------------------------------
  32. class ICpuTopology
  33. {
  34. public:
  35. virtual ~ICpuTopology()
  36. {
  37. }
  38. virtual BOOL IsDefaultImpl() const = 0;
  39. virtual DWORD NumberOfProcessCores() const = 0;
  40. virtual DWORD NumberOfSystemCores() const = 0;
  41. virtual DWORD_PTR CoreAffinityMask( DWORD coreIdx ) const = 0;
  42. };
  43. namespace
  44. {
  45. ///////////////////////////////////////////////////////////////////////////////////
  46. // Local Class Definitions
  47. ///////////////////////////////////////////////////////////////////////////////////
  48. //---------------------------------------------------------------------------------
  49. // Name: DefaultImpl
  50. // Desc: Provides a default implementation for the ICpuTopology interface when
  51. // GetLogicalProcessorInformation and CPUID are not supported for whatever
  52. // reason. This is a ConcreteImplementor class in the traditional Bridge
  53. // Pattern.
  54. //---------------------------------------------------------------------------------
  55. class DefaultImpl : public ICpuTopology
  56. {
  57. public:
  58. //-----------------------------------------------------------------------------
  59. // DefaultImpl::IsDefaultImpl
  60. //-----------------------------------------------------------------------------
  61. /*virtual*/ BOOL IsDefaultImpl() const
  62. {
  63. return TRUE;
  64. }
  65. //-----------------------------------------------------------------------------
  66. // DefaultImpl::NumberOfProcessCores
  67. //-----------------------------------------------------------------------------
  68. /*virtual*/ DWORD NumberOfProcessCores() const
  69. {
  70. return 1;
  71. }
  72. //-----------------------------------------------------------------------------
  73. // DefaultImpl::IsNumberOfSystemCores
  74. //-----------------------------------------------------------------------------
  75. /*virtual*/ DWORD NumberOfSystemCores() const
  76. {
  77. return 1;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // DefaultImpl::CoreAffinityMask
  81. //-----------------------------------------------------------------------------
  82. /*virtual*/ DWORD_PTR CoreAffinityMask( DWORD coreIdx ) const
  83. {
  84. DWORD_PTR coreAffinity = 0;
  85. if( 1 == coreIdx )
  86. {
  87. DWORD_PTR dwSystemAffinity;
  88. GetProcessAffinityMask( GetCurrentProcess(), &coreAffinity, &dwSystemAffinity );
  89. }
  90. return coreAffinity;
  91. }
  92. };
  93. //---------------------------------------------------------------------------------
  94. // Name: GlpiImpl
  95. // Desc: Provides the GetLogicalProcessorInformation implementation for the
  96. // ICpuTopology interface. This is a ConcreteImplementor class in the
  97. // traditional Bridge Pattern.
  98. //---------------------------------------------------------------------------------
  99. class GlpiImpl : public ICpuTopology
  100. {
  101. public:
  102. //-----------------------------------------------------------------------------
  103. // Name: GlpiImpl::GlpiImpl
  104. // Desc: Initializes the internal structures/data with information retrieved
  105. // from a call to GetLogicalProcessorInformation.
  106. //-----------------------------------------------------------------------------
  107. GlpiImpl() : m_pSlpi( NULL ),
  108. m_nItems( 0 )
  109. {
  110. _ASSERT( IsSupported() );
  111. GlpiFnPtr pGlpi = GetGlpiFn_();
  112. _ASSERT( pGlpi );
  113. DWORD cbBuffer = 0;
  114. pGlpi( 0, &cbBuffer );
  115. m_pSlpi = ( SYSTEM_LOGICAL_PROCESSOR_INFORMATION* )malloc( cbBuffer );
  116. pGlpi( m_pSlpi, &cbBuffer );
  117. m_nItems = cbBuffer / sizeof( SYSTEM_LOGICAL_PROCESSOR_INFORMATION );
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Name: GlpiImpl::~GlpiImpl
  121. //-----------------------------------------------------------------------------
  122. /*virtual*/ ~GlpiImpl()
  123. {
  124. free( m_pSlpi );
  125. m_pSlpi = 0;
  126. m_nItems = 0;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Name: GlpiImpl::IsDefaultImpl
  130. //-----------------------------------------------------------------------------
  131. /*virtual*/ BOOL IsDefaultImpl() const
  132. {
  133. return FALSE;
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Name: GlpiImpl::NumberOfProcessCores
  137. // Desc: Gets the total number of physical processor cores available to the
  138. // current process.
  139. //-----------------------------------------------------------------------------
  140. /*virtual*/ DWORD NumberOfProcessCores() const
  141. {
  142. DWORD_PTR dwProcessAffinity, dwSystemAffinity;
  143. GetProcessAffinityMask( GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity );
  144. DWORD nCores = 0;
  145. for( DWORD i = 0; i < m_nItems; ++i )
  146. {
  147. if( ( RelationProcessorCore == m_pSlpi[i].Relationship ) &&
  148. ( m_pSlpi[i].ProcessorMask & dwProcessAffinity ) )
  149. {
  150. ++nCores;
  151. }
  152. }
  153. return nCores;
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Name: GlpiImpl::NumberOfSystemCores
  157. // Desc: Gets the total number of physical processor cores enabled on the
  158. // system.
  159. //-----------------------------------------------------------------------------
  160. /*virtual*/ DWORD NumberOfSystemCores() const
  161. {
  162. DWORD nCores = 0;
  163. for( DWORD i = 0; i < m_nItems; ++i )
  164. {
  165. if( RelationProcessorCore == m_pSlpi[i].Relationship )
  166. ++nCores;
  167. }
  168. return nCores;
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Name: GlpiImpl::CoreAffinityMask
  172. // Desc: Gets an affinity mask that corresponds to the requested processor
  173. // core.
  174. //-----------------------------------------------------------------------------
  175. /*virtual*/ DWORD_PTR CoreAffinityMask( DWORD coreIdx ) const
  176. {
  177. DWORD_PTR dwProcessAffinity, dwSystemAffinity;
  178. GetProcessAffinityMask( GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity );
  179. for( DWORD i = 0; i < m_nItems; ++i )
  180. {
  181. if( RelationProcessorCore == m_pSlpi[i].Relationship )
  182. {
  183. if( !coreIdx-- )
  184. {
  185. return m_pSlpi[i].ProcessorMask & dwProcessAffinity;
  186. }
  187. }
  188. }
  189. return 0;
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Name: GlpiImpl::IsSupported
  193. //-----------------------------------------------------------------------------
  194. static BOOL IsSupported()
  195. {
  196. return NULL != GetGlpiFn_();
  197. }
  198. private:
  199. // GetLogicalProcessorInformation function pointer
  200. typedef BOOL( WINAPI* GlpiFnPtr )(
  201. SYSTEM_LOGICAL_PROCESSOR_INFORMATION*,
  202. PDWORD
  203. );
  204. //-----------------------------------------------------------------------------
  205. // Name: GlpiImpl::VerifyGlpiFn_
  206. // Desc: Gets a pointer to the GetLogicalProcessorInformation function only if
  207. // it is supported on the current platform.
  208. // GetLogicalProcessorInformation is supported on Windows Server 2003 and
  209. // XP64, however there is a bug with the implementation. Therefore, only
  210. // GetLogicalProcessorInformation on Windows Vista is supported in this
  211. // sample.
  212. //-----------------------------------------------------------------------------
  213. static GlpiFnPtr VerifyGlpiFn_()
  214. {
  215. // VerifyVersionInfo function pointer
  216. typedef BOOL ( WINAPI* VviFnPtr )( LPOSVERSIONINFOEX,
  217. DWORD,
  218. DWORDLONG );
  219. HMODULE hMod = GetModuleHandle( TEXT( "kernel32" ) );
  220. #ifdef _UNICODE
  221. VviFnPtr pVvi = (VviFnPtr) GetProcAddress( hMod, "VerifyVersionInfoW" );
  222. #else
  223. VviFnPtr pVvi = ( VviFnPtr )GetProcAddress( hMod, "VerifyVersionInfoA" );
  224. #endif
  225. GlpiFnPtr pGlpi = NULL;
  226. if( pVvi )
  227. {
  228. // VerSetConditionMask function pointer
  229. typedef ULONGLONG ( WINAPI* VscmFnPtr )( ULONGLONG,
  230. DWORD,
  231. BYTE );
  232. VscmFnPtr pVscm = ( VscmFnPtr )GetProcAddress( hMod, "VerSetConditionMask" );
  233. _ASSERT( pVscm );
  234. // Check for Windows Vista
  235. OSVERSIONINFOEX osvi = { sizeof( OSVERSIONINFOEX ) };
  236. osvi.dwMajorVersion = 6;
  237. osvi.dwMinorVersion = 0;
  238. osvi.wServicePackMajor = 0;
  239. osvi.wServicePackMinor = 0;
  240. ULONGLONG dwlMask = 0;
  241. dwlMask = pVscm( dwlMask, VER_MAJORVERSION, VER_GREATER_EQUAL );
  242. dwlMask = pVscm( dwlMask, VER_MINORVERSION, VER_GREATER_EQUAL );
  243. dwlMask = pVscm( dwlMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
  244. dwlMask = pVscm( dwlMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL );
  245. if( pVvi( &osvi, VER_MAJORVERSION
  246. | VER_MINORVERSION
  247. | VER_SERVICEPACKMAJOR
  248. | VER_SERVICEPACKMINOR,
  249. dwlMask ) )
  250. {
  251. pGlpi = ( GlpiFnPtr )GetProcAddress( hMod, "GetLogicalProcessorInformation" );
  252. _ASSERT( pGlpi );
  253. }
  254. }
  255. return pGlpi;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Name: GlpiImpl::GetGlpiFn_
  259. // Desc: Gets a cached pointer to the GetLogicalProcessorInformation function.
  260. //-----------------------------------------------------------------------------
  261. static GlpiFnPtr GetGlpiFn_()
  262. {
  263. static GlpiFnPtr pGlpi = VerifyGlpiFn_();
  264. return pGlpi;
  265. }
  266. // Private Members
  267. SYSTEM_LOGICAL_PROCESSOR_INFORMATION* m_pSlpi;
  268. DWORD m_nItems;
  269. };
  270. //---------------------------------------------------------------------------------
  271. // Name: ApicExtractor
  272. // Desc: A utility class that provides an interface for decoding a processor
  273. // APIC ID. An APIC ID is an 8-bit identifier given to each logical
  274. // processor on system boot and can be retrieved by the CPUID instruction.
  275. // Each APIC ID is composed of a PACKAGE_ID, CORE_ID and SMT_ID that describe
  276. // the relationship of a logical processor within the processor topology of
  277. // the system.
  278. //---------------------------------------------------------------------------------
  279. class ApicExtractor
  280. {
  281. public:
  282. //-----------------------------------------------------------------------------
  283. // Name: ApicExtractor::ApicExtractor
  284. //-----------------------------------------------------------------------------
  285. ApicExtractor( DWORD nLogProcsPerPkg = 1, DWORD nCoresPerPkg = 1 )
  286. {
  287. SetPackageTopology( nLogProcsPerPkg, nCoresPerPkg );
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Name: ApicExtractor::SmtId
  291. //-----------------------------------------------------------------------------
  292. BYTE SmtId( BYTE apicId ) const
  293. {
  294. return apicId & m_smtIdMask.mask;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Name: ApicExtractor::CoreId
  298. //-----------------------------------------------------------------------------
  299. BYTE CoreId( BYTE apicId ) const
  300. {
  301. return ( apicId & m_coreIdMask.mask ) >> m_smtIdMask.width;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Name: ApicExtractor::PackageId
  305. //-----------------------------------------------------------------------------
  306. BYTE PackageId( BYTE apicId ) const
  307. {
  308. return ( apicId & m_pkgIdMask.mask ) >>
  309. ( m_smtIdMask.width + m_coreIdMask.width );
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Name: ApicExtractor::PackageCoreId
  313. //-----------------------------------------------------------------------------
  314. BYTE PackageCoreId( BYTE apicId ) const
  315. {
  316. return ( apicId & ( m_pkgIdMask.mask | m_coreIdMask.mask ) ) >>
  317. m_smtIdMask.width;
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Name: ApicExtractor::GetLogProcsPerPkg
  321. //-----------------------------------------------------------------------------
  322. DWORD GetLogProcsPerPkg() const
  323. {
  324. return m_nLogProcsPerPkg;
  325. }
  326. //-----------------------------------------------------------------------------
  327. // Name: ApicExtractor::GetCoresPerPkg
  328. //-----------------------------------------------------------------------------
  329. DWORD GetCoresPerPkg() const
  330. {
  331. return m_nCoresPerPkg;
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Name: ApicExtractor::SetPackageTopology
  335. // Desc: You should call SetPackageTopology with the number of logical
  336. // processors per package and number of cores per package before calling
  337. // the sub id accessors (SmtId(), CoreId(), PackageId(), PackageCoreId())
  338. // as this information is required to effectively decode an APIC ID into
  339. // its sub parts.
  340. //-----------------------------------------------------------------------------
  341. void SetPackageTopology( DWORD nLogProcsPerPkg, DWORD nCoresPerPkg )
  342. {
  343. m_nLogProcsPerPkg = ( BYTE )nLogProcsPerPkg;
  344. m_nCoresPerPkg = ( BYTE )nCoresPerPkg;
  345. // fix for Phenom x3 and similar CPUs - it reports 3 logical processors per package, and 4 cores per package
  346. // so one core is probably just disabled for yield, but it causes a bug in GetMaskWidth that propagates
  347. if( m_nCoresPerPkg > m_nLogProcsPerPkg )
  348. {
  349. m_nCoresPerPkg = m_nLogProcsPerPkg;
  350. }
  351. m_smtIdMask.width = GetMaskWidth_( m_nLogProcsPerPkg / m_nCoresPerPkg );
  352. m_coreIdMask.width = GetMaskWidth_( m_nCoresPerPkg );
  353. m_pkgIdMask.width = 8 - ( m_smtIdMask.width + m_coreIdMask.width );
  354. m_pkgIdMask.mask = ( BYTE )( 0xFF << ( m_smtIdMask.width + m_coreIdMask.width ) );
  355. m_coreIdMask.mask = ( BYTE )( ( 0xFF << m_smtIdMask.width ) ^ m_pkgIdMask.mask );
  356. m_smtIdMask.mask = ( BYTE )~( 0xFF << m_smtIdMask.width );
  357. }
  358. private:
  359. //-----------------------------------------------------------------------------
  360. // Name: ApicExtractor::GetMaskWidth_
  361. // Desc: Gets the width of a sub id bit field in an APIC ID. The width of a
  362. // sub id (CORE_ID, SMT_ID) is only wide enough to support the maximum
  363. // number of ids that needs to be represented in the topology.
  364. //-----------------------------------------------------------------------------
  365. static BYTE GetMaskWidth_( BYTE maxIds )
  366. {
  367. --maxIds;
  368. // find index of msb
  369. BYTE msbIdx = 8;
  370. BYTE msbMask = 0x80;
  371. while( msbMask && !( msbMask & maxIds ) )
  372. {
  373. --msbIdx;
  374. msbMask >>= 1;
  375. }
  376. return msbIdx;
  377. }
  378. struct IdMask
  379. {
  380. BYTE width;
  381. BYTE mask;
  382. };
  383. // Private Members
  384. BYTE m_nLogProcsPerPkg;
  385. BYTE m_nCoresPerPkg;
  386. IdMask m_smtIdMask;
  387. IdMask m_coreIdMask;
  388. IdMask m_pkgIdMask;
  389. };
  390. //---------------------------------------------------------------------------------
  391. // Name: Cpuid
  392. // Desc: A utility class that wraps the functionality of the CPUID instruction.
  393. // Call the Call() method with the desired CPUID function, and use the
  394. // register accessors to retrieve the register values.
  395. //---------------------------------------------------------------------------------
  396. class Cpuid
  397. {
  398. public:
  399. // FnSet values are used to indicate a CPUID function set.
  400. enum FnSet
  401. {
  402. Std = 0x00000000,
  403. Ext = 0x80000000
  404. };
  405. //-----------------------------------------------------------------------------
  406. // Name: Cpuid::Cpuid
  407. //-----------------------------------------------------------------------------
  408. Cpuid() : m_eax( 0 ),
  409. m_ebx( 0 ),
  410. m_ecx( 0 ),
  411. m_edx( 0 )
  412. {
  413. }
  414. // Register accessors
  415. DWORD Eax() const
  416. {
  417. return m_eax;
  418. }
  419. DWORD Ebx() const
  420. {
  421. return m_ebx;
  422. }
  423. DWORD Ecx() const
  424. {
  425. return m_ecx;
  426. }
  427. DWORD Edx() const
  428. {
  429. return m_edx;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Name: Cpuid::Call
  433. // Desc: Calls the CPUID instruction with the specified function. Returns TRUE
  434. // if the CPUID function was supported, FALSE if it wasn't.
  435. //-----------------------------------------------------------------------------
  436. BOOL Call( FnSet fnSet, DWORD fn )
  437. {
  438. if( IsFnSupported( fnSet, fn ) )
  439. {
  440. UncheckedCall_( fnSet, fn );
  441. return true;
  442. }
  443. return false;
  444. }
  445. //-----------------------------------------------------------------------------
  446. // Name: Cpuid::IsVendor
  447. // Desc: Compares a string with the vendor string encoded in the CPUID
  448. // instruction.
  449. //-----------------------------------------------------------------------------
  450. static BOOL IsVendor( const char* strVendor )
  451. {
  452. // Cache the vendor string
  453. static const Cpuid cpu( Std );
  454. return cpu.Ebx() == *reinterpret_cast<const DWORD*>( strVendor )
  455. && cpu.Ecx() == *reinterpret_cast<const DWORD*>( strVendor + 8 )
  456. && cpu.Edx() == *reinterpret_cast<const DWORD*>( strVendor + 4 );
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Name: Cpuid::IsFnSupported
  460. // Desc: Checks to see if a CPUID function is supported. Different processors
  461. // support different functions. This method is automatically called from
  462. // the Call() method, so you don't need to call it beforehand.
  463. //-----------------------------------------------------------------------------
  464. static BOOL IsFnSupported( FnSet fnSet, DWORD fn )
  465. {
  466. // Cache the maximum supported standard function
  467. static const DWORD MaxStdFn = Cpuid( Std ).Eax();
  468. // Cache the maximum supported extended function
  469. static const DWORD MaxExtFn = Cpuid( Ext ).Eax();
  470. bool ret = false;
  471. switch( fnSet )
  472. {
  473. case Std:
  474. ret = ( fn <= MaxStdFn );
  475. break;
  476. case Ext:
  477. ret = ( fn <= MaxExtFn );
  478. break;
  479. default:
  480. _ASSERT( 0 ); // should never get here
  481. break;
  482. }
  483. return ret;
  484. }
  485. private:
  486. //-----------------------------------------------------------------------------
  487. // Name: Cpuid::Cpuid
  488. // Desc: This constructor is private and is only used to set a Cpuid object to
  489. // initial values retrieved from CPUID functions 0x00000000 and
  490. // 0x80000000. Good for caching values from the CPUID instruction that
  491. // are not variable, like the encoded vendor string and the maximum
  492. // supported CPUID function values.
  493. //-----------------------------------------------------------------------------
  494. explicit Cpuid( FnSet fnSet )
  495. {
  496. UncheckedCall_( fnSet, 0 );
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Name: Cpuid::UncheckedCall_
  500. // Desc: Calls the CPUID instruction without checking for CPUID function
  501. // support.
  502. //-----------------------------------------------------------------------------
  503. void UncheckedCall_( FnSet fnSet, DWORD fn )
  504. {
  505. #ifdef _WIN64
  506. // Inline assembly is not supported in 64-bit. Ideally, we would prefer to
  507. // use the __cpuid intrinsic to avoid having to drop to assembly altogether.
  508. // However, as of MSVC 9.0, the __cpuid intrinsic does not enable the
  509. // ability to set the ECX register, which is required for obtaining certain
  510. // extended CPU information. To overcome these issues, we must call the
  511. // Cpuid64() external function, which is written in assembly and located in
  512. // the cpuid64.asm file included in this project. This project contains a build
  513. // step that invokes 64-bit MASM on cpuid64.asm when building a 64-bit target.
  514. m_eax = fnSet | fn;
  515. m_ecx = 0;
  516. Cpuid64(this);
  517. #else
  518. __asm
  519. {
  520. mov ecx, 0
  521. mov eax, fn
  522. or eax, fnSet
  523. cpuid
  524. mov edi, this
  525. mov [edi].m_eax, eax
  526. mov [edi].m_ebx, ebx
  527. mov [edi].m_ecx, ecx
  528. mov [edi].m_edx, edx
  529. }
  530. #endif
  531. }
  532. // Private Members
  533. DWORD m_eax;
  534. DWORD m_ebx;
  535. DWORD m_ecx;
  536. DWORD m_edx;
  537. };
  538. //---------------------------------------------------------------------------------
  539. // Name: CpuidImpl
  540. // Desc: Provides the CPUID instruction implementation for the ICpuTopology
  541. // interface. This is a ConcreteImplementor class in the traditional Bridge
  542. // Pattern.
  543. //---------------------------------------------------------------------------------
  544. class CpuidImpl : public ICpuTopology
  545. {
  546. public:
  547. // CpuidFnMasks are used when extracting bit-encoded information retrieved from
  548. // the CPUID instruction
  549. enum CpuidFnMasks
  550. {
  551. HTT = 0x10000000, // Fn0000_0001 EDX[28]
  552. LogicalProcessorCount = 0x00FF0000, // Fn0000_0001 EBX[23:16]
  553. ApicId = 0xFF000000, // Fn0000_0001 EBX[31:24]
  554. NC_Intel = 0xFC000000, // Fn0000_0004 EAX[31:26]
  555. NC_Amd = 0x000000FF, // Fn8000_0008 ECX[7:0]
  556. CmpLegacy_Amd = 0x00000002, // Fn8000_0001 ECX[1]
  557. ApicIdCoreIdSize_Amd = 0x0000F000 // Fn8000_0008 ECX[15:12]
  558. };
  559. enum
  560. {
  561. MaxLogicalProcessors = sizeof( DWORD_PTR ) * 8
  562. };
  563. //-----------------------------------------------------------------------------
  564. // Name: CpuidImpl::CpuidImpl
  565. // Desc: Initializes internal structures/data with information retrieved from
  566. // calling the CPUID instruction.
  567. //-----------------------------------------------------------------------------
  568. CpuidImpl() : m_nItems( 0 )
  569. {
  570. _ASSERT( IsSupported() );
  571. DWORD nLogProcsPerPkg = 1;
  572. DWORD nCoresPerPkg = 1;
  573. Cpuid cpu;
  574. // Determine if hardware threading is enabled.
  575. cpu.Call( Cpuid::Std, 1 );
  576. if( cpu.Edx() & HTT )
  577. {
  578. // Determine the total number of logical processors per package.
  579. nLogProcsPerPkg = ( cpu.Ebx() & LogicalProcessorCount ) >> 16;
  580. // Determine the total number of cores per package. This info
  581. // is extracted differently dependending on the cpu vendor.
  582. if( Cpuid::IsVendor( GenuineIntel ) )
  583. {
  584. if( cpu.Call( Cpuid::Std, 4 ) )
  585. {
  586. nCoresPerPkg = ( ( cpu.Eax() & NC_Intel ) >> 26 ) + 1;
  587. }
  588. }
  589. else
  590. {
  591. _ASSERT( Cpuid::IsVendor( AuthenticAMD ) );
  592. if( cpu.Call( Cpuid::Ext, 8 ) )
  593. {
  594. // AMD reports the msb width of the CORE_ID bit field of the APIC ID
  595. // in ApicIdCoreIdSize_Amd. The maximum value represented by the msb
  596. // width is the theoretical number of cores the processor can support
  597. // and not the actual number of current cores, which is how the msb width
  598. // of the CORE_ID bit field has been traditionally determined. If the
  599. // ApicIdCoreIdSize_Amd value is zero, then you use the traditional method
  600. // to determine the CORE_ID msb width.
  601. DWORD msbWidth = cpu.Ecx() & ApicIdCoreIdSize_Amd;
  602. if( msbWidth )
  603. {
  604. // Set nCoresPerPkg to the maximum theortical number of cores
  605. // the processor package can support (2 ^ width) so the APIC
  606. // extractor object can be configured to extract the proper
  607. // values from an APIC.
  608. nCoresPerPkg = 1 << ( msbWidth >> 12 );
  609. }
  610. else
  611. {
  612. // Set nCoresPerPkg to the actual number of cores being reported
  613. // by the CPUID instruction.
  614. nCoresPerPkg = ( cpu.Ecx() & NC_Amd ) + 1;
  615. }
  616. }
  617. }
  618. }
  619. // Configure the APIC extractor object with the information it needs to
  620. // be able to decode the APIC.
  621. m_apicExtractor.SetPackageTopology( nLogProcsPerPkg, nCoresPerPkg );
  622. DWORD_PTR dwProcessAffinity, dwSystemAffinity;
  623. HANDLE hProcess = GetCurrentProcess();
  624. HANDLE hThread = GetCurrentThread();
  625. GetProcessAffinityMask( hProcess, &dwProcessAffinity, &dwSystemAffinity );
  626. if( 1 == dwSystemAffinity )
  627. {
  628. // Since we only have 1 logical processor present on the system, we
  629. // can explicitly set a single APIC ID to zero.
  630. _ASSERT( 1 == nLogProcsPerPkg );
  631. m_apicIds[m_nItems++] = 0;
  632. }
  633. else
  634. {
  635. // Set the process affinity to the system affinity if they are not
  636. // equal so that all logical processors can be accounted for.
  637. if( dwProcessAffinity != dwSystemAffinity )
  638. {
  639. SetProcessAffinityMask( hProcess, dwSystemAffinity );
  640. }
  641. // Call cpuid on each active logical processor in the system affinity.
  642. DWORD_PTR dwPrevThreadAffinity = 0;
  643. for( DWORD_PTR dwThreadAffinity = 1;
  644. dwThreadAffinity && dwThreadAffinity <= dwSystemAffinity;
  645. dwThreadAffinity <<= 1 )
  646. {
  647. if( dwSystemAffinity & dwThreadAffinity )
  648. {
  649. if( 0 == dwPrevThreadAffinity )
  650. {
  651. // Save the previous thread affinity so we can return
  652. // the executing thread affinity back to this state.
  653. _ASSERT( 0 == m_nItems );
  654. dwPrevThreadAffinity = SetThreadAffinityMask( hThread,
  655. dwThreadAffinity );
  656. }
  657. else
  658. {
  659. _ASSERT( m_nItems > 0 );
  660. SetThreadAffinityMask( hThread, dwThreadAffinity );
  661. }
  662. // Allow the thread to switch to masked logical processor.
  663. Sleep( 0 );
  664. // Store the APIC ID
  665. cpu.Call( Cpuid::Std, 1 );
  666. m_apicIds[m_nItems++] = ( BYTE )( ( cpu.Ebx() & ApicId ) >> 24 );
  667. }
  668. }
  669. // Restore the previous process and thread affinity state.
  670. SetProcessAffinityMask( hProcess, dwProcessAffinity );
  671. SetThreadAffinityMask( hThread, dwPrevThreadAffinity );
  672. Sleep( 0 );
  673. }
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Name: CpuidImpl::IsDefaultImpl
  677. //-----------------------------------------------------------------------------
  678. /*virtual*/ BOOL IsDefaultImpl() const
  679. {
  680. return FALSE;
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Name: CpuidImpl::NumberOfProcessCores
  684. // Desc: Gets the number of processor cores available to the current process.
  685. // The total accounts for cores that may have been masked out by process
  686. // affinity.
  687. //-----------------------------------------------------------------------------
  688. /*virtual*/ DWORD NumberOfProcessCores() const
  689. {
  690. DWORD_PTR dwProcessAffinity, dwSystemAffinity;
  691. GetProcessAffinityMask( GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity );
  692. BYTE pkgCoreIds[MaxLogicalProcessors] = { 0 };
  693. DWORD nPkgCoreIds = 0;
  694. for( DWORD i = 0; i < m_nItems; ++i )
  695. {
  696. if( dwProcessAffinity & ( ( DWORD_PTR )1 << i ) )
  697. {
  698. AddUniquePkgCoreId_( i, pkgCoreIds, nPkgCoreIds );
  699. }
  700. }
  701. return nPkgCoreIds;
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Name: CpuidImpl::NumberOfSystemCores
  705. // Desc: Gets the number of processor cores on the system.
  706. //-----------------------------------------------------------------------------
  707. /*virtual*/ DWORD NumberOfSystemCores() const
  708. {
  709. BYTE pkgCoreIds[MaxLogicalProcessors] = { 0 };
  710. DWORD nPkgCoreIds = 0;
  711. for( DWORD i = 0; i < m_nItems; ++i )
  712. {
  713. AddUniquePkgCoreId_( i, pkgCoreIds, nPkgCoreIds );
  714. }
  715. return nPkgCoreIds;
  716. }
  717. //-----------------------------------------------------------------------------
  718. // Name: CpuidImpl::CoreAffinityMask
  719. // Desc: Gets an affinity mask that corresponds to a specific processor core.
  720. // coreIdx must be less than the total number of processor cores
  721. // recognized by the operating system (NumberOfSystemCores()).
  722. //-----------------------------------------------------------------------------
  723. /*virtual*/ DWORD_PTR CoreAffinityMask( DWORD coreIdx ) const
  724. {
  725. BYTE pkgCoreIds[MaxLogicalProcessors] = { 0 };
  726. DWORD nPkgCoreIds = 0;
  727. for( DWORD i = 0; i < m_nItems; ++i )
  728. {
  729. AddUniquePkgCoreId_( i, pkgCoreIds, nPkgCoreIds );
  730. }
  731. DWORD_PTR dwProcessAffinity, dwSystemAffinity;
  732. GetProcessAffinityMask( GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity );
  733. DWORD_PTR coreAffinity = 0;
  734. if( coreIdx < nPkgCoreIds )
  735. {
  736. for( DWORD i = 0; i < m_nItems; ++i )
  737. {
  738. if( m_apicExtractor.PackageCoreId( m_apicIds[i] ) == pkgCoreIds[coreIdx] )
  739. {
  740. coreAffinity |= ( dwProcessAffinity & ( ( DWORD_PTR )1 << i ) );
  741. }
  742. }
  743. }
  744. return coreAffinity;
  745. }
  746. //-----------------------------------------------------------------------------
  747. // Name: CpuidImpl::IsSupported
  748. // Desc: Indicates if a CpuidImpl object is supported on this platform.
  749. // Support is only granted on Intel and AMD platforms where the current
  750. // calling process has security rights to query process affinity and
  751. // change it if the process and system affinity differ. CpuidImpl is
  752. // also not supported if thread affinity cannot be set on systems with
  753. // more than 1 logical processor.
  754. //-----------------------------------------------------------------------------
  755. static BOOL IsSupported()
  756. {
  757. BOOL bSupported = Cpuid::IsVendor( GenuineIntel )
  758. || Cpuid::IsVendor( AuthenticAMD );
  759. if( bSupported )
  760. {
  761. DWORD_PTR dwProcessAffinity, dwSystemAffinity;
  762. HANDLE hProcess = GetCurrentProcess();
  763. // Query process affinity mask
  764. bSupported = GetProcessAffinityMask( hProcess, &dwProcessAffinity, &dwSystemAffinity );
  765. if( bSupported )
  766. {
  767. if( dwProcessAffinity != dwSystemAffinity )
  768. {
  769. // The process and system affinities differ. Attempt to set
  770. // the process affinity to the system affinity.
  771. bSupported = SetProcessAffinityMask( hProcess, dwSystemAffinity );
  772. if( bSupported )
  773. {
  774. // Restore previous process affinity
  775. bSupported = SetProcessAffinityMask( hProcess, dwProcessAffinity );
  776. }
  777. }
  778. if( bSupported && ( dwSystemAffinity > 1 ) )
  779. {
  780. // Attempt to set the thread affinity
  781. HANDLE hThread = GetCurrentThread();
  782. DWORD_PTR dwThreadAffinity = SetThreadAffinityMask( hThread, dwProcessAffinity );
  783. if( dwThreadAffinity )
  784. {
  785. // Restore the previous thread affinity
  786. bSupported = 0 != SetThreadAffinityMask( hThread, dwThreadAffinity );
  787. }
  788. else
  789. {
  790. bSupported = FALSE;
  791. }
  792. }
  793. }
  794. }
  795. return bSupported;
  796. }
  797. private:
  798. //-----------------------------------------------------------------------------
  799. // Name: CpuidImpl::AddUniquePkgCoreId_
  800. // Desc: Adds the package/core id extracted from the APIC ID at m_apicIds[idx]
  801. // in the if the package/core id is unique to the pkgCoreIds array.
  802. // nPkgCore is an in/out parm that will reflect the total number of items
  803. // in pkgCoreIds array. It will be incrememted if a unique package/core
  804. // id is found and added.
  805. //-----------------------------------------------------------------------------
  806. void AddUniquePkgCoreId_( DWORD idx, BYTE* pkgCoreIds, DWORD& nPkgCoreIds ) const
  807. {
  808. _ASSERT( idx < m_nItems );
  809. _ASSERT( NULL != pkgCoreIds );
  810. DWORD j;
  811. for( j = 0; j < nPkgCoreIds; ++j )
  812. {
  813. if( pkgCoreIds[j] == m_apicExtractor.PackageCoreId( m_apicIds[idx] ) )
  814. break;
  815. }
  816. if( j == nPkgCoreIds )
  817. {
  818. pkgCoreIds[j] = m_apicExtractor.PackageCoreId( m_apicIds[idx] );
  819. ++nPkgCoreIds;
  820. }
  821. }
  822. // Private Members
  823. BYTE m_apicIds[MaxLogicalProcessors];
  824. BYTE m_nItems;
  825. ApicExtractor m_apicExtractor;
  826. // Supported Vendor Strings
  827. static const char GenuineIntel[];
  828. static const char AuthenticAMD[];
  829. };
  830. // Static initialization of vendor strings
  831. const char CpuidImpl::GenuineIntel[] = "GenuineIntel";
  832. const char CpuidImpl::AuthenticAMD[] = "AuthenticAMD";
  833. } // unnamed-namespace
  834. //-------------------------------------------------------------------------------------
  835. // Name: CpuTopology::CpuTopology
  836. // Desc: Initializes this object with the appropriately supported cpu topology
  837. // implementation object.
  838. //-------------------------------------------------------------------------------------
  839. CpuTopology::CpuTopology( BOOL bForceCpuid ) : m_pImpl( NULL )
  840. {
  841. ForceCpuid( bForceCpuid );
  842. }
  843. //-------------------------------------------------------------------------------------
  844. // Name: CpuTopology::~CpuTopology
  845. //-------------------------------------------------------------------------------------
  846. CpuTopology::~CpuTopology()
  847. {
  848. Destroy_();
  849. }
  850. //-------------------------------------------------------------------------------------
  851. // Name: CpuTopology::NumberOfProcessCores
  852. // Desc: Gets the total number of physical processor cores available to the current
  853. // process.
  854. //-------------------------------------------------------------------------------------
  855. DWORD CpuTopology::NumberOfProcessCores() const
  856. {
  857. return m_pImpl->NumberOfProcessCores();
  858. }
  859. //-------------------------------------------------------------------------------------
  860. // Name: CpuTopology::NumberOfSystemCores
  861. // Desc: Gets the total number of physical processor cores enabled on the system.
  862. //-------------------------------------------------------------------------------------
  863. DWORD CpuTopology::NumberOfSystemCores() const
  864. {
  865. return m_pImpl->NumberOfSystemCores();
  866. }
  867. //-------------------------------------------------------------------------------------
  868. // Name: CpuTopology::CoreAffinityMask
  869. // Desc: Gets an affinity mask that corresponds to the requested processor core.
  870. //-------------------------------------------------------------------------------------
  871. DWORD_PTR CpuTopology::CoreAffinityMask( DWORD coreIdx ) const
  872. {
  873. return m_pImpl->CoreAffinityMask( coreIdx );
  874. }
  875. //-------------------------------------------------------------------------------------
  876. // Name: CpuTopology::IsDefaultImpl
  877. // Desc: Returns TRUE if m_pImpl is a DefaultImpl object, FALSE if not. Used to
  878. // indicate whether or not the prescribed methods (CPUID or
  879. // GetLogicalProcessorInformation) are supported on the system.
  880. //-------------------------------------------------------------------------------------
  881. BOOL CpuTopology::IsDefaultImpl() const
  882. {
  883. return m_pImpl->IsDefaultImpl();
  884. }
  885. //-------------------------------------------------------------------------------------
  886. // Name: CpuTopology::ForceCpuid
  887. // Desc: Constructs a cpu topology object. If bForce is FALSE, then a GlpiImpl object
  888. // is first attempted, then CpuidImpl, then finally DefaultImpl. If bForce is
  889. // TRUE, then GlpiImpl is never attempted.
  890. //-------------------------------------------------------------------------------------
  891. void CpuTopology::ForceCpuid( BOOL bForce )
  892. {
  893. Destroy_();
  894. if( !bForce && GlpiImpl::IsSupported() )
  895. {
  896. m_pImpl = new GlpiImpl();
  897. }
  898. else if( CpuidImpl::IsSupported() )
  899. {
  900. m_pImpl = new CpuidImpl();
  901. }
  902. else
  903. {
  904. m_pImpl = new DefaultImpl();
  905. }
  906. }
  907. //-------------------------------------------------------------------------------------
  908. // Name: CpuTopology::Destroy_
  909. //-------------------------------------------------------------------------------------
  910. void CpuTopology::Destroy_()
  911. {
  912. delete m_pImpl;
  913. m_pImpl = NULL;
  914. }
  915. #endif