The Go Blog

Go 1.12でデプロイするものをデバッグする

David Chase
2019年3月21日

はじめに

Go 1.11とGo 1.12は、開発者が本番環境にデプロイするのと同じ最適化されたバイナリをデバッグできるようにする上で、大きな進歩を遂げました。

Goコンパイラがより高速なバイナリを生成するためにますます積極的になるにつれて、デバッグ可能性の面で後退していました。Go 1.10では、ユーザーはDelveのようなインタラクティブなツールから優れたデバッグ体験を得るために、最適化を完全に無効にする必要がありました。しかし、ユーザーはデバッグ可能性のためにパフォーマンスを犠牲にするべきではありません。特に本番サービスを実行している場合は。問題が本番環境で発生している場合、本番環境でデバッグする必要があります。そして、それは最適化されていないバイナリをデプロイすることを要求すべきではありません。

Go 1.11と1.12では、最適化されたバイナリ(Goコンパイラのデフォルト設定)でのデバッグ体験の向上に重点を置きました。改善点には以下が含まれます。

  • より正確な値の検査、特に関数エントリー時の引数について;
  • ステートメントの境界をより正確に識別し、ステップ実行がよりスムーズになり、ブレークポイントがプログラマの期待する場所に設定されることが多くなりました;
  • そして、DelveがGo関数を呼び出すための予備的なサポート(ゴルーチンとガベージコレクションにより、CやC++よりも複雑になります)。

Delveで最適化されたコードをデバッグする

Delveは、LinuxとmacOSの両方をサポートするx86上のGo用デバッガです。Delveはゴルーチンやその他のGo機能を認識しており、最高のGoデバッグ体験の1つを提供します。Delveは、GoLandVS CodeVimのデバッグエンジンでもあります。

Delveは通常、デバッグするコードを-gcflags "all=-N -l"で再構築します。これはインライン化とほとんどの最適化を無効にします。Delveで最適化されたコードをデバッグするには、まず最適化されたバイナリをビルドし、次にdlv exec your_programを使用してデバッグします。または、クラッシュからのコアファイルがある場合は、dlv core your_program your_coreで調べることができます。1.12と最新のDelveリリースでは、最適化されたバイナリでも多くの変数を調べることができます。

改善された値の検査

Go 1.10で生成された最適化されたバイナリをデバッグする場合、変数値は通常、完全に利用できませんでした。対照的に、Go 1.11から、変数が完全に最適化されて消滅していない限り、最適化されたバイナリでも通常は変数を調べることができます。Go 1.11では、コンパイラがDWARFロケーションリストを出力し始め、デバッガがレジスタに出入りする変数を追跡し、異なるレジスタとスタックスロットに分割された複雑なオブジェクトを再構築できるようになりました。

改善されたステップ実行

これは、1.10でデバッガで単純な関数をステップ実行する例を示しており、欠陥(スキップされた行と繰り返された行)が赤い矢印で強調表示されています。

このような欠陥により、プログラムをステップ実行しているときにどこにいるかを見失いやすくなり、ブレークポイントをヒットすることを妨げます。

Go 1.11と1.12はステートメントの境界情報を記録し、最適化とインライン化を通じてソース行番号をより適切に追跡します。その結果、Go 1.12では、このコードをステップ実行すると、すべての行で停止し、期待される順序で停止します。

関数呼び出し

Delveの関数呼び出しサポートはまだ開発中ですが、単純なケースは機能します。例えば

(dlv) call fib(6)
> main.main() ./hello.go:15 (PC: 0x49d648)
Values returned:
    ~r1: 8

今後の展望

Go 1.12は、最適化されたバイナリのデバッグ体験を向上させるためのステップであり、さらなる改善計画があります。

デバッグ可能性とパフォーマンスの間には根本的なトレードオフがあるため、私たちは最優先のデバッグ欠陥に焦点を当て、進捗を監視し、回帰を捕捉するための自動メトリクスを収集するよう取り組んでいます。

私たちは、変数ロケーションに関するデバッガのための正しい情報を生成することに焦点を当てているため、変数を印刷できる場合は正しく印刷されます。また、特に呼び出しサイトのような重要なポイントで、変数値をより多くの時間利用できるようにすることも検討していますが、多くの場合、これを改善するにはプログラム実行を遅くする必要があります。最後に、ステップ実行の改善に取り組んでいます。パニック発生時のステップ実行の順序、ループ周辺のステップ実行の順序、そして可能な限りソース順に従うことに一般的に焦点を当てています。

macOSサポートに関する注意

Go 1.11はバイナリサイズを削減するためにデバッグ情報の圧縮を開始しました。これはDelveによってネイティブにサポートされていますが、LLDBもGDBもmacOSでの圧縮されたデバッグ情報をサポートしていません。LLDBまたはGDBを使用している場合、2つの回避策があります。-ldflags=-compressdwarf=falseでバイナリをビルドするか、splitdwarfgo get golang.org/x/tools/cmd/splitdwarf)を使用して既存のバイナリのデバッグ情報を解凍します。

次の記事:Go 2018年調査結果
前の記事:Goモジュールを使用する
ブログインデックス