model: rename `as_notnullable` to `undecorate`
[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 var rta_metrics_phase: Phase = new RTAMetricsPhase(self, null)
27 end
28
29 private class RTAMetricsPhase
30 super Phase
31 redef fun process_mainmodule(mainmodule, given_mmodules)
32 do
33 if not toolcontext.opt_rta.value and not toolcontext.opt_all.value then return
34 var csv = toolcontext.opt_csv.value
35 var out = "{toolcontext.opt_dir.value or else "metrics"}/rta"
36 out.mkdir
37
38 print toolcontext.format_h1("\n# RTA metrics")
39
40 print toolcontext.format_h2("\n ## Live instances by mainmodules")
41 var mmetrics = new MetricSet
42 mmetrics.register(new MNLC(toolcontext.modelbuilder))
43 mmetrics.register(new MNLT(toolcontext.modelbuilder))
44 mmetrics.register(new MNCT(toolcontext.modelbuilder))
45 mmetrics.register(new MNLI(toolcontext.modelbuilder))
46 mmetrics.register(new MNLM(toolcontext.modelbuilder))
47 mmetrics.register(new MNLMD(toolcontext.modelbuilder))
48 mmetrics.register(new MNLDD(toolcontext.modelbuilder))
49 mmetrics.collect(new HashSet[MModule].from([mainmodule]))
50 mmetrics.to_console(1, not toolcontext.opt_nocolors.value)
51 if csv then mmetrics.to_csv.save("{out}/{mainmodule}.csv")
52
53 var mtypes = new HashSet[MType]
54 var analysis = new RapidTypeAnalysis(toolcontext.modelbuilder, mainmodule)
55 analysis.run_analysis
56 mtypes.add_all(analysis.live_types)
57 mtypes.add_all(analysis.live_cast_types)
58
59 print toolcontext.format_h2("\n ## Total live instances by mclasses")
60 var cmetrics = new MetricSet
61 cmetrics.register(analysis.cnli)
62 cmetrics.register(analysis.cnlc)
63 cmetrics.to_console(1, not toolcontext.opt_nocolors.value)
64 if csv then cmetrics.to_csv.save("{out}/mclasses.csv")
65
66 print toolcontext.format_h2("\n ## Total live instances by mtypes")
67 var tmetrics = new MetricSet
68 tmetrics.register(analysis.tnli)
69 tmetrics.register(analysis.tnlc)
70 tmetrics.to_console(1, not toolcontext.opt_nocolors.value)
71 if csv then tmetrics.to_csv.save("{out}/mtypes.csv")
72
73 print toolcontext.format_h2("\n ## MType complexity")
74 var gmetrics = new MetricSet
75 gmetrics.register(new TAGS)
76 gmetrics.register(new TDGS)
77 gmetrics.collect(mtypes)
78 gmetrics.to_console(1, not toolcontext.opt_nocolors.value)
79 if csv then gmetrics.to_csv.save("{out}/complexity.csv")
80
81 callsite_info(analysis)
82
83 # dump type and method infos
84 if csv then
85 analysis.live_types_to_csv.save("{out}/rta_types.csv")
86 analysis.live_methods_to_tree.write_to_file("{out}/rta_methods.dat")
87 end
88 end
89
90 fun callsite_info(rta: RapidTypeAnalysis)
91 do
92 print toolcontext.format_h2("\n ## Callsites")
93 print "* {rta.live_callsites.length} live callsites"
94
95 var csep = new Counter[MPropDef]
96 var cglo = new Counter[MPropDef]
97 var morphisme = new Counter[Int]
98 for cs in rta.live_callsites do
99 csep.inc(cs.mpropdef)
100 var targets = rta.live_targets(cs)
101 for d in targets do
102 cglo.inc(d)
103 end
104 morphisme.inc(targets.length)
105 end
106
107 print toolcontext.format_h3("MMethodDef locally designated (by number of CallSites)")
108 csep.print_summary
109 csep.print_elements(5)
110
111 print toolcontext.format_h3("MMethodDef possibly invoked at runtime (by number of CallSites)")
112 cglo.print_summary
113 cglo.print_elements(5)
114 end
115 end
116
117 # Summary metrics
118
119 # MModule Metric: Number of Live Types
120 class MNLI
121 super MModuleMetric
122 super IntMetric
123 redef fun name do return "mnli"
124 redef fun desc do return "number of live instances in a mmodule"
125
126 var modelbuilder: ModelBuilder
127 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
128
129 redef fun collect(mainmodules) do
130 for mainmodule in mainmodules do
131 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
132 analysis.run_analysis
133 values[mainmodule] = analysis.tnli.sum
134 end
135 end
136 end
137
138 # MModule Metric: Number of Live Types
139 class MNLT
140 super MModuleMetric
141 super IntMetric
142 redef fun name do return "mnlt"
143 redef fun desc do return "number of live mtypes in a mmodule"
144
145 var modelbuilder: ModelBuilder
146 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
147
148 redef fun collect(mainmodules) do
149 for mainmodule in mainmodules do
150 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
151 analysis.run_analysis
152 values[mainmodule] = analysis.live_types.length
153 end
154 end
155 end
156
157 # MModule Metric: Number of Live Cast Types
158 class MNCT
159 super MModuleMetric
160 super IntMetric
161 redef fun name do return "mnct"
162 redef fun desc do return "number of live cast mtypes in a mmodule"
163
164 var modelbuilder: ModelBuilder
165 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
166
167 redef fun collect(mainmodules) do
168 for mainmodule in mainmodules do
169 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
170 analysis.run_analysis
171 values[mainmodule] = analysis.live_cast_types.length
172 end
173 end
174 end
175
176 # MModule Metric: Number of Live Classes
177 class MNLC
178 super MModuleMetric
179 super IntMetric
180 redef fun name do return "mnlc"
181 redef fun desc do return "number of live mclasses in a mmodule"
182
183 var modelbuilder: ModelBuilder
184 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
185
186 redef fun collect(mainmodules) do
187 for mainmodule in mainmodules do
188 var live = new HashSet[MClass]
189 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
190 analysis.run_analysis
191 for mtype in analysis.live_types do
192 live.add(mtype.mclass)
193 end
194 values[mainmodule] = live.length
195 end
196 end
197 end
198
199 # MModule Metric: Number of Live Methods
200 class MNLM
201 super MModuleMetric
202 super IntMetric
203 redef fun name do return "mnlm"
204 redef fun desc do return "number of live methods in a mmodule"
205
206 var modelbuilder: ModelBuilder
207 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
208
209 redef fun collect(mainmodules) do
210 for mainmodule in mainmodules do
211 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
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 MModuleMetric
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 var modelbuilder: ModelBuilder
226 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
227
228 redef fun collect(mainmodules) do
229 for mainmodule in mainmodules do
230 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
231 analysis.run_analysis
232 values[mainmodule] = analysis.live_methoddefs.length
233 end
234 end
235 end
236
237 # MModule Metric: Number of Dead MethodDefs
238 class MNLDD
239 super MModuleMetric
240 super IntMetric
241 redef fun name do return "mnldd"
242 redef fun desc do return "number of dead method definitions in a mmodule"
243
244 var modelbuilder: ModelBuilder
245 init(modelbuilder: ModelBuilder) do self.modelbuilder = modelbuilder
246
247 redef fun collect(mainmodules) do
248 for mainmodule in mainmodules do
249 var dead = 0
250 var analysis = new RapidTypeAnalysis(modelbuilder, mainmodule)
251 analysis.run_analysis
252 for mmethod in analysis.live_methods do
253 for mdef in mmethod.mpropdefs do
254 if analysis.live_methoddefs.has(mdef) or mdef.is_abstract then continue
255 dead += 1
256 end
257 end
258 values[mainmodule] = dead
259 end
260 end
261 end
262
263 # MClass metrics
264
265 # Class Metric: Number of Live Instances
266 #
267 # count all the `new` made on each mclass
268 class CNLI
269 super MClassMetric
270 super IntMetric
271 redef fun name do return "cnli"
272 redef fun desc do return "number of live instances for a mclass"
273
274 redef fun collect(mclasses) do end
275 end
276
277 # Class Metric: Number of Live Cast
278 #
279 # count all the cast made on each mclass type
280 class CNLC
281 super MClassMetric
282 super IntMetric
283 redef fun name do return "cnlc"
284 redef fun desc do return "number of live cast for a mclass type"
285
286 redef fun collect(mclasses) do end
287 end
288
289 # MType metrics
290
291 # A metric about MType
292 interface MTypeMetric
293 super Metric
294 redef type ELM: MType
295 end
296
297 # Type Metric: Number of Live Instances
298 #
299 # count all the `new` made on each types
300 class TNLI
301 super MTypeMetric
302 super IntMetric
303 redef fun name do return "tnli"
304 redef fun desc do return "number of live instances for a mtype"
305
306 redef fun collect(mtypes) do end
307 end
308
309 # Type Metric: Number of Live Cast
310 #
311 # count all the cast made to each types
312 class TNLC
313 super MTypeMetric
314 super IntMetric
315 redef fun name do return "tnlc"
316 redef fun desc do return "number of live casts to a mtype"
317
318 redef fun collect(mtypes) do end
319 end
320
321 # Type Metric: Arity of Generic Signature
322 #
323 # tags(List[X]) = 1
324 # tags(Map[X, Y]) = 2
325 class TAGS
326 super MTypeMetric
327 super IntMetric
328 redef fun name do return "tags"
329 redef fun desc do return "arity of generic signature"
330
331 redef fun collect(mtypes) do
332 for mtype in mtypes do
333 if mtype isa MGenericType then
334 values[mtype] = mtype.arguments.length
335 else
336 values[mtype] = 0
337 end
338 end
339 end
340 end
341
342 # Type Metric: Depth of Generic Signature
343 #
344 # tdgs(List[X]) = 1
345 # tdgs(Map[X, List[Y]]) = 2
346 class TDGS
347 super MTypeMetric
348 super IntMetric
349 redef fun name do return "tdos"
350 redef fun desc do return "depth of generic signature"
351
352 redef fun collect(mtypes) do
353 for mtype in mtypes do
354 values[mtype] = mtype.signature_depth
355 end
356 end
357 end
358
359 # rta redef
360
361 redef class RapidTypeAnalysis
362 var cnli = new CNLI
363 var cnlc = new CNLC
364 var tnli = new TNLI
365 var tnlc = new TNLC
366
367 redef fun add_new(recv, mtype) do
368 super
369 tnli.values.inc(mtype)
370 cnli.values.inc(mtype.mclass)
371 end
372
373 redef fun add_cast(mtype) do
374 super
375 tnlc.values.inc(mtype)
376
377 mtype = mtype.undecorate
378 if mtype isa MClassType then
379 cnlc.values.inc(mtype.mclass)
380 end
381 end
382 end
383
384 # model redefs
385
386 redef class MType
387 private fun signature_depth: Int do
388 var mtype = self.undecorate
389 if not mtype isa MGenericType then return 0
390
391 var depth = 0
392 for ft in mtype.arguments do
393 var ftd = ft.signature_depth
394 if ftd > depth then depth = ftd
395 end
396 return depth + 1
397 end
398 end
399