Metrix++ is a tool to collect and analyse code metrics. Any metric is useless if it is not used. Metrix++ offers great usage capabilities and assists with variety of application use cases:
The workflow sections below demonstarate basic application usecases.
The tool can parse C/C++, C# and Java source code files. The parser identifies certain regions in the code, such as classes, functions, namespaces, interfaces, etc. It obviously detects comments, strings and code for preprocessor. The identified regions form a tree of nested source code blocks, which are refered after and additionally scanned by metrics plugins. This concept allows to attribute metrics per regions, what gives fine grained data and rich input to analysis tools. The following example demonstrates regions concept.
Source code | Regions tree [type: name: content type] |
---|---|
// simple C++ code #include <myapi.h> // I explain the following class class MyClass { public: int m_var; // some member // I explain the following function MyClass(): m_var(0) { char str[] = "unused string" // nested region for good measure struct MyStruct {}; } // Do not judge ugly code below #define get_max(a,b) ((a)>(b)?(a):(b)) set_max(int b) { m_var = get_max(m_var, b); } }; // this is the last line |
file: __global__: comment file: __global__: code file: __global__: preprocessor file: __global__: code class: MyClass: comment class: MyClass: code class: MyClass: code class: MyClass: code, comment class: MyClass: code function: MyClass: comment function: MyClass: code function: MyClass: code, string function: MyClass: code struct: MyStruct: comment struct: MyStruct: code function: MyClass: code class: MyClass: code function: set_max: comment function: set_max: preprocessor function: set_max: code function: set_max: code function: set_max: code class: MyClass: code file: __global__: comment |
Metrics highlighed in blue are per file metrics. Other metrics are per region metrics. Region term is explained in the previous chapter.
Metric (enable option) | Brief description | Motivation |
---|---|---|
std.general.size | Size of a file in bytes. |
|
std.code.length.total | The same as 'std.general.size' metric, but attributed to code regions. | |
std.code.lines.total | Number of non-blank lines of code of any content type (exectuable, comments, etc.) | |
std.code.lines.code | Number of non-blank lines of code excluding preprocessor and comments. | |
std.code.lines.preprocessor | Number of non-blank lines of preprocessor code. |
|
std.code.lines.comments | Number of non-blank lines of comments. |
|
std.code.complexity.cyclomatic | McCabe cyclomatic complexity metric. |
|
std.suppress | An option enables collection of Metrix++ suppressions and 2 metrics: 'std.suppress:count' and 'std.suppress.file:count'. The first is number of suppressions per region. The second is the same but applies for file-scope metrics. |
|
std.general.procerrors | Number of errors detected by Metrix++ code parser. Errors, like mismatched brackets, may result in bad identification of regions. |
|
std.general.proctime | Seconds spent on processing a file. |
|
In order to get the tool working, dowload the archive with the latest stable version and unpack it to some folder. First run of the tool will trigger the installation within the folder, where it was launched.
Corresponding checkout from the version control system is the following:
svn checkout svn://svn.code.sf.net/p/metrixplusplus/code/releases/latest Metrix++
In order to checkout the latest version under development, use this command:
svn checkout svn://svn.code.sf.net/p/metrixplusplus/code/mainline Metrix++
Python Runtime Environment (version 2.7.* or later, version 3.* has not been tested)
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 3 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with the Metrix++; if not, contact Project Administrator
The workflow and application usecases are demonstrated using source code of boost/interprocess library. Boost versions 1.52 and 1.54 are used and refered below as 'previous' and 'current' accordingly.
The first obvious step is to collect the data. The 'collect' tool has got multiple options to enable various metrics plugins. Let's collect number of lines of code and cyclomatic complexity metrics for the previous (1.52.0 version) boost interprocess library. Assuming that 2 versions of boost library are unpacked in the current working directory:
> cd boost_1_52_0 > python "/path/to/metrix++.py" collect --std.code.lines.code --std.code.complexity.cyclomatic -- boost/interprocess > cd ../ # return back to working directory
The list of arguments after '--' enumerates paths where to read source files. As a result of execution of this command, a file metrixpp.db will be written in the current working directory. It can be redefined with help of --db-file option.
Metrix++ has got rich functionality in comparing code bases and reducing processing scope to modified or new code. So, let's collect the same data for the current (1.54.0 version) boost interprocess library.
> cd boost_1_54_0 > python "/path/to/metrix++.py" collect --std.code.lines.code --std.code.complexity.cyclomatic -- boost/interprocess --db-file-prev=../boost_1_52_0/metrixpp.db > cd ../ # return back to working directory
The option --db-file-prev points out to the file with data collected in the previous step. So, eventually it executed iterative collection. It can speed up the exectuion significantly, depending on amount of changes between two version.
Check other options of the collect tool by executing:
> python "/path/to/metrix++.py" collect --help
It is time to look at the data. The command:
> python "/path/to/metrix++.py" view --db-file=boost_1_54_0/metrixpp.db
prints summary metrics, like minimum/maximum, and distribution/frequency tables:
:: info: Overall metrics for 'std.code.complexity:cyclomatic' metric Average : 0.652902698283 Minimum : 0 Maximum : 37 Total : 1597.0 Distribution : 2446 regions in total (including 0 suppressed) Metric value : Ratio : R-sum : Number of regions 0 : 0.771 : 0.771 : 1886 ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 1 : 0.110 : 0.881 : 268 ||||||||||| 2 : 0.044 : 0.925 : 108 |||| 3 : 0.025 : 0.949 : 60 || 4 : 0.016 : 0.966 : 40 || 5 : 0.007 : 0.973 : 18 | 6 : 0.006 : 0.979 : 14 | 7 : 0.004 : 0.983 : 10 8 : 0.003 : 0.986 : 8 9 : 0.002 : 0.988 : 4 10 : 0.004 : 0.991 : 9 11 : 0.002 : 0.993 : 4 12 : 0.001 : 0.994 : 3 13 : 0.001 : 0.995 : 2 14 : 0.001 : 0.996 : 2 15-16 : 0.001 : 0.997 : 3 17-18 : 0.001 : 0.998 : 3 20 : 0.000 : 0.999 : 1 23-25 : 0.001 : 1.000 : 2 37 : 0.000 : 1.000 : 1 :: info: Overall metrics for 'std.code.lines:code' metric Average : 6.64356984479 Minimum : 0 Maximum : 201 Total : 23970.0 Distribution : 3608 regions in total (including 0 suppressed) Metric value : Ratio : R-sum : Number of regions 0-1 : 0.088 : 0.088 : 319 ||||||||| 2 : 0.320 : 0.409 : 1155 |||||||||||||||||||||||||||||||| 3 : 0.108 : 0.517 : 390 ||||||||||| 4 : 0.081 : 0.598 : 294 |||||||| 5 : 0.080 : 0.678 : 290 |||||||| 6 : 0.061 : 0.739 : 220 |||||| 7 : 0.049 : 0.788 : 176 ||||| 8 : 0.030 : 0.818 : 109 ||| 9 : 0.025 : 0.843 : 89 || 10-11 : 0.032 : 0.876 : 117 ||| 12-13 : 0.020 : 0.895 : 71 || 14 : 0.012 : 0.907 : 43 | 15-16 : 0.017 : 0.924 : 61 || 17-19 : 0.015 : 0.939 : 55 || 20-22 : 0.013 : 0.952 : 46 | 23-26 : 0.011 : 0.963 : 40 | 27-30 : 0.009 : 0.972 : 33 | 31-39 : 0.009 : 0.981 : 33 | 40-65 : 0.009 : 0.991 : 34 | 66-201 : 0.009 : 1.000 : 33 | :: info: Directory content: Directory : .
The same command with --db-file-prev option enables comparision and change trends are shown in [] brackets:
> python "/path/to/metrix++.py" view --db-file=boost_1_54_0/metrixpp.db --db-file-prev=boost_1_52_0/metrixpp.db
:: info: Overall metrics for 'std.code.complexity:cyclomatic' metric Average : 0.652902698283 [+0.00362138411453] Minimum : 0 [+0] Maximum : 37 [+1] Total : 1597.0 [+16.0] Distribution : 2446 [+11] regions in total (including 0 [+0] suppressed) Metric value : Ratio : R-sum : Number of regions 0 : 0.771 : 0.771 : 1886 [+5 ] ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 1 : 0.110 : 0.881 : 268 [+4 ] ||||||||||| 2 : 0.044 : 0.925 : 108 [+0 ] |||| 3 : 0.025 : 0.949 : 60 [+2 ] || 4 : 0.016 : 0.966 : 40 [-1 ] || 5 : 0.007 : 0.973 : 18 [-1 ] | 6 : 0.006 : 0.979 : 14 [+1 ] | 7 : 0.004 : 0.983 : 10 [+1 ] 8 : 0.003 : 0.986 : 8 [+1 ] 9 : 0.002 : 0.988 : 4 [+0 ] 10 : 0.004 : 0.991 : 9 [-2 ] 11 : 0.002 : 0.993 : 4 [+1 ] 12 : 0.001 : 0.994 : 3 [+0 ] 13 : 0.001 : 0.995 : 2 [+0 ] 14 : 0.001 : 0.996 : 2 [+0 ] 15-16 : 0.001 : 0.997 : 3 [-1 ] 17-18 : 0.001 : 0.998 : 3 [+1 ] 20 : 0.000 : 0.999 : 1 [+0 ] 23-25 : 0.001 : 1.000 : 2 [+0 ] 36-37 : 0.000 : 1.000 : 1 [+0 ] :: info: Overall metrics for 'std.code.lines:code' metric Average : 6.64356984479 [+0.012181964309] Minimum : 0 [+0] Maximum : 201 [+4] Total : 23970.0 [+223.0] Distribution : 3608 [+27] regions in total (including 0 [+0] suppressed) Metric value : Ratio : R-sum : Number of regions 0-1 : 0.088 : 0.088 : 319 [+3 ] ||||||||| 2 : 0.320 : 0.409 : 1155 [+9 ] |||||||||||||||||||||||||||||||| 3 : 0.108 : 0.517 : 390 [-3 ] ||||||||||| 4 : 0.081 : 0.598 : 294 [+7 ] |||||||| 5 : 0.080 : 0.678 : 290 [+7 ] |||||||| 6 : 0.061 : 0.739 : 220 [-1 ] |||||| 7 : 0.049 : 0.788 : 176 [-2 ] ||||| 8 : 0.030 : 0.818 : 109 [-1 ] ||| 9 : 0.025 : 0.843 : 89 [+4 ] || 10-11 : 0.032 : 0.876 : 117 [+9 ] ||| 12-13 : 0.020 : 0.895 : 71 [-9 ] || 14 : 0.012 : 0.907 : 43 [+0 ] | 15-16 : 0.017 : 0.924 : 61 [+0 ] || 17-19 : 0.015 : 0.939 : 55 [+6 ] || 20-22 : 0.013 : 0.952 : 46 [-3 ] | 23-26 : 0.011 : 0.963 : 40 [+2 ] | 27-30 : 0.009 : 0.972 : 33 [-3 ] | 31-39 : 0.009 : 0.981 : 33 [+0 ] | 40-65 : 0.009 : 0.991 : 34 [+1 ] | 66-201 : 0.009 : 1.000 : 33 [+1 ] | :: info: Directory content: Directory : .
There are two ways to reduce the analysis scope for the view tool. The first is to enumerate paths of interest. For example, the following command reduces scope to 'allocators' sub-directory within the processed code.
> python "/path/to/metrix++.py" view --db-file=boost_1_54_0/metrixpp.db -- ./boost/interprocess/allocators
The second is to specify --scope-mode option, which instructs the tool to process only modified and/or new files/regions. For example, view the summary metrics for all modified and new regions:
> python "/path/to/metrix++.py" view --db-file=boost_1_54_0/metrixpp.db --db-file-prev=boost_1_52_0/metrixpp.db --scope-mode=touched
:: info: Overall metrics for 'std.code.complexity:cyclomatic' metric Average : 1.84924623116 [-0.0230941943761] Minimum : 0 [+0] Maximum : 37 [+1] Total : 368.0 [+16.0] Distribution : 199 [+11] regions in total (including 0 [+0] suppressed) Metric value : Ratio : R-sum : Number of regions 0 : 0.608 : 0.608 : 121 [+5 ] ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 1 : 0.131 : 0.739 : 26 [+4 ] ||||||||||||| 2 : 0.070 : 0.809 : 14 [+0 ] ||||||| 3 : 0.060 : 0.869 : 12 [+2 ] |||||| 4 : 0.015 : 0.884 : 3 [-1 ] || 5 : 0.015 : 0.899 : 3 [-1 ] || 6 : 0.005 : 0.905 : 1 [+1 ] | 7 : 0.015 : 0.920 : 3 [+1 ] || 8 : 0.015 : 0.935 : 3 [+1 ] || 9 : 0.010 : 0.945 : 2 [+0 ] | 10 : 0.010 : 0.955 : 2 [-2 ] | 11 : 0.005 : 0.960 : 1 [+1 ] | 12 : 0.005 : 0.965 : 1 [+0 ] | 13 : 0.005 : 0.970 : 1 [+0 ] | 16 : 0.005 : 0.975 : 1 [-1 ] | 17 : 0.005 : 0.980 : 1 [+0 ] | 18 : 0.010 : 0.990 : 2 [+1 ] | 20 : 0.005 : 0.995 : 1 [+0 ] | 36-37 : 0.005 : 1.000 : 1 [+0 ] | :: info: Overall metrics for 'std.code.lines:code' metric Average : 15.9645390071 [-0.815853149771] Minimum : 0 [+0] Maximum : 201 [+6] Total : 4502.0 [+223.0] Distribution : 282 [+27] regions in total (including 0 [+0] suppressed) Metric value : Ratio : R-sum : Number of regions 0-1 : 0.053 : 0.053 : 15 [+3 ] ||||| 2 : 0.124 : 0.177 : 35 [+9 ] |||||||||||| 3 : 0.053 : 0.230 : 15 [-3 ] ||||| 4 : 0.060 : 0.291 : 17 [+7 ] |||||| 5 : 0.089 : 0.379 : 25 [+7 ] ||||||||| 6 : 0.060 : 0.440 : 17 [-1 ] |||||| 7 : 0.050 : 0.489 : 14 [-2 ] ||||| 8-9 : 0.074 : 0.564 : 21 [+3 ] ||||||| 10 : 0.035 : 0.599 : 10 [+5 ] |||| 11 : 0.082 : 0.681 : 23 [+4 ] |||||||| 12-13 : 0.043 : 0.723 : 12 [-9 ] |||| 14-15 : 0.039 : 0.762 : 11 [-1 ] |||| 16-18 : 0.028 : 0.791 : 8 [+4 ] ||| 19-22 : 0.039 : 0.830 : 11 [+0 ] |||| 23-26 : 0.039 : 0.869 : 11 [+2 ] |||| 27-32 : 0.028 : 0.897 : 8 [-3 ] ||| 38-50 : 0.025 : 0.922 : 7 [+0 ] || 51-69 : 0.025 : 0.947 : 7 [+1 ] || 71-100 : 0.032 : 0.979 : 9 [+2 ] ||| 101-201 : 0.021 : 1.000 : 6 [-1 ] || :: info: Directory content: Directory : .
The same view tool can print detailed metrics per file and per every region in the specified file. In order to get detailed metrics, enumerate files of interest after '--'. For example:
> python "/path/to/metrix++.py" view --db-file=boost_1_54_0/metrixpp.db --db-file-prev=boost_1_52_0/metrixpp.db -- ./boost/interprocess/detail/managed_open_or_create_impl.hpp
produces output similar to this (truncated to make the page shorter):
./interprocess/detail/managed_open_or_create_impl.hpp:302: info: Metrics per 'priv_open_or_create' region Region name : priv_open_or_create Region type : function Offsets : 8314-14526 Line numbers : 301-467 Modified : True std.code.complexity:cyclomatic: 37 [+1] std.code.lines:code: 148 [+4]
The 'view' command has got an option to alter the output format. It is possible to get the same data in xml pr python disctionary formats. This can be particularly useful for integration of the tool with other applications. For example, an editor may re-collect and show context based metrics when a file is saved.
> python "/path/to/metrix++.py" view --format=xml
Check other options of the view tool by executing:
> python "/path/to/metrix++.py" view --help
...
Metrix++ has got suppressions capability. Suppressions are collected from comments in code and used by post-processing tools, like 'limit'. It allows to take fine grained control over false-positive warnings, if there are.
Metrix++ has got suppressions capability. Suppressions are collected from comments in code and used by post-processing tools, like 'limit'. It allows to take fine grained control over false-positive warnings, if there are.
describe METRIXPLUSPLUS_PATH environment variable
...
...
...