世界を動かす技術を、日本語で。

%CPU使用率は誤解である

概要

  • サーバーの CPU利用率 と実際の処理能力の関係に関する検証
  • stress-ng を用いたベンチマークテストの結果分析
  • ハイパースレッディングターボブースト の影響
  • CPU利用率の 直線的増加の誤解 について解説
  • 適切なパフォーマンス評価方法の提案

CPU利用率と実際のパフォーマンスの乖離

  • サーバー管理では CPU・メモリ・ネットワーク利用率 が注目される傾向

  • 一般的に「CPU利用率50%なら倍の処理が可能」と考えられがち

  • 実際には CPU利用率の増加が直線的ではない 現象

  • stress-ngを用いて 様々なワークロード でベンチマークを実施

  • Ubuntu+Ryzen 9 5900X(12コア/24スレッド)環境、Precision Boost Overdrive有効化

    • 24ワーカーで1〜100%利用率をテスト
    • 1〜24ワーカーで100%利用率をテスト
    • 各テストで「Bogo ops(完了した疑似処理回数)」を測定

テスト結果の詳細

  • General CPUテスト :CPU利用率50%時、実際の処理能力は60〜65%
  • 64-bit整数計算 :CPU利用率50%時、実際の処理能力は65〜85%
  • 行列計算 :CPU利用率50%時、実際の処理能力は80〜100%
  • 追加ワーカーが 処理能力に寄与しない現象 も観測

乖離の原因

  • ハイパースレッディング

    • 物理コア数を超えると 論理コア間でリソース共有 発生
    • 12ワーカーまでは各物理コアに割り当て、以降はリソース競合
    • ワークロードによって 性能低下の度合いが異なる
  • ターボブースト

    • 利用コア数が増えると クロック周波数が低下
    • 低負荷時4.9GHz→高負荷時4.3GHzまでダウン
    • CPU利用率計算式(busy cycles/total cycles)の影響で 線形に増加しない

運用上の注意点と推奨アプローチ

  • CPU利用率の数値だけでキャパシティを判断するのは危険
  • 利用率50%以上では システムモニタの数値が過小評価 となる場合が多い
  • プロセッサやメーカー毎に挙動が大きく異なる 点にも注意
  • 適切な評価方法
    • サーバーが エラーや遅延なく処理できる最大作業量 をベンチマークで計測

    • 現在の 実際の作業量 を監視

    • CPU利用率ではなく、作業量同士を比較 して判断

    • Bogo opsはLinuxのBogoMIPSに由来する簡易ベンチマーク指標

CPUの制約と環境要因

  • プロセッサは 熱設計制約 下で動作
    • 一部コアのみ稼働時は 高クロック動作 が可能
    • 全コア稼働時は クロックダウン で熱制御
  • 電力制約 もサーバー環境では重要な要素

まとめ

  • サーバー運用では CPU利用率の数値を鵜呑みにせず実際の処理能力 をベンチマーク等で把握することが重要
  • ハイパースレッディングターボブースト の影響を理解し、 ワークロード特性に応じた運用 を推奨

Hackerたちの意見

システム内でコアを指す言い方が混乱を招くし、標準的じゃないね。著者は5900Xを24コアのマシンとして話してるけど、実際には12コアの上に12個のスレッドが乗っかってるって感じで説明してる。実際には、24のハイパースレッドがほぼ対称的に動いてて、12コアの上で実行されてるんだ。2つの命令パイプラインが同じ機能ユニットを共有してるってわけ。

数年前、専門的な技術知識がない兄にハイパースレッディングを説明しようとしたとき、彼は「2重のトイレットペーパーみたいなもんだ」って例えを出した。24個の別々のものがあるわけじゃないけど、12個がそれぞれのものの約2倍の役に立つって感じ。ただ、分けて使うことはできないし、ちゃんと動くとは期待できない。

フィードバックありがとう。君の言う通りだと思うから、いくつかの参照を変更して、プロセッサの説明を12コア/24スレッドに更新したよ。でも、OSが24コアのように利用率を報告するから、場合によっては「コア」という言葉が正しいと思うこともある。

インテルがハイパースレッディングの論理的逆のソフトウェア定義コアを出荷する時(もし出るなら)、面白くなりそうだね。大きなコアに2つの命令パイプラインが大きなALUを共有する代わりに、リソースを組み合わせて1つのコアになる2つ(またはそれ以上)のコアを持つって感じ。ほぼ同じだけど、かなり違う。 https://patents.google.com/patent/EP4579444A1/en

利用率は嘘じゃなくて、ちゃんと定義された量の測定なんだ。ただ、人々はそれを元にキャパシティモデルを推測しようとするから、現実と期待がずれてくる。ハイパースレッディング(SMT)やターボ(クロックスケーリング)は、非線形を引き起こす要因の一部に過ぎない。他にも、コア間で共有されるリソースがあって、負荷が増えると「枯渇」するものがある。例えば、メモリ帯域幅やインターコネクトのキャパシティ、プロセッサキャッシュなどだ。ボトルネックはソフトウェアから来ることもあって、スピンロックみたいなものは利用率に非線形の影響を与える。さらに、ほとんどのCPU利用率の指標は、数秒から1分の長い時間で平均を取るけど、レイテンシに敏感なサーバーのパフォーマンスに本当に重要なのは、数十ミリ秒から数百ミリ秒のスケールで起こることなんだ。数秒の平均では、バースト的な動作とスムーズな動作を区別できない。後者はスケールアップのキャパシティがずっと大きい可能性がある。残念ながら、提案されたアプローチもあまり正確じゃない。なぜなら、2つの本質的に不安定な概念に依存してるからだ。>「サーバーがエラーや許容できないレイテンシを出す前に、どれだけの作業ができるかをベンチマークしよう。」この測定は非常にノイズが多い。サーバーが不安定になり始めるポイントを検出したいからだ。非常にシンプルなキューイング理論モデルを見ても、飽和に近い導関数は爆発的になるから、非決定的なノイズは極端に増幅される。>「現在サーバーがどれだけの作業をしているかを報告しよう。」「作業」の安定した定義はほとんどない。RPSなのか?リクエストコストは日中でも変動する。命令数なのか?同じく、典型的なIPCも変わる。結局、負荷テストアプローチから得られる信頼区間は、利用率測定から経験モデルを構築するのと同じくらい大きくなるかもしれない。正しく利用率を測定すればだけど。

100%のCPU使用率を示す2つのワークロードがあって、1つはかなり多くの電力を消費してCPUをもっと熱くする場合はどうなるの?そのワークロードはCPUのトランジスタをもっと使ってるってことだよね。

同意するよ。実際に何をしているか分かっているなら、perfやftraceを使って短期間で詳細なプロセッサメトリクスを取得できるし、キャッシュミスからのCPUスタールやメモリアクセスからのスタール、スケジューラーの影響などが見えるんだ。ただ、ほとんどのメトリクスはあまり実用的じゃないけどね(ほとんどの人はIPCやキャッシュヒット、ブランチヒットの数字をどう扱うか分からないから)。大抵の人が気にするのはレイテンシと利用率の組み合わせだよ。ざっくり言うと、多くのワークロードでは、80%のCPU利用率まではレイテンシに大きな影響が出ないんだ。それ以上は利用率を上げられるけど、レイテンシが悪化し始める。利用率がレイテンシにどれだけ影響するかを知るには、特定のワークロードを測定する必要があるよ。また、レイテンシをどれだけ気にするかはやっていることによる。多くの場合、人はレイテンシよりスループットを重視するから、それが最優先の指標ならそれに最適化すればいい。アプリケーションのレイテンシとスループットの両方を気にするなら、両方を測定して、許容できるトレードオフを決める必要があるね。

IEEE Hot Interconnectsが終わったばかりで、ウルトライーサネットのレイテンシパフォーマンスチューニングについて話してたよ。2秒や5秒のビューではスムーズに見えるけど、100msでは明らかなフレームバースト効果が見える。プロファイリングをワークロードに合わせないと、偽陰性が元の問題を悪化させるから、他を探したほうがいいよ。

これ、めっちゃ共感できる。昔、60%の利用率のサーバーには全く余裕がないってマネージャーに説明しようとしたら、まるで二つの頭があるかのように見られた。あの頃、この記事があったらよかったのに!

キューイング理論も教えてあげたいね。60%をちょっと超えるまでは、作業キューの待機遅延はほとんど無視できる。70%になると目立ってきて、80%では倍増する。そしてそこからはもうカオスになる。目安としては、60%がゼロで、80%が遅延が指数関数的に増える転換点。私が運用していた最大のクラスターでは、目標のP95時間で約65%のCPU使用率に達したけど、これは理論的なマークにほぼぴったりだった。

その通りだね。ハイパースレッドをパフォーマンスの2倍としてカウントするのは無理がある。実際には、うまくいけば15-30%しか効果がないし、使うとレイテンシが倍増する。コアの利用率が上がるにつれてクロックスピードの損失を考慮しないのも、非線形な理由の一つだ。デスクトップ向けの現代のソフトウェアでは、特に注意が必要だよ。OSから得られる情報を使って、少なくともこの2つの要素を含む利用率をより良く推定することは可能だと思う。キャッシュや利用可能なメモリ帯域幅を超えた場合のパフォーマンスの低下や、増加するパイプラインスタールによる既存スレッドへの影響を考慮するのは少し難しくなるけど、今よりは確実に改善できるはず。

事情を複雑にするけど、HTのパフォーマンスはCPUアーキテクチャやワークロードによって大きく変わるんだ。例えば、AMDの実装、特に後のZenコアでは、IntelのCPUで見られるスレッドのパフォーマンスに近いんだよ。ただし、メモリ帯域幅が不足していない場合ね。

5年前の面接でこれを説明しようとしたんだけど、相手は俺が嘘つきだと思ったみたい。

別の話題で同じようなことがあったけど、ずっと気にしてたな。振り返ってみると、なんとか危機を逃れたって感じ。

ベンチマークは基本的にアプリケーションのパフォーマンステストで、これが最も正確な表現だよ。サーバーが実行している特定のアプリを、実際のデータやシナリオでテストして、リクエストをどんどん増やしていくんだ。サーバーが落ちるまでね。それ以外の方法では、そのアプリでのサーバーの実際の最大パフォーマンスを正確に示すことはできないよ。リクエスト数やペイロードサイズ、パラメータ数など、関連するすべての変数についてこれを行って、観測モニターを設定するための複数の実世界の最大パフォーマンス指標を持つようにしよう。信頼できるパフォーマンスに近づくための一つの方法は、アプリケーションを実行する際にCPUスケジューラの制限を適用して、特定の閾値を下回るようにすることだよ。そうすれば、一定のパフォーマンスを維持できる可能性が高くなる。特にディスクI/Oが妨げられたり、システム負荷が急上昇したり、可用性が低下したりする場合、長時間100%のCPUで運用するのは避けたいよね。システム負荷のせいで2000台のサーバーが5000msのpingタイムになるのは、楽しい日ではないよ。(実際、完全に正確なビューは得られないけどね。パフォーマンスはサーバーごとに変わるから。2つの同じサーバーを異なるラックに置いて、同じアプリを実行すると、実際のパフォーマンスが異なることもある。片方のラックがもう片方より熱いかもしれないし、隠れたハードウェアやファームウェアの違いがあるかもしれないし。サーバー内でも、あるCPUが別のサーバーのより熱いコンポーネントに近いだけで、影響が出ることもあるからね。)

CPU利用率が期待通りに機能しない方法はたくさんあるよ。こんなスタイルの記事は予想してなかった。普通のLinux/Windowsの利用率を期待してたのに、何だかRAMがボトルネックになってて、CPUは実際には静かで、もしかしたらダウンクロックしてるかも。CPU利用率は、OS(WindowsでもLinuxでも)がスレッドをどれだけコアに割り当てるかだけなんだ。スレッドがmemcpyで100%ブロックされていても、それはCPU利用率としてカウントされる。------- ハイパースレッドは助けになるよ:もし1つのスレッドが本当にCPUバウンド(もっと具体的にはAVX / ベクターユニットバウンド)で、2つ目のスレッドがハイパースレッドでmemcpy / RAMバウンドなら、リソースの利用率が高くなることでマジックのようにパフォーマンスが向上するんだ。(ロード/ストアユニットはAVX計算ユニットとは別だからね)。いずれにせよ、これは常に新しい発見があるテーマで、CPU利用率が多くの人が考えるよりもはるかに直感的ではないことが分かる。新しい視点を学ぶのは面白いよね。

嘘かもしれないけど、実用的なものではあるよ。サイト信頼性エンジニアリングにちょっと関わったとき、CPU利用率(CPUバウンドタスクの)をキューイング理論と組み合わせて、大きなイベントの前にサーバーをスケールする方法を選んだんだ。%CPUの提案は「古い知恵」とは逆行していて、ずっと保守的だった。結果的に、他の方法よりもずっと低コストでうまくいったよ。言いたいのは、半端な指標だからって使うのを恐れないでほしいってこと。もしそれが一番の指標なら、十分かもしれないからね。ただ、CPU利用率に関しては、いろんな理由で生産環境では40%を超えない方がいいよ。40%なら、通常はまだ少し余裕があるから。著者のミスは、利用率が高くなるのを避けるためにキューイング理論の基本を使わなかったことだね!

CPU%とloadavgの組み合わせで、システムの状態がわかることが多いよ。loadavgが高くてネットワークやIOを待ってるのに、CPU%は低いっていうシステムもあったし。高負荷のトレースはCPU%ほど簡単じゃないから、io%、net%、syscallsとかもチェックしないといけない。

全く同じことに気づいた。著者が言ってることは、何十年も前からキュー理論の本に書かれてることなのに、今になってやっと気づいたみたい。

ブレンダン・グレッグの「CPU利用率は間違っている」を思い出すけど、このブログはその重要なポイントを話してないね。CPU利用率はCPUが忙しいかどうかを測る指標で、待機しているかどうかも含まれてるんだよね。[0] そのブログでは、IPC(サイクルあたりの命令数)指標が、実際にはその忙しい状態の中に隠れた有用な作業を測るものだって説明してる。[0]: https://www.brendangregg.com/blog/2017-05-09/cpu-utilization...

最近はCPU使用率を単なるヒントとして捉えてる。結論じゃなくてね。レスポンスタイムやキューの長さも見て、アプリがアイドル状態に見えるときに何をしてるのかを考えるようにしてる。