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: // |
---|