プロファイラの種類
LLVM にはすでに、コードをインストルメントして インストルメンテーション プロファイリング を行えるツールが含まれています。サンプリングまたは統計的プロファイリング とは異なり、コードのインストルメントが必要で、リソース消費も大きくなる一方、 呼び出しを一切取りこぼさずに非常に高い精度を実現できます。
簡単に言うと、インストルメンテーションプロファイラは、すべての関数呼び出しを追跡するためのコードを新たに挿入します。 一方、統計的プロファイラではコードを変更する必要がなく、定期的にスナップショットを取得して アプリケーションの状態を確認します。そのため、スナップショット取得時に実行中だった関数だけが 対象になります。perf は非常によく知られた 統計的プロファイラです。
XRay のインテグレーションを使用した ClickHouse のプロファイリング
ClickHouse 25.12 では、XRay が統合されており、関数に新しいインストルメンテーションポイントをシームレスに追加できます。 そのため、公式リリースにはこの機能がすでに含まれており、有効にしていないときでも全体的なパフォーマンスに 影響を与えることなく、必要に応じてトリガーできます。重要なのは、有用な情報を得るために必要最小限の インストルメンテーションポイントだけを有効にすることです。
新しいプロファイル用インストルメンテーションポイントは、SYSTEM INSTRUMENT ADD
PROFILE
ステートメントを使って追加できます。インストルメントする対象の関数は、
system.symbols システムテーブルから取得できます。たとえば、
sleepForNanoseconds 関数をプロファイリングしたいとします。これは、実行にどれくらい時間がかかるかを確認するのに
便利な関数です。
SYSTEM INSTRUMENT ADD 'sleepForNanoseconds' PROFILEその後、プロファイリングしたい時間だけ実行したままにしてから、停止します。
SYSTEM INSTRUMENT REMOVE ALLsystem.trace_log に収集されたデータを Chrome 形式 に変換し、Perfetto で 可視化します。各エントリの query_id、cpu_id、stacktrace に 注目してください。

XRay を使用したネイティブアプリケーションのプロファイリング
以下のセクションは、XRay の内部的な仕組みと、ネイティブアプリケーションのプロファイリングにそのまま利用する方法を理解するための参考として残しています。
コードをインストルメントする
次のソースコードを想像してください。
#include <chrono>
#include <cstdio>
#include <thread>
void one()
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
void two()
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
int main()
{
printf("Start\n");
for (int i = 0; i < 10; ++i)
{
one();
two();
}
printf("Finish\n");
}XRayでインストルメントするには、次のようないくつかのフラグを追加する必要があります。
clang++ -o test test.cpp -fxray-instrument -fxray-instruction-threshold=1- コードをインストルメントするには
-fxray-instrumentが必要です。 -fxray-instruction-threshold=1は、この例のように 非常に小さい関数であっても、すべての関数をインストルメントするために使用します。デフォルトでは、命令数が少なくとも 200 の 関数がインストルメントされます。
コードが正しくインストルメントされていることは、バイナリに新しいセクションが追加されているかどうかを確認することで確かめられます。
objdump -h -j xray_instr_map test
test: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
17 xray_instr_map 000005c0 000000000002f91c 000000000002f91c 0002f91c 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA適切な環境変数の値を設定してプロセスを実行し、トレースを収集する
デフォルトでは、明示的に要求しない限り、プロファイラによる収集は行われません。つまり、
profiling を行っていない限り、オーバーヘッドはごくわずかです。XRAY_OPTIONS にさまざまな値を設定することで、
プロファイラがいつ収集を開始するか、またどのように収集するかを構成できます。
XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1" ./test
==74394==XRay: Log file in 'xray-log.test.14imlN'
Start
Finish
==74394==Cleaned up log for TID: 74394トレースを変換する
XRay のトレースは、いくつかのフォーマットに変換できます。trace_event フォーマットは、パースしやすく、
すでに対応しているツールもいくつかあるため、ここではこれを使用します:
llvm-xray convert --symbolize --instr_map=./test --output-format=trace_event xray-log.test.14imlN | gzip > test-trace.txt.gzトレースを可視化する
speedscope.app や Perfetto のような Web ベースの UI を使用できます。
Perfetto は複数のスレッドの可視化やデータのクエリをしやすくしますが、speedscope は データのフレームグラフやサンドイッチビューの生成に適しています。
時系列順

左側に偏る

サンドイッチ

ドキュメントを確認する
- SYSTEM INSTRUMENT — インストルメンテーションポイントを追加 または削除します。
- system.instrumentation — インストルメントされたポイントを確認します。
- system.symbols — インストルメンテーションポイントを追加するための シンボルを確認します。
- system.trace_log — インストルメンテーションポイントを使用して収集されたデータを確認します。
- XRay Instrumentation
- 詳細については、Debugging with XRay のドキュメントを参照してください。