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