bootstrap のデバッグ
デバッグ(および bootstrap のプロファイリング)には、主に 2 つの方法があります。1 つ目は println ロギングによる方法で、2 つ目は tracing 機能による方法です。
println ロギング
Bootstrap には、構造化されていない広範なロギングがあります。その大半は --verbose フラグの背後にゲートされています(さらに詳細を得るには -vv を渡します)。
実行された Cargo コマンドの詳細な出力や、その他の種類の詳細ログを確認したい場合は、bootstrap を呼び出すときに -v または -vv を渡してください。ログは構造化されておらず、圧倒される量になる可能性があることに注意してください。
$ ./x dist rustc --dry-run -vv
learning about cargo
running: RUSTC_BOOTSTRAP="1" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "metadata" "--format-version" "1" "--no-deps" "--manifest-path" "/home/jyn/src/rust2/Cargo.toml" (failure_mode=Exit) (created at src/bootstrap/src/core/metadata.rs:81:25, executed at src/bootstrap/src/core/metadata.rs:92:50)
running: RUSTC_BOOTSTRAP="1" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "metadata" "--format-version" "1" "--no-deps" "--manifest-path" "/home/jyn/src/rust2/library/Cargo.toml" (failure_mode=Exit) (created at src/bootstrap/src/core/metadata.rs:81:25, executed at src/bootstrap/src/core/metadata.rs:92:50)
...
bootstrap における tracing
Bootstrap には条件付きの tracing 機能があり、次の機能を提供します。
tracingのイベントと span を使用した構造化ロギングを有効にします。- 実行されたステップとコマンドの階層と所要時間を可視化するために使用できる Chrome trace file を生成します。
- 生成された
chrome-trace.jsonファイルは、Chrome のchrome://tracingタブで開けます。または、たとえば Perfetto を使用して開けます。
- 生成された
- 実行されたステップ間の依存関係を可視化する GraphViz グラフを生成します。
- 生成された
step-graph-*.dotファイルは、たとえば xdot を使用して開いてステップグラフを可視化できます。または、たとえばdot -Tsvgを使用して GraphViz ファイルを SVG ファイルに変換できます。
- 生成された
- コマンド実行サマリーを生成します。これには、どのコマンドが実行されたか、それらの実行のうちいくつがキャッシュされたか、実行に最も時間がかかったコマンドはどれかが示されます。
- 生成された
command-stats.txtファイルは、シンプルで人間が読みやすい形式です。
- 生成された
構造化ログは標準エラー出力(stderr)に書き込まれます。一方、その他の出力は <build-dir>/bootstrap-trace/<pid> ディレクトリ内のファイルに保存されます。利便性のため、bootstrap は最後に生成されたトレース出力ディレクトリへのシンボリックリンクも <build-dir>/bootstrap-trace/latest に作成します。
--dry-runで bootstrap を実行すると、tracing 出力ディレクトリが変わる可能性があることに注意してください。Bootstrap は、実行の最後に tracing 出力ファイルが保存されたパスを常に表示します。
tracing 出力の有効化
条件付きの tracing 機能を有効にするには、BOOTSTRAP_TRACING 環境変数を指定して bootstrap を実行します。
$ BOOTSTRAP_TRACING=trace ./x build library --stage 1
出力例1:
$ BOOTSTRAP_TRACING=trace ./x build library --stage 1 --dry-run
Building bootstrap
Finished `dev` profile [unoptimized] target(s) in 0.05s
15:56:52.477 INFO > tool::LibcxxVersionTool {target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.575 INFO > compile::Assemble {target_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }} (builder/mod.rs:1715)
15:56:52.575 INFO > tool::Compiletest {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.576 INFO > tool::ToolBuild {build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, tool: "compiletest", path: "src/tools/compiletest", mode: ToolBootstrap, source_type: InTree, extra_features: [], allow_features: "internal_output_capture", cargo_args: [], artifact_kind: Binary} (builder/mod.rs:1715)
15:56:52.576 INFO > builder::Libdir {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.576 INFO > compile::Sysroot {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, force_recompile: false} (builder/mod.rs:1715)
15:56:52.578 INFO > compile::Assemble {target_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }} (builder/mod.rs:1715)
15:56:52.578 INFO > tool::Compiletest {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.578 INFO > tool::ToolBuild {build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu, tool: "compiletest", path: "src/tools/compiletest", mode: ToolBootstrap, source_type: InTree, extra_features: [], allow_features: "internal_output_capture", cargo_args: [], artifact_kind: Binary} (builder/mod.rs:1715)
15:56:52.578 INFO > builder::Libdir {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, target: x86_64-unknown-linux-gnu} (builder/mod.rs:1715)
15:56:52.578 INFO > compile::Sysroot {compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, force_recompile: false} (builder/mod.rs:1715)
Finished `release` profile [optimized] target(s) in 0.11s
Tracing/profiling output has been written to <src-root>/build/bootstrap-trace/latest
Build completed successfully in 0:00:00
tracing 出力の制御
環境変数 BOOTSTRAP_TRACING は、tracing_subscriber フィルター を受け付けます。BOOTSTRAP_TRACING=trace を設定すると、すべてのログが有効になりますが、圧倒される量になる可能性があります。そのため、フィルターを使用してログに記録されるデータ量を減らすことができます。
どの種類の tracing ログを必要とするかを制御するには、互いに直交する 2 つの方法があります。
- ログのレベルを指定できます。例:
debugまたはtrace。- レベルを選択すると、同等またはより高い優先度レベルを持つすべてのイベント/スパンが表示されます。
- ログのターゲットも制御できます。例:
bootstrap、bootstrap::core::config、またはCONFIG_HANDLINGやSTEPのようなカスタムターゲット。- カスタムターゲットは、関心のあるスパンの種類を限定するために使用されます。
BOOTSTRAP_TRACING=traceの出力は非常に冗長になる可能性があるためです。現在、以下のカスタムターゲットを使用できます。CONFIG_HANDLING: config 処理に関連するスパンを表示します。STEP: 実行されたすべてのステップを表示します。実行されたコマンドはinfoイベントレベルを持ちます。COMMAND: 実行されたすべてのコマンドを表示します。実行されたコマンドはtraceイベントレベルを持ちます。IO: 実行された I/O 操作を表示します。実行されたコマンドはtraceイベントレベルを持ちます。- 現在、多くの I/O はトレースされていないことに注意してください。
- カスタムターゲットは、関心のあるスパンの種類を限定するために使用されます。
もちろん、これらを組み合わせることもできます(カスタムターゲットログは通常、追加で TRACE ログレベルの背後で制御されます)。
$ BOOTSTRAP_TRACING=CONFIG_HANDLING=trace,STEP=info,COMMAND=trace ./x build library --stage 1
BOOTSTRAP_TRACING を使用して指定するレベルは、Chrome トレースファイルに記録されるスパンにも影響することに注意してください。
FIXME(#96176): compiler() と compiler_for() の個別の tracing
追加のターゲット COMPILER と COMPILER_FOR は、
builder.compiler() と builder.compiler_for() が何を行うかをトレースするのに役立ちます。
#96176 が解決された場合、これらは削除されるべきです。
bootstrap で tracing を使用する
tracing::* マクロと tracing::instrument proc-macro 属性の両方を、tracing feature の背後で制御する必要があります。例:
#[cfg(feature = "tracing")]
use tracing::instrument;
struct Foo;
impl Step for Foo {
type Output = ();
#[cfg_attr(feature = "tracing", instrument(level = "trace", name = "Foo::should_run", skip_all))]
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
trace!(?run, "entered Foo::should_run");
todo!()
}
fn run(self, builder: &Builder<'_>) -> Self::Output {
trace!(?run, "entered Foo::run");
todo!()
}
}
#[instrument] については、以下が推奨されます。
- 細かい粒度では
traceレベルの背後で制御し、コア関数では場合によってdebugレベルの背後で制御します。 name = ".."を通じて instrumentation 名を明示的に選択し、たとえば異なるステップのrunを区別します。- tracing によって挙動の分岐を引き起こさないよう注意してください。たとえば、tracing 基盤が有効な場合にのみ追加のものをビルドする、といったことです。
rust-analyzer 統合?
残念ながら、bootstrap は rust-analyzer.linkedProjects であるため、https://github.com/rust-lang/rust-analyzer/issues/8521 で説明されているようにサポートが不足しており、関連する補完を得るために tracing feature を有効にして bootstrap 自体をチェック/ビルドするよう r-a に依頼することはできません。
-
この出力は常に今後変更される可能性があります。 ↩