Metrica
Descrizione dettagliata delle metriche fornite da CODESYS Static Analysis
Suggerimento
IL Dimensione del codice, Dimensione variabile, Dimensione della pila, E Numero di chiamate le metriche vengono riportate solo per le POU delle librerie integrate nel progetto.
Metrica: Dimensione del codice (numero di byte)
Categorie: Informativo, Efficienza
Numero di byte con cui un blocco funzione contribuisce al codice dell'applicazione
Il numero dipende anche dal generatore di codice. Ad esempio, il generatore di codice per i processori ARM generalmente genera più byte rispetto al generatore di codice per i processori x86.
Metrica: Dimensione variabile (numero di byte)
Categorie: Informativo, Efficienza
Dimensione della memoria statica utilizzata dall'oggetto
Per i blocchi funzione, questa è la dimensione utilizzata per un'istanza del blocco funzione (che può includere lacune di memoria, a seconda dell'allineamento della memoria). Per programmi, funzioni ed elenchi di variabili globali, questa è la somma delle dimensioni di tutte le variabili statiche.
Esempio
FUNCTION FUN1 : INT VAR_INPUT a,b : INT; END_VAR VAR c,d : INT; END_VAR VAR_STAT f,g,h : INT; END_VAR
La funzione ha 3 variabili statiche di tipo INT
(f
, g
, E h
), ognuno dei quali richiede 2 byte di memoria. Di conseguenza, FUN1
ha una dimensione variabile di 6 byte.
Metrica: Dimensione dello stack (numero di byte)
Categorie: Informativo, Efficienza, Affidabilità
Numero di byte necessari per richiamare una funzione o un blocco funzione
Le variabili di ingresso e le variabili di uscita sono allineate alla memoria. Ciò può creare un divario tra queste variabili e le variabili locali. Questo divario viene conteggiato.
I valori restituiti delle funzioni chiamate che non rientrano in un registro vengono inseriti nello stack. Il maggiore di questi valori determina la memoria aggiuntiva allocata, che conta anch'essa. Le funzioni o i blocchi funzionali richiamati all'interno delle POU in questione dispongono di un proprio stack frame. Pertanto, la memoria per tali chiamate non viene conteggiata.
A seconda del generatore di codice utilizzato, anche i risultati intermedi dei calcoli utilizzano lo stack. Questi risultati non vengono conteggiati.
//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;
Ipotesi: per il calcolo, supporre a CODESYS Control Win che utilizza il generatore di codice x86.
L'esempio precedente ha una dimensione del chiamante di 8 byte: 4 byte per i due INT inputs
e 4 byte per il valore restituito. Il dispositivo ha un allineamento dello stack di 4 byte, quindi c'è uno spazio di 2 byte. La dimensione del chiamante è 8 byte: tre variabili locali con 2 byte ciascuna più il gap di 2 byte per l'allineamento dello stack. Di conseguenza, la dimensione totale dello stack è di FUN1
è di 16 byte.
VAR_STAT
non viene memorizzato nello stack e pertanto non aumenta la dimensione dello stack di una POU.
Metrica: Numero di chiamate (chiamate)
Categoria: Informativo
Numero di chiamate della POU sotto Unità di programma
//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;
Se PLC_PRG
viene chiamato in un'attività, viene conteggiata anche questa chiamata.
FB1
ha esattamente una chiamata (in PLC_PRG
).
METH
ha due chiamate, entrambe in entrata FB1
.
Metrica: Numero di chiamate da attività (attività)
Categorie: Manutenibilità, Affidabilità
Numero di compiti (Compiti) dove il POU specificato sotto Unità di programma è chiamato
Nel caso dei blocchi funzione viene contato il numero di task in cui viene chiamato il blocco funzione stesso o qualsiasi blocco funzione nell'albero ereditario del blocco funzione.
Per i metodi e le azioni viene visualizzato il numero di task in cui viene richiamato il blocco funzione (principale).
FUNCTION_BLOCK FB //...
FUNCTION_BLOCK FB2 EXTENDS FB //...
FUNCTION_BLOCK FB3 EXTENDS FB2 //...
Ogni blocco funzione viene richiamato autonomamente PROGRAM
. Ogni PROGRAM
ha il suo compito.
IL Chiamato nei compiti restituisce la metrica in 1 per FB3
e 2 per FB2
perché le chiamate da FB3
E FB2
vengono contati. La metrica risulta in 3 per FB
perché in questo caso le chiamate da FB3
, FB2
, E FB
vengono contati.
Metrica:Numero di variabili globali utilizzate (globali)
Categorie: Manutenibilità, Riutilizzabilità
Numero di variabili globali utilizzate nella POU sotto Unità di programma
//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;
IL PRG
il programma utilizza 3 variabili da GVL
: gvla
, gvlb
, E gvlc
.
Metrica: Numero di accessi diretti agli indirizzi (IO)
Categorie: Riutilizzabilità, Manutenibilità
Numero di accessi diretti all'indirizzo (IO) nell'implementazione dell'oggetto.
//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
L'esempio ha 5 accessi diretti all'indirizzo.
Metrica: Numero di variabili locali (locali)
Categorie: Informativo, Efficienza
Numero di variabili dichiarate nel VAR
zona del POU. Le variabili ereditate non vengono conteggiate.
//Declaration FUNCTION_BLOCK FB VAR_INPUT END_VAR VAR_OUTPUT END_VAR VAR i,j,k,l : INT; m,n,o : BOOL; END_VAR
Nel blocco funzione vengono dichiarate 7 variabili locali.
Metrica: Numero di variabili di input (input)
Categorie: Manutenibilità, Riutilizzabilità
Limite superiore predefinito per il corrispondente SA0166 regola: 10
Numero di variabili dichiarate in VAR_INPUT
dell'unità di programma. Le variabili di input ereditate non vengono conteggiate.
FUNCTION_BLOCK FB VAR_INPUT i : INT; r : REAL; END_VAR
Nel blocco funzione vengono dichiarate 2 variabili di ingresso: i
E r
.
METHOD METH : BOOL VAR_INPUT j : INT; l : LREAL; END_VAR
Il metodo ha 2 input: j
E l
Metrica: Numero di variabili di output (output)
Categorie: Manutenibilità, Riutilizzabilità
Limite superiore predefinito per il corrispondente SA0166 regola: 10
Numero di variabili in VAR_OUTPUT
dell'unità di programma
Nel caso dei blocchi funzione, questo è il numero di variabili di uscita personalizzate (VAR_OUTPUT
). Nel caso di metodi e funzioni, questo è il numero di variabili di output personalizzate più uno se hanno un valore restituito. Viene conteggiato anche il valore restituito. Le variabili di output ereditate non vengono conteggiate.
Un numero elevato di variabili di output è indice di una violazione del principio di unicità della responsabilità.
FUNCTION_BLOCK FB VAR_OUTPUT i : INT; // +1 output r : REAL; // +1 output END_VAR
Il blocco funzione ha 2 variabili di uscita: i
E r
METHOD METH : BOOL VAR_INPUT j : INT; l : LREAL; END_VAR
Il metodo ha 3 output: METH
, j
, E l
METHOD METH1 // +0 outputs (no return type) VAR_OUTPUT ar : ARRAY[0..10] OF INT; // +1 output l : LREAL; // +1 output END_VAR
IL METH1
il metodo ha 2 output: ar
E i
Metrica: NOS – Numero di dichiarazioni
Categoria: Informativo
Numero di istruzioni nell'implementazione di un blocco funzione, funzione o metodo
Le istruzioni nella dichiarazione, le istruzioni vuote o i pragma non vengono conteggiate.
//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
L'esempio ha 6 istruzioni.
Metrica: Percentuale di commenti
Categoria: Manutenibilità
Percentuale di commenti nel codice sorgente
Questo numero viene calcolato secondo la seguente formula:
Percentuale = 100 * <caratteri nei commenti> / <somma dei caratteri nel codice sorgente e dei caratteri nei commenti>
Più spazi consecutivi nel codice sorgente vengono conteggiati come uno spazio, il che impedisce un peso elevato del codice sorgente con rientro. Per gli oggetti vuoti (senza codice sorgente e senza commenti), viene restituita una percentuale pari a 0.
Parte della dichiarazione:
FUNCTION_BLOCK FB //comments in the declaration are counted, as well VAR_TEMP hugo : INT; END_VAR
Implementazione:
hugo := hugo + 1; //Declaration: 40 letters non comment; 50 letters comment //Implementation: 13 letters non comment; 152 letters comment // 100 * 202 / 255 -> 79% comments
Il calcolo della percentuale 100 * 202 / 255 restituisce 79%.
Metrica: Complessità (McCabe)
Categoria: Testabilità
Limite superiore consigliato: 10
La complessità ciclomatica secondo McCabe è una misura della leggibilità e testabilità del codice sorgente. Viene calcolato contando il numero di rami binari nel flusso di controllo della POU. Tuttavia, la complessità ciclomatica penalizza l’elevata ramificazione perché l’elevata ramificazione aumenta il numero di casi di test richiesti per un’elevata copertura del test.
IF
dichiarazione// 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
Lo snippet di codice ha una complessità ciclomatica pari a 4.
CASE
dichiarazione// 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
Lo snippet di codice ha una complessità ciclomatica pari a 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
Lo snippet di codice ha una complessità ciclomatica pari a 4.
Anche le seguenti affermazioni aumentano la complessità ciclomatica:
//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';
Lo snippet di codice ha una complessità ciclomatica pari a 3.
Metrica: Complessità cognitiva
Categoria: Manutenibilità
Limite superiore predefinito per la corrispondente regola SA0178: 20
La complessità cognitiva è una misura della leggibilità e della comprensibilità del codice sorgente introdotto da Sonarsource™ nel 2016. Tuttavia, penalizza l'annidamento pesante del flusso di controllo e delle espressioni booleane complesse. La complessità cognitiva viene calcolata solo per le implementazioni di testo strutturato.
Gli esempi seguenti mostrano come viene calcolata la complessità cognitiva.
Suggerimento
IL Mostra complessità cognitiva per l'editor corrente Il comando può essere utilizzato per visualizzare ulteriormente gli incrementi per il testo strutturato.
Le affermazioni che manipolano il flusso di controllo aumentano la complessità cognitiva di 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
Lo snippet di codice ha una complessità cognitiva pari a 4.
Quando si annida il flusso di controllo, viene aggiunto un incremento di 1 per ogni livello di annidamento.
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
Lo snippet di codice ha una complessità cognitiva pari a 8.
Poiché le espressioni booleane svolgono un ruolo importante nella comprensione del codice sorgente, vengono prese in considerazione anche nel calcolo della complessità cognitiva.
Comprendere le espressioni booleane associate allo stesso operatore booleano non è così difficile come comprendere un'espressione booleana che contiene operatori booleani alternati. Pertanto, qualsiasi catena di operatori booleani identici in un'espressione aumenta la complessità cognitiva.
b := b1; //+0: a simple expression, containing no operators, has no increment
L'espressione semplice senza operatore ha un incremento pari a 0.
b := b1 AND b2; //+1: one chain of AND operators
L'espressione con un AND
il collegamento ha un incremento di 1.
b := b1 AND b2 AND b3; //+1: one more AND, but the number of chains of operators does not change
L'espressione ne ha uno in più AND
. Ma poiché si tratta dello stesso operatore, il numero della catena formata con operatori identici non cambia.
b := b1 AND b2 OR b3; //+2: one chain of AND operators and one chain of OR operators
L'espressione ha una catena di AND
operatori e una catena di OR
operatori. Ciò si traduce in un incremento di 2.
b := b1 AND b2 OR b3 AND b4 AND b5; //+3
Lo snippet di codice ha un incremento di 3.
b := b1 AND NOT b2 AND b3; //+1: the unary NOT operator is not considered in the cognitive complexity
L'operatore unario NOT
non è considerato nella complessità cognitiva.
Il testo strutturato dispone di istruzioni ed espressioni aggiuntive che modificano il flusso di controllo.
Le seguenti affermazioni vengono penalizzate con un incremento di complessità cognitiva:
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
E RETURN
Le affermazioni non aumentano la complessità cognitiva.
Metrica: DIT – Profondità dell'albero dell'ereditarietà
Categoria: Manutenibilità
Numero di eredità fino al raggiungimento di un blocco funzione che non estende nessun altro blocco funzione
FUNCTION_BLOCK MyBaseFB // ... FUNCTION_BLOCK AChildFB EXTENDS MyBaseFB // ... FUNCTION_BLOCK AGrandChildFB EXTENDS AChildFB // ...
MyBaseFB
ha un DIT pari a 0 perché è esso stesso un blocco funzione che non estende nessun altro blocco funzione.
Per AChildFB
, il DIT è 1 perché è necessario un passaggio per arrivare a MyBaseFB
.
AGrandChildFB
ha un DIT pari a 2: è necessario un passaggio AChildFB
e un altro a MyBaseFB
.
Metrica: NOC – Numero di bambini
Categorie: Riutilizzabilità, Manutenibilità
Numero di blocchi funzione che estendono il blocco funzione base indicato. I blocchi funzione che estendono indirettamente un blocco funzione base non vengono conteggiati.
FUNCTION_BLOCK MyBaseFB // ... FUNCTION_BLOCK AChildFB EXTENDS MyBaseFB // ... FUNCTION_BLOCK AGrandChildFB EXTENDS AChildFB // ...
MyBaseFB
ha solo un (1) oggetto figlio: AChildFB
, che a sua volta ha l'unico oggetto figlio, AGrandChildFB
. AGrandChildFB
non ha oggetti figlio.
Metriche: RFC – Risposta per classe
Categorie: Manutenibilità, Riutilizzabilità
Numero di diversi POU, metodi o azioni che vengono richiamati e che quindi generano una risposta del POU specificato sotto Unità di programma
//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;
Iniziare con
FUN
ECUBE
, queste funzioni hanno un RFC pari a 0 perché nessuna di esse chiama altre funzioni, blocchi funzione o metodi per i propri calcoli.FB1.METH
usiFUN
ECUBE
, che si traduce in un RFC di 2.Il blocco funzione
FB1
stesso chiamaMETH
EFUN
, che aumenta il suo RFC di 2.Per FB1 occorre tenere conto anche del relativo metodo METH. METH utilizza FUN e CUBE. FUN è già stato aggiunto alla RFC. Pertanto, solo l'uso di CUBE in METH aumenta la RFC per FB1 a 3
Metrica: CBO – Accoppiamento tra oggetti
Categorie: Manutenibilità, Riutilizzabilità
Limite superiore predefinito per la corrispondente regola SA0179: 30
Numero di altri blocchi funzione istanziati e utilizzati in un blocco funzione
Un blocco funzione con un elevato accoppiamento tra oggetti è probabile che sia coinvolto in molti compiti diversi e quindi violi il principio di responsabilità unica.
// 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
L'estensione di un blocco funzione non aumenta l'accoppiamento tra gli oggetti.
i_fb3
è istanziato nell'implementazione diFB_Base
e passato a FB_Child (EXTENDS
). La chiamataFB_Child
non aumenta l'accoppiamento tra gli oggetti.Il CBO di
FB_Child
è 2.
Metrica: Complessità di riferimento (Elshof)
Categorie: Efficienza, manutenibilità, riusabilità
Complessità del flusso dati di una POU
La complessità di riferimento viene calcolata secondo la seguente formula:
<numero di variabili utilizzate> / <numero di accessi alle variabili>
Vengono considerati solo gli accessi variabili nella parte di implementazione della 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)
Fare riferimento alla complessità nei risultati dello snippet di codice:
6 numero di variabili utilizzate /7 numero di accessi variabile = 0,85
Attenzione:
c
Ek
non vengono utilizzate e pertanto non contano come "variabili utilizzate".L'incarico
k : INT := GVL.m
non viene conteggiato perché fa parte della dichiarazione del programma.
Metrica: Mancanza di Coesione dei Metodi – LCOM
Mancanza di coesione dei metodi – LCOM
Categorie: Manutenibilità, Riutilizzabilità
La coesione tra i blocchi funzione, le loro azioni, transizioni e metodi descrive se accedono o meno alle stesse variabili.
La mancanza di coesione dei metodi descrive quanto fortemente gli oggetti di un blocco funzione sono collegati tra loro. Minore è la mancanza di coesione, più forte è la connessione tra gli oggetti.
È probabile che i blocchi funzionali con un'elevata mancanza di coesione siano coinvolti in molti compiti diversi e quindi violino il principio della responsabilità unica.
La metrica viene calcolata secondo la seguente formula:
MAX(0, <numero di coppie di oggetti senza coesione> - <numero di coppie di oggetti con coesione>)
//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);
Coppie di oggetti senza connessione (4 coppie):
FB,
FB.ACT
FB
,FB.METH
FB.ACT
,FB.SecondMETH
FB.METH
,FB.SecondMETH
Coppie di oggetti con connessione (2 coppie):
FB
,FB.SecondMETH
(entrambi usanoc
)FB.ACT
,FB.METH
(entrambi usanoi
)
FB |
|
|
| |
---|---|---|---|---|
|
| 0 | 0 | . |
| 0 |
| . | . |
| 0 | . | . | . |
| - | . | . | . |
Metrica: Numero di rami SFC
Categorie: Testabilità, Manutenibilità
Numero di rami alternativi e paralleli di una POU del linguaggio di implementazione SFC (sequential function chart).
![]() |
Il frammento di codice sopra in SFC ha 4 rami: 3 rami alternativi e 1 ramo parallelo
Metrica: Numero di passaggi SFC
Categoria: Manutenibilità
Numero di passi in una POU in SFC (diagramma funzionale sequenziale)
Vengono contati solo i passi contenuti nella POU programmata in SFC. Non vengono conteggiati i passaggi presenti nelle implementazioni di azioni o transizioni richiamate nelle POU.
![]() |
Lo snippet di codice in SFC ha 10 passaggi.