SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

CPUIDチュートリアル

CPUID命令によるプロセッサ環境の判別

プロセッサの種類の検出とパフォーマンスの検証

  • X ポスト
  • このエントリーをはてなブックマークに追加

SMP/HTT/Multicoreの検出

 ここまで実装して、「以下の条件で検出する場合、各プロセッサごとのCPUID情報は必要ないのではないか?」ということに気が付きました。

 前ページでの検討が若干無駄になりますが、以下の条件を元に、簡易版のSMP/HTT/Multicoreの検出を考えました。

  1. SMPは同一のCPUを用いていることを前提とする
  2. SMP環境下のCPUは全て同じものと考えます。例えば2つのCPUを物理的に搭載している場合、1つのCPUがHTT対応で、もう1つのCPUがHTT非対応、というケースは想定から外します。今の所、Intel/AMDともにSMPシステムを構築する場合、CPUは全て同じ種類のものを使用しなければならないとしています。
  3. 機能が有効であるならば使用されていることを前提とする
  4. 例えばMulticore/HTT機能が有効である場合、OSがこれを使用していると考えます。つまりMulticore/HTTが有効になっているにもかかわらず、これを使用しないケースは存在しないこととします。

 上記の考え方を前提とした場合、一番最初のCPU(任意のCPU)だけを見るだけで全体を把握して良い事になります。いわゆる手抜きです。

検出のアルゴリズム

 簡易版の検出方法のアルゴリズムについては、以下の通りです。

  1. OSが認識しているProcessor数の取得
  2. 準備編で使用したGetProcessAffinityMask()にて全体のProcessor数を取得します。
  3. Multicoreが有効である場合、Core数の取得
    1. Intel製CPU
    2. Multicoreが有効である場合、CPUID(4)のEAX(bit31-26)にCore数が記載されています。例えばbit31-26が1だった場合、Core数は1+1=2となります。ちなみにCPUID(4)を取得する場合、EDX=0にする必要があります。EDX=0以外の場合、Core数が保障できないようです。仕様書からは読み取りにくい部分なので注意してください。
    3. AMD製CPU
    4. CPUID(8000-0008)のECX(bit 7-0)にCore数が記載されています。例えばbit7-0が1だった場合、Core数は1+1=2となります。
    5. その他のCPU
    6. Multicoreはサポートされていないとして扱います。
  4. HTTが有効である場合、HTT数の取得
  5. HTTをサポートしているのはIntel製のCPUしかないので、Intel製以外のCPUはサポートされていないものとして扱います。簡易版の場合、HTTとMulticoreが混在する環境では正確に双方を区別する方法が見つかりませんでした。そこで全体の論理プロセッサ数からMulticoreのCore数を差し引くことでHTT数を検出することにしました。
    1. 論理プロセッサ数の取得
    2. CPUID(1)のEBX(bit 23-16)に論理プロセッサ数が記載されています。論理プロセッサ数はHTT+Coreを加えたものが反映されています。
    3. MulticoreのCore 数の取得
    4. 「Multicoreが有効である場合、Core数の取得」で取得したCore数を使用します。
    5. HTT 数の検出
    6. 今の所、論理プロセッサ数に影響があるのはHTTとMulticoreしかありません。よって、論理プロセッサ数からCore数を差し引いた値がHTT数となります。
      つまりHTTの数は「HTT 数 = 論理プロセッサ数 / Core 数」であらわすことが出来ます。
    以下はHTT検出関数です。大体の流れは、見れば分かると思います。
    内部関数GetHyperThreadingNum()のSource
    DWORD
    GetHyperThreadingNum(
        IN  PCPUID_INFOR pci,
        IN  DWORD cntcpu
        )
    {
        DWORD num = 0;
        DWORD llp = 0;
        DWORD core = 0;
        PCPUIDS_DATA pcpus = NULL;
    
        if( NULL == pci ){ return 0; }
    
        switch(GetCPUVendor(pci)){
        case CPUVENDOR_INTEL:
            num = 0;
            // Count Logical Processor number (HTT+core)
            if( !GetProcessorData(pci,cntcpu,
                CPUID_LOGICAL_PROCESSOR_NUM, &llp) ){
                break;
            }
            // HTT enable? (if Logical Processor is 1,
                    // then HTT is NOT working.)
            if( !IsFeature(pci,cntcpu,FLAG_CPUID_HTT) || llp<2 ){
                break;
            }
            // Get Multicore number
            core = GetMultiCoreNum(pci,cntcpu);
            if( 0 != core ){
                if( (llp/core) < 2 ){
                    break;
                }
            }
            num = llp;
            break;
        default:
            num = 0;
            break;
        }
    
        return num;
    }
    

 以下は添付のプログラム「sample.exe」を実行した時の出力結果です。「sample.exe」のソースは「src\x86work」にあります。プログラムを構築する場合、ソース中にある「sample.dsw」を使用してください。

HTT(2つ)をサポートしていた場合
Brand Srting = [              Intel(R) Pentium(R) 4 CPU 3.20GHz]
Total processor            = [2]
Physical  Processor number = [1]
Multicore Processor number = [0]
HTT       Processor number = [2]
マルチプロセッサ(2つ)と各々のプロセッサが HTT(2つ)をサポートしていた場合
Brand Srting = [                  Intel(R) Xeon(TM) CPU 2.80GHz]
Total processor            = [4]
Physical  Processor number = [2]
Multicore Processor number = [0]
HTT       Processor number = [2]
Multicore(2つ)をサポートしていた場合
Brand Srting = [              Intel(R) Pentium(R) D CPU 3.00GHz]
Total processor            = [2]
Physical  Processor number = [1]
Multicore Processor number = [2]
HTT       Processor number = [0]

簡易版の問題点

 簡易版の方針で示した前提条件が崩れた場合、正しくHTT/Multicoreを検出できなくなります。

  • 1.の前提が崩れる場合
  • 参考資料『Are Three Cores Better Than Two?』を見ると、プロセッサが 3つ認識された状態で動作しています。実際には異なるCPUなのですが、動作可能のようです。
    このような条件下の場合、簡易版ではプロセッサを誤検出してしまいます。ただし、このような条件は今後発生するとは思えませんし、実際、動作させるところまでが手一杯だったようです。
  • 2.の前提が崩れる場合
  • Windows 2000 Professionalで現象を確認しています。HTT/マルチプロセッサのどちらも有効なのですがプロセッサ数は2つしか認識されません。Windows 2000 ProfessionalのCPU動作条件は2プロセッサまでなのが原因であろうと思われます。Windows XPでは、同じ環境で問題なく4プロセッサとして認識出来ること確認しています。
    このような条件下の場合、簡易版ではHTTとして動作していると認識してしまいます。調査してみた所、実際にはマルチプロセッサの方が有効で、HTTの機能は有効であるにもかかわらず使用されていない状態のようでした。
    未確認ですが、OS起動時の設定ファイルである「boot.ini」にパラメータ「/numproc」を使用することでも、プロセッサ数を任意に変更することが可能のようです。

簡易版の改良のアドバイス

 今回は面倒だったので実装しませんでしたが、おそらく下記の方法で、上記の前提条件が無くても正しく検出できるはずです。HTT/Multicoreが両方搭載されている場合、若干面倒ですがLocalAPICの割り振られる規則を元に判断することは可能です。

  1. 全てのProcessorのCPUIDを取得
  2. 各ProcessorごとのLocalAPICを抽出
  3. LocalAPICとProcessor数より、論理プロセッサか物理プロセッサかどうかを判断し集計

まとめ

 仕様書の読み間違いや自らの思い込みにより、かなり回り道になってしまいましたが、大体当初の目的を果たせたのではないかと考えています。最後に私がはまったネタをいくつか披露しておきます。参考になれば幸いです。

  • HTTフラグ(CPUID(1)EDX bit-28)はHTTのみ有効?
  • 名前からしてみて当然HTTのみの対応かと思い違いをしていました。実際に確かめてみた所、Multicoreが有効だった場合でも有効でした。
  • Multicoreは論理プロセッサ?
  • 当初、CPUの作りからMulticoreは物理プロセッサであろうと思い込んでいました。実際に確かめてみた所、論理プロセッサとして認識されていました。論理プロセッサ数=HTT数と考えていただけに、かなり認識方法を変更せざるを得ませんでした。
  • Multicore数が返却されない?
  • Intel製CPUの場合、Multicoreが有効であるにもかかわらずMulticore数が0ということがありました。どうやらCPUID(4)での問い合わせは、入力値ECXが影響するようです。ECXを0に設定することで正しい値が返却されます。CPUIDの仕様は、入力はEAXのみに影響されるはずですが、CPUID(4)に限ってはECXが影響されるよう変更されているようです。

参考資料

 CPUID命令については、『CPUID命令によるCPUの性能・機能の把握』の参考資料を参照してください。

  1. Intel 『Hyper-Threading Technology and Multi-Core Processor Detection
  2. Hyper-Threading 機能と Multicore の違いを検出するアルゴリズムの解説があります。
  3. Intel 『Detecting Support for Hyper-Threading Technology Enabled Processors
  4. Hyper-Threading 機能の検出方法についてのサンプルプログラムが掲載されています。
  5. Tom's Hardware『Are Three Cores Better Than Two?
  6. 記事では「Dualcore 対応 CPU」+「Dualcore 非対応 CPU」の組み合わせで動作させています。このような状況でも一応、動作することを知った時は驚きました。
  7. @IT 『頭脳放談 第16回 x86を延命させる「Hyper-Threading Technology」、その魅惑の技術』 Massa POP Izumida 著、2001年9月
  8. HTTについて参考にしました。よく纏まっています。
  9. MSDN 『Using Visual C++ 2005 Express Edition with the Microsoft Platform SDK
  10. Visual C++ 2005 Express Edition(VC2005EE)でPlatform SDKを併用する方法についての記載があります。VC2005EEのデフォルトの設定環境では「windows.h」がインストールされていません。今回のサンプルプログラムは「windows.h」を必要とするので、サンプルプログラムを構築するには別途Platform SDKから「windows.h」を抽出する必要があります。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
CPUIDチュートリアル連載記事一覧

もっと読む

この記事の著者

Mc.N(エムシイエヌ)

SyncHack 管理人。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/247 2006/01/16 12:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング