1 | //
|
---|
2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
|
---|
3 | //
|
---|
4 | // The contents of this file are covered under the licence agreement in the
|
---|
5 | // file "LICENCE" distributed with Cforall.
|
---|
6 | //
|
---|
7 | // DeclStats.cpp -- Print statistics about a translation unit's declarations.
|
---|
8 | //
|
---|
9 | // Author : Andrew Beach
|
---|
10 | // Created On : Fri Oct 1 14:26:00 2021
|
---|
11 | // Last Modified By : Andrew Beach
|
---|
12 | // Last Modified On : Wed Oct 8 11:24:00 2021
|
---|
13 | // Update Count : 0
|
---|
14 | //
|
---|
15 |
|
---|
16 | #include "DeclStats.hpp"
|
---|
17 |
|
---|
18 | #include "AST/LinkageSpec.hpp"
|
---|
19 | #include "AST/Pass.hpp"
|
---|
20 | #include "AST/Print.hpp"
|
---|
21 | #include "Common/VectorMap.h"
|
---|
22 |
|
---|
23 | #include <iostream>
|
---|
24 | #include <map>
|
---|
25 | #include <sstream>
|
---|
26 | #include <unordered_map>
|
---|
27 | #include <unordered_set>
|
---|
28 |
|
---|
29 | // Everything but printDeclStats at the bottom is hidden.
|
---|
30 | namespace {
|
---|
31 |
|
---|
32 | template<typename T>
|
---|
33 | void sum( T & l, const T & r ) { l += r; }
|
---|
34 |
|
---|
35 | void sum( VectorMap<unsigned> & l, const VectorMap<unsigned> & r ) {
|
---|
36 | l.reserve( r.size() );
|
---|
37 | for ( unsigned i = 0 ; i < r.size() ; ++i ) {
|
---|
38 | l[i] += r[i];
|
---|
39 | }
|
---|
40 | }
|
---|
41 |
|
---|
42 | template<typename KeyT>
|
---|
43 | void sum( std::map<KeyT, unsigned> & l, const std::map<KeyT, unsigned> & r ) {
|
---|
44 | for ( const auto & entry : r ) {
|
---|
45 | l[ entry.first ] += entry.second;
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | template<typename KeyT>
|
---|
50 | void sum( std::unordered_map<KeyT, unsigned> & l,
|
---|
51 | const std::unordered_map<KeyT, unsigned> & r ) {
|
---|
52 | for ( const auto & entry : r ) {
|
---|
53 | l[ entry.first ] += entry.second;
|
---|
54 | }
|
---|
55 | }
|
---|
56 |
|
---|
57 | /// Stores statistics on a single group of arguments or return values.
|
---|
58 | struct ArgPackStats {
|
---|
59 | /// Count of decls with each number of elements.
|
---|
60 | VectorMap<unsigned> n;
|
---|
61 | /// Count of decls with each number of basic type elements.
|
---|
62 | VectorMap<unsigned> n_basic;
|
---|
63 | /// Count of decls with each number of generic type elements.
|
---|
64 | VectorMap<unsigned> n_generic;
|
---|
65 | /// Count of decls with each number of polymorphic elements.
|
---|
66 | VectorMap<unsigned> n_poly;
|
---|
67 | /// Count of decls with each number of non-generic compound types.
|
---|
68 | VectorMap<unsigned> n_compound;
|
---|
69 | /// Count of decls with each percentage of basic type elements.
|
---|
70 | std::map<unsigned, unsigned> p_basic;
|
---|
71 | /// Count of decls with each percentage of generic type elements.
|
---|
72 | std::map<unsigned, unsigned> p_generic;
|
---|
73 | /// Count of decls with each percentage of polymorphic elements.
|
---|
74 | std::map<unsigned, unsigned> p_poly;
|
---|
75 | /// Count of decls with each percentage of non-generic compound type elements.
|
---|
76 | std::map<unsigned, unsigned> p_compound;
|
---|
77 | /// Count of decls with each number of distinct types in the pack.
|
---|
78 | VectorMap<unsigned> n_types;
|
---|
79 | /// Count of decls with each percentage of new types in lists.
|
---|
80 | /// Types used in the parameter list that recur in the return list are not considered to be new.
|
---|
81 | std::map<unsigned, unsigned> p_new;
|
---|
82 |
|
---|
83 | ArgPackStats& operator+=( const ArgPackStats& other ) {
|
---|
84 | sum(n, other.n);
|
---|
85 | sum(n_basic, other.n_basic);
|
---|
86 | sum(n_generic, other.n_generic);
|
---|
87 | sum(n_poly, other.n_poly);
|
---|
88 | sum(n_compound, other.n_compound);
|
---|
89 | sum(p_basic, other.p_basic);
|
---|
90 | sum(p_generic, other.p_generic);
|
---|
91 | sum(p_poly, other.p_poly);
|
---|
92 | sum(p_compound, other.p_compound);
|
---|
93 | sum(n_types, other.n_types);
|
---|
94 | sum(p_new, other.p_new);
|
---|
95 |
|
---|
96 | return *this;
|
---|
97 | }
|
---|
98 | };
|
---|
99 |
|
---|
100 | /// Collected statistics on a group of declarations.
|
---|
101 | struct Stats {
|
---|
102 | /// Total number of declarations in these statistics.
|
---|
103 | unsigned n_decls;
|
---|
104 | /// Count of declarations with each number of assertion parameters.
|
---|
105 | VectorMap<unsigned> n_type_params;
|
---|
106 | /// Count of generic types with each number of type parameters.
|
---|
107 | VectorMap<unsigned> n_generic_params;
|
---|
108 | /// Count of maximum nesting depth of types.
|
---|
109 | VectorMap<unsigned> n_generic_nesting;
|
---|
110 | /// Count of declarations with each name.
|
---|
111 | std::unordered_map<std::string, unsigned> by_name;
|
---|
112 | /// Count of uses of each basic type.
|
---|
113 | std::unordered_map<std::string, unsigned> basic_type_names;
|
---|
114 | /// Count of uses of each generic type name (includes "*", "[]", "(*)", "[,]").
|
---|
115 | std::unordered_map<std::string, unsigned> generic_type_names;
|
---|
116 | /// Count of uses of each non-generic aggregate type.
|
---|
117 | std::unordered_map<std::string, unsigned> compound_type_names;
|
---|
118 | /// Count of decls using each basic type.
|
---|
119 | std::unordered_map<std::string, unsigned> basic_type_decls;
|
---|
120 | /// Count of decls using each generic type (includes "*", "[]", "(*)", "[,]").
|
---|
121 | std::unordered_map<std::string, unsigned> generic_type_decls;
|
---|
122 | /// Count of decls using each compound type.
|
---|
123 | std::unordered_map<std::string, unsigned> compound_type_decls;
|
---|
124 | /// Stats for the parameter lists.
|
---|
125 | ArgPackStats params;
|
---|
126 | /// Stats for the return lists.
|
---|
127 | ArgPackStats returns;
|
---|
128 |
|
---|
129 | /// Count of declarations with each number of assertions.
|
---|
130 | std::map<unsigned, unsigned> n_assns;
|
---|
131 | /// Stats for the assertions' parameters.
|
---|
132 | ArgPackStats assn_params;
|
---|
133 | /// Stats for the assertions' return types.
|
---|
134 | ArgPackStats assn_returns;
|
---|
135 |
|
---|
136 | Stats& operator+=( const Stats& other ) {
|
---|
137 | sum( n_decls, other.n_decls );
|
---|
138 | sum( n_type_params, other.n_type_params );
|
---|
139 | sum( n_generic_params, other.n_generic_params );
|
---|
140 | sum( n_generic_nesting, other.n_generic_nesting );
|
---|
141 | sum( by_name, other.by_name );
|
---|
142 | sum( basic_type_names, other.basic_type_names );
|
---|
143 | sum( generic_type_names, other.generic_type_names );
|
---|
144 | sum( compound_type_names, other.compound_type_names );
|
---|
145 | sum( basic_type_decls, other.basic_type_decls );
|
---|
146 | sum( generic_type_decls, other.generic_type_decls );
|
---|
147 | sum( compound_type_decls, other.compound_type_decls );
|
---|
148 | sum( params, other.params );
|
---|
149 | sum( returns, other.returns );
|
---|
150 | sum( n_assns, other.n_assns );
|
---|
151 | sum( assn_params, other.assn_params );
|
---|
152 | sum( assn_returns, other.assn_returns );
|
---|
153 |
|
---|
154 | return *this;
|
---|
155 | }
|
---|
156 |
|
---|
157 | };
|
---|
158 |
|
---|
159 | void update_max( unsigned & max, unsigned value ) {
|
---|
160 | if ( max < value ) max = value;
|
---|
161 | }
|
---|
162 |
|
---|
163 | // Where all unnamed specs are counted as one named spec group.
|
---|
164 | constexpr unsigned num_named_specs = 8;
|
---|
165 |
|
---|
166 | unsigned linkage_index( ast::Linkage::Spec spec ) {
|
---|
167 | switch ( spec.val ) {
|
---|
168 | case ast::Linkage::Intrinsic.val: return 0;
|
---|
169 | case ast::Linkage::C.val: return 1;
|
---|
170 | case ast::Linkage::Cforall.val: return 2;
|
---|
171 | case ast::Linkage::AutoGen.val: return 3;
|
---|
172 | case ast::Linkage::Compiler.val: return 4;
|
---|
173 | case ast::Linkage::BuiltinCFA.val: return 5;
|
---|
174 | case ast::Linkage::BuiltinC.val: return 6;
|
---|
175 | default: return 7;
|
---|
176 | }
|
---|
177 | }
|
---|
178 |
|
---|
179 | struct DeclStats : public ast::WithShortCircuiting {
|
---|
180 | /// Stores separate stats per linkage.
|
---|
181 | Stats by_linkage[num_named_specs];
|
---|
182 | /// Stores manglenames already seen to avoid double-counting.
|
---|
183 | std::unordered_set<std::string> seen_names;
|
---|
184 | /// Overall stats.
|
---|
185 | Stats total;
|
---|
186 | /// Count of expressions with (depth, fanout)
|
---|
187 | std::map<std::pair<unsigned, unsigned>, unsigned> exprs_by_fanout_at_depth;
|
---|
188 |
|
---|
189 | /// Count that we have seen a named type.
|
---|
190 | void countType(
|
---|
191 | const std::string & name, unsigned & n,
|
---|
192 | std::unordered_map<std::string, unsigned> & names,
|
---|
193 | std::unordered_map<std::string, unsigned> & decls,
|
---|
194 | std::unordered_set<std::string> & elSeen ) {
|
---|
195 | ++n;
|
---|
196 | ++names[ name ];
|
---|
197 | if ( elSeen.insert( name ).second ) {
|
---|
198 | ++decls[ name ];
|
---|
199 | }
|
---|
200 | }
|
---|
201 |
|
---|
202 | /// Perform type analysis on a subtype.
|
---|
203 | void analyzeSubtype( const ast::Type * type, Stats & stats,
|
---|
204 | std::unordered_set<std::string> & elSeen, unsigned & n_poly,
|
---|
205 | bool & seen_poly, unsigned & max_depth, unsigned depth ) {
|
---|
206 | // This kind of gets in the way of grouping arguments.
|
---|
207 | unsigned ignored = 0;
|
---|
208 | analyzeType(
|
---|
209 | type, stats, elSeen, ignored, ignored, n_poly, ignored,
|
---|
210 | seen_poly, max_depth, depth + 1 );
|
---|
211 | }
|
---|
212 |
|
---|
213 | /// Perform type analysis on each subtype.
|
---|
214 | void analyzeSubtypes(
|
---|
215 | const std::vector<ast::ptr<ast::Type>> & types, Stats & stats,
|
---|
216 | std::unordered_set<std::string> & elSeen, unsigned & n_poly,
|
---|
217 | bool & seen_poly, unsigned & max_depth, unsigned depth ) {
|
---|
218 | for ( const auto & type : types ) {
|
---|
219 | analyzeSubtype( type, stats, elSeen, n_poly, seen_poly, max_depth, depth );
|
---|
220 | }
|
---|
221 | }
|
---|
222 |
|
---|
223 | /// Perform sub-type analysis on each subtype in an argument pack.
|
---|
224 | void analyzeSubPack(
|
---|
225 | const std::vector<ast::ptr<ast::Type>> & types, Stats & stats,
|
---|
226 | std::unordered_set<std::string> & elSeen, unsigned & n_poly,
|
---|
227 | bool & seen_poly, unsigned & max_depth, unsigned depth,
|
---|
228 | unsigned & n_subs ) {
|
---|
229 | // ... and count voids?
|
---|
230 | for ( const auto & type : types ) {
|
---|
231 | if ( type.as<ast::VoidType>() ) {
|
---|
232 | ++n_subs;
|
---|
233 | }
|
---|
234 | // Could this be in `else`?
|
---|
235 | analyzeSubtype( type, stats, elSeen, n_poly, seen_poly, max_depth, depth );
|
---|
236 | }
|
---|
237 | }
|
---|
238 |
|
---|
239 | /// Analyze and gather stats from a single type.
|
---|
240 | void analyzeType( const ast::ptr<ast::Type> & type, Stats & stats,
|
---|
241 | std::unordered_set<std::string> & elSeen,
|
---|
242 | unsigned & n_basic, unsigned & n_generic, unsigned & n_poly,
|
---|
243 | unsigned & n_agg, bool & seen_poly,
|
---|
244 | unsigned & max_depth, unsigned depth ) {
|
---|
245 | // Almost a visit, except it is only types.
|
---|
246 | if ( const ast::BasicType * t = type.as<ast::BasicType>() ) {
|
---|
247 | const std::string name = ast::BasicType::typeNames[ t->kind ];
|
---|
248 | countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
|
---|
249 | update_max( max_depth, depth );
|
---|
250 | } else if ( auto t = type.as<ast::PointerType>() ) {
|
---|
251 | static const std::string name = "*";
|
---|
252 | countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
|
---|
253 | analyzeSubtype( t->base, stats, elSeen, n_poly, seen_poly, max_depth, depth );
|
---|
254 | ++stats.n_generic_params.at( 1 );
|
---|
255 | } else if ( auto t = type.as<ast::ArrayType>() ) {
|
---|
256 | static const std::string name = "[]";
|
---|
257 | countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
|
---|
258 | analyzeSubtype( t->base, stats, elSeen, n_poly, seen_poly, max_depth, depth );
|
---|
259 | ++stats.n_generic_params.at( 1 );
|
---|
260 | } else if ( auto t = type.as<ast::ReferenceType>() ) {
|
---|
261 | static const std::string name = "&";
|
---|
262 | countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
|
---|
263 | analyzeSubtype( t->base, stats, elSeen, n_poly, seen_poly, max_depth, depth );
|
---|
264 | ++stats.n_generic_params.at( 1 );
|
---|
265 | } else if ( auto t = type.as<ast::FunctionType>() ) {
|
---|
266 | static const std::string name = "(*)";
|
---|
267 | countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen );
|
---|
268 | unsigned n_subs = 0;
|
---|
269 | analyzeSubPack( t->returns, stats, elSeen, n_poly, seen_poly, max_depth, depth, n_subs );
|
---|
270 | analyzeSubPack( t->params, stats, elSeen, n_poly, seen_poly, max_depth, depth, n_subs );
|
---|
271 | ++stats.n_generic_params.at( n_subs );
|
---|
272 | } else if ( auto t = type.as<ast::TypeInstType>() ) {
|
---|
273 | if ( !seen_poly ) {
|
---|
274 | ++n_poly;
|
---|
275 | seen_poly = true;
|
---|
276 | }
|
---|
277 | countType( t->name, n_agg, stats.compound_type_names,
|
---|
278 | stats.compound_type_decls, elSeen );
|
---|
279 | update_max( max_depth, depth );
|
---|
280 | } else if ( auto t = type.as<ast::BaseInstType>() ) {
|
---|
281 | auto & params = t->params;
|
---|
282 | if ( params.empty() ) {
|
---|
283 | countType( t->name, n_agg, stats.compound_type_names,
|
---|
284 | stats.compound_type_decls, elSeen );
|
---|
285 | update_max( max_depth, depth );
|
---|
286 | } else {
|
---|
287 | countType( t->name, n_generic, stats.generic_type_names,
|
---|
288 | stats.generic_type_decls, elSeen );
|
---|
289 | ++stats.n_generic_params.at( params.size() );
|
---|
290 | }
|
---|
291 | } else if ( auto t = type.as<ast::TupleType>() ) {
|
---|
292 | static const std::string name = "[,]";
|
---|
293 | countType( name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
|
---|
294 | analyzeSubtypes( t->types, stats, elSeen, n_poly, seen_poly, max_depth, depth );
|
---|
295 | ++stats.n_generic_params.at( t->size() );
|
---|
296 | } else if ( type.as<ast::VarArgsType>() ) {
|
---|
297 | static const std::string name = "...";
|
---|
298 | countType( name, n_agg, stats.compound_type_names, stats.compound_type_decls, elSeen );
|
---|
299 | update_max( max_depth, depth );
|
---|
300 | } else if ( type.as<ast::ZeroType>() ) {
|
---|
301 | static const std::string name = "0";
|
---|
302 | countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
|
---|
303 | update_max( max_depth, depth );
|
---|
304 | } else if ( type.as<ast::OneType>() ) {
|
---|
305 | static const std::string name = "1";
|
---|
306 | countType( name, n_basic, stats.basic_type_names, stats.basic_type_decls, elSeen );
|
---|
307 | update_max( max_depth, depth );
|
---|
308 | }
|
---|
309 | }
|
---|
310 |
|
---|
311 | /// Update an ArgPackStats based on the list of types it repersents.
|
---|
312 | void analyzeArgPack(
|
---|
313 | const std::vector<ast::ptr<ast::Type>> & types,
|
---|
314 | Stats & stats,
|
---|
315 | ArgPackStats & packStats,
|
---|
316 | // What are these two used for?
|
---|
317 | std::unordered_set<std::string> & seen,
|
---|
318 | std::unordered_set<std::string> & elSeen ) {
|
---|
319 | std::unordered_set<std::string> type_names;
|
---|
320 | unsigned n = 0;
|
---|
321 | unsigned n_basic = 0;
|
---|
322 | unsigned n_generic = 0;
|
---|
323 | unsigned n_poly = 0;
|
---|
324 | unsigned n_compound = 0;
|
---|
325 | unsigned n_new = 0;
|
---|
326 |
|
---|
327 | for ( auto & type : types ) {
|
---|
328 | n += type->size();
|
---|
329 |
|
---|
330 | std::stringstream ss;
|
---|
331 | ast::print( ss, type );
|
---|
332 | type_names.insert( ss.str() );
|
---|
333 | if ( seen.insert( ss.str() ).second ) {
|
---|
334 | ++n_new;
|
---|
335 | }
|
---|
336 |
|
---|
337 | bool seen_poly = false;
|
---|
338 | unsigned max_depth = 0;
|
---|
339 | analyzeType(
|
---|
340 | type, stats, elSeen, n_basic, n_generic, n_poly, n_compound,
|
---|
341 | seen_poly, max_depth, 0
|
---|
342 | );
|
---|
343 | ++stats.n_generic_nesting.at( max_depth );
|
---|
344 | }
|
---|
345 |
|
---|
346 | ++packStats.n.at( n );
|
---|
347 | ++packStats.n_basic.at( n_basic );
|
---|
348 | ++packStats.n_generic.at( n_generic );
|
---|
349 | ++packStats.n_poly.at( n_poly );
|
---|
350 | ++packStats.n_compound.at( n_compound );
|
---|
351 | if ( n > 0 ) {
|
---|
352 | ++packStats.p_basic[ n_basic * 100 / n ];
|
---|
353 | ++packStats.p_generic[ n_generic * 100 / n ];
|
---|
354 | ++packStats.p_poly[ n_poly * 100 / n ];
|
---|
355 | ++packStats.p_compound[ n_compound * 100 / n ];
|
---|
356 | if ( n > 1 ) {
|
---|
357 | ++packStats.p_new[ (n_new - 1) * 100 / (n - 1) ];
|
---|
358 | }
|
---|
359 | }
|
---|
360 | ++packStats.n_types.at( types.size() );
|
---|
361 | }
|
---|
362 |
|
---|
363 | /// Perform type analysis on a function type, storing information in the
|
---|
364 | /// given ArgPackStats.
|
---|
365 | void analyzeFunctionType( const ast::FunctionType * type, Stats& stats,
|
---|
366 | ArgPackStats Stats::* param_pack,
|
---|
367 | ArgPackStats Stats::* return_pack ) {
|
---|
368 | // I still don't know what these are for.
|
---|
369 | std::unordered_set<std::string> seen;
|
---|
370 | std::unordered_set<std::string> elSeen;
|
---|
371 | analyzeArgPack( type->params, stats, stats.*param_pack, seen, elSeen );
|
---|
372 | analyzeArgPack( type->returns, stats, stats.*return_pack, seen, elSeen );
|
---|
373 | }
|
---|
374 |
|
---|
375 | /// If the assertion is a function, return the function type.
|
---|
376 | static const ast::FunctionType * getAssertionFunctionType(
|
---|
377 | const ast::ptr<ast::DeclWithType> & assertion ) {
|
---|
378 | if ( auto * assertionObject = assertion.as<ast::ObjectDecl>() ) {
|
---|
379 | if ( auto * ptrTy = assertionObject->type.as<ast::PointerType>() ) {
|
---|
380 | return ptrTy->base.as<ast::FunctionType>();
|
---|
381 | } else {
|
---|
382 | return assertionObject->type.as<ast::FunctionType>();
|
---|
383 | }
|
---|
384 | } else if ( auto * assertionDecl = assertion.as<ast::FunctionDecl>() ) {
|
---|
385 | return assertionDecl->type;
|
---|
386 | }
|
---|
387 | return nullptr;
|
---|
388 | }
|
---|
389 |
|
---|
390 | void analyzeFunctionDecl( const ast::FunctionDecl * decl ) {
|
---|
391 | Stats & stats = by_linkage[ linkage_index( decl->linkage ) ];
|
---|
392 |
|
---|
393 | ++stats.n_decls;
|
---|
394 | const ast::FunctionType * type = decl->type.get();
|
---|
395 | const ast::FunctionType::ForallList & forall = type->forall;
|
---|
396 | ++stats.n_type_params.at( forall.size() );
|
---|
397 | unsigned num_assertions = 0;
|
---|
398 | for ( const ast::ptr<ast::TypeInstType> & instType : forall ) {
|
---|
399 | num_assertions += instType->base->assertions.size();
|
---|
400 | for ( const auto & assertion : instType->base->assertions ) {
|
---|
401 | if ( auto assertionType = getAssertionFunctionType( assertion ) ) {
|
---|
402 | analyzeFunctionType( assertionType, stats,
|
---|
403 | &Stats::assn_params, &Stats::assn_returns );
|
---|
404 | }
|
---|
405 | }
|
---|
406 | }
|
---|
407 | ++stats.n_assns[ num_assertions ];
|
---|
408 | ++stats.by_name[ decl->name ];
|
---|
409 | analyzeFunctionType( type, stats, &Stats::params, &Stats::returns );
|
---|
410 | }
|
---|
411 |
|
---|
412 | void analyzeUntypedExpr( const ast::UntypedExpr * expr, unsigned depth ) {
|
---|
413 | unsigned fanout = expr->args.size();
|
---|
414 | ++exprs_by_fanout_at_depth[ std::make_pair( depth, fanout ) ];
|
---|
415 |
|
---|
416 | for ( const ast::ptr<ast::Expr> & arg : expr->args ) {
|
---|
417 | if ( const auto * untyped = arg.as<ast::UntypedExpr>() ) {
|
---|
418 | analyzeUntypedExpr( untyped, depth + 1 );
|
---|
419 | }
|
---|
420 | }
|
---|
421 | }
|
---|
422 |
|
---|
423 | public:
|
---|
424 | void previsit( const ast::UntypedExpr * expr ) {
|
---|
425 | visit_children = false;
|
---|
426 | analyzeUntypedExpr( expr, 0 );
|
---|
427 | }
|
---|
428 |
|
---|
429 | void previsit( const ast::FunctionDecl * decl ) {
|
---|
430 | const std::string & mangleName = decl->mangleName;
|
---|
431 | const std::string & indexName = mangleName.empty() ? decl->name : mangleName;
|
---|
432 | if ( seen_names.insert( indexName ).second ) {
|
---|
433 | analyzeFunctionDecl( decl );
|
---|
434 | }
|
---|
435 | }
|
---|
436 |
|
---|
437 | private:
|
---|
438 |
|
---|
439 | // Trying to avoid duplication by templates.
|
---|
440 | // I couldn't do it in all cases.
|
---|
441 | template<typename T, typename U>
|
---|
442 | using getter = std::function<U(T const &)>;
|
---|
443 |
|
---|
444 | /// Print a single role, for every linkage and the totals.
|
---|
445 | void printRow( const std::string & name, getter<Stats, unsigned> extract ) {
|
---|
446 | std::cout << "\"" << name << "\",";
|
---|
447 | for ( const Stats & stats : by_linkage ) {
|
---|
448 | std::cout << "," << extract( stats );
|
---|
449 | }
|
---|
450 | std::cout << "," << extract( total ) << std::endl;
|
---|
451 | }
|
---|
452 |
|
---|
453 | /// Print every row in a group of maps.
|
---|
454 | template<typename Func>
|
---|
455 | void printAllMap( const std::string & name, Func && extract ) {
|
---|
456 | // Get all rows from the total stats.
|
---|
457 | for ( auto & entry : extract( total ) ) {
|
---|
458 | auto & key = entry.first;
|
---|
459 | std::cout << "\"" << name << "\"," << key;
|
---|
460 | for ( const auto & stats : by_linkage ) {
|
---|
461 | const auto & map = extract( stats );
|
---|
462 | auto it = map.find( key );
|
---|
463 | if ( map.end() == it ) {
|
---|
464 | std::cout << ",0";
|
---|
465 | } else {
|
---|
466 | std::cout << "," << it->second;
|
---|
467 | }
|
---|
468 | }
|
---|
469 | std::cout << "," << entry.second << std::endl;
|
---|
470 | }
|
---|
471 | }
|
---|
472 |
|
---|
473 | /// Accumalate information, then print every row in the remaining maps.
|
---|
474 | template<typename Func>
|
---|
475 | void printAllSparseHisto( const std::string & name, Func && extract ) {
|
---|
476 | std::map<unsigned, unsigned> histos[num_named_specs];
|
---|
477 | std::map<unsigned, unsigned> histo_total;
|
---|
478 |
|
---|
479 | // Collect all data into the histograms.
|
---|
480 | for ( const auto & entry : extract( total ) ) {
|
---|
481 | ++histo_total[ entry.second ];
|
---|
482 | }
|
---|
483 |
|
---|
484 | for ( unsigned i = 0 ; i < num_named_specs ; ++i ) {
|
---|
485 | for ( const auto & entry : extract( by_linkage[i] ) ) {
|
---|
486 | ++histos[ i ][ entry.second ];
|
---|
487 | }
|
---|
488 | }
|
---|
489 |
|
---|
490 | // Get all rows from the total stats.
|
---|
491 | for ( const auto & entry : histo_total ) {
|
---|
492 | const unsigned & key = entry.first;
|
---|
493 | std::cout << "\"" << name << "\"," << key;
|
---|
494 | for ( unsigned i = 0 ; i < num_named_specs ; ++i ) {
|
---|
495 | auto it = histos[i].find( key );
|
---|
496 | if ( histos[i].end() == it ) {
|
---|
497 | std::cout << ",0";
|
---|
498 | } else {
|
---|
499 | std::cout << "," << it->second;
|
---|
500 | }
|
---|
501 | }
|
---|
502 | std::cout << "," << entry.second << std::endl;
|
---|
503 | }
|
---|
504 | }
|
---|
505 |
|
---|
506 | void printAllPack( const std::string & name, ArgPackStats Stats::* field ) {
|
---|
507 | printAllMap("n_basic_" + name, [&field](const Stats& stats) { return (stats.*field).n_basic; });
|
---|
508 | printAllMap("n_generic_" + name, [&field](const Stats& stats) { return (stats.*field).n_generic; });
|
---|
509 | printAllMap("n_poly_" + name, [&field](const Stats& stats) { return (stats.*field).n_poly; });
|
---|
510 | printAllMap("n_compound_" + name, [&field](const Stats& stats) { return (stats.*field).n_compound; });
|
---|
511 | printAllMap("n_" + name, [&field](const Stats& stats) { return (stats.*field).n; });
|
---|
512 | printAllMap("%_basic_" + name, [&field](const Stats& stats) { return (stats.*field).p_basic; });
|
---|
513 | printAllMap("%_generic_" + name, [&field](const Stats& stats) { return (stats.*field).p_generic; });
|
---|
514 | printAllMap("%_poly_" + name, [&field](const Stats& stats) { return (stats.*field).p_poly; });
|
---|
515 | printAllMap("%_compound_" + name, [&field](const Stats& stats) { return (stats.*field).p_compound; });
|
---|
516 | printAllMap("n_distinct_types_" + name, [&field](const Stats& stats) { return (stats.*field).n_types; });
|
---|
517 | printAllMap("%_new_types_in_" + name, [&field](const Stats& stats) { return (stats.*field).p_new; });
|
---|
518 | }
|
---|
519 |
|
---|
520 | static void printPairMap (
|
---|
521 | const std::string & name,
|
---|
522 | const std::map<std::pair<unsigned, unsigned>, unsigned> & map ) {
|
---|
523 | for ( const auto & entry : map ) {
|
---|
524 | const auto & key = entry.first;
|
---|
525 | std::cout << "\"" << name << "\"," << key.first << ','
|
---|
526 | << key.second << ',' << entry.second << std::endl;
|
---|
527 | }
|
---|
528 | }
|
---|
529 |
|
---|
530 | public:
|
---|
531 | void print() {
|
---|
532 | for ( auto & stats : by_linkage ) {
|
---|
533 | total += stats;
|
---|
534 | }
|
---|
535 |
|
---|
536 | std::cout << ",,\"intrinsic\",\"Cforall\",\"C\",\"autogen\",\"compiler\",\"builtinCFA\",\"builtinC\",\"other\",\"TOTAL\"" << std::endl;
|
---|
537 |
|
---|
538 | printAllMap("n_type_params", [](const Stats& stats) { return stats.n_type_params; });
|
---|
539 | printAllMap("n_generic_params", [](const Stats& stats) { return stats.n_generic_params; });
|
---|
540 | printAllMap("n_generic_nesting", [](const Stats& stats) { return stats.n_generic_nesting; });
|
---|
541 | printRow("n_decls", [](const Stats& stats) { return stats.n_decls; });
|
---|
542 | printRow("unique_names", [](const Stats& stats) { return stats.by_name.size(); });
|
---|
543 | printAllSparseHisto("overloads", [](const Stats& stats) { return stats.by_name; });
|
---|
544 | printRow("basic_type_names", [](const Stats& stats) { return stats.basic_type_names.size(); });
|
---|
545 | printAllSparseHisto("basic_type_uses", [](const Stats& stats) { return stats.basic_type_names; });
|
---|
546 | printAllSparseHisto("decls_using_basic_type", [](const Stats& stats) { return stats.basic_type_decls; });
|
---|
547 | printRow("generic_type_names", [](const Stats& stats) { return stats.generic_type_names.size(); });
|
---|
548 | printAllSparseHisto("generic_type_uses", [](const Stats& stats) { return stats.generic_type_names; });
|
---|
549 | printAllSparseHisto("decls_using_generic_type", [](const Stats& stats) { return stats.generic_type_decls; });
|
---|
550 | printRow("compound_type_names", [](const Stats& stats) { return stats.compound_type_names.size(); });
|
---|
551 | printAllSparseHisto("compound_type_uses", [](const Stats& stats) { return stats.compound_type_names; });
|
---|
552 | printAllSparseHisto("decls_using_compound_type", [](const Stats& stats) { return stats.compound_type_decls; });
|
---|
553 | printAllPack("params", &Stats::params);
|
---|
554 | printAllPack("returns", &Stats::returns);
|
---|
555 | printAllMap("n_assns", [](const Stats& stats) { return stats.n_assns; });
|
---|
556 | printAllPack("assn_params", &Stats::assn_params);
|
---|
557 | printAllPack("assn_returns", &Stats::assn_returns);
|
---|
558 | std::cout << std::endl;
|
---|
559 |
|
---|
560 | printPairMap( "exprs by depth+fanout", exprs_by_fanout_at_depth );
|
---|
561 | }
|
---|
562 | };
|
---|
563 |
|
---|
564 | } // namespace
|
---|
565 |
|
---|
566 | void printDeclStats( ast::TranslationUnit & translationUnit ) {
|
---|
567 | ast::Pass<DeclStats> stats;
|
---|
568 | accept_all( translationUnit, stats );
|
---|
569 | stats.core.print();
|
---|
570 | }
|
---|
571 |
|
---|
572 | // Local Variables: //
|
---|
573 | // tab-width: 4 //
|
---|
574 | // mode: c++ //
|
---|
575 | // compile-command: "make install" //
|
---|
576 | // End: //
|
---|