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

ロック lint の命名規則

ロック lint サブコマンドの多くは、 ロック名、変数名、ポインタ名、関数名の指定が必要です。一方、C では、名前をあいまいにしておくことが可能です。たとえば、foo と名付けられた複数の変数が存在し、その中の 1 つが extern で、残りが static であったりします。

C 言語には、変数の有効範囲に関する規則によって隠されている、あいまいな名前の変数を参照する方法がありません。しかし、ロック lint では、そうした変数を参照する方法が必要です。そのため、解析対象となるコード中の各記号には公式な名前が与えられ、ロック lint がその記号を参照する際に使用されます。表 A-3 は、関数の公式な名前の例を示します。

表 A-3 公式関数名の例

公式名 

定義 

:func

extern 関数

file:func

static 関数

表 A-4 は、ロック、ポインタ、本来の変数などの使用方法に応じた、変数の公式な名前を示します。

表 A-4 公式変数名の例

公式名 

定義 

:var

extern 変数 

file:var

static 変数 (ファイル範囲指定) 

:func/var

extern 関数中で定義された変数 

file:func/var

static 関数中で定義された変数 

tag::mbr

名前未定の struct のメンバー 

file@line::mbr

名前未定で、タグもない struct のメンバー 

さらに、これらの公式名の後には、struct のメンバーであることを意味する指定子 .mbr が、任意の回数続くことがあります。

表 A-5 は、ロック lint の命名スキーマの例を示します。

表 A-5 ロック lint の命名スキーマの例

例 

意味 

:bar

外部変数または関数 bar 

:main/bar

extern 関数 main 内で定義されている static 変数 bar 

zot.c:foo/bar.zot

ファイル zot.c 内の static 関数 foo で定義された、static 変数 bar のメンバー zot 

foo::bar.zot.bim

struct のインスタンスに名前が関連付けられていない (ポインタを介してアクセスされた)、タグ foo が付いた struct のメンバー bar のメンバー zot のメンバー bim 

ロック lint はこうした方法で名前を参照するといっても、これはユーザーに強制されるものではありません。あいまいにさえならなければ、識別に必要な最小限の名前を使用するだけでもかまいません。たとえば、変数 bar を定義している関数 foo が 1 つだけならば、foo/bar によって zot.c:foo/bar を参照できます。同じ名前の変数がほかになければ、bar だけでも参照できます。

C では、プログラマは、タグを割り当てることなく構造体を宣言できます。そうした構造体に対するポインタを使用する場合、ロック lint は、構造体を参照するためのタグを作成しなければなりません。ロック lint は filename@line_number という形式のタグを生成します。たとえば、ファイル foo.c の 42 行目にタグなしの構造体を宣言した後、ポインタを使ってその構造体のインスタンスのメンバー bar を参照すると、次のようになります。


typedef struct { ...  } foo;
foo *p;
func1() { p->bar = 0; }

ロック lint は、それを foo.c@42::bar に対する参照とみなします。

union のメンバーは同じメモリロケーションを共有するため、ロック lint は union のメンバーすべてを同じ変数として扱います。これは、どのメンバーが利用されたかに関わらず、メンバー名 % を利用することで遂行されます。ビットフィールドは一般的に変数におけるメモリの共有を含むため、これらも同様に扱われます。つまり、ビットフィールドのメンバー名の代わりに % が使用されます。

ロックおよび変数をリストすると、.ll ファイルによって表されるコード内で実際に使用されているロックおよび変数のみが表示されます。宣言はされていても、使用されていないロック、変数、ポインタおよび関数についての情報はロック lint から得られません。同様に、ポインタを介した単純な型に対するアクセスの情報も得られません。


int *ip = &i;
*ip = 0;

単純な名前 (foo など) を使用する場合は、サブコマンド言語のキーワードと競合する可能性が出てきます。こうした競合は、単語を二重引用符で囲むことによって避けられますが、シェルにコマンドを入力する場合、シェルは通常、引用符の外側の部分から処理することを念頭に置いてください。そのため、以下の例のように、引用符をエスケープする必要があります。


% lock_lint ignore foo in func ¥"func"¥

同じベース名を持つ 2 つのファイルが解析の対象となり、いずれのファイルにも同じ名前の static 変数が含まれる場合、混乱が生じます。ロック lint は、2 つの変数が同じものとみなすことになります。

タグのない struct に対する定義を複製する場合、ロック lint はその定義を同じ struct と認識しません。ロック lint は struct が定義されているファイル名と行番号を基にタグ (x.c@24 など) を作成するため、そのタグは 2 つの定義で異なるからです。

関数に同じ名前を持った自動変数が複数含まれている場合、ロック lint はその違いを区別できません。ロック lint は、関数ポインタとして使用されている場合を除き、自動変数を無視するため、こうした事態は頻繁には生じません。たとえば、以下のコードで、ロック lint は、2 つの関数ポインタに :foo/fp という名前を使用しています。


int foo(void (*fp)()) {
    (*fp)();
    {
        void (*fp)() = get_func();
        (*fp)();
     ...