Rustでも継続的プロファイリングしよう!
「本番環境で実行中のアプリケーションをプロファイリング」
継続的インテグレーション、継続的デリバリ、継続的デプロイ、継続的テストなど、「継続的な何か」の導入数が多いほど、おしゃれな会社であることをアピールできそうです。
今回は、Rustで実装されたアプリケーションの継続的プロファイリングを検討してみました。
業界標準データフォーマット
継続的プロファイリングに関して、複数の商用サービス(Google Cloud Profiler、Datadog Continuous Profilerなど)やOSS(profefe、Pyroscopeなど)が存在しますが、その多くが、Googleが開発したpprofというプロファイリングデータの可視化・分析ツールのデータフォーマットを利用しています。それらのプロダクトは、対象のアプリケーションが、定期的にプロファイルデータを取得し、pprofのデータフォーマットをサーバに送信します。
pprofのフォーマットは、Protocol Buffersで定義されており、取得したスタックトレースや関数名などに関する情報が含まれています。Rustの継続的プロファイリングも、pprofのフォーマットを使うのがよさそうです。
ユーザモードとカーネルモードのプロファイリング
前回の記事で紹介したように、Rustはプロファイリングツールを標準機能として提供しませんが、複数のプロファイリングツールが開発されています。その中の1つ、pprof-rsは、pprofフォーマットでの出力をサポートしています。
Linuxのパフォーマンスチューニング界の第一人者、Brendan Gregg氏は、「は?ユーザモードのプロファイラ?」と言っており[1]、ユーザモードで動作するpprof-rsでは、おしゃれ感をアピールできそうにありません。今回は、カーネルモードで動作するプロファイリングツールのperfを使ってみます。
カーネルモードを利用するツールは、CPUの機能を利用し、低いオーバヘッドでプロファイリングできる、などの利点を持ちます。前回の記事では、そんな話の流れじゃなかったと、もやもやした気持ちになるかもしれませんが、忘れてください。
perfフォーマットからpprofへの変換
perfは独自のデータフォーマットを利用しているため、pprofフォーマットへの変換が必要です。検索して見つかったGoogleが開発しているperf_data_converterを試してみましたが、エラーのため変換できませんでした。
$ perf_to_profile -i perf.data -o cpu.pprof[WARNING:src/quipper/perf_reader.cc:1318] Skipping 200 bytes of metadata: HEADER_CPU_TOPOLOGY
[WARNING:src/quipper/perf_reader.cc:1065] Skipping unsupported event PERF_RECORD_CPU_MAP
[ERROR:src/quipper/sample_info_reader.cc:385] PERF_SAMPLE_REGS_USER is not yet supported.
[ERROR:src/quipper/perf_reader.cc:1049] Couldn't read event PERF_RECORD_SAMPLE
[ERROR:src/perf_data_converter.cc:749] Could not read input perf.data
[FATAL:src/perf_to_profile.cc:33] Expected profile vector to have one element.
上記の問題は2018年に報告されているのですが、これまで対応されていません。皆さんは、今すぐ、おしゃれ感をアピールしたいという気持ちですよね。perfのフォーマットをpprofに変換するツールをRustで実装してみました。あとは、導入する継続的プロファイリングのプロダクトのサーバに、送信する機能を実装するだけですね。
まとめ
Rustでパフォーマンスを追求したいというエンジニアのみなさま、NTTでは仲間を募集中です。
[1] I always start with kernel-based profilers (perf(1) and profile(8)) and use user-based ones as a last resort. Gregg, Brendan. Systems Performance (2nd ed.).