- 一般的にサーバー性能の限界は
top のような監視ツールの % CPU使用率 で判断されるが、実際にはこの指標は 性能を線形に反映しない
- Ryzen 9 5900X 環境で stress-ng を使ってテストした結果、使用率50%のとき実際の作業量は60〜100% に達し、指標との大きな乖離があった
- 主な原因は ハイパースレッディング と ターボブースト で、論理コア間のリソース共有やクロック速度の変化が指標を歪める
- したがって単純なCPU使用率の代わりに、実際に処理可能な作業量のベンチマークと現在のスループットの比較 のほうがより正確な指標となる
- CPU使用率を線形に解釈すると 性能推定に大きな誤り が生じるため、システム計画時には ベンチマークベースのアプローチ が必要
サーバーのCPU使用率の数値と実際のスループットの不一致
- サーバー運用では、多くの人が最大使用率に近いかどうかを確認したがる
- 一般的には
top などの監視ツールを通じて、ネットワーク、メモリ、CPU使用率のうち最も高い値を参照する
- しかし実際には、CPU使用率の数値と処理可能な作業量が線形に増加しない問題が発生する
テスト環境と方法
- Ubuntuデスクトップ + Ryzen 9 5900X (12コア/24スレッド) ベースの実験
- Precision Boost Overdrive(Turbo)を有効化
- stress-ng でさまざまな負荷(1〜24ワーカー、1〜100%使用率)をシミュレーション
- 測定指標: システムが報告する CPU使用率 と実際の演算量(Bogo ops)
結果の要約
- 一般的なCPU負荷: 使用率50%時に実際は60〜65%のスループット
- 64ビット整数演算: 使用率50%時に65〜85%のスループット
- 行列演算(Matrix math): 使用率50%時に80〜100%のスループット
- 実際には追加ワーカーが性能に寄与しなくても、CPU使用率は上昇する
原因分析
-
ハイパースレッディング
- 12個の物理コア + 12個の論理コア構成
- 12個以下のワーカーは物理コアに最適配置されるが、それを超えると 論理コア共有 により性能が低下
- 特に SIMD演算(行列演算) では共有リソースがないため性能向上は不可能
-
ターボブースト
- 低負荷時は4.9GHz → フルロード時は4.3GHzへと 15%のクロック低下
- CPU使用率の計算式(= busy cycles / total cycles)に歪みが生じる
- 分母(総サイクル数)が減ることで、使用率の上昇幅が実際の作業量より過大評価される
示唆
- CPU使用率は絶対的な性能指標ではない
- サーバー容量の算定および性能予測の際には:
- 1. ベンチマークで最大スループットを測定
- 2. リアルタイムのスループットを監視
- 3. 2つの値を比較して 性能限界への接近度を判断
- CPUアーキテクチャ(AMD vs Intel)、ハイパースレッディング効率、ターボの動作方式により ばらつきが大きいため、プロセッサごとの分析が必要
結論
- CPU使用率は単なる busy cycles の比率 にすぎず、実際の処理性能を正確には反映しない
- 効率的に活用されている場合、"50%使用率" でも すでに最大性能の80〜100%水準 である可能性がある
- したがって 性能監視とシステム計画 は、CPU使用率ではなく ベンチマークベースの作業スループット を中心に行うべきである
3件のコメント
実際のHPC構成環境では、基本的にハイパースレッディングを無効にしてクラスターを構成します。
Hacker Newsのコメント
CPU utilization は明確に定義された量を測定しているので、嘘ではないと思う。ただ、人々がこれを外挿して容量モデルを作ろうとすると、現実と期待のずれを経験する。
Hyperthreading(SMT)や Turbo(クロックスケーリング)は、非線形性を生む多くの変数の一部にすぎず、コア間で共有されるメモリ帯域幅、インターコネクト容量、プロセッサキャッシュなども、負荷が増すにつれて「枯渇」する資源だ。
ソフトウェア面でも、たとえば spinlock のような現象は utilization に非線形な影響を与えうる。
たいていの CPU utilization 指標は数秒〜1分単位の長い平均を取るが、レイテンシに敏感なサーバーの性能にとって重要なことは、数十〜数百ミリ秒の間に起こる。
だから、数秒単位の平均 utilization では、burst パターンと滑らかなパターンを区別できない。
しかし提案されていたやり方、つまり「エラーや許容不能なレイテンシが発生する前まで、サーバーがどれだけ仕事をこなせるかをベンチマークする」アプローチも、本質的には不安定だ。
サーバーが不安定になり始める点を探そうとすると、測定値は非常に noisy になり、待ち行列理論の上でも臨界点近辺ではあらゆるノイズが増幅される。
また、「サーバーが今こなしている仕事量」自体もしばしば不安定にしか定義できない(RPSなのか? リクエストごとのコストは違うし、IPCも時間帯によって変わる)。
結局、負荷テストのアプローチから得られる信頼区間も、utilization 指標から経験モデルを作るのと大差ない。前提は utilization を正しく測定することだ。
もし自分が perf や ftrace を使えるなら、短期間に非常に詳細なプロセッサメトリクスを取得できて、cache miss や memory access による CPU stall、スケジューラの影響など、さまざまな原因を直接見られる。
ただ、たいていの人は IPC やキャッシュヒット率のような指標を渡されても、それで何をすべきか分からない。
結局、多くの人が本当に関心を持っているのはレイテンシと utilization だ。
大まかに言えば、ほとんどのワークロードでは CPU utilization が 80% を超えるまでは、レイテンシに大きな問題はない。
しかしそれを超える utilization では、ワークロードのレイテンシに深刻な影響を与え始める。
どの程度レイテンシに影響するかは、それぞれのワークロードを自分で測ってみないと分からない。
レイテンシにどれだけ敏感かも、組織や目的によって異なるし、時には throughput の最適化のほうが重要なこともある。
レイテンシと throughput の両方を気にするなら、両方を測定して、適切なトレードオフを自分で決めるべきだ。
「仕事量」の定義自体が揺らぐことが、重要なポイントの一つだと思う。
たとえば public-facing なサービスで実ユーザーのリクエストを扱うのか、それともバックエンドで溜めておいたデータを落ち着いて計算する AI 学習向けワークロードなのかでも違う。
私の考えでは、burst がしばしば避けられない現代のマルチコア・ハイパースレッド CPU 環境では、CPU utilization が 60% なら、すでに「高負荷」のサーバーと見なす。
もし1日のかなりの時間で 60% を超えているなら、仕事を分割するのが適切だと考える(主にユーザーリクエストに応答するサービスを前提としている)。
以前は、こうした基準からクラウドのオートスケールをよく検討することになった。
今では 100 コア超のサーバーでも 3 万ドル前後で使えるので、状況はさらに複雑になっている。
今なら、実サーバーのハードウェアをやや過剰にプロビジョニングし、必要に応じてクラウドサービス(あるいは Kubernetes ベースの社内クラウド)へ拡張する Hybrid な方式を志向するだろう。
StackOverflow は初期のころ、専用ラックと 10Gbps アップリンクで膨大なトラフィックを効率よくさばいていたし、今ではそれよりも簡単にこうした運用ができる。
要するに、私の基準では CPU load が 65% を 30 分以上維持していれば、すでに 100% 効果的に使っていると見なし、近いうちにスケールが必要だと判断する。
最近の学会 IEEE Hot Interconnects のキーノートでも、Ultra Ethernet のレイテンシチューニング事例が言及されていた。
2秒や5秒単位では平坦に見えても、100ms スケールで見ると frame burst 現象がはっきり表れる。
つまり、プロファイリングの測定ウィンドウが実際のワークロードに合っていないと、false negative による誤った判断を下しやすくなり、それが問題をさらに悪化させる原因になる。
指摘には全面的に同意する。
CPU utilization が線形でない性質のために、% という表現自体が実態と乖離する。
つまり、% 単位で測定した CPU utilization こそが嘘だ、という主張だ。
もし2つのワークロードがどちらも CPU 使用率 100% を記録していても、一方がはるかに多くの電力を消費し、CPU 温度も大きく上がるなら、実際にはそのワークロードのほうがより多くのトランジスタ資源を活用しているのではないか、という疑問が出てくる。
CPU utilization は完璧な尺度ではないとしても、実用上は十分役に立ってきた。
簡単な SRE 業務の経験でも、CPU バウンドなタスクを前提に、待ち行列理論に CPU utilization の数値を組み合わせて大規模イベント前のサーバー規模を見積もったことがあり、より「伝統的」なアプローチの代わりに、もっと保守的に提案した %CPU 基準でも、結果はずっとコスト効率が良かった。
要は、多少不正確な尺度でも現場で使い物になるなら、過度に心配せず活用してみるべきということだ。
ただし production 環境の CPU utilization は必ず 40% を超えないように保っていた。さまざまな状況に備えて少し headroom を確保するためだ。
著者には、「高い utilization を待ち行列理論的に避ける」ことへの論理的根拠が不足している点が惜しい。
多少雑な指標でも、現場で適切に使えるなら十分だと思う。
たとえば、各ホストごとの percentile metric の単純平均や最大値をそのまま使ったり、ホスト単位のヒストグラムを最終集計時に percentile として計算したりしても、実務上はその切り替えが運用に大きな差を生まなかった経験がある。
数学的に厳密に正しいかどうかを気にしすぎる人もいるが、現実の運用には大きな影響がないことも多い。
40% というのは、実際かなり緩い(余裕のある)利用率だと思う。
CPU% と loadavg を一緒に見れば、システムの状態をかなりよく把握できると思う。
loadavg が高いのに CPU% が低いなら、ネットワークや I/O で詰まっていたり、システムコールなどで待たされている可能性がある。
こういう場合、単に CPU% だけを見ていると、苦しんでいる箇所を見落とすかもしれない。
まったく同じ話を聞いたことがある気がする。
著者の述べている内容は、待ち行列理論の書籍で何十年も繰り返されてきた話なのに、今ようやく発見したかのように書かれているのが不思議だ。
Brendan Gregg の "CPU Utilization is Wrong" を思い出した。
このブログの核心は、CPU utilization は CPU が忙しいという「状態」だけを指標にしており、CPU が待機状態にあっても busy と見なしてしまうことだ。
そして IPC は、その busy な状態の中に隠れている実際の有効仕事量を把握するための尺度だ。
もし別の Brendan がいるなら、ぜひ教えてほしい。
ハイパースレッドが提供する性能を2倍として数えるべきではないと思う。
現実には、ハイパースレッドをうまく活用しても性能向上は 15〜30% 程度にとどまることが多かった。その代わり、レイテンシは2倍になることがある。
コア utilization が高まるときのクロック低下も必ず考慮すべきで、現実では非線形だという点には常に注意している。
OS が提供する情報だけでも、ハイパースレッド効果とクロック低下まで計算に入れれば、ずっと正確な utilization 推定が可能になる。
さらにその先の、キャッシュ/メモリ帯域幅の制約やパイプラインストールが性能低下につながる現象までモデル化するのも、そこまで難しいことではないと思う。
状況を複雑にする要因として、ハイパースレッド効率は CPU アーキテクチャやワークロードごとに大きく異なる。
たとえば AMD(特に最近の Zen)の実装は、Intel よりかなり独立した性能を出す傾向がある(メモリ帯域幅のボトルネックがないと仮定すれば)。
メモリバウンドなアプリケーションなら、ハイパースレッドでより良い scaling を見やすい。
以前担当していたレンダラーのプロジェクトはメモリバウンドで、ハイパースレッドだけで 60〜70% の性能向上を経験した。
以前、i7-3770K(4C/8T)で POV-Ray の簡単なベンチマークを回したことがある。
1スレッド→2スレッドはちょうど2倍、2→4でも2倍、4→8ではわずか 15% 増にとどまった。
キャッシュミスを人為的に繰り返すような特殊なベンチマークなら、SMT でほぼ2倍の性能を引き出せるかもしれないが、現実的かは疑問だ。
追記すると、POV-Ray のテストをまた回してみようかと考えている。久しぶりで懐かしい。
著者は、%CPU utilization の数値に応じて性能が線形に伸びないことに気づき、その結果として %CPU utilization 自体が「嘘」だと結論づけたのだと思う。
ハイパースレッドやクロック低下がなくても、Apple silicon のように変数が少ないと思われる場合ですら、正比例の scaling にはならない。
複数コアを同時に使い始めると、データ転送のオーバーヘッドなど CPU 以外の資源ボトルネックがしばしば問題になり、似たような状況がよく起きる。
著者の使うコアという用語は混乱を招くし、標準とも違う。
5900X を 24コアシステムと呼んでいるが、実際には 12 個の物理コアに 24 個のハイパースレッドが動いている構造だ。
12 個が物理コアで、残りの 12 個は各コアに付属して動作するスレッドだ。
Instruction pipeline が 2セットあっても、内部の functional unit は共有している。
数年前、ハイパースレッディングをよく知らない弟に説明しようとしたときの比喩で印象に残っているのは、まるで2層のトイレットペーパーのようだというものだった。
24 個を別々に切り離せるわけではないが、12 個を2倍うまく使うのに近い。
フィードバックを受けて、12コア/24スレッドという表記に修正した。
ただ、自分の OS が利用率を 24コアとして表示するので、そこが混乱のもとだった。
Intel がソフトウェア定義コアを出してきたら面白いかもしれない。
ハイパースレッディングの論理的な逆で、2つ以上のコアが資源を共有して「1つの大きなコア」に変換される構造だ。
以下の特許リンクを参照。
https://patents.google.com/patent/EP4579444A1/en
SMT のペアが同じ種類のワークロードを実行すると、内部資源や実行ユニットの競合のために SMT の効果は下がる。
もし workload がまったく異なれば、むしろ boost が大きくなることもある。
今では最新 CPU で Pコア、Eコア、Turbo/非Turbo まで変数に入ってくるので、状況はさらに複雑だ。
SMT の追加は Turbo の追加よりワット当たり性能の改善効果が大きい、という研究があって、とても興味深かった。
本当に共感できる話だ。
昔ある日、サーバー CPU が 60% まで埋まっていて、これ以上は余裕がないとマネージャーに説明したら、何か変な顔をされたことがある。
あのとき、まさにこういう説明があればよかったと思う。
待ち行列理論も一緒に説明すれば効果抜群だ。
60% 未満では待ち行列遅延はほぼ無視できるレベルだ。
70% を超えるあたりから遅延がはっきり感じられ、80% からはほぼ倍増する。
実際の自分の経験では、P95 時間を基準に 65% を目標に合わせていて、これは理論的な基準とほぼ一致していた。
要するに「60% が利用率の限界、80% から遅延が爆発する」が実務上のルールだ。
ただし、ワークロードによってまったく変わりうる。
特に今のようにサーバー CPU が 32コアずつある時代では、なおさらそうだと思う。
CPU utilization は期待どおりに機能しないことが多い。
こういうタイプの記事なら、本来は Linux/Windows 上で回っている Utilization 値の話を想像していたが、実際には RAM ボトルネックのために CPU がのんびり待機したりダウンクロックしていたりする例も多い。
実際、CPU utilization とは、OS が(Windows でも Linux でも)各コアにどれだけスレッドを割り当てているかを見るものにすぎない。
しかも、そのスレッドが memcpy で 100% 待たされていても utilization として記録される。
ハイパースレッドの利点は、片方のスレッドが AVX/ベクターユニットに縛られ、もう片方のスレッドが単純な memcpy/RAM に縛られているような場合に、それぞれのユニット利用率を引き上げて、全体の性能と utilization を高められる点にある。
要するに CPU Utilization は、長年にわたって直感的に理解しにくいテーマであり、毎回新しい見方が発見され続けている。
それでも、いつも面白いテーマだ。
ハイパースレッドコアが本物のコアと同じように動くと信じることこそ、本当の「嘘」だ。
結局、20年以上使われ続けるうちに本来の本質を忘れ、なぜ性能測定値がおかしくなるのかを繰り返し思い知らされる。
もう一つは、プロセッサは根本的には「実行中」(100%)か「待機中」(0%)しかない。
その中間に % を与えるということ自体が、特定時間単位の平均値にすぎないのだと改めて考えさせられる。
以前こんな会話をしたことがある。
マネージャー: CPU utilization が 100% だから、サーバーをもっと大きいインスタンスに変えるべきではないかと聞いてきた。
私: 「でも今、CPU は本当に役に立つ仕事をしているんですか?」
結果として、busy waiting も CPU utilization として記録されるため、実際の有効仕事量とは無関係に数字だけが上がる場合がある。
正しい表現です。