プログラムのパフォーマンス解析

ロック lint の analyze フェーズ

解析中に遭遇する各問題箇所は、1 行または数行に渡って報告され、その先頭行はアスタリスクから始まります。可能な箇所では、ロック lint は問題箇所にたどり着くまでの呼び出しの完全なトレースバックを提供します。解析は以下のフェーズを経て進行します。

  1. ロックに関して変数の副作用を持った関数をチェックします。

    disallow シーケンスによって、ロック副作用を持った関数を解析対象から外すよう指定されている場合、ロック lint は正しくない結果を生成します。そうした disallow シーケンスが見つかると、報告が行われ、解析は行われません。

  2. 保持するロックの順序に関する情報を準備します。

    ロック lint は、アサートされているロックの順序に関する情報を処理します。ロック lint がアサートされているロックの順序の中に循環部分を検出した場合、その循環部分はエラーとして報告されます。

  3. ターゲットのない関数ポインタをチェックします。

    ロック lint は、関数ポインタの割り当て状況をつねに推測できるわけではありません。このフェーズでは、ロック lint は、1 つのターゲット (ソースから推測されるか、func.ptr ターゲットが宣言されている) も存在しないと思われる関数ポインタを報告します。

  4. 無視される変数へのアクセスを削除します。

    パフォーマンスを改善するため、ロック lint は、この時点で無視されている変数に対する参照を削除します (これは vars サブコマンドの出力に影響します)。

  5. 解析の対象となる関数を準備します。

    このフェーズでは、ロック lint は、各関数がロックについてどんな副作用を持っているかを確認します (副作用とは、関数から戻る前に復旧しないロック状態の変化を指します)。以下の状況では、エラーが生じます。

    • 副作用がロック lint の予想と一致しない場合。

    • 副作用が、関数が通過するパスに応じて異なる場合。

    • そうした副作用を持った関数が再帰的である場合。

    ロック lint は、assert side effect サブコマンドを使って副作用が追加されている箇所を除き、関数がロックに副作用を持たないと予想します。

  6. allow/disallow に対する呼び出しシーケンスの確認を準備します。

    この時点で、ロック lint はすでに指示されているさまざまな allow/disallow サブコマンドを処理します。エラーや警告は報告されません。

  7. 関数ポインタターゲットのロック副作用をチェックします。

    関数ポインタを介した呼び出しは、複数の関数をターゲットにしていることがあります。特定の関数ポインタのターゲットである関数はすべて、ロックに同じ副作用を持たなければなりません (該当する場合) 。副作用が異なる複数のターゲットを関数ポインタが持つ場合、解析は行われません。

  8. 状態変数のロックの使用法の整合性をチェックします。

    この時点で、ロック lint は、特定の状態変数での待機が同じ相互排他ロックを使用しているかをチェックします。また、その状態変数を保護している特定のロックをアサートする場合、ロック lint は、状態変数での待機中、必ずそのロックを使用するかをユーザに確認します。

  9. 各関数に制御が渡されたときに、整合性が保持されるロックを確認します。

    このフェーズでは、ロック lint は、関数へのエントリに際して保持されるべきロックのアサーションの破綻を報告します (「assert」 サブコマンドを参照)。すでに保持されている相互排他ロックをロックしたり、保持されていないロックを解放するなどのエラーもまた報告されます。匿名のロック (foo::lock など) を2 回以上ロックしても、declare one コマンドを使用してそうでない状況を指示していない限り、エラーと見なされません (匿名データについての詳細は、 「ロックの逆転」 を参照してください)。

  10. 各変数がアクセスされたときに、整合性が保持されるロックを確認します。

    このフェーズでは、ロック lint は、変数がアクセスされるときに保持されるべきロックのアサーションの破綻を報告します (「assert」サブコマンドを参照)。また、書き込み禁止の変数に対する書き込みも報告されます。

    時には、特定の関数がまったく呼び出されなかったというメッセージを受け取る場合もあります。ルート関数でない一連の関数が交互に呼び出し合うと、こうした状況は起こります。ただ 1 つの関数もその外部から呼び出されないと、ロック lint は、それらの関数はまったく呼び出されなかったと報告します。その後の解析において、declare root サブコマンドを使うことで、こうした状況を修復できます。

    また、disallow サブコマンドを使って、関数にたどりつくまでのすべてのシーケンスを禁じる場合にも、関数がまったく呼び出されないというメッセージが報告されます。

いったん解析を実行した後では、vars および order サブコマンドの出力において、さらに多くの潜在的な問題を見つけ出すことが可能です。