forked from Ericsson/CodeCompass
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcppmetricsparser.h
More file actions
227 lines (195 loc) · 7.5 KB
/
cppmetricsparser.h
File metadata and controls
227 lines (195 loc) · 7.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#ifndef CC_PARSER_CPPMETRICSPARSER_H
#define CC_PARSER_CPPMETRICSPARSER_H
#include <parser/abstractparser.h>
#include <parser/parsercontext.h>
#include <model/cppastnodemetrics.h>
#include <model/cppastnodemetrics-odb.hxx>
#include <model/cppcohesionmetrics.h>
#include <model/cppcohesionmetrics-odb.hxx>
#include <model/cppfunction.h>
#include <model/cppfunction-odb.hxx>
#include <model/cpprecord.h>
#include <model/cpprecord-odb.hxx>
#include <util/dbutil.h>
#include <util/parserutil.h>
#include <util/threadpool.h>
#include <util/odbtransaction.h>
namespace cc
{
namespace parser
{
template<typename TTask>
class MetricsTasks
{
public:
typedef typename std::vector<TTask>::const_iterator TTaskIter;
const TTaskIter& begin() const { return _begin; }
const TTaskIter& end() const { return _end; }
std::size_t size() const { return _size; }
MetricsTasks(
const TTaskIter& begin_,
const TTaskIter& end_,
std::size_t size_
) :
_begin(begin_),
_end(end_),
_size(size_)
{}
private:
TTaskIter _begin;
TTaskIter _end;
std::size_t _size;
};
class CppMetricsParser : public AbstractParser
{
public:
CppMetricsParser(ParserContext& ctx_);
virtual ~CppMetricsParser();
virtual bool cleanupDatabase() override;
virtual bool parse() override;
virtual bool isDatabaseIndexRequired() const override
{
return true;
}
private:
// Calculate the count of parameters for every function.
void functionParameters();
// Calculate the McCabe complexity of functions.
void functionMcCabe();
// Calculate the bumpy road metric for every function.
void functionBumpyRoad();
// Calculate the McCabe complexity of types.
void typeMcCabe();
// Calculate the lack of cohesion between member variables
// and member functions for every type.
void lackOfCohesion();
// Calculate the efferent coupling of types.
void efferentTypeLevel();
// Calculate the afferent coupling of types.
void afferentTypeLevel();
// Calculate the efferent coupling at module level.
void efferentModuleLevel();
// Calculate the afferent coupling at module level.
void afferentModuleLevel();
// Calculate relational cohesion at module level.
void relationalCohesionModuleLevel();
// Returns module path query based on parser configuration.
odb::query<model::File> getModulePathsQuery();
// Returns cohesion record query based on parser configuration.
odb::query<model::CohesionCppRecordView> getCohesionRecordQuery();
/// @brief Constructs an ODB query that you can use to filter only
/// the database records of the given parameter type whose path
/// is rooted under any of this parser's input paths.
/// @tparam TQueryParam The type of database records to query.
/// This type must represent an ODB view that has access to
/// (i.e. is also joined with) the File table.
/// @return A query containing the disjunction of filters.
template<typename TQueryParam>
odb::query<TQueryParam> getFilterPathsQuery() const
{
return cc::util::getFilterPathsQuery<TQueryParam>(
_inputPaths.begin(), _inputPaths.end());
}
/// @brief Calculates a metric by querying all objects of the
/// specified parameter type and passing them one-by-one to the
/// specified worker function on parallel threads.
/// This call blocks the caller thread until all workers are finished.
/// @tparam TQueryParam The type of parameters to query.
/// @param name_ The name of the metric (for progress logging).
/// @param partitions_ The number of jobs to partition the query into.
/// @param query_ A filter query for retrieving only
/// the eligible parameters for which a worker should be spawned.
/// @param worker_ The logic of the worker thread.
template<typename TQueryParam>
void parallelCalcMetric(
const char* name_,
std::size_t partitions_,
const odb::query<TQueryParam>& query_,
const std::function<void(const MetricsTasks<TQueryParam>&)>& worker_)
{
typedef MetricsTasks<TQueryParam> TMetricsTasks;
typedef typename TMetricsTasks::TTaskIter TTaskIter;
typedef std::pair<std::size_t, TMetricsTasks> TJobParam;
// Define the thread pool and job wrapper function.
LOG(info) << name_ << " : Collecting jobs from database...";
std::unique_ptr<util::JobQueueThreadPool<TJobParam>> pool =
util::make_thread_pool<TJobParam>(_threadCount,
[&](const TJobParam& job)
{
LOG(debug) << '(' << job.first << '/' << partitions_
<< ") " << name_;
worker_(job.second);
});
// Cache the results of the query that will be dispatched to workers.
std::vector<TQueryParam> tasks;
util::OdbTransaction {_ctx.db} ([&, this]
{
// Storing the result directly and then calling odb::result<>::cache()
// on it does not work: odb::result<>::size() will always throw
// odb::result_not_cached. As of writing, this is a limitation of SQLite.
// So we fall back to the old-fashioned way: std::vector<> in memory.
for (const TQueryParam& param : _ctx.db->query<TQueryParam>(query_))
tasks.emplace_back(param);
});
// Ensure that all workers receive at least one task.
std::size_t taskCount = tasks.size();
if (partitions_ > taskCount)
partitions_ = taskCount;
// Dispatch jobs to workers in discrete packets.
LOG(info) << name_ << " : Dispatching jobs on "
<< _threadCount << " thread(s)...";
std::size_t prev = 0;
TTaskIter it_prev = tasks.cbegin();
std::size_t i = 0;
while (i < partitions_)
{
std::size_t next = taskCount * ++i / partitions_;
std::size_t size = next - prev;
TTaskIter it_next = it_prev;
std::advance(it_next, size);
pool->enqueue(TJobParam(i, TMetricsTasks(it_prev, it_next, size)));
prev = next;
it_prev = it_next;
}
// Await the termination of all workers.
pool->wait();
LOG(info) << name_ << " : Calculation finished.";
}
/// @brief Calculates a metric by querying all objects of the
/// specified parameter type and passing them one-by-one to the
/// specified worker function on parallel threads.
/// This call blocks the caller thread until all workers are finished.
/// @tparam TQueryParam The type of parameters to query.
/// @param name_ The name of the metric (for progress logging).
/// @param partitions_ The number of jobs to partition the query into.
/// @param worker_ The logic of the worker thread.
template<typename TQueryParam>
void parallelCalcMetric(
const char* name_,
std::size_t partitions_,
const std::function<void(const MetricsTasks<TQueryParam>&)>& worker_)
{
parallelCalcMetric<TQueryParam>(
name_,
partitions_,
odb::query<TQueryParam>(),
worker_);
}
int _threadCount;
std::vector<std::string> _inputPaths;
std::unordered_set<model::FileId> _fileIdCache;
std::unordered_map<model::CppAstNodeId, model::FileId> _astNodeIdCache;
static const int functionParamsPartitionMultiplier = 5;
static const int functionMcCabePartitionMultiplier = 5;
static const int functionBumpyRoadPartitionMultiplier = 5;
static const int lackOfCohesionPartitionMultiplier = 25;
static const int efferentCouplingTypesPartitionMultiplier = 5;
static const int afferentCouplingTypesPartitionMultiplier = 5;
static const int efferentCouplingModulesPartitionMultiplier = 5;
static const int afferentCouplingModulesPartitionMultiplier = 5;
static const int relationalCohesionPartitionMultiplier = 5;
static const int typeMcCabePartitionMultiplier = 5;
};
} // parser
} // cc
#endif // CC_PARSER_CPPMETRICSPARSER_H