メトリクス
提供されるメトリクスの詳細な説明 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
(f
、 g
、 そして h
)、それぞれに 2 バイトのメモリが必要です。結果として、 FUN1
可変サイズは 6 バイトです。
メトリック: スタック サイズ (バイト数)
カテゴリー: 有益、効率、信頼性
関数または関数ブロックの呼び出しに必要なバイト数
入力変数と出力変数はメモリに合わせて配置されます。これにより、これらの変数とローカル変数の間にギャップが生じる可能性があります。このギャップがカウントされます。
呼び出された関数の戻り値がレジスタに収まらない場合は、スタックにプッシュされます。これらの値の最大値によって追加の割り当てメモリが決まり、これもカウントされます。検討中の POU 内で呼び出される関数または関数ブロックには、独自のスタック フレームがあります。したがって、そのような呼び出しのためのメモリはカウントされません。
使用するコード ジェネレーターによっては、計算の中間結果でもスタックが使用されます。これらの結果はカウントされません。
//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 のコール数 プログラムユニット
//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 は以下で指定されます。 プログラムユニット と呼ばれます
ファンクション ブロックの場合、ファンクション ブロック自体、またはファンクション ブロックの継承ツリー内の任意のファンクション ブロックが呼び出されるタスクの数がカウントされます。
メソッドとアクションの場合、(親) ファンクション ブロックが呼び出されるタスクの数が表示されます。
FUNCTION_BLOCK FB //...
FUNCTION_BLOCK FB2 EXTENDS FB //...
FUNCTION_BLOCK FB3 EXTENDS FB2 //...
各関数ブロックは独自に呼び出されます。 PROGRAM
。それぞれ PROGRAM
には独自のタスクがあります。
の タスクで呼び出される メトリクスは 1 を返します FB3
と2 FB2
なぜなら、からの電話は FB3
そして FB2
カウントされます。メトリクスの結果は 3 になります。 FB
この場合、からの呼び出しは FB3
、 FB2
、 そして FB
カウントされます。
メトリック: 使用されるグローバル変数の数 (グローバル)
カテゴリー: 保守性、再利用性
POU で使用されているグローバル変数の数 プログラムユニット
//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
: gvla
、 gvlb
、 そして gvlc
。
メトリクス: ダイレクト アドレス アクセス (IO) の数
カテゴリー: 再利用性、保守性
ダイレクトアドレスアクセス数(IO) オブジェクトの実装で。
//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 の領域。継承された変数はカウントされません。
//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
プログラム単位の。継承された入力変数はカウントされません。
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 を加えたものになります。戻り値もカウントされます。継承された出力変数はカウントされません。
出力変数の数が多い場合は、一意の責任の原則に違反していることを示します。
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 つの出力があります。 METH
、 j
、 そして 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 – ステートメントの数
カテゴリー: 有益な情報
ファンクションブロック、関数、またはメソッドの実装におけるステートメントの数
宣言内のステートメント、空のステートメント、またはプラグマはカウントされません。
//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 のパーセンテージが返されます。
宣言部分:
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 の制御フロー内のバイナリ分岐の数をカウントすることによって計算されます。ただし、分岐が多いとテスト カバレッジを高めるために必要なテスト ケースの数が増加するため、循環的な複雑さによって分岐が多くなると不利になります。
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 です。
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 です。
// 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 です。
次のステートメントも循環的複雑さを増大させます。
//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™ によって導入されたソース コードの読みやすさと理解しやすさの尺度です。ただし、制御フローの大量のネストや複雑なブール式にはペナルティが課せられます。認知の複雑さは、構造化テキストの実装についてのみ計算されます。
次の例は、認知の複雑性がどのように計算されるかを示しています。
ヒント
の 現在のエディターの認知的複雑性を表示 コマンドを使用すると、構造化テキストの増分をさらに表示できます。
制御フローを操作するステートメントは認知の複雑さを 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 です。
制御フローをネストする場合、ネストのレベルごとに 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 です。
ブール式はソース コードを理解する上で重要な役割を果たすため、認知の複雑さを計算するときにも考慮されます。
同じブール演算子に関連付けられたブール式を理解することは、交互のブール演算子を含むブール式を理解することほど難しくありません。したがって、式内に同一のブール演算子が連鎖すると、認知の複雑さが増大します。
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
認知の複雑さでは考慮されていません。
構造化テキストには、制御フローを変更する追加のステートメントと式があります。
次のステートメントには、認知の複雑さが増すというペナルティが課されます。
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 – 継承ツリーの深さ
カテゴリー: メンテナンス性
他の機能ブロックを拡張しない機能ブロックに到達するまでの継承の数
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 – 子供の数
カテゴリー: 再利用性、保守性
指定された基本機能ブロックを拡張する機能ブロックの数。基本機能ブロックを間接的に拡張する機能ブロックはカウントされません。
FUNCTION_BLOCK MyBaseFB // ... FUNCTION_BLOCK AChildFB EXTENDS MyBaseFB // ... FUNCTION_BLOCK AGrandChildFB EXTENDS AChildFB // ...
MyBaseFB
子オブジェクトは 1 つだけあります: AChildFB
、これには 1 つの子オブジェクトがあり、 AGrandChildFB
。 AGrandChildFB
には子オブジェクトがありません。
メトリック: RFC – クラスの応答
カテゴリー: 保守性、再利用性
呼び出されて、以下で指定された POU の応答を生成するさまざまな POU、メソッド、またはアクションの数。 プログラムユニット
//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
インスタンス化され、ファンクション ブロック内で使用される他のファンクション ブロックの数
オブジェクト間の結合度が高い機能ブロックは、多くの異なるタスクに関与する可能性が高いため、固有責任の原則に違反します。
// 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 の実装部分の変数アクセスのみが考慮されます。
//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, <凝集性のないオブジェクト ペアの数> - <凝集性のあるオブジェクト ペアの数>)
//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
FB
、FB.METH
FB.ACT
、FB.SecondMETH
FB.METH
、FB.SecondMETH
接続のあるオブジェクトのペア (2 ペア):
FB
、FB.SecondMETH
(どちらも使用しますc
)FB.ACT
、FB.METH
(どちらも使用しますi
)
FB |
|
|
| |
---|---|---|---|---|
|
| 0 | 0 | . |
| 0 |
| . | . |
| 0 | . | . | . |
| - | . | . | . |
指標: SFC ブランチ数
カテゴリー: テスト容易性、保守容易性
SFC(逐次関数チャート)実装言語のPOUの代替分岐および並列分岐の数
![]() |
SFC の上記のコード スニペットには 4 つの分岐があります: 3 つの代替分岐と 1 つの並列分岐です。
メトリック: SFC ステップ数
カテゴリー: メンテナンス性
SFC の POU のステップ数 (逐次関数チャート)
SFC でプログラムされた POU に含まれるステップのみがカウントされます。 POU で呼び出されるアクションまたは遷移の実装に含まれるステップはカウントされません。
![]() |
SFC のコード スニペットには 10 のステップがあります。