none
プロセッサアフィニティの挙動について RRS feed

  • 質問

  • いつもお世話になっております。
    以下、マイクロソフトのサイトにWOW64環境でのプロセッサアフィニティの挙動が記載されておりますが、これに関して3点ご質問させて頂きます。
    <https://docs.microsoft.com/ja-jp/windows/win32/winprog64/processor-affinity>

    (1) プロセッサアフィニティ設定時の上位32bitについて
    64bit Windowsで32bitアプリからSetProcessAffinityMask関数を呼び出した際は、
    上記サイトの「Functions that set processor affinity, such as SetThreadAffinityMask, restrict processors to the first 32 processors under WOW64.」
    に該当するかと思われますが、この場合アフィニティマスクの上位32bitはどのようになりますでしょうか?
    0埋めでしょうか?元の値を保持しますでしょうか?
    また、WOW64環境においては、GetProcessAffinityMask で取得したアフィニティマスクを
    そのままSetProcessAffinityMaskで設定した場合に、アフィニティマスクが同じになるとは限らないという認識で問題ないでしょうか?

    (2) 代替のAPIについて
    上記サイトによると、WOW64環境ではGetProcessAffinityMaskは論理和としてアフィニティマスクが取得されてしまうため、正確な情報が取得できません。
    64bit Windowsで32bitアプリから、プロセッサ64個分の全てのアフィニティを参照/設定する代替のAPIはありますでしょうか?(可能であれば、Win XP互換)
    下名が探したところ見つけることはできませんでした。
    無理やりですが、64bitアプリ(exe)を作り、そこ経由で64bit版のSetProcessAffinityMask/GetProcessAffinityMaskをコールすれば可能かと思いましたが可能でしょうか?
    (できるとしても多分やりませんが)

    (3) WOW64環境でのタスクマネージャの「関係の設定」について
    タスクマネージャの仕様になりますが、64bit Windowsでタスクマネージャから32bitアプリの「関係の設定」を開いた場合、
    33個以上のプロセッサを積んで入れば、その分(33個以上)のCPUが表示/設定できるのでしょうか?
    タスクマネージャ自身が64bitアプリだから、32bitアプリでも64個分のプロセッサアフィニティを参照できるのという理解でよいでしょうか?

    ※なお、プロセッサグループについては、今回の質問とは関係ないものと思っております。

    質問ばかりで申し訳ございませんが、ご存知の方がいらっしゃいましたら、
    部分的な回答でも問題ありませんので、ご回答のほど誠によろしくお願い致します。
    2020年5月29日 3:08

すべての返信

  • (1) プロセッサアフィニティ設定時の上位32bitについて
    SetProcessAffinityMask() API 2nd Parameter は DWORD_PTR であり、この Data Type は 32/64 ビット各プロセスで、Data Size が異なります。
    下記は Windows 10 x64 環境で、32/64 ビット各プロセスでの DWORD_PTR の Data Size を、デバッガ上で確認した結果です。
    ----------------------------------
    <32 Bit Process>
    0:009> ??sizeof(DWORD_PTR)
    unsigned int 4

    <64 Bit Process>
    0:007> ??sizeof(DWORD_PTR)
    unsigned int64 8
    ----------------------------------
    従って 32 ビット プロセスには、「上位32bit」は存在しないはずです。

    (2) 代替のAPIについて
    Affinity Mask が示す値はビット マップです。
    Processor 0 が Affinity Mask Bit 0、Processor 1 が Affinity Mask Bit 1 と、各ビットが各プロセッサ (CPU) に対応しています。
    WOW64 配下で動作する 32 ビット プロセスは "Processor Affinity Under WOW64" でも明記されている様に、最大でも Processor 0 から Processor 31 までの最初の 32 個に制限されるようシミュレートされるとのことから、Processor 32 以降に割り当てられることはないと考えれます。

    (3) WOW64環境でのタスクマネージャの「関係の設定」について
    環境が無いので確認したわけではありませんが、"Processor Affinity Under WOW64" でも明記されていることから、WOW64 配下で動作する 32 ビット プロセスに対し 33 個以上の CPU 設定が表示されることは無いと思います。
    2020年5月29日 6:13
  • そもそも、そのページに書いてあるとおり simulate a computer with 32 processors when called under WOW64なのです。
    1.上位は0です。64bit側apiで32-63bitを立てていた場合、wow64でSet(Get)と呼んでも戻りません。
    2.wow64上では、ありません。なんらかのipc経由でwin64側のApiを叩けば可能です。
    3.手元のserver 2016では、タスクマネージャー上で、wow64 processに対して、64まで関係の設定は出来ます。

    jzkey

    2020年6月1日 3:34
  • > 2.wow64上では、ありません。なんらかのipc経由でwin64側のApiを叩けば可能です。
    > 3.手元のserver 2016では、タスクマネージャー上で、wow64 processに対して、64まで関係の設定は出来ます。

    これら↑は、32 Bit Process 内の Thread でも、Processor 32 - 63 への割り当てが可能ということでしょうか?
    可能である場合は、それをどのように検証されたのでしょか?

    (質問者でないのに質問してしまって申し訳ありませんが、その確認方法を教えて欲しかったので。)

    2020年6月1日 5:01
  • 56 threadのpc上で、while(1) SwitchToThread();なスレッドを64個発生させ、taskmgrの関係性の設定したりapi叩いたりして、Cpu使用率をみました。
    ただ、実施したのはあくまでprocess affinity apiで、threadのはいじってませんが、同じこととは思います。

    jzkey

    2020年6月1日 5:20
  • > 56 threadのpc上で、while(1) SwitchToThread();なスレッドを64個発生させ、
    > taskmgrの関係性の設定したりapi叩いたりして、Cpu使用率をみました。
    > ただ、実施したのはあくまでprocess affinity apiで、
    > threadのはいじってませんが、同じこととは思います。

    返信ありがとうございます。
    実施された内容は、任意の Process 内で起動している Thread の個数に関連した検証であって、それら Thread がどの Processor 上で実行されているかとは別次元の話だと思います。
    2020年6月1日 5:31
  • 例えば、wow64のprocess affinityが(=win64apiから触ろうが)32個分しかないとすれば、56 cpuマシンにおいてタスクマネージャーの総cpu使用率は100%になりえません。threadはaffinityのないcpuでは動けないので、24個のcpuでは負荷は0%になるためです。
    実際には、win64apiで触ると100%にでき、wow64のapiで触ると60%程度にしか出来ません。その意味で、同次元と思いますが。

    jzkey

    2020年6月1日 6:04
  • > 例えば、wow64のprocess affinityが(=win64apiから触ろうが)32個分しかないとすれば、
    > 56 cpuマシンにおいてタスクマネージャーの総cpu使用率は100%になりえません。
    > threadはaffinityのないcpuでは動けないので、24個のcpuでは負荷は0%になるためです。

    32 Bit Process の場合でも、個々の Process 内に 33 個以上の Thread の生成は可能です。
    実際、32 Bit OS 環境下でも Explorer 等の主要プロセス内には、通常の状態であっても 100 個近い (場合によっては 100 個以上の) Thread が生成されています。
    提示された検証方法が正しいのであれば、Explorer Process の CPU 使用率は、常に 100% でなければ辻褄が合わないと思います。

    また、Task Manager で表示される CPU の利用率は、概ね 1sec 間隔での平均値だと思います。
    PC 上で起動している全ての Thread は、NT カーネルから割り当てられる Quantum 値 (タイムスライス) 以上の CPU 占有は出来ませんが、ざっくり計算しても1つの Thread に割り当てられるタイムスライスの最大値は概ね 100ms 程度だと考えれらます。
    さらに Task Manager での CPU 使用率の更新間隔の間には、当然各種ハードウェア割り込み処理 (クロック, マウス etc.) が発生し、それらリクエストはソフトウェア処理よりも優先され、CPU リソースを消費します。
    従って、Task Manager CPU 使用率の目視確認で、個々の Thread が動作している Processor を判断することは不可能だと思います。

    • 編集済み お馬鹿 2020年6月1日 7:01
    2020年6月1日 6:59
  • まずそもそも試験の目的はWOW64で生えてきたthteadのアフィニティが32なのか64なのか、という事です。
    私は、本質的にはMASKは64個あり、WOW64のAPIで触るときのみ(APIが32bitなので)、その上位32bitは0になる、と主張しています。
    前回の返信について、while(1) SwitchToThread();なスレッドを64個発生させた、というのが大前提です。(別にwhile(1);でもいいですが。要はビジーループだ、というわけです)

    なので、Explorerが100個スレッドを生成しているとか言われましても、比較できないわけですね。ExplorerのスレッドのほとんどはWaitFor~とかでなにかを待っているだけですので(ExplorerがビジーループなどのCPUインテンシブなスレッドを100個も生成しているなら、ウイルスチェックなどをお勧めしますヨ)

    Quantumとかタイムスライスも、教科書的にはその通りですが、それには「他にCPUを必要とするスレッドが幾らでも居る」前提がつきます。別に裏でCineBenchを動かしているわけでもないですから。CPUを(むやみに)ほしがるスレッドは自分以外にはない、と言っていいですよね。ビジーループなthreadが1s中の100msしかCPUを使えないなら、残り900msは何をしているんですか?寝ているのですか?

    ハードウエア割り込み云々については、マウスとかキーボードとかの割り込みでCPUが何秒も占拠されてしまうような30年まえのハードウエアならいざ知らず、現代のPCでは誤差でしょう。


    jzkey

    2020年6月1日 10:28
  • > 私は、本質的にはMASKは64個あり、WOW64のAPIで触るときのみ(APIが32bitなので)、
    > その上位32bitは0になる、と主張しています。

    「WOW64のAPIで触るときのみ」とは、どのような意味でしょうか?
    その前提がよくわかりません。
    32 Bit Process の対となる 64 Bit Process のことを言っているのでしょうか?
    その場合、対となる 64 Bit Process にどうやって Affinity Mask をセットするのでしょうか?
    私には「IPC 経由」でやる方法が思い浮かびませんでした。

    > CPUを(むやみに)ほしがるスレッドは自分以外にはない、
    > と言っていいですよね。
    > ビジーループなthreadが1s中の100msしかCPUを使えないなら、
    > 残り900msは何をしているんですか?寝ているのですか?

    その認識が、私とは全く異なります。
    CPU の使用率が低い状態でも、システムには数百のスレッドが生成された状態にあり、常に何らかの処理を行っています。
    "Process Monitor" でキャプチャすれば、一目瞭然です。
    一度 CPU 使用率の低い状態での「完全メモリ ダンプ」を採取して、そのダンプ内にどれほどの Thread が記録されているか、確認したほうがいいと思います。

    そもそも私の疑問は、下記一点のみです。
    > 例えば、wow64のprocess affinityが(=win64apiから触ろうが)32個分しかないとすれば、
    > 56 cpuマシンにおいてタスクマネージャーの総cpu使用率は100%になりえません。
    > threadはaffinityのないcpuでは動けないので、24個のcpuでは負荷は0%になるためです。
    上記見解は即ち、
    「システム全体で生成されている Thread の総数が CPU 個数を上回った場合、CPU 使用率は 100% なる。」
    と同義であるということですか?
    同義であるというなら、その認識自体がおかしいと思います。
    同義でないなら、どこが違うのか明確にしていただきたいです。
    どっちなんですか?
    2020年6月2日 2:50
  • SetProcessAffinityMaskは、第一引数でprocess handleを取ります。Win64api経由での設定とは、別建ての64bit processが、対象の32bit processをOpenProcessして、当該apiを呼ぶ話です。taskman(64bit)の「関係の設定」でも同じでしょう。
    肝心なのは、64bit processが、32bit processのprocess affinityを設定するということです。ま、逆は出来ませんね。

    > システムには数百のスレッドが生成された状態にあり、常に何らかの処理を行っています
    何百スレッドが常になんらかの処理をしているなら、定義からしてcpu使用率は高くなるわけですが。いくつスレッドがあろうと、ほぼ寝ているから使用率は低くなります

    >「システム全体で生成されている Thread の総数が CPU 個数を上回った場合、CPU 使用率は 100% なる。」
    全然違います。いうなら、「システムが全般的に十分暇なとき(=cpu使用率が0-1%のとき)、1つのprocessがビジーループするThreadをcpu個数以上たてたら、そのprocessが利用できるcpu個数(process affinityやprocessor groupによる制限)が、cpu利用率から推定できる」ですか。

    jzkey

    2020年6月2日 3:51
  • > SetProcessAffinityMaskは、第一引数でprocess handleを取ります。
    > Win64api経由での設定とは、別建ての64bit processが、
    > 対象の32bit processをOpenProcessして、当該apiを呼ぶ話です。
    その方法で Affinity Mask の設定が可能である場合、矛盾が発生すると思います。
    例えば、32 Bit Process が SetThreadAffinityMask() で自身の Affinity を設定している場合に、外部 64 Bit Process から同様に SetThreadAffinityMask() で設定されてしまうと、以降 32 Bit Process からの GetThreadAffinityMask() では正しい Affinity Mask が取得できないことになると思います。
    この矛盾を説明するために、質問者さんが提示した "Processor Affinity Under WOW64" のドキュメントが公開されている、というのが私の認識です。
    つまり、"Processor Affinity Under WOW64" ドキュメントでは "unctions such as GetProcessAffinityMask simulate a computer with 32 processors when called under WOW64." と関数コールに限定した記述になっていますが、"under WOW64" の対象は 1st Parameter で 32 Bit Prrocess を指定したケース全般のことを説明しているんだと考えています。
    提示された方法での SetProcessAffinityMask() コールは、成功しているのでしょうか?

    > いくつスレッドがあろうと、ほぼ寝ているから使用率は低くなります
    Windows システムでは多数のサービス プロセスが多数のスレッドを起動させていますし、Task Manager では表示されませんが System プロセスは常に数百の Thread を稼働させています。
    CPU 使用率が低いから「ほぼ寝ている」という認識になるのか、私にはわかりません。
    先にも説明したように、"Process Monitor" でキャプチャすれば、CPU 使用率が低い状態でもサービス等のプロセスが常にファイル/レジストリ等のリソースにアクセスしていることが確認できるはずです。
    さらにデバッガをカーネル モード接続してトレースすれば、System プロセス内のほとんどの Thread が寝ていないことも確認できるはずです。

    >「システムが全般的に十分暇なとき(=cpu使用率が0-1%のとき)、
    > 1つのprocessがビジーループするThreadをcpu個数以上たてたら、
    > そのprocessが利用できるcpu個数(process affinityやprocessor groupによる制限)が、
    > cpu利用率から推定できる」
    なぜ自アプリ スレッドの挙動のみで CPU 割り当てを推測できるのか、私には理解できません。
    例えば自アプリを起動させ負荷をかけた場合、たとえそれが「ビジーループするThread」であったとしても、そのプロセスが「単体」だけで動くことはあり得ません。
    自アプリ起動に応じて、System プロセス内に何らかの Worker Thread が生成される可能性がありますし、セキュリティ ソフトのサービスがそのアプリ プロセスの監視を始めるかもしれません。
    つまり自アプリの実行に伴い、関連するサービスや System の Thread が併せて動作することになるはずです。
    また System プロセス (ntoskrnl.exe) 内の Thread に対しては Affinity Mask の設定は不可能ですし、主要サービス (smss.exe, csrss.exe, services.exe, etc.) は Affinity Mask の設定を許容していません。
    つまり、自アプリ以外の Thread が Processor 33 以降の CPU リソースを使用している可能性は十分に考えられるはずですし、自アプリ以外のスレッドが「寝ている」とする根拠も私にはわかりませんでしたし、それらの影響を考慮しない目視で CPU の割り当てを推定できると断言できる理由もわかりませんでした。
    2020年6月2日 7:57
  • 一つ目のご質問に関しましては、わたくし、実際にWindows Server2016で実行した結果を申し上げているわけでして、もちろん実装詳細につきましては、以降のwindowsなどでは、変更されているかもしれませんが、Server2016におきましては、その仰る、矛盾した動作をしておりますし、どころか最初からGetPricessAffinityMaskで正しい結果など、ある意味とれてはいないわけであります。
    二つ目のご質問ですが、そもそもほぼ寝ていないスレッドが多数あるにもかかわらず、Cpu使用率が低いなどという方こそ、全く理解に苦しむ事態でありまして、そのような使用率とは、一体どのように算定されるのか、教えていだだきたいところで、あります。
    三つ目のご指摘ですが、確認したところ、システム全体のcpu使用率は、当該プロセス単体のcpu使用率とほぼ同一であったことを、ここでお伝え申し上げます。

    jzkey

    2020年6月2日 8:51
  • > 矛盾した動作をしておりますし、
    > どころか最初からGetPricessAffinityMaskで正しい結果など、
    > ある意味とれてはいないわけであります。
    ???
    jzkey さんは私とは真逆の、「なんらかのipc経由でwin64側のApiを叩けば可能」との見解だったからこそ、その根拠をご教授いただきたくお伺いしてきたわけですが、「可能/不可能」の一体どっちなんですか?
    MS のモデレータさんも jzkey さんの見解が正しいと判断されたようですが、私には可能であるとする理由が未だにわかりません。
    MS モデレータとして、jzkey さんの返信を回答候補に設定された Haruka6002 さんの見解もぜひお伺いしたいです。
    MS モデレータという立場であれば、私を含めた外部の人間よりは「はるかに」正確な情報を基に判断されているはずなので、「回答の候補に設定」をポチッするだけでなく、その情報を発信してほしいものです。

    > そもそもほぼ寝ていないスレッドが多数あるにもかかわらず、
    > Cpu使用率が低いなどという方こそ、
    > 全く理解に苦しむ事態でありまして、
    > そのような使用率とは、
    > 一体どのように算定されるのか、
    > 教えていだだきたいところで、あります。
    CPU 使用率算出の概要については、下記サイトに説明があります。
    ----------------------------------------
    Analyze CPU usage
    https://docs.microsoft.com/ja-jp/visualstudio/profiling/cpu-usage?view=vs-2019

    CPU 使用率を確認するパフォーマンス カウンターについて
    https://docs.microsoft.com/ja-jp/archive/blogs/askcorejp/processor_information
    ----------------------------------------
    何度も書いていますが、「寝ていないスレッド」の存在の有無で判断している訳ではありません。
    (私が読んだ限り、上記サイトでの説明でも、そんな判断基準に言及している記述は見当たりません。)
    上記サイトでは、CPU 使用率を算出する代表的な Performance Counter として以下が挙げられています。
    ☆ Processor Time
    ☆ Privileged Time
    ☆ User Time
    ☆ Interupt Time
    ☆ DPC Time
    ☆ Idle Time
    上記以外にも、各種 Worker Queue (特に System Process 内の System Worker Queue) にキューイングされている Pending 状態のリクエスト数等も加味されるはずです。
    ちなみに、jzkey さんが「誤差」だと言っているハードウェア割込み関連 ("Interupt Time", "DPC Time") の Performance Counter も、CPU 使用率算出の基になる重要な要素の一つです。

    > システム全体のcpu使用率は、
    > 当該プロセス単体のcpu使用率とほぼ同一であった
    何度も書いていますが、個々のプロセスの CPU 使用率と、その Process 内の Thread が稼働している CPU に相関関係などないというのが私の見解であり、その根拠は先述した通りです。
    自プロセス内のスレッドにのみ着目し、他プロセスが生成するスレッドの影響を無視し、「GetPricessAffinityMaskで正しい結果などある意味とれてはいない」状態での目視による CPU 使用率の確認にどのような意味があるのか、私にはやっぱりわかりませんでした。

    • 編集済み お馬鹿 2020年6月3日 3:22
    2020年6月3日 3:22
  • どうも、キリがないようてすの最後にします。あとはご自分で納得いくまでご検証くださるか、どのような検証が必要かおしえてもらえます、
    >例えば、32 Bit Process が SetThreadAffinityMask() で自身の Affinity を設定している場合に、外部 64 Bit Process から同様に SetThreadAffinityMask() で設定されてしまうと、以降 32 Bit Process からの GetThreadAffinityMask() では正しい Affinity Mask が取得できないことに
    そのようになる、なった、と私は一貫して主張しています。正確には外部64 bit processの与えた64個に対し、自分/32 bit processからは下位32個分のみしか取れない。外部64 bit processからなら、64個正しく取れる。
    最後についても、ほかのthread/process/dpc/interruptが使用するcpu時間が無視できるくらい低いからこそ、自プロセスの個別使用率が100%になります。また、もしかしたら別にremote threadが生える可能性も否定しませんが、結論に差はありません。

    jzkey


    • 回答の候補に設定 jzkey 2020年6月3日 5:27
    • 回答の候補の設定解除 jzkey 2020年6月3日 5:27
    • 編集済み jzkey 2020年6月3日 5:27
    2020年6月3日 5:09
  • jzkey さんご自身が、自分の返信内容は一貫しているとお考えなら、確かにこれ以上聞いても無駄のようですね。
    また「そもそもほぼ寝ていないスレッドが多数あるにもかかわらず、Cpu使用率が低いなどという方こそ、全く理解に苦しむ」とのことから、その解となるサイトを提示しましたが、そちらもきちんとご確認いただけなかったようで残念です。
    2020年6月3日 8:44