metrics: update ModelView
[nit.git] / src / metrics / rta_metrics.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Metrics from RTA
18 module rta_metrics
19
20 private import rapid_type_analysis
21 import metrics_base
22 import mmodules_metrics
23 import mclasses_metrics
24
25 redef class ToolContext
26
27 # RTA related metrics phase
28 var rta_metrics_phase: Phase = new RTAMetricsPhase(self, null)
29 end
30
31 private class RTAMetricsPhase
32 super Phase
33 redef fun process_mainmodule(mainmodule, given_mmodules)
34 do
35 if not toolcontext.opt_rta.value and not toolcontext.opt_all.value then return
36 var csv = toolcontext.opt_csv.value
37 var out = "{toolcontext.opt_dir.value or else "metrics"}/rta"
38 out.mkdir
39
40 var model = toolcontext.modelbuilder.model
41 var model_view = new ModelView(model, mainmodule)
42 model_view.min_visibility = protected_visibility
43
44 print toolcontext.format_h1("\n# RTA metrics")
45
46 print toolcontext.format_h2("\n ## Live instances by mainmodules")
47 var mmetrics = new MetricSet
48 mmetrics.register(new MNLC(model_view, toolcontext.modelbuilder))
49 mmetrics.register(new MNLT(model_view, toolcontext.modelbuilder))
50 mmetrics.register(new MNCT(model_view, toolcontext.modelbuilder))
51 mmetrics.register(new MNLI(model_view, toolcontext.modelbuilder))
52 mmetrics.register(new MNLM(model_view, toolcontext.modelbuilder))
53 mmetrics.register(new MNLMD(model_view, toolcontext.modelbuilder))
54 mmetrics.register(new MNLDD(model_view, toolcontext.modelbuilder))
55 mmetrics.collect(new HashSet[MModule].from([mainmodule]))
56 mmetrics.to_console(1, not toolcontext.opt_nocolors.value)
57 if csv then mmetrics.to_csv.write_to_file("{out}/{mainmodule}.csv")
58
59 var mtypes = new HashSet[MType]
60 var analysis = new MetricsRapidTypeAnalysis(toolcontext.modelbuilder, mainmodule, model_view)
61 analysis.run_analysis
62 mtypes.add_all(analysis.live_types)
63 mtypes.add_all(analysis.live_cast_types)
64
65 print toolcontext.format_h2("\n ## Total live instances by mclasses")
66 var cmetrics = new MetricSet
67 cmetrics.register(analysis.cnli)
68 cmetrics.register(analysis.cnlc)
69 cmetrics.to_console(1, not toolcontext.opt_nocolors.value)
70 if csv then cmetrics.to_csv.write_to_file("{out}/mclasses.csv")
71
72 print toolcontext.format_h2("\n ## Total live instances by mtypes")
73 var tmetrics = new MetricSet
74 tmetrics.register(analysis.tnli)
75 tmetrics.register(analysis.tnlc)
76 tmetrics.to_console(1, not toolcontext.opt_nocolors.value)
77 if csv then tmetrics.to_csv.write_to_file("{out}/mtypes.csv")
78
79 print toolcontext.format_h2("\n ## MType complexity")
80 var gmetrics = new MetricSet
81 gmetrics.register(new TAGS)
82 gmetrics.register(new TDGS)
83 gmetrics.collect(mtypes)
84 gmetrics.to_console(1, not toolcontext.opt_nocolors.value)
85 if csv then gmetrics.to_csv.write_to_file("{out}/complexity.csv")
86
87 callsite_info(analysis)
88
89 # dump type and method infos
90 if csv then
91 analysis.live_types_to_csv.write_to_file("{out}/rta_types.csv")
92 analysis.live_methods_to_tree.write_to_file("{out}/rta_methods.dat")
93 end
94 end
95
96 fun callsite_info(rta: RapidTypeAnalysis)
97 do
98 print toolcontext.format_h2("\n ## Callsites")
99 print "* {rta.live_callsites.length} live callsites"
100
101 var csep = new Counter[MPropDef]
102 var cglo = new Counter[MPropDef]
103 var morphisme = new Counter[Int]
104 for cs in rta.live_callsites do
105 csep.inc(cs.mpropdef)
106 var targets = rta.live_targets(cs)
107 for d in targets do
108 cglo.inc(d)
109 end
110 morphisme.inc(targets.length)
111 end
112
113 print toolcontext.format_h3("MMethodDef locally designated (by number of CallSites)")
114 csep.print_summary
115 csep.print_elements(5)
116
117 print toolcontext.format_h3("MMethodDef possibly invoked at runtime (by number of CallSites)")
118 cglo.print_summary
119 cglo.print_elements(5)
120 end
121 end
122
123 # Summary metrics
124
125 # RTA related metric that needs a `modelbuilder`
126 class RTAMetric
127 super MModuleMetric
128
129 # Modelbuilder used to access AST
130 var modelbuilder: ModelBuilder
131 end
132
133 # MModule Metric: Number of Live Types
134 class MNLI
135 super RTAMetric
136 super IntMetric
137 redef fun name do return "mnli"
138 redef fun desc do return "number of live instances in a mmodule"
139
140
141 redef fun collect(mainmodules) do
142 for mainmodule in mainmodules do
143 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
144 analysis.run_analysis
145 values[mainmodule] = analysis.tnli.sum
146 end
147 end
148 end
149
150 # MModule Metric: Number of Live Types
151 class MNLT
152 super RTAMetric
153 super IntMetric
154 redef fun name do return "mnlt"
155 redef fun desc do return "number of live mtypes in a mmodule"
156
157 redef fun collect(mainmodules) do
158 for mainmodule in mainmodules do
159 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
160 analysis.run_analysis
161 values[mainmodule] = analysis.live_types.length
162 end
163 end
164 end
165
166 # MModule Metric: Number of Live Cast Types
167 class MNCT
168 super RTAMetric
169 super IntMetric
170 redef fun name do return "mnct"
171 redef fun desc do return "number of live cast mtypes in a mmodule"
172
173 redef fun collect(mainmodules) do
174 for mainmodule in mainmodules do
175 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
176 analysis.run_analysis
177 values[mainmodule] = analysis.live_cast_types.length
178 end
179 end
180 end
181
182 # MModule Metric: Number of Live Classes
183 class MNLC
184 super RTAMetric
185 super IntMetric
186 redef fun name do return "mnlc"
187 redef fun desc do return "number of live mclasses in a mmodule"
188
189 redef fun collect(mainmodules) do
190 for mainmodule in mainmodules do
191 var live = new HashSet[MClass]
192 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
193 analysis.run_analysis
194 for mtype in analysis.live_types do
195 live.add(mtype.mclass)
196 end
197 values[mainmodule] = live.length
198 end
199 end
200 end
201
202 # MModule Metric: Number of Live Methods
203 class MNLM
204 super RTAMetric
205 super IntMetric
206 redef fun name do return "mnlm"
207 redef fun desc do return "number of live methods in a mmodule"
208
209 redef fun collect(mainmodules) do
210 for mainmodule in mainmodules do
211 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
212 analysis.run_analysis
213 values[mainmodule] = analysis.live_methods.length
214 end
215 end
216 end
217
218 # MModule Metric: Number of Live MethodDefs
219 class MNLMD
220 super RTAMetric
221 super IntMetric
222 redef fun name do return "mnlmd"
223 redef fun desc do return "number of live method definitions in a mmodule"
224
225 redef fun collect(mainmodules) do
226 for mainmodule in mainmodules do
227 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
228 analysis.run_analysis
229 values[mainmodule] = analysis.live_methoddefs.length
230 end
231 end
232 end
233
234 # MModule Metric: Number of Dead MethodDefs
235 class MNLDD
236 super RTAMetric
237 super IntMetric
238 redef fun name do return "mnldd"
239 redef fun desc do return "number of dead method definitions in a mmodule"
240
241 redef fun collect(mainmodules) do
242 for mainmodule in mainmodules do
243 var dead = 0
244 var analysis = new MetricsRapidTypeAnalysis(modelbuilder, mainmodule, model_view)
245 analysis.run_analysis
246 for mmethod in analysis.live_methods do
247 for mdef in mmethod.mpropdefs do
248 if analysis.live_methoddefs.has(mdef) or mdef.is_abstract then continue
249 dead += 1
250 end
251 end
252 values[mainmodule] = dead
253 end
254 end
255 end
256
257 # MClass metrics
258
259 # Class Metric: Number of Live Instances
260 #
261 # count all the `new` made on each mclass
262 class CNLI
263 super MClassMetric
264 super IntMetric
265 redef fun name do return "cnli"
266 redef fun desc do return "number of live instances for a mclass"
267
268 redef fun collect(mclasses) do end
269 end
270
271 # Class Metric: Number of Live Cast
272 #
273 # count all the cast made on each mclass type
274 class CNLC
275 super MClassMetric
276 super IntMetric
277 redef fun name do return "cnlc"
278 redef fun desc do return "number of live cast for a mclass type"
279
280 redef fun collect(mclasses) do end
281 end
282
283 # MType metrics
284
285 # A metric about MType
286 interface MTypeMetric
287 super Metric
288 redef type ELM: MType
289 end
290
291 # Type Metric: Number of Live Instances
292 #
293 # count all the `new` made on each types
294 class TNLI
295 super MTypeMetric
296 super IntMetric
297 redef fun name do return "tnli"
298 redef fun desc do return "number of live instances for a mtype"
299
300 redef fun collect(mtypes) do end
301 end
302
303 # Type Metric: Number of Live Cast
304 #
305 # count all the cast made to each types
306 class TNLC
307 super MTypeMetric
308 super IntMetric
309 redef fun name do return "tnlc"
310 redef fun desc do return "number of live casts to a mtype"
311
312 redef fun collect(mtypes) do end
313 end
314
315 # Type Metric: Arity of Generic Signature
316 #
317 # tags(List[X]) = 1
318 # tags(Map[X, Y]) = 2
319 class TAGS
320 super MTypeMetric
321 super IntMetric
322 redef fun name do return "tags"
323 redef fun desc do return "arity of generic signature"
324
325 redef fun collect(mtypes) do
326 for mtype in mtypes do
327 if mtype isa MGenericType then
328 values[mtype] = mtype.arguments.length
329 else
330 values[mtype] = 0
331 end
332 end
333 end
334 end
335
336 # Type Metric: Depth of Generic Signature
337 #
338 # tdgs(List[X]) = 1
339 # tdgs(Map[X, List[Y]]) = 2
340 class TDGS
341 super MTypeMetric
342 super IntMetric
343 redef fun name do return "tdos"
344 redef fun desc do return "depth of generic signature"
345
346 redef fun collect(mtypes) do
347 for mtype in mtypes do
348 values[mtype] = mtype.signature_depth
349 end
350 end
351 end
352
353 # rta redef
354
355 # Custom RTA analyzer
356 class MetricsRapidTypeAnalysis
357 super RapidTypeAnalysis
358
359 # Model view used to linearize classes
360 var view: ModelView
361
362 # Class Live Instances
363 var cnli: CNLI is lazy do return new CNLI(view)
364
365 # Class Live Casts
366 var cnlc: CNLC is lazy do return new CNLC(view)
367
368 # Type Live Instances
369 var tnli = new TNLI
370
371 # Rtpe Live Casts
372 var tnlc = new TNLC
373
374 redef fun add_new(recv, mtype) do
375 super
376 tnli.values.inc(mtype)
377 cnli.values.inc(mtype.mclass)
378 end
379
380 redef fun add_cast(mtype) do
381 super
382 tnlc.values.inc(mtype)
383
384 mtype = mtype.undecorate
385 if mtype isa MClassType then
386 cnlc.values.inc(mtype.mclass)
387 end
388 end
389 end
390
391 # model redefs
392
393 redef class MType
394 private fun signature_depth: Int do
395 var mtype = self.undecorate
396 if not mtype isa MGenericType then return 0
397
398 var depth = 0
399 for ft in mtype.arguments do
400 var ftd = ft.signature_depth
401 if ftd > depth then depth = ftd
402 end
403 return depth + 1
404 end
405 end