51

Windows、Mac、およびいくつかの Linux フレーバーで実行されるマルチスレッドの C++ アプリケーションがあります。

簡単に言うと、最大の効率で実行するには、物理​​プロセッサ/コアごとに 1 つのスレッドをインスタンス化できる必要があります。物理プロセッサ/コアよりも多くのスレッドを作成すると、プログラムのパフォーマンスが大幅に低下します。これら 3 つのプラットフォームすべてで、論理プロセッサ/コアの数を正しく正しく検出できます。物理プロセッサ/コアの数を正しく検出できるようにするには、ハイパートレッディングがサポートされていてアクティブかどうかを検出する必要があります。

したがって、私の質問は、ハイパー スレッディングがサポートされ、有効になっているかどうかを検出する方法があるかどうかです。もしそうなら、どのように正確に。

4

14 に答える 14

30

編集: これは Intel の進行中の混乱により、もはや 100% 正しくありません。

私が質問を理解する方法は、システム内の論理コアと物理コアの数を検出するのとは異なる、CPU コアと CPU スレッドの数を検出する方法を尋ねているということです。CPU コアは、独自のパッケージまたはダイがない限り、OS によって物理コアと見なされないことがよくあります。たとえば、OS は Core 2 Duo に 1 つの物理 CPU と 2 つの論理 CPU があると報告し、ハイパースレッドを備えた Intel P4 はまったく同じように報告されますが、2 つのハイパースレッド対 2 つの CPU コアは非常にパフォーマンスに関しては別物です。

以下のソリューションを組み合わせるまで、私はこれに苦労しました。これは、AMD プロセッサと Intel プロセッサの両方で機能すると信じています。私の知る限り、AMD にはまだ CPU スレッドがありませんが、CPU スレッドを持つ可能性のある将来の AMD プロセッサで動作すると思われるそれらを検出する方法を提供しています。

簡単に言えば、CPUID 命令を使用する手順は次のとおりです。

  1. CPUID 関数 0 を使用して CPU ベンダーを検出する
  2. CPU ID 機能 1 からの CPU 機能 EDX の HTT ビット 28 を確認します。
  3. CPUID 関数 1 から EBX[23:16] から論理コア数を取得します。
  4. 実際の非スレッド CPU コア数を取得する
    1. vendor == 'GenuineIntel' の場合、これは 1 に CPUID 関数 4 の EAX[31:26] を加えたものです。
    2. vendor == 'AuthenticAMD' の場合、これは CPUID 関数 0x80000008 からの 1 プラス ECX[7:0] です。

難しそうに聞こえますが、うまくいけば、このトリックを実行するプラットフォームに依存しない C++ プログラムを次に示します。

#include <iostream>
#include <string>

using namespace std;


void cpuID(unsigned i, unsigned regs[4]) {
#ifdef _WIN32
  __cpuid((int *)regs, (int)i);

#else
  asm volatile
    ("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
     : "a" (i), "c" (0));
  // ECX is set to zero for CPUID function 4
#endif
}


int main(int argc, char *argv[]) {
  unsigned regs[4];

  // Get vendor
  char vendor[12];
  cpuID(0, regs);
  ((unsigned *)vendor)[0] = regs[1]; // EBX
  ((unsigned *)vendor)[1] = regs[3]; // EDX
  ((unsigned *)vendor)[2] = regs[2]; // ECX
  string cpuVendor = string(vendor, 12);

  // Get CPU features
  cpuID(1, regs);
  unsigned cpuFeatures = regs[3]; // EDX

  // Logical core count per CPU
  cpuID(1, regs);
  unsigned logical = (regs[1] >> 16) & 0xff; // EBX[23:16]
  cout << " logical cpus: " << logical << endl;
  unsigned cores = logical;

  if (cpuVendor == "GenuineIntel") {
    // Get DCP cache info
    cpuID(4, regs);
    cores = ((regs[0] >> 26) & 0x3f) + 1; // EAX[31:26] + 1

  } else if (cpuVendor == "AuthenticAMD") {
    // Get NC: Number of CPU cores - 1
    cpuID(0x80000008, regs);
    cores = ((unsigned)(regs[2] & 0xff)) + 1; // ECX[7:0] + 1
  }

  cout << "    cpu cores: " << cores << endl;

  // Detect hyper-threads  
  bool hyperThreads = cpuFeatures & (1 << 28) && cores < logical;

  cout << "hyper-threads: " << (hyperThreads ? "true" : "false") << endl;

  return 0;
}

Windows または OSX でこれを実際にテストしたことはまだありませんが、CPUID 命令は i686 マシンで有効であるため、動作するはずです。明らかに、これは PowerPC では機能しませんが、ハイパースレッドもありません。

以下は、いくつかの異なる Intel マシンでの出力です。

Intel(R) Core(TM)2 Duo CPU T7500 @ 2.20GHz:

 logical cpus: 2
    cpu cores: 2
hyper-threads: false

Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz:

 logical cpus: 4
    cpu cores: 4
hyper-threads: false

Intel(R) Xeon(R) CPU E5520 @ 2.27GHz (x2 物理 CPU パッケージ付き):

 logical cpus: 16
    cpu cores: 8
hyper-threads: true

Intel(R) Pentium(R) 4 CPU 3.00GHz:

 logical cpus: 2
    cpu cores: 1
hyper-threads: true
于 2010-06-21T06:36:50.807 に答える
24

これは、意図した物理コアの数ではなく、論理コアの数であることに注意してください。

C++11 を使用できる場合 (以下の alfC のコメントに感謝します):

#include <iostream>
#include <thread>

int main() {
    std::cout << std::thread::hardware_concurrency() << std::endl;
    return 0;
}

それ以外の場合は、Boost ライブラリがオプションになります。上記と同じコードですが、インクルードが異なります。<boost/thread.hpp>の代わりに含めます<thread>

于 2010-05-27T13:44:25.673 に答える
18

ここに記載されている Windows のみのソリューション:

GetLogicalProcessorInformation

Linux の場合、/proc/cpuinfo ファイル。私は現在 Linux を実行していないため、詳細を説明することはできません。物理/論理プロセッサ インスタンスをカウントできます。論理カウントが物理カウントの 2 倍の場合、HT が有効になっています (x86 の場合のみ)。

于 2010-05-26T00:48:56.597 に答える
9

上記のアイデアのいくつかからアイデアとコンセプトを収集して、このソリューションを思いつきました。批評してください。

//EDIT INCLUDES

#ifdef _WIN32
    #include <windows.h>
#elif MACOS
    #include <sys/param.h>
    #include <sys/sysctl.h>
#else
    #include <unistd.h>
#endif

ほとんどすべての OS で、標準の「コア数の取得」機能は論理コア数を返します。ただし、物理コア数を取得するには、まず CPU にハイパー スレッディングがあるかどうかを検出する必要があります。

uint32_t registers[4];
unsigned logicalcpucount;
unsigned physicalcpucount;
#ifdef _WIN32
SYSTEM_INFO systeminfo;
GetSystemInfo( &systeminfo );

logicalcpucount = systeminfo.dwNumberOfProcessors;

#else
logicalcpucount = sysconf( _SC_NPROCESSORS_ONLN );
#endif

これで論理コア数がわかりました。意図した結果を得るには、まずハイパー スレッディングが使用されているかどうか、または使用可能かどうかを確認する必要があります。

__asm__ __volatile__ ("cpuid " :
                      "=a" (registers[0]),
                      "=b" (registers[1]),
                      "=c" (registers[2]),
                      "=d" (registers[3])
                      : "a" (1), "c" (0));

unsigned CPUFeatureSet = registers[3];
bool hyperthreading = CPUFeatureSet & (1 << 28);

1つのコアのみをハイパースレッディングするハイパースレッディングを備えたIntel CPUがないためです(少なくとも私が読んだものからではありません)。これにより、これが本当に痛みのない方法であることがわかります。ハイパー スレッディングが利用可能な場合、論理プロセッサは物理プロセッサのちょうど 2 倍になります。それ以外の場合、オペレーティング システムはすべてのシングル コアの論理プロセッサを検出します。つまり、論理コア数と物理コア数は同じになります。

if (hyperthreading){
    physicalcpucount = logicalcpucount / 2;
} else {
    physicalcpucount = logicalcpucount;
}

fprintf (stdout, "LOGICAL: %i\n", logicalcpucount);
fprintf (stdout, "PHYSICAL: %i\n", physicalcpucount);
于 2015-04-21T01:22:21.000 に答える
5

これが古いスレッドであることは知っていますが、誰もhwlocについて言及していません。hwloc ライブラリは、ほとんどの Linux ディストリビューションで利用でき、Windows でもコンパイルできます。次のコードは、物理プロセッサの数を返します。i7 CPU の場合は 4。

#include <hwloc.h>

int nPhysicalProcessorCount = 0;

hwloc_topology_t sTopology;

if (hwloc_topology_init(&sTopology) == 0 &&
    hwloc_topology_load(sTopology) == 0)
{
    nPhysicalProcessorCount =
        hwloc_get_nbobjs_by_type(sTopology, HWLOC_OBJ_CORE);

    hwloc_topology_destroy(sTopology);
}

if (nPhysicalProcessorCount < 1)
{
#ifdef _OPENMP
    nPhysicalProcessorCount = omp_get_num_procs();
#else
    nPhysicalProcessorCount = 1;
#endif
}
于 2015-04-02T14:06:17.093 に答える
0

これは Python で非常に簡単に実行できます。

$ python -c "import psutil; psutil.cpu_count(logical=False)"
4

psutilソースコードを見て、何が起こっているのかを確認 できますか?

于 2016-06-03T16:26:26.233 に答える
0

3つすべてが同じ方法で情報を公開するかどうかはわかりませんが、NTカーネルがPOSIX標準(NTがサポートしていると思われる)に従ってデバイス情報を報告すると安全に想定できる場合は、それを解決できます標準。

ただし、デバイス管理の違いは、クロスプラットフォーム開発の障害の 1 つとしてよく挙げられます。せいぜいこれを 3 つのロジック ストランドとして実装するだけで、すべてのプラットフォームを均等に処理するために 1 つのコードを記述しようとはしません。

わかりました、すべて C++ を想定しています。ASM については、x86 または amd64 CPU でのみ実行されると思いますか? アーキテクチャごとに 1 つずつ、2 つの分岐パスが引き続き必要です。AMD (IIRC) とは別に Intel をテストする必要がありますが、概して、CPUID を確認するだけです。それはあなたが見つけようとしているものですか?Intel/AMD ファミリー CPU の ASM からの CPUID は?

于 2010-05-25T03:07:29.650 に答える
0

OpenMP はトリックを行う必要があります。

// test.cpp
#include <omp.h>
#include <iostream>

using namespace std;

int main(int argc, char** argv) {
  int nThreads = omp_get_max_threads();
  cout << "Can run as many as: " << nThreads << " threads." << endl;
}

ほとんどのコンパイラは OpenMP をサポートしています。gcc ベースのコンパイラ (*nix、MacOS) を使用している場合は、次を使用してコンパイルする必要があります。

$ g++ -fopenmp -o test.o test.cpp

(コンパイラに stdc++ ライブラリを使用するように指示する必要がある場合もあります):

$ g++ -fopenmp -o test.o -lstdc++ test.cpp

私の知る限り、OpenMP はこの種の問題を解決するように設計されています。

于 2012-09-27T22:05:49.047 に答える