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