File-level metrics
* Note: The following metrics are calculated during pre-processing: NOCOMMSECT, LINESCOMM, BYTESCOMM, NOMACROS, NOLOCALINC, NOSYSINC, NO3DPINC, INCLDIRECTIVES, DIRECTIVES. If a Klocwork project is built with pre-processed files or the Klocwork compiler (kwcc) is run with the never-cpp option, the values for these metrics will be zero.
Checksum descriptionThe CHECKSUM metric is the CRC32 checksum for a file. CRC stands for Cyclic Redundancy Check. The 32 comes from the fact it calculates a 32-bit checksum. CRC32 is an algorithm for calculating a unique identifier for a file. It is used in programs like PKZIP to identify files and make sure that they are original. (There is 1 in 232 chance of two files having the same CRC32 checksum and being mistaken as being the same file). It is calculated recursively for characters read from the source file. This metric uses the standard calculation algorithm: At the start of calculation crc32 is set to 0xffffffff. crc32 = 0^0xffffffff; For each next character ch read from the file crc32 is updated by the formula: crc32(ch) = (ch>>8)^ table[(ch& 0xff) xor crc32]; where: table is a pre-generated 256-element table crc32 is the value of crc32 calculated at the previous step After all characters from the file are read, crc32 is inverted: crc32 = crc32 ^ 0xffffffff; Note: This metric may be a negative number when the actual value (stored as an integer) does not fit into ..MAX_INTEGER interval and wraps into the -MAX_INTEGER..0 interval.
Functional file coupling and cohesionThere are four levels of coupling metrics for each of two types of relationships—uses and used-by—and a metric that is the sum of both. See 'Functional file coupling (total)' below. Coupling and cohesion metrics are calculated for both C/C++ and Java projects; however, the following examples use C/C++ sample files.
Sample files: a.h, b.h, and example.cppCOUPLING and COHESION metrics are calculated using an example consisting of three files a.h, b.h, and example.cpp (see below). /space/test/coupling_test>cat -n a.h 1 #ifndef __A_H__ 2 #define __A_H__ 3 4 class Foo { 5 6 }; 7 8 class Bar { 9 Foo * foo; 10 11 }; 12 13 #endif space/test/coupling_test>cat -n b.h 1 #ifndef __B_H__ 2 #define __B_H__ 3 4 class ZZZ { 5 6 }; 7 8 #endif /space/test/coupling_test>cat -n example.cpp 1 #include "a.h" 2 #include "b.h" 3 4 Foo *foo1; 5 Bar *bar; 6 ZZZ *zzz; The relations that are calculated for these three files compiled together are:* example.cpp;INCLUDES;b.h;example.cpp;2 example.cpp;INCLUDES;a.h;example.cpp;1 foo;VARIABLE_USES_CLASS;Foo;example.cpp;4 bar;VARIABLE_USES_CLASS;Bar;example.cpp;5 zzz;VARIABLE_USES_CLASS;ZZZ;example.cpp;6 foo;CLASS-DATA-MEMBER_USES_CLASS;Foo;a.h;9 For functional file coupling/cohesion we pick up only the following relations: foo;VARIABLE_USES_CLASS;Foo;example.cpp;4 bar;VARIABLE_USES_CLASS;Bar;example.cpp;5 zzz;VARIABLE_USES_CLASS;ZZZ;example.cpp;6 foo;CLASS-DATA-MEMBER_USES_CLASS;Foo;a.h;9 *Note: The format of the relation printout is: <source>;<relation_kind>;<destination>;<file>;<line> Sample file a.h entities and relationsEntities in File a.h a.h;FILE;coupling_test;a.h;1 __A_H__;MACRO;a.h;a.h;2 Foo;CLASS;a.h;a.h;4 Bar;CLASS;a.h;a.h;8 foo;CLASS-DATA-MEMBER;Bar;a.h;9 Relations in File a.h Entities described in file a.h participate in three of the four relations in Sample files: a.h, b.h, and example.cpp: foo;VARIABLE_USES_CLASS;Foo;example.cpp;4 bar;VARIABLE_USES_CLASS;Bar;example.cpp;5 foo;CLASS-DATA-MEMBER_USES_CLASS;Foo;a.h;9 Uses and used-by coupling metrics "Uses" and "used by" coupling metrics 1 to 4 are calculated on relations that have an entity declared in one file as a source and an entity declared in another file as a destination. That means that relation foo;CLASS-DATA-MEMBER_USES_CLASS;Foo;a.h;9 does not participate in calculation of the coupling metrics as a relations that has source and destination within one file. As for the two other relations, entities of the file a.h participate in these two left relationships as destinations: "foo;VARIABLE_USES_CLASS;Foo;example.cpp;4", "bar;VARIABLE_USES_CLASS;Bar;example.cpp;5" That means that entities of file a.h does not have any relationships to entities outside file a.h. As a result all the COUPLINGU metrics 1 to 4 should be equal to 0. See Sample file a.h: Coupling (uses) metric.
Sample file a.h: Coupling (uses) metricsA nontrivial measure of the file uses relationships associated with this file. More specifically, the metric represents an information-dense measure of the relationship of this file to every other file in the system that it uses. The formulas below are applied to sample file a.h. See Sample file a.h entities and relations. For Klocwork system-level reports on C and C++ systems, the non-trivial measure for uses coupling is as follows: COUPLING U1 CpU1 (Fj) = where i = 1, ..., n is the index of relevant relation-kind. For file a.h, the relation-kinds are VARIABLE_USES_CLASS, CLASS-DATA-MEMBER_USES_CLASS. Fj is the file of interest in system S, for any j in system S. For this example, Fj is file a.h Fk are other files within the system S( l=1, ..., lj is the index related to the functions/methods/procedures (call them units) within file Fj (that is, consider the first unit in the file Fj as unit 1, the 2nd as unit 2, ..., the last as unit lj), and m=1, ..., mk is the index related to the units within file Fk. Units of file a.h are: CLASS Foo, CLASS Bar, and CLASS-DATA-MEMBER foo. In file b.h they are the CLASS ZZZ, in file example.cpp they are the VARIABLEs foo, bar and zzz. URIi( Fj(l), Fk(m)) is a function that counts the number of instances of a uses relationship (or relationship instances, RI) of type i between unit l of file Fj and unit m within file Fk.(unit l in Fj uses unit m in Fk). It may be 0, 1, or more. There are no relations that have source in file a.h and destination outside file a.h. So, URIi(Fj(l), Fk(m)) for any units acceptable as arguments Fj(l), and Fk(m) will return 0 when COUPLINGU1 is calculated for file a.h . When we sum log2(0 +1) which is 0, the overall sum of COUPLINGU1 is 0. Wi- is the weight of the relationships of type i. In the example where we calculate COUPLINGU1 for the file a.h, weights are not important since we get 0. Also, by default weights of all the relationships are equal to 1 (all the relations are equal in their influence to function coupling). Potentially we can make some relations more influential and some less influential by setting their weights to higher or lower values (for example, set weight for CLASS-DATA-MEMBER_USES_CLASS to 1 and the weight of VARIABLE_USES_CLASS to 0.5). Also, as one may see from the formula, the more relations with source in file a.h and destination outside a.h the higher the metric will be. Also the more different pairs of (source, destination) we have, the higher the metric will be. Several relations for different pairs of (source, destination) contribute to COUPLINGU1 more than the same number of relations between entities of the same pair (source, destination). The logarithm decreases the value of the second, third, (and so on) relations within the same pair (source, destination). COUPLINGU2, COUPLINGU3 and COUPLINGU4 For the same reason (absence of outgoing relations) COUPLINGU2, COUPLINGU3 and COUPLINGU4 are equal to 0. These are the formulas we use to calculate them: The difference between COUPLINGU1 and COUPLINGU2 is the point where the logarithm is applied. For COUPLINGU1 we calculate relations for each pair of units and apply the logarithm to each. For COUPLINGU2 we don't differentiate between pairs of units; we just sum relations of a specific kind going from entities of one file to entities of another file and apply the logarithm to this count (+1). COUPLINGU3 is almost the same metric as COUPLINGU2, we just don't apply any weights to the relations. Since by default all the relation weights are equal to 1, COUPLINGU2 is equal to COUPLINGU3. COUPLINGU4 does not differentiate between various kinds of relations — it sums relations with the source units in the file (a.h in our example) — and destination units in other files (files other than a.h), then the logarithm is applied to the calculated sum + 1.
Sample file example.cpp: Coupling (uses) metricsThis topic applies the four coupling (uses) metrics to file example.cpp. There are three relations with the source in file example.cpp and destination outside example.cpp: foo;VARIABLE_USES_CLASS;Foo;example.cpp;4 bar;VARIABLE_USES_CLASS;Bar;example.cpp;5 zzz;VARIABLE_USES_CLASS;ZZZ;example.cpp;6 So: URIVARIABLE_USES_CLASS(VARIABLE foo, CLASS Foo) = 1, VARIABLE foo uses CLASS Foo URIVARIABLE_USES_CLASS(VARIABLE bar, CLASS Bar) = 1, VARIABLE bar uses CLASS Bar URIVARIABLE_USES_CLASS(VARIABLE zzz, CLASS ZZZ) = 1, VARIABLE zzz uses CLASS ZZZ COUPLING U1 As a result, COUPLINGU1 = log2(URIVARIABLE_USES_CLASS(VARIABLE foo, CLASS Foo) + 1) + log2(URIVARIABLE_USES_CLASS(VARIABLE bar, CLASS Bar) + 1) + log2(URIVARIABLE_USES_CLASS(VARIABLE zzz, CLASS ZZZ)+ 1) = 3 COUPLINGU2 = COUPLINGU3 = COUPLINGU4 = log2(URIVARIABLE_USES_CLASS(VARIABLE foo, CLASS Foo) + URIVARIABLE_USES_CLASS(VARIABLE bar, CLASS Bar) + 1) + log2(URIVARIABLE_USES_CLASS(VARIABLE zzz, CLASS ZZZ)+ 1) = 2.58496 For COUPLINGU1 we have three logarithms, because the logarithm is applied to the relation count for each pair (source, destination) separately. COUPLINGU2, COUPLINGU3, and COUPLINGU4 For COUPLINGU2, COUPLINGU3 and COUPLINGU4 we have only two logarithms because we don't differentiate between pairs of units, we differentiate only between pairs of files, and the available pairs are (example.cpp, a.h) and (example.cpp, b.h).
Sample file a.h: Coupling (used-by) metricsFor Klocwork system-level reports on C and C++ systems, the non-trivial measure for used-by coupling is as follows (the following formulas are applied to sample file a.h): CpUB1 (Fj) = where i = 1 ..., n is the index of relevant relation-kind. For file a.h, this applies to VARIABLE_USES_CLASS, CLASS-DATA-MEMBER_USES_CLASS. Fj is the file of interest in system S, for any j in system S. In this example, it's file a.h. Fk are other files within the system S( l=1, ..., lj is the index related to the functions/methods/classes/types (call them units) within file Fj (that is, consider the first unit in the file Fj as unit 1, the 2nd as unit 2, ..., the last as unit lj). For file a.h, CLASS Foo, CLASS Bar, and m=1, ..., mk is the index related to the units within file Fk. For file b.h, it's CLASS ZZZ . For file example.cpp, it's VARIABLEs foo, bar and zzz. UBRIi( Fj(l), Fk(m) ) is a function that counts the number of instances of a used-by relationship (or relationship instances, RI) of type i between unit l of file Fj and unit m within file Fk. It may be 0, 1, or more. Using our sample files, UBRI(CLASS Foo, VARIABLE foo) = 1, CLASS Foo is used by VARIABLE foo UBRI(CLASS Bar, VARIABLE bar) = 1. CLASS Boo is used by VARIABLE bar Wi - weight of the relationships of type i. By default, in the sample files, all weights are equal to 1. For file a.h: COUPLINGUB1 = log2(UBRIVARIABLE_USES_CLASS (CLASS Foo, VARIABLE foo) + 1) + log2(UBRIVARIABLE_USES_CLASS (CLASS Bar, VARIABLE bar) + 1) = 2 COUPLINGUB2 = COUPLINGUB3 = COUPLINGUB4 = log2(UBRIVARIABLE_USES_CLASS (CLASS Foo, VARIABLE foo) + UBRIVARIABLE_USES_CLASS (CLASS Bar, VARIABLE bar) + 1) = 1.58496 COUPLINGUB2, COUPLINGUB3 and COUPLINGUB4 For the same reason (absence of outgoing relations) COUPLINGUB2, COUPLINGUB3 and COUPLINGUB4 are equal to 0. These are the formulas we use to calculate them: The difference between COUPLINGUB1 and COUPLINGUB2 is the point where the logarithm is applied. For COUPLINGUB1 we calculate relations for each pair of units and apply the logarithm to each. For COUPLINGUB2 we don't differentiate between pairs of units; we just sum relations of a specific kind going from entities of one file to entities of another file and apply the logarithm to this count (+1). COUPLINGUB3 is almost the same metric as COUPLINGUB2, we just don't apply any weights to the relations. Since by default all the relation weights are equal to 1, COUPLINGUB2 is equal to COUPLINGUB3. COUPLINGUB4 does not differentiate between various kinds of relations — it sums relations with the source units in the file (a.h in our example) — and destination units in other files (files other than a.h), then the logarithm is applied to the calculated sum + 1.
Functional file coupling (total)A nontrivial measure of the file uses and used-by relationships associated with this file. It is the sum of the file coupling (uses) and file coupling (used-by).
Functional file cohesionFunctional file cohesion is a non-trivial measure of the within-file used-by relationships associated with a file. More specifically, the metric represents a normalized information-dense measure of functions, routines, or units within a file and their relationships with other functions, routines, or units within the same file. COHESION metrics in general are similar to the used and used-by COUPLING metrics. The difference between COUPLING and COHESION metrics is in the relations that we aggregate to calculate metrics. For COUPLING metrics, we pick relations with the source and destination units located in different files. This is opposite to COHESION metrics for which we pick relations with source and destination units in the same file. Here are the formulas used to calculate COHESION 1 to 4 metrics: COHESION1 metric where i = 1, ..., n is the index of relevant relation-kind, Fj is the file of interest in system S, l=1, ..., lj is the index related to the functions/methods/classes/types (call them units) within file Fj (that is, consider the first unit in the file Fj as unit 1, the 2nd as unit 2, ..., the last as unit lj), and m=1, ..., mj is also the index related to the units within file Fj, except that m URIi( Fj(l), Fj(m) ) is a function that counts the number of instances of a uses relationship (or relationship instances, RI) of type i between unit l of file Fj and unit m within file Fj (unit l uses unit m). It may be 0, 1, or more. Using the nomenclature defined earlier, this is equivalent to computing the "micro" version of the metrics defined in the relationships metrics table, Wi - weight of the relationships of type i. COHESION2 metric The COHESION3 metric does not take weights into account. By default, with all the weights equal to 1, COHESION2 is equal to COHESION3. COHESION3 metric Using Sample files: a.h, b.h, and example.cpp, the only file that has relationships with source and destination inside is header a.h. And the relation with source and destination in one file is: foo;CLASS-DATA-MEMBER_USES_CLASS;Foo;a.h;9 So, URICLASS-DATA-MEMBER_USES_CLASS (CLASS-DATA-MEMBER foo, CLASS Foo) = 1 That's why, for file a.h: COHESION1 = COHESION2 = COHESION3 = COHESION4 = log2(URICLASS-DATA-MEMBER_USES_CLASS (CLASS-DATA-MEMBER foo, CLASS Foo) + 1) = 1 |