Counter Strike : Global Offensive Source Code
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.

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