« TMPGEnc 再質問回答 | メイン | 最大公約数 - ユークリッドの互除法 »

2008年02月05日

日常の備忘録:: CPU拡張命令とコア数

    

CPU拡張命令とコア数を調べるものを作ってみた。
ソースと実行ファイルをここにおいて置く。
OS は NT系のみ。
ソースの中身は以下と同じ。

Core 2 Duo E6750 と Athlon X2 64 3800+ で実行したら、正しいと思われるのが取得できているが、他でもきちんと動くかどうかわからない。
論理CPU数と物理コア数も両方2だし。
おかしかったら教えてもらえるとありがたいです。

#include <stdio.h>
#include <windows.h>
#include <intrin.h>

#define CPU_X86_MMX      (1<<0)
#define CPU_X86_3DNOW    (1<<1)
#define CPU_X86_3DNOWEXT (1<<2)
#define CPU_X86_MMXEXT   (1<<3)
#define CPU_X86_SSE      (1<<4)
#define CPU_X86_SSE2     (1<<5)
#define CPU_X86_SSE3     (1<<6)
#define CPU_X86_SSSE3    (1<<7)
#define CPU_X86_SSE41    (1<<8)
#define CPU_X86_SSE42    (1<<9)
#define CPU_X86_SSE4a    (1<<10)

enum CpuVendor {
  CPU_V_Unknown,
  CPU_V_Intel,
  CPU_V_AMD,
  CPU_V_Transmeta,
  CPU_V_Cyrix,
  CPU_V_IDT,
  CPU_V_Rise,
  CPU_V_NexGen,
  CPU_V_UMC,
  CPU_V_NSC,
  CPU_V_Compaq,
  CPU_V_EOT
};
void GetCpuid( int op, int& eax, int& ebx, int& ecx, int& edx)
{
  int info[4] = {0,0,0,0};
  __cpuid( info, op );
  eax = info[0];
  ebx = info[1];
  ecx = info[2];
  edx = info[3];
}
static int GetCpuVendor( int& max )
{
  enum CpuVendor  ret = CPU_V_Unknown;
  int eax, ebx, ecx, edx;
  GetCpuid( 0, eax, ebx, ecx, edx );
  max = eax;

#define MAKE_VENDOR_CODE( a, b, c, d )  ( ((d) << 24) | ((c) << 16) | ((b) << 8) | (a) )
  // GenuineIntel
  static const int Intel_EBX = MAKE_VENDOR_CODE( 'G', 'e', 'n', 'u' );
  static const int Intel_EDX = MAKE_VENDOR_CODE( 'i', 'n', 'e', 'I' );
  static const int Intel_ECX = MAKE_VENDOR_CODE( 'n', 't', 'e', 'l' );

  // AuthenticAMD
  static const int AMD_EBX = MAKE_VENDOR_CODE( 'A', 'u', 't', 'h' );
  static const int AMD_EDX = MAKE_VENDOR_CODE( 'e', 'n', 't', 'i' );
  static const int AMD_ECX = MAKE_VENDOR_CODE( 'c', 'A', 'M', 'D' );

  // GenuineTMx86
  static const int Transmeta_EBX = MAKE_VENDOR_CODE( 'G', 'e', 'n', 'u' );
  static const int Transmeta_EDX = MAKE_VENDOR_CODE( 'i', 'n', 'e', 'T' );
  static const int Transmeta_ECX = MAKE_VENDOR_CODE( 'M', 'x', '8', '6' );

  // CyrixInstead
  static const int Cyrix_EBX = MAKE_VENDOR_CODE( 'C', 'y', 'r', 'i' );
  static const int Cyrix_EDX = MAKE_VENDOR_CODE( 'x', 'I', 'n', 's' );
  static const int Cyrix_ECX = MAKE_VENDOR_CODE( 't', 'e', 'a', 'd' );

  // CentaurHauls
  static const int IDT_EBX = MAKE_VENDOR_CODE( 'C', 'e', 'n', 't' );
  static const int IDT_EDX = MAKE_VENDOR_CODE( 'a', 'u', 'r', 'H' );
  static const int IDT_ECX = MAKE_VENDOR_CODE( 'a', 'u', 'l', 's' );

  // RiseRiseRise
  static const int Rise_EBX = MAKE_VENDOR_CODE( 'R', 'i', 's', 'e' );
  static const int Rise_EDX = MAKE_VENDOR_CODE( 'R', 'i', 's', 'e' );
  static const int Rise_ECX = MAKE_VENDOR_CODE( 'R', 'i', 's', 'e' );

  // NexGenDriven
  static const int NexGen_EBX = MAKE_VENDOR_CODE( 'N', 'e', 'x', 'G' );
  static const int NexGen_EDX = MAKE_VENDOR_CODE( 'e', 'n', 'D', 'r' );
  static const int NexGen_ECX = MAKE_VENDOR_CODE( 'i', 'v', 'e', 'n' );

  // UMC UMC UMC 
  static const int UMC_EBX = MAKE_VENDOR_CODE( 'U', 'M', 'C', ' ' );
  static const int UMC_EDX = MAKE_VENDOR_CODE( 'U', 'M', 'C', ' ' );
  static const int UMC_ECX = MAKE_VENDOR_CODE( 'U', 'M', 'C', ' ' );

  // Geode By NSC
  static const int NSC_EBX = MAKE_VENDOR_CODE( 'G', 'e', 'o', 'd' );
  static const int NSC_EDX = MAKE_VENDOR_CODE( 'e', ' ', 'B', 'y' );
  static const int NSC_ECX = MAKE_VENDOR_CODE( 'N', 'S', 'C', ' ' );

  // Compaq FX32!
  static const int Compaq_EBX = MAKE_VENDOR_CODE( 'C', 'o', 'm', 'p' );
  static const int Compaq_EDX = MAKE_VENDOR_CODE( 'a', 'q', ' ', 'F' );
  static const int Compaq_ECX = MAKE_VENDOR_CODE( 'X', '3', '2', '!' );
#undef MAKE_VENDOR_CODE

  if( ebx == Intel_EBX && edx == Intel_EDX && ecx == Intel_ECX ) {
    ret = CPU_V_Intel;
  } else if( ebx == AMD_EBX && edx == AMD_EDX && ecx == AMD_ECX ) {
    ret = CPU_V_AMD;
  } else if( ebx == Transmeta_EBX && edx == Transmeta_EDX && ecx == Transmeta_ECX ) {
    ret = CPU_V_Transmeta;
  } else if( ebx == Cyrix_EBX && edx == Cyrix_EDX && ecx == Cyrix_ECX ) {
    ret = CPU_V_Cyrix;
  } else if( ebx == IDT_EBX && edx == IDT_EDX && ecx == IDT_ECX ) {
    ret = CPU_V_IDT;
  } else if( ebx == Rise_EBX && edx == Rise_EDX && ecx == Rise_ECX ) {
    ret = CPU_V_Rise;
  } else if( ebx == NexGen_EBX && edx == NexGen_EDX && ecx == NexGen_ECX ) {
    ret = CPU_V_NexGen;
  } else if( ebx == UMC_EBX && edx == UMC_EDX && ecx == UMC_ECX ) {
    ret = CPU_V_UMC;
  } else if( ebx == NSC_EBX && edx == NSC_EDX && ecx == NSC_ECX ) {
    ret = CPU_V_NSC;
  } else if( ebx == Compaq_EBX && edx == Compaq_EDX && ecx == Compaq_ECX ) {
    ret = CPU_V_Compaq;
  }
  return ret;
}
unsigned long GetCpuFeature( int& physicalCore )
{
  physicalCore = 1;

  int maxCpuId = 0;
  int vendor = GetCpuVendor( maxCpuId );

  unsigned long flags = 0;
  int eax, ebx, ecx, edx;
  GetCpuid( 0x80000000, eax, ebx, ecx, edx );
  int maxCpuIdEx = eax;

  int featureEx = 0, featureExEcx = 0;
  if( maxCpuIdEx > 0x80000000 ) {
    GetCpuid( 0x80000001, eax, ebx, ecx, edx );
    featureExEcx = ecx;
    featureEx = edx;
  }
  if( featureEx & (1<<22) ) flags |= CPU_X86_MMXEXT;
  if( featureEx & (1<<31) ) flags |= CPU_X86_3DNOW;
  if( featureEx & (1<<30) ) flags |= CPU_X86_3DNOWEXT;
  if( featureExEcx & (1<<6) ) flags |= CPU_X86_SSE4a;

  GetCpuid(1,eax,ebx,ecx,edx);
  int featureEcx = ecx;
  int feature = edx;

  if( feature & (1<<23) ) flags |= CPU_X86_MMX;
  if( feature & (1<<25) ) {
    if( vendor == CPU_V_Intel ) flags |= CPU_X86_SSE|CPU_X86_MMXEXT;
    else  flags |= CPU_X86_SSE;
  }
  if( feature & (1<<26) ) flags |= CPU_X86_SSE2;
  if( featureEcx & 1 ) flags |= CPU_X86_SSE3;
  if( featureEcx & (1<<9) ) flags |= CPU_X86_SSSE3;
  if( featureEcx & (1<<19) ) flags |= CPU_X86_SSE41;
  if( featureEcx & (1<<20) ) flags |= CPU_X86_SSE42;

  if( vendor == CPU_V_Intel && maxCpuId >= 0x00000004 ) {
    GetCpuid( 0x00000004, eax, ebx, ecx, edx );
    physicalCore = ((eax >> 26) & 0x3F) + 1;
  }

  if( vendor == CPU_V_AMD && maxCpuIdEx >= 0x80000008 ) {
    GetCpuid( 0x80000008, eax, ebx, ecx, edx );
    physicalCore = (ecx & 0xFF) + 1;
  }
  return flags;
}

#ifdef _TEST_
#include <iostream>
int main(int argc, char* argv[])
{
  int  logicalCore = 1;
  DWORD  pamask, samask;
  if( GetProcessAffinityMask( GetCurrentProcess(), &pamask, &samask) ) {
    unsigned long  ret;
    _BitScanReverse( &ret, pamask );
    logicalCore = ret+1;
  }
  int physicalCore = 1;
  unsigned long flag = GetCpuFeature( physicalCore );

  std::cout << "Logical core : " << logicalCore << std::endl;
  std::cout << "Physical core : " << physicalCore << std::endl;
  std::cout << "Supported feature :";
  if( flag & CPU_X86_MMX ) std::cout << " MMX";
  if( flag & CPU_X86_3DNOW ) std::cout << " 3DNow";
  if( flag & CPU_X86_3DNOWEXT ) std::cout << " 3DNowEx";
  if( flag & CPU_X86_MMXEXT ) std::cout << " MMX2";
  if( flag & CPU_X86_SSE ) std::cout << " SSE";
  if( flag & CPU_X86_SSE2 ) std::cout << " SSE2";
  if( flag & CPU_X86_SSE3 ) std::cout << " SSE3";
  if( flag & CPU_X86_SSSE3 ) std::cout << " SSSE3";
  if( flag & CPU_X86_SSE41 ) std::cout << " SSE4.1";
  if( flag & CPU_X86_SSE42 ) std::cout << " SSE4.2";
  if( flag & CPU_X86_SSE4a ) std::cout << " SSE4a";
  std::cout << std::endl;

  return 0;
}
#endif // _TEST_



投稿者 Takenori : 2008年02月05日 21:27




comments powered by Disqus
Total : Today : Yesterday : なかのひと