Windows の CPU 使用率を収集してグラフ化してみる

Windows の CPU 使用率を収集して、Python (pandas+matplotlib) でグラフ化してみようという話です。

## パフォーマンス データ収集（CPU）
`logman` コマンドによりパフォーマンス データは簡単に収集できます。CPU 使用率を取得したい場合には、`"\Processor Information(*)\% Processor Utility"` を指定すれば OK です。
```powershell:PowerShell or コマンド プロンプト
# 1. CPU の使用率データを取得するデータ コレクター セットを作成
logman create counter "Perf_CPU" -c "\Processor Information(*)\% Processor Utility" -f csv -si 00:00:05 -o "C:\path\to\Logs\PerfLogging"

# 2. データ コレクター セットでログ取得を開始
logman start "Perf_CPU"

# 3. ログ取得を終了
logman stop "Perf_CPU"

# 4. 作成したデータコレクターセットを削除
logman delete "Perf_CPU"
```

Windows のパフォーマンス収集方法についての一般的な内容は、以下の Web サイトに書いたので、パフォーマンス ログ収集に興味があれば、一読いただければと思います。

パフォーマンス ログ収集 | Microsoft Japan Windows Technology Support Blog
https://jpwinsup.github.io/blog/2021/06/07/Performance/SystemResource/PerformanceLogging/

## CSVファイルの形式
### ヘッダー
```text
"(PDH-CSV 4.0) ("
"\\ComputerName\Processor Information(0,0)\% Processor Utility"
"\\ComputerName\Processor Information(0,1)\% Processor Utility"
"\\ComputerName\Processor Information(0,2)\% Processor Utility"
"\\ComputerName\Processor Information(0,3)\% Processor Utility"
"\\ComputerName\Processor Information(0,4)\% Processor Utility"
"\\ComputerName\Processor Information(0,5)\% Processor Utility"
"\\ComputerName\Processor Information(0,6)\% Processor Utility"
"\\ComputerName\Processor Information(0,7)\% Processor Utility"
"\\ComputerName\Processor Information(0,_Total)\% Processor Utility"
"\\ComputerName\Processor Information(_Total)\% Processor Utility"
※ 見やすくするため、ヘッダーごとに改行しています。
```

1列目に謎の文字列"(PDH-CSV 4.0) (" が入っていますが、あとは CPUコアごとのデータと Total のヘッダーになります。中括弧の意味は、(0,4) = CPU0 の Core4 になります。なお、CPU を物理的に2個搭載しているサーバーなどでは、(1,0)、(1,1)、(1,2)... のデータも存在します。

(0,_Total)は、CPU0 の CPU 使用率、(_Total)は、端末に搭載しているすべての CPU の使用率という意味になります。

### データ
```text
"09/01/2024 17:59:38.102","47.122997226400272552","35.14188125643801186","41.022807332658764778","39.859085387270773992","35.931130229351772698","30.722207450208369295","38.218370531626831621","36.887222990085248853","38.113454862442544879","38.114960321492084461"
```
1列目に日時、それ以降の列に CPU 使用率のデータが入っています。


## CPU パフォーマンスのグラフ化（Python）
おなじみの pandas, matplotlib で CSV をグラフ化していきます。
```python
import re
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# CSVファイルを読み込む
df = pd.read_csv('PerfLogging_000001.csv', index_col=0, parse_dates=True)

# ヘッダーを変更
headers_list = df.columns.tolist()
new_headers = []
for header in headers_list:
    # 正規表現で文字を抽出
    match = re.search(r'\((\d+),(\w+)\)', header)
    if match:
        new_headers.append(f"CPU{match.group(1)},{match.group(2)}")
    else:
        new_headers.append('Overall')
df.columns = new_headers

# データフレームの整理
df.index.name = 'Date'
df.fillna(' ', inplace=True)
df.replace(' ', '0.0', inplace=True)
df = df.astype('float64', errors='ignore')

# データフレームの列数に応じてサブプロットの数を決定
num_columns = len(df.columns)
num_rows = (num_columns + 1) // 2

# プロットの設定（2列のレイアウト）
fig, axes = plt.subplots(num_rows, 2, figsize=(9, 21))
axes = axes.flatten()  # 2D配列を1Dに変換

# 各列ごとにグラフを作成
for i, column in enumerate(df.columns):
    df[column].plot(ax=axes[i], title=column)
    axes[i].xaxis.set_major_formatter(mdates.DateFormatter('%m/%d %H:%M:%S'))
    axes[i].set_xlabel('Date')
    axes[i].set_ylabel('CPU Usage (%)')
    axes[i].set_ylim(0, (df.max().max() // 50 + 1) * 50)
    axes[i].grid(True)

# 不要なサブプロットを削除
for j in range(i + 1, len(axes)):
    fig.delaxes(axes[j])

# PNGファイルとして保存
plt.tight_layout()
plt.savefig('plot.png', dpi=100)
```
![plot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3853334/3aaf66cb-d350-c6c1-5a73-1c62fc713480.png)

:::note info
CPU 使用率が 100% を超えていても異常ではありません。詳細は、Microsoft の Web サイトに書いてあります。

CPU usage over 100% if Intel Turbo Boost is active
https://learn.microsoft.com/en-us/troubleshoot/windows-client/performance/cpu-usage-exceeds-100
:::

## さいごに
昔は AI 関連で pandas と matplotlib を多用していましたが、最近、また必要になったので復習のつもりでやってみました。もっとこうしたほうがいいよというのがあれば教えてください。