Claude Media
Claude Codeでstraceのシステムコール集計を読み、遅いプロセスを絞る

Claude Codeでstraceのシステムコール集計を読み、遅いプロセスを絞る

strace -c -fの集計ファイルだけをClaude Codeに読ませ、stat・futex・fsyncの偏りから遅い処理を絞る手順と、本番へのアタッチ範囲の線引きをまとめます。

本番のLinuxサーバーで特定のプロセスだけが遅いとき、strace -c の集計は最初の一手になります。システムコールごとの回数・時間・エラー数が1枚の表に収まるので、どこで時間を使っているかの当たりがつきます。この表をClaude Codeに読ませて仮説を出させるのが本記事の流れです。

ポイントは、straceを動かすのは人間で、Claude Codeには出力ファイルだけを渡すことです。本番にClaude Codeを直接つなぐ必要はありません。

strace -cの集計は何を数えているか

strace -c は、システムコールごとの時間・呼び出し回数・エラー回数を数え、プロセスの終了時に要約を出します。通常のトレース出力は抑えられます。-C なら、要約に加えて通常の出力も流れます。

時間の列は、既定ではカーネル内で使ったCPU時間(システム時間)です。ディスクやロックを待った実時間ではありません。待ちを見たいときは -w を足して、各システムコールの開始から終了までの実時間で集計します。

オプションの役割は次のとおりです。

オプション役割
-c役割回数・時間・エラー数の要約だけを出す
-f役割forkやcloneで増えた子プロセスも追う。-c と併用すると全プロセスの合計になる
-w役割時間列を実時間(開始から終了まで)にする
-S calls役割要約を呼び出し回数順に並べる(既定は時間順)
-p PID役割動いているプロセスにアタッチする。Ctrl-Cで切り離すと、対象はそのまま動き続ける

-f -p PID はマルチスレッドのプロセスで全スレッドにアタッチします。-f なしだと、PIDに対応するスレッドしか見えません。Webサーバーやランタイムの多くはスレッドやワーカーを持つので、-f は付けておく前提です。

集計ファイルに引数やデータは載らない

-c は通常出力を抑えるため、ファイルパスや読み書きしたバッファの中身といった引数は集計に出ません。出るのはシステムコール名と数字だけです。この性質が、Claude Codeに渡す入力として扱いやすい理由です。

本番では人が採取し、Claude Codeは集計ファイルを読む

分担は次のとおりです。

手順

採取から読解までの分担

  1. 1

    人が対象プロセスを決める

    遅い処理を担うプロセスのPIDを、pgrep や監視画面から選びます。

  2. 2

    人が時間を区切って採取する

    数十秒だけアタッチし、集計をファイルに書き出します。

  3. 3

    集計ファイルを作業ディレクトリへ移す

    本番サーバーの外、手元のリポジトリ内の perf/ などへコピーします。

  4. 4

    Claude Code が読んで仮説を出す

    ファイルの読み取りだけで進め、コマンドは実行させません。

採取の例です。timeout で時間を区切っておくと、アタッチしたまま忘れる事故を防げます。

timeout 30 strace -c -f -w -S calls \
  -p "$(pgrep -o -f my-worker)" \
  -o /tmp/strace-summary.txt

-o はトレース出力の書き出し先をファイルにする指定です。timeout で止めたときに要約がファイルへ出るかは、検証環境で一度確かめてから本番で使ってください。Ctrl-Cで止めた場合、straceは切り離されて対象を動かしたままにします。手元に持ち帰ったあと、Claude Codeには次のように頼みます。

perf/strace-summary.txt は本番ワーカーを 30 秒 strace -c -f -w した集計です。
実時間の合計が大きい上位 5 件と、errors が calls の 1 割を超える行を挙げ、
それぞれ何が起きていそうか仮説を 2 つずつ書いてください。
コマンドは実行せず、ファイルの読み取りだけで答えてください。

「仮説を2つずつ」と求めるのは、集計だけでは原因が1つに決まらないからです。次節の設定で、読み取り以外ができない状態にしておきます。

Claude Codeの権限を読み取り専用に寄せる

Bashコマンドは、読み取り専用として認識される組み込みのコマンド群を除いて、既定で確認を求められます。そのコマンド群の例は ls、cat、grep、stat、du などで、strace は挙げられていません。つまり既定のManualモードでも strace は確認が出ます。ただし「このコマンドは今後確認しない」を一度選ぶと、リポジトリ単位の許可規則として保存されます。事前にdenyを置いておくほうが確実です。

.claude/settings.json の例です。

{
  "permissions": {
    "allow": [
      "Read(./perf/**)"
    ],
    "deny": [
      "Bash(strace *)",
      "Bash(ltrace *)",
      "Bash(gdb *)",
      "Bash(ssh *)"
    ]
  }
}

この設定は、集計ファイルの読み取りを許し、アタッチ系のコマンドと本番へのログインを止めます。

deny規則だけでは止まらない呼び方がある

Bashのdeny規則は、Claudeが書いたコマンド文字列にマッチします。/usr/bin/strace ... のようにパスを付けた呼び方や、sh -c 'strace ...' の中は、同じ規則では止まりません。規則はセキュリティ境界ではない、というのが権限ドキュメントの説明です。

文字列に依存しない制限が必要なら、サンドボックスを併用します。サンドボックスはOSの仕組みでシェルコマンドのファイルとネットワークへのアクセスを制限します。macOSではSeatbelt、LinuxとWSL2ではbubblewrapで動きます。呼び出し前に全文を検査したい場合はPreToolUseフックも使えます。deny規則はフックの結果にかかわらず先に評価され、一致すれば呼び出しは止まります。

読み方の約束をCLAUDE.mdに置く

毎回プロンプトに書くのが面倒なら、perf/ の扱いをCLAUDE.mdに短く書いておきます。ファイル名と採取条件を揃えておけば、複数日の集計を並べて比べるときにも使えます。

## perf/ の strace 集計
- ファイル名は strace-<対象名>-<日付>-<wall|cpu>.txt。wall は -w あり、cpu は -w なし
- 読み取りのみ。strace・gdb など、アタッチするコマンドは実行しない
- 回答には上位の行を引用し、仮説と、次に人が採るべき集計を 1 つ書く

これはClaudeの振る舞いを方向づけるだけで、実行を止める強制力はありません。止めるのは前節のdeny規則とサンドボックスの役割です。

集計の表を読む

次は、読み方を示すための例示です。数値は説明用の架空の値で、実際のサーバーから採ったものではありません。

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 41.20    3.912004          12    326001           futex
 22.75    2.160110          18    120004    119870 stat
 17.03    1.617200        1617      1000           fsync
  9.10    0.864000           4    216000           read
  ...

この表から立てられる仮説は、おおむね3通りに分かれます。システムコールの意味に基づく一般的な読み方で、確定ではありません。

  • statのerrorsがcallsのほぼ全部: 存在しないファイルを何度も探している可能性があります。設定の探索パスや、モジュールの解決順を疑います。呼び出し回数を減らせるかが論点です
  • futexが呼び出し回数でも時間でも上位: スレッド間のロック待ちが多い可能性があります。ただし待機中のスレッドが休んでいるだけの場合もあります。-w の実時間と見比べて判断します
  • fsyncが1回あたり長い: ディスクへの確定書き込みで待たされている可能性があります。呼び出し回数は少ないので、まとめて書く・間隔を空けるといった設計側の話になります

システム時間と実時間をずらして見る

-w なしの集計は、カーネル内のCPU時間です。ロックやディスクを待っている時間は大きく出ません。「遅い」の正体が待ちなら、-w ありの集計を取り直します。Claude Codeには、2つの集計ファイルを並べて「システム時間では小さいのに実時間で大きい行」を挙げさせると、待ちが支配的なシステムコールが絞れます。

絞り込みの次の一手は人が決める

集計は「どのシステムコールが怪しいか」までしか言えません。引数まで見たければ -e trace= で対象を絞ってもう一度採取しますが、ここから出力にパスや書き込みデータが載ります。

timeout 10 strace -f -tt -T -e trace=stat,fsync \
  -s 64 -p "$PID" -o /tmp/strace-detail.txt

-s 64 は文字列引数の表示を64バイトまでにする指定です。-tt は時刻、-T は各システムコールにかかった時間を付けます。この詳細ファイルをClaude Codeに渡す前に、人間が中身を読んで、顧客名やトークンらしき文字列がないかを確かめてください。通常は、集計だけで仮説を立て、仮説を確かめるのは検証環境で行います。

本番にアタッチしてよい範囲の線引き

straceは動いているプロセスを追跡するため、対象のプロセスは通常より遅くなります。manページにも、トレースされたプロセスは遅くなると明記されています。負荷を抑えるオプションとして --seccomp-bpf がありますが、-f と併用したときだけ効き、-p でアタッチしたプロセスには適用されません。本記事の手順は -p でアタッチするので、このオプションは負荷を下げる手段になりません。アタッチ時間を短く区切ることで影響を抑えます。

線引きの一例です。

状況方針
検証環境で再現できる方針検証環境で strace -c -f を取る。本番には触らない
再現せず、障害が起きている方針短時間(数十秒)の -c だけを、権限を持つ人が取る
詳細トレース(-e trace=)が必要方針対象を絞り、出力を人が確認してから共有する
常時トレースしたい方針本番にstraceを常駐させない。計測基盤側に任せる

どの行でも、Claude Codeが直接アタッチすることはありません。人が採った集計を渡す構成なので、本番への接続権限をエージェントに与える話は発生しません。

よくあるつまずき

落とし穴

-f を付け忘れて、子プロセスやスレッドの分が丸ごと抜ける

-f なしだと、forkした子プロセスは追跡されません。ワーカーをforkする構成では、親は待っているだけで、実際の処理が集計に出ません。集計の合計時間が極端に小さいときは、まず -f を疑います。

次の3つも、集計を読む前に確認します。

  • -c と通常出力は両立しません。通常の出力も欲しいときは -C を使います
  • 時間順の既定の並びでは、1回は長いが回数が少ない行が埋もれることがあります。-S calls と並べて見ます
  • Ctrl-Cやタイムアウトでstraceを止めると、対象プロセスは切り離されて動き続けます。集計は、止めるまでに観測した分だけです。30秒で打ち切れば30秒分になります

アプリケーション側の関数単位で遅い箇所を探すなら、Nodeのcpuprofileを解析する手順のほうが近道です。データベースのクエリが疑わしいときは、pg_stat_statementsの集計から入ります。straceは、どちらにも当てはまらないとき、あるいはシステム側の待ちを切り分けたいときの道具です。

まとめ

集計ファイルだけを渡す構成なら、本番のプロセスを遅くするのは人が数十秒アタッチする間だけで済みます。Claude Codeの役割は、表から仮説を2つずつ立てることと、-w 付きとなしの2つの集計を突き合わせることです。結論を出すのは、検証環境での再現のあとです。

読み取り専用の設定は、deny規則だけで完結しません。文字列に依存しない境界が必要なら、サンドボックスとフックを重ねてください。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/permissions
  2. code.claude.com/docs/en/sandboxing
  3. man7.org/linux/man-pages/man1/strace.1.html
この記事を共有:XはてブLinkedIn