この記事の要点
- Swift サービス向けのインプロセス・サンプリングプロファイラ Swift Profile Recorder(apple/swift-profile-recorder)がオープンソースとして公開されました。Apple が数年にわたり本番環境での Swift サービスの運用・デバッグに使ってきたツールです。
- 最大の特徴は、プロファイラを Swift パッケージとして自分のプロセス内で動かす点です。外部の eBPF / DTrace /
perfのような特別な権限やシステム依存を必要としないため、権限が制限された多様な実行環境でもプロファイリングを導入できます。 - 収集したサンプルは
curlで HTTP エンドポイントから読み出せます。出力は Linux perf script 形式・pprof 形式・FlameGraph の collapsed 形式など業界標準のフォーマットに対応しており、Speedscope や Firefox Profiler などの既存ツールでそのまま可視化・分析できます。現在は macOS と Linux をサポートします。
何が発表されたのか
プロファイリングは、アプリケーションがどこで時間を費やしているか(計算中なのか、ロック取得を待っているのか、ファイル I/O でブロックされているのか)を把握するための強力な手法です。アプリケーションの活動のサンプルを収集することで、その挙動への洞察を得られます。
モダンな OS には perf(Linux)・sample・Instruments(Apple)といったプロファイリングツールがあり、さらに DTrace や eBPF のようなカーネル機構も利用できます。コミュニティからも、Parca Agent と eBPF を活用して継続的にプロファイリングを行う swift-parca が最近提供されました。しかしこれらの既存手法には、次のような採用上の制約があります。
- 別プロセスにアタッチしたり、eBPF / DTrace プログラムをカーネルにロードしたりするのに特別な権限が必要になる場合がある
- Linux ディストリビューションによっては、追加コンポーネントの導入が必要になる
- 利用できるプロファイリング技術が OS ごとに大きく異なる
Swift Profile Recorder はこれらを避けるため、別のアプローチを取ります。プロファイラを Swift パッケージとして実装し、自分のプロセス内(in-process)で動かすのです。これにより、外部のプロファイリングツールが動作できない環境でも自分のコードをプロファイリングでき、追加のシステムコンポーネントのインストールや特別な権限も不要になります。OS の違いも吸収でき、現時点で macOS と Linux をサポートします。
Apple 自身も、OS 開発のビルド・テスト基盤を支える大規模な分散ストレージ・コンピュートシステムでこのツールを活用しています。これらのワークロードはレイテンシに敏感である一方、eBPF などのツールにアクセスできないサンドボックス環境で動き、一部は macOS 上で動作するため、最適でないコードを把握する手段として Swift Profile Recorder が作られました。具体的には、性能リグレッションの個別事例を安全に診断する用途と、基盤全体から多数のサンプルを集めて共通パターンを特定する継続的プロファイリング(Continuous Profiling)の用途で使われています。
何に使えるのか
導入は最小限の設定で済みます。まず Package.swift に依存を追加します。
// In your Package.swift
.package(url: "https://github.com/apple/swift-profile-recorder.git", .upToNextMinor(from: "0.3.0"))
// In your target dependencies
.product(name: "ProfileRecorderServer", package: "swift-profile-recorder")
次に、アプリケーションの起動処理でプロファイリングサーバーをバックグラウンドで起動します。
import ProfileRecorderServer
@main
struct YourApp {
func run() async throws {
// Start the profiling server in the background
async let _ = ProfileRecorderServer(configuration: .parseFromEnvironment()).runIgnoringFailures(logger: logger)
// Your application code continues here
}
}
configuration: .parseFromEnvironment() を指定した場合、プロファイリングサーバーは環境変数で有効化します。次のように URL パターンを指定して起動します。
PROFILE_RECORDER_SERVER_URL_PATTERN=unix:///tmp/my-app-samples-{PID}.sock ./my-app
サンプルの収集は curl で行えます。専用ツールの使い方を覚える必要はなく、HTTP エンドポイントにリクエストするだけです。
curl --unix-socket /tmp/my-app-samples-12345.sock \
-sd '{"numberOfSamples":1000,"timeInterval":"10ms"}' \
http://localhost/sample | swift demangle --compact > samples.perf
可視化と既存ツールとの連携
生成したプロファイルは、業界標準のフォーマットに対応しているため、人気の可視化ツールでそのまま扱えます。
- Speedscope(speedscope.app):
.perfファイルをドラッグ&ドロップすると、すぐに flame graph が表示されます - Firefox Profiler(profiler.firefox.com): プロファイルをアップロードして詳細なタイムライン分析ができます
- 従来の FlameGraph ツール: Brendan Gregg 氏の FlameGraph スクリプトでカスタムな可視化ができます
- そのほか
.perf/.pprof/ collapsed 形式に対応した多くのツール
加えて、Swift Profile Recorder は Parca や Pyroscope へサンプルを送るソースとしても利用できます。なお、本番環境で eBPF によるシステム全体のプロファイリングを導入できる場合は、Parca Agent と swift-parca の併用が推奨されています。
導入・今後の位置づけ
Swift Profile Recorder はオープンソースプロジェクトとして活発に開発されており、バグ報告・機能リクエスト・貢献が歓迎されています。Kubernetes 上で Swift アプリケーションを動かしている場合や、性能問題を調査している場合など、幅広いユースケースでのフィードバックが求められています(たとえば Lambda 関数への組み込みも可能とされています)。
先に発表された swift-parca と合わせて、サーバーサイド Swift のエコシステムには複数のプロファイリングツールと手法が揃いつつあります。