Skip to main content

メトリクス

提供されるメトリクスの詳細な説明 CODESYS Static Analysis

ヒント

コードサイズ可変サイズスタックサイズ、 そして コール数 メトリクスは、プロジェクトに統合されているライブラリからの POU についてのみレポートされます。

メトリクス: コードサイズ (バイト数)

カテゴリ: 有益、効率

ファンクション ブロックがアプリケーション コードに寄与するバイト数

この数はコード ジェネレーターによっても異なります。たとえば、ARM プロセッサ用のコード ジェネレータは通常、x86 プロセッサ用のコード ジェネレータよりも多くのバイトを生成します。

メトリック: 可変サイズ (バイト数)

カテゴリー: 有益、効率化

オブジェクトが使用する静的メモリのサイズ

関数ブロックの場合、これは関数ブロックのインスタンスに使用されるサイズです (メモリ アライメントに応じて、メモリ ギャップが含まれる場合があります)。プログラム、関数、およびグローバル変数リストの場合、これはすべての静的変数のサイズの合計です。

FUNCTION FUN1 : INT
VAR_INPUT
    a,b : INT;
END_VAR
VAR
    c,d : INT;
END_VAR
VAR_STAT
    f,g,h : INT;
END_VAR

この関数には次の型の 3 つの静的変数があります。 INT (fg、 そして h)、それぞれに 2 バイトのメモリが必要です。結果として、 FUN1 可変サイズは 6 バイトです。

メトリック: スタック サイズ (バイト数)

カテゴリー: 有益、効率、信頼性

関数または関数ブロックの呼び出しに必要なバイト数

入力変数と出力変数はメモリに合わせて配置されます。これにより、これらの変数とローカル変数の間にギャップが生じる可能性があります。このギャップがカウントされます。

呼び出された関数の戻り値がレジスタに収まらない場合は、スタックにプッシュされます。これらの値の最大値によって追加の割り当てメモリが決まり、これもカウントされます。検討中の POU 内で呼び出される関数または関数ブロックには、独自のスタック フレームがあります。したがって、そのような呼び出しのためのメモリはカウントされません。

使用するコード ジェネレーターによっては、計算の中間結果でもスタックが使用されます。これらの結果はカウントされません。

132.
//Declaration
FUNCTION FUN1 : INT
VAR_INPUT
    a,b : INT;
END_VAR
VAR
    c,d,e : INT;
END_VAR
VAR_STAT
    f,g,h : INT;
END_VAR

//Implementation
c := b;
d := a;
e := a+b;

仮定: 計算のために、次のことを仮定します。 CODESYS Control Win x86 コードジェネレーターを使用します。

上の例の呼び出し元のサイズは 8 バイトです。つまり、2 つの呼び出し元のサイズは 4 バイトです。 INT inputs 戻り値用の 4 バイト。デバイスのスタック アライメントは 4 バイトであるため、2 バイトのギャップがあります。呼び出し元のサイズは 8 バイトです。それぞれ 2 バイトの 3 つのローカル変数に、スタック アライメント用の 2 バイトのギャップを加えたものです。その結果、スタックの合計サイズは、 FUN1 は 16 バイトです。

VAR_STAT スタックに格納されないため、POU のスタック サイズは増加しません。



メトリクス: コール数 (コール)

カテゴリー: 有益な情報

POU のコール数 プログラムユニット

133.
//Declaration PLC_PRG
PROGRAM PLC_PRG
VAR
    myFB : FB1;
END_VAR

//Implementation
myFB(b := FALSE);
//Declaration FB1
FUNCTION_BLOCK FB1
VAR_INPUT
    b : BOOL;
END_VAR
VAR
    i : INT;
END_VAR

//Implementation
METH(i);
IF b THEN
    METH(i*i);
END_IF
//Declaration FB1.METH
METHOD METH : BOOL
VAR_INPUT
    i : INT;
END_VAR

//Implementation
METH := i >= 42;

もし PLC_PRG タスク内で呼び出された場合、この呼び出しもカウントされます。

FB1 呼び出しが 1 つだけあります ( PLC_PRG)。

METH 2 つの呼び出しがあり、両方とも FB1



メトリック: タスクからの呼び出し数 (タスク)

カテゴリー:保守性、信頼性

タスクの数 (タスク) ここで、POU は以下で指定されます。 プログラムユニット と呼ばれます

ファンクション ブロックの場合、ファンクション ブロック自体、またはファンクション ブロックの継承ツリー内の任意のファンクション ブロックが呼び出されるタスクの数がカウントされます。

メソッドとアクションの場合、(親) ファンクション ブロックが呼び出されるタスクの数が表示されます。

134.
FUNCTION_BLOCK FB
//...
FUNCTION_BLOCK FB2 EXTENDS FB
//...
FUNCTION_BLOCK FB3 EXTENDS FB2
//...

各関数ブロックは独自に呼び出されます。 PROGRAM。それぞれ PROGRAM には独自のタスクがあります。

タスクで呼び出される メトリクスは 1 を返します FB3 と2 FB2 なぜなら、からの電話は FB3 そして FB2 カウントされます。メトリクスの結果は 3 になります。 FB この場合、からの呼び出しは FB3FB2、 そして FB カウントされます。



メトリック: 使用されるグローバル変数の数 (グローバル)

カテゴリー: 保守性、再利用性

POU で使用されているグローバル変数の数 プログラムユニット

135.
//GVL
VAR_GLOBAL
    gvla : INT;
    gvlb : INT;
    gvlc : INT;
END_VAR
/PRG declaration
PROGRAM PRG
VAR
    x : INT := GVL.gvlc;
    y : INT;
END_VAR

//PRG implementation
x := GVL.gvla;
y := GVL.gvla*GVL.gvlb;

PRG プログラムは次の 3 つの変数を使用します GVL: gvlagvlb、 そして gvlc



メトリクス: ダイレクト アドレス アクセス (IO) の数

カテゴリー: 再利用性、保守性

ダイレクトアドレスアクセス数(IO) オブジェクトの実装で。

136.
//Declaration
PROGRAM PRG
VAR
    xVar : BOOL:= %IX0.0; // +1 direct address access
    byVar : BYTE;
END_VAR

//Implementation
xVar := %IX0.0; // +1 direct address access
%QX0.0 := xVar; // +1
%MX0.1 := xVar; // +1
%MB1 := byVar; // +1

この例には 5 つの直接アドレス アクセスがあります。



メトリック: ローカル変数の数 (ローカル)

カテゴリー: 有益、効率化

で宣言された変数の数 VAR POU の領域。継承された変数はカウントされません。

137.
//Declaration
FUNCTION_BLOCK FB
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
    i,j,k,l : INT;
    m,n,o : BOOL;
END_VAR

ファンクションブロック内では7つのローカル変数が宣言されています。



メトリクス: 入力変数 (Input) の数

カテゴリー: 保守性、再利用性

対応するデフォルトの上限 SA0166 ルール: 10

で宣言された変数の数 VAR_INPUT プログラム単位の。継承された入力変数はカウントされません。

138.
FUNCTION_BLOCK FB
VAR_INPUT
    i : INT;
    r : REAL;
END_VAR

関数ブロックでは、2 つの入力変数が宣言されています。 i そして r

METHOD METH : BOOL
VAR_INPUT
    j : INT;
    l : LREAL;
END_VAR

このメソッドには 2 つの入力があります。 j そして l



メトリック: 出力変数の数 (出力)

カテゴリー: 保守性、再利用性

対応するデフォルトの上限 SA0166 ルール: 10

変数の数 VAR_OUTPUT プログラム単位の

ファンクション ブロックの場合、これはカスタム出力変数の数です (VAR_OUTPUT)。メソッドと関数の場合、これはカスタム出力変数の数に戻り値がある場合は 1 を加えたものになります。戻り値もカウントされます。継承された出力変数はカウントされません。

出力変数の数が多い場合は、一意の責任の原則に違反していることを示します。

139.
FUNCTION_BLOCK FB
VAR_OUTPUT
    i : INT;    // +1 output
    r : REAL;   // +1 output
END_VAR

関数ブロックには 2 つの出力変数があります。 i そして r

METHOD METH : BOOL
VAR_INPUT
    j : INT;
    l : LREAL;
END_VAR

このメソッドには 3 つの出力があります。 METHj、 そして l

METHOD METH1                    // +0 outputs (no return type)
VAR_OUTPUT
    ar : ARRAY[0..10] OF INT;   // +1 output
    l : LREAL;                  // +1 output
END_VAR

METH1 メソッドには 2 つの出力があります。 ar そして i



メトリック: NOS – ステートメントの数

カテゴリー: 有益な情報

ファンクションブロック、関数、またはメソッドの実装におけるステートメントの数

宣言内のステートメント、空のステートメント、またはプラグマはカウントされません。

140.
//Declaration:
FUNCTION POU : BOOL
VAR_INPUT
END_VAR
VAR
    c : INT := 100; // statements in the declaration are not counted
END_VAR
VAR_OUTPUT
    test : INT;
    i : INT;
END_VAR

//Implementation:
IF TRUE THEN //if statement: +1
    test := 0; // +1
END_IF

WHILE test = 1 DO //while statement: +1
    ; // empty statements do not add to the statement count
END_WHILE

FOR c := 0 TO 10 BY 2 DO //for statement: +1
    i := i+i; // +1
END_FOR

{text 'simple text pragma'} //pragmas are not counted
test := 2; //+1

この例には 6 つのステートメントがあります。



指標: コメントの割合

カテゴリー: メンテナンス性

ソースコード内のコメントの割合

この数値は次の式に従って計算されます。

パーセンテージ = 100 * <コメント内の文字数> / <ソース コード内の文字数とコメント内の文字数の合計>

ソース コード内の複数の連続したスペースは 1 つのスペースとしてカウントされるため、インデントされたソース コードの重み付けが高くなります。空のオブジェクト (ソース コードもコメントもなし) の場合は、0 のパーセンテージが返されます。

141.

宣言部分:

FUNCTION_BLOCK FB //comments in the declaration are counted, as well
VAR_TEMP
    hugo : INT;
END_VAR

実装:

hugo := hugo + 1;
//Declaration: 40 letters non comment; 50 letters comment
//Implementation: 13 letters non comment; 152 letters comment
// 100 * 202 / 255 -> 79% comments

パーセンテージ 100 * 202 / 255 を計算すると、79% が返されます。



指標: 複雑さ (McCabe)

カテゴリー: テスト容易性

推奨上限:10

McCabe 氏によると、循環的複雑さはソース コードの読みやすさとテストしやすさの尺度です。これは、POU の制御フロー内のバイナリ分岐の数をカウントすることによって計算されます。ただし、分岐が多いとテスト カバレッジを高めるために必要なテスト ケースの数が増加するため、循環的な複雑さによって分岐が多くなると不利になります。

142. 例: IF 声明
// every POU has an initial cyclomatic complexity of 1, since it has at least 1 branch
IF b1 THEN                // +1 for the THEN branch
    ;
    ELSIF b2 THEN        // +1 for the THEN branch of the IF inside the else
        ;
ELSE                    
    IF b3 OR b4 THEN    // +1 for the THEN branch
        ;
    END_IF
END_IF

コード スニペットの循環複雑度は 4 です。



143. 例: CASE 声明
// every POU has an initial cyclomatic complexity of 1, since it has at least 1 branch
CASE a OF
    1:	;    // +1
    2:	;    // +1
    3,4,5:	;    // +1
ELSE    // the ELSE statement does not increase the cyclomatic complexity
    ;
END_CASE

コード スニペットの循環複雑度は 4 です。



144. 例: ループステートメント
// every POU has an initial cyclomatic complexity of 1, since it has at least 1 branch
WHILE b1 DO    // +1 for the WHILE loop
    ;
END_WHILE

REPEAT    // +1 for the REPEAT loop
    ;
    UNTIL b2
END_REPEAT

FOR a := 0 TO 100 BY 2 DO    // +1 for the REPEAT loop
    ;
END_FOR

コード スニペットの循環複雑度は 4 です。



145. 例: その他のステートメント

次のステートメントも循環的複雑さを増大させます。

//Declaration
FUNCTION FUN : STRING
VAR_INPUT
    condition_return : BOOL;
    condition_jmp : BOOL;
END_VAR
VAR
END_VAR

//Implementation
// every POU has an initial cyclomatic complexity of 1, since it has at least 1 branch
JMP(condition_jmp) lbl;    //Conditional jumps increase the cyclomatic complexity by 1

FUN := 'u';
RETURN(condition_return);    //Conditional returns increase the cyclomatic complexity by 1, too

lbl:
FUN := 't';

コード スニペットの循環複雑度は 3 です。



指標: 認知の複雑さ

カテゴリー: メンテナンス性

対応する SA0178 ルールのデフォルトの上限: 20

認知的複雑さは、2016 年に Sonarsource™ によって導入されたソース コードの読みやすさと理解しやすさの尺度です。ただし、制御フローの大量のネストや複雑なブール式にはペナルティが課せられます。認知の複雑さは、構造化テキストの実装についてのみ計算されます。

次の例は、認知の複雑性がどのように計算されるかを示しています。

ヒント

現在のエディターの認知的複雑性を表示 コマンドを使用すると、構造化テキストの増分をさらに表示できます。

146. 例: 制御フロー

制御フローを操作するステートメントは認知の複雑さを 1 増加させます

IF TRUE THEN    // +1 cognitive complexity
    ;
END_IF

WHILE TRUE DO    //+1 cognitive complexity
    ;
END_WHILE

FOR i := 0 TO 10 BY 1 DO    //+1 cognitive complexity
    ;
END_FOR

REPEAT    //+1 cognitive complexity
    ;
UNTIL TRUE
END_REPEAT

コード スニペットの認知複雑度は 4 です。



147. 例: 制御フローのネスト

制御フローをネストする場合、ネストのレベルごとに 1 ずつ追加されます。

IF TRUE THEN                        //+1 cognitive complexity
    WHILE TRUE DO                   //+2 (+1 for the loop itself, +1 for the nesting inside the IF)
        FOR i := 0 TO 10 BY 1 DO    //+3 (+1 for the FOR loop itself, +2 for the nesting inside the WHILE and the IF)
			;
        END_FOR
    END_WHILE

    REPEAT                          //+2 (+1 for the loop itself, +1 for the nesting inside the IF)
        ;
        UNTIL TRUE
    END_REPEAT
END_IF

コード スニペットの認知複雑度は 8 です。



148. 例: ブール式

ブール式はソース コードを理解する上で重要な役割を果たすため、認知の複雑さを計算するときにも考慮されます。

同じブール演算子に関連付けられたブール式を理解することは、交互のブール演算子を含むブール式を理解することほど難しくありません。したがって、式内に同一のブール演算子が連鎖すると、認知の複雑さが増大します。

b := b1;    //+0: a simple expression, containing no operators, has no increment

演算子のない単純な式の増分は 0 です。

b := b1 AND b2;    //+1: one chain of AND operators

を使った表現は、 AND リンクの増分は 1 です。

b := b1 AND b2 AND b3;    //+1: one more AND, but the number of chains of operators does not change

この式にはもう 1 つあります AND。ただし、同じ演算子であるため、同じ演算子で形成されるチェーンの数は変わりません。

b := b1 AND b2 OR b3;    //+2: one chain of AND operators and one chain of OR operators

式には次のような連鎖があります。 AND 演算子と一連の OR オペレーター。これにより、増分は 2 になります。

b := b1 AND b2 OR b3 AND b4 AND b5;    //+3

コード スニペットの増分は 3 です。

b := b1 AND NOT b2 AND b3;    //+1: the unary NOT operator is not considered in the cognitive complexity

単項演算子 NOT 認知の複雑さでは考慮されていません。



149. 例: インクリメントのあるその他のステートメント

構造化テキストには、制御フローを変更する追加のステートメントと式があります。

次のステートメントには、認知の複雑さが増すというペナルティが課されます。

aNewLabel:
x := MUX(i, a,b,c); //+1 for MUX operator
y := SEL(b, i,j);   //+1 for SEL operator
JMP aNewLabel;      //+1 for JMP to label

EXIT そして RETURN ステートメントは認知の複雑さを増加させません。



メトリック: DIT – 継承ツリーの深さ

カテゴリー: メンテナンス性

他の機能ブロックを拡張しない機能ブロックに到達するまでの継承の数

150.
FUNCTION_BLOCK MyBaseFB
// ...
FUNCTION_BLOCK AChildFB EXTENDS MyBaseFB
// ...
FUNCTION_BLOCK AGrandChildFB EXTENDS AChildFB
// ...

MyBaseFB は、それ自体が他の機能ブロックを拡張しない機能ブロックであるため、DIT は 0 です。

のために AChildFBに到達するには 1 つのステップが必要であるため、DIT は 1 です。 MyBaseFB

AGrandChildFB DIT は 2 です。次の手順が 1 つ必要です。 AChildFB そしてもう一つは MyBaseFB



指標: NOC – 子供の数

カテゴリー: 再利用性、保守性

指定された基本機能ブロックを拡張する機能ブロックの数。基本機能ブロックを間接的に拡張する機能ブロックはカウントされません。

151.
FUNCTION_BLOCK MyBaseFB
// ...
FUNCTION_BLOCK AChildFB EXTENDS MyBaseFB
// ...
FUNCTION_BLOCK AGrandChildFB EXTENDS AChildFB
// ...

MyBaseFB 子オブジェクトは 1 つだけあります: AChildFB、これには 1 つの子オブジェクトがあり、 AGrandChildFBAGrandChildFB には子オブジェクトがありません。



メトリック: RFC – クラスの応答

カテゴリー: 保守性、再利用性

呼び出されて、以下で指定された POU の応答を生成するさまざまな POU、メソッド、またはアクションの数。 プログラムユニット

152.
//Declaration FB1
FUNCTION_BLOCK FB1
VAR
    d,x,y : INT;
END_VAR

//Implementation
x := METH(d+10);
y := FUN(42, 0.815);
//Declaration FB1.METH
METHOD METH : INT
VAR_INPUT
    i : INT;
END_VAR

//Implementation
METH := FUN(CUBE(i), 3.1415);
//Declaration CUBE
FUNCTION CUBE : INT
VAR_INPUT
    i : INT;
END_VAR

//Implementation
CUBE := i*i*i;
//Declaration Function FUN
FUNCTION FUN : INT
VAR_INPUT
    a : INT;
    lr : LREAL;
END_VAR

//Implementation
FUN := LREAL_TO_INT(lr*10)*a;
  • で始まります FUN そして CUBE、これらの関数は計算のために他の関数、関数ブロック、またはメソッドを呼び出していないため、RFC は 0 です。

  • FB1.METH 用途 FUN そして CUBE、その結果、RFC は 2 になります。

  • ファンクションブロック FB1 それ自体が呼び出します METH そして FUN、これにより RFC が 2 増加します。

    FB1 の場合、その METH メソッドも考慮する必要があります。 METH は FUN と CUBE を使用します。 FUN はすでに RFC に追加されています。したがって、METH で CUBE を使用する場合のみ、FB1 の RFC が 3 に増加します。



メトリック: CBO – オブジェクト間の結合

カテゴリー: 保守性、再利用性

対応する SA0179 ルールのデフォルトの上限: 30

インスタンス化され、ファンクション ブロック内で使用される他のファンクション ブロックの数

オブジェクト間の結合度が高い機能ブロックは、多くの異なるタスクに関与する可能性が高いため、固有責任の原則に違反します。

153.
// Declaration
FUNCTION_BLOCK FB_Child EXTENDS FB_Base objects // +0 for EXTENDS
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
    i_fb1 : FB1; // +1 instantiated here
    i_fb2 : FB2; // +1 instantiated here
END_VAR

//Implementation
i_fb3(); // +0 instantiated in FB_Base, no increment for call
  • 機能ブロックを拡張しても、オブジェクト間の結合は増加しません。

  • i_fb3 の実装でインスタンス化されます FB_Base そして FB_Child に渡されます (EXTENDS)。コールイン FB_Child オブジェクト間の結合は増加しません。

  • のCBO FB_Child は2です。



指標: 参照の複雑さ (Elshof)

カテゴリー: 効率、保守性、再利用性

POUのデータフローの複雑さ

参照の複雑さは、次の式に従って計算されます。

<使用する変数の数> / <変数のアクセス数>

POU の実装部分の変数アクセスのみが考慮されます。

154.
//Declaration
PROGRAM PRG
VAR
    i, j : INT;
    k : INT := GVL.m;
    b, c : BOOL;
    myFB : FB;
END_VAR

//Implementation
myFB(paramA := b);      // +3 accesses (myFB, paramA and b)
i := j;                 // +2 accesses (i and j)
j := GVL.d;             // +2 accesses (j and GVL.d)

コード スニペットの複雑さを参照すると、次のようになります。

6 使用される変数の数 / 7 変数アクセス数 = 0.85

注意:

  • c そして k は使用されていないため、「使用された変数」としてカウントされません。

  • 課題 k : INT := GVL.m はプログラムの宣言の一部であるためカウントされません。



指標: 手法の一貫性の欠如 – LCOM

手法の一貫性の欠如 – LCOM

カテゴリー: 保守性、再利用性

関数ブロック、そのアクション、遷移、およびメソッド間の結合度は、それらが同じ変数にアクセスするかどうかを示します。

メソッドの凝集性の欠如は、機能ブロックのオブジェクトが互いにどの程度強く結びついているかを表します。凝集性の欠如が低いほど、オブジェクト間の接続は強くなります。

凝集度が著しく低い機能ブロックは、多くの異なるタスクに関与する可能性が高いため、固有の責任の原則に違反します。

メトリックは次の式に従って計算されます。

MAX(0, <凝集性のないオブジェクト ペアの数> - <凝集性のあるオブジェクト ペアの数>)

155.
//Declaration
FUNCTION_BLOCK FB
VAR_INPUT
    a : BOOL;
END_VAR
VAR_OUTPUT
END_VAR
VAR
    i,b : BOOL;
END_VAR

//Implementation
i := 42;
//FB.ACT
i:= 0;
//FB.METH Declaration
METHOD METH : BOOL
VAR_INPUT
	c : BOOL;
END_VAR

//Implementation
METH := c;
i := 1;
//FB.SecondMETH Declaration
METHOD SecondMETH : INT
VAR_INPUT
END_VAR

//Implementation
SecondMETH := SEL(c,3,4);

接続のないオブジェクト ペア (4 ペア):

  • FB, FB.ACT

  • FBFB.METH

  • FB.ACTFB.SecondMETH

  • FB.METHFB.SecondMETH

接続のあるオブジェクトのペア (2 ペア):

  • FBFB.SecondMETH (どちらも使用します c

  • FB.ACTFB.METH (どちらも使用します i)

4. この表は、どの変数が FB のどのオブジェクトに接続されているかを示しています。

FB

FB.ACT

FB.METH

FB.SecondMETH

FB.SecondMETH

c

0

0

.

FB.METH

0

i

.

.

FB.ACT

0

.

.

.

FB

-

.

.

.





指標: SFC ブランチ数

カテゴリー: テスト容易性、保守容易性

SFC(逐次関数チャート)実装言語のPOUの代替分岐および並列分岐の数

156.
_san_img_metric_sfc_branch_count.png

SFC の上記のコード スニペットには 4 つの分岐があります: 3 つの代替分岐と 1 つの並列分岐です。



メトリック: SFC ステップ数

カテゴリー: メンテナンス性

SFC の POU のステップ数 (逐次関数チャート)

SFC でプログラムされた POU に含まれるステップのみがカウントされます。 POU で呼び出されるアクションまたは遷移の実装に含まれるステップはカウントされません。

157.
_san_img_metric_sfc_steps_count.png

SFC のコード スニペットには 10 のステップがあります。