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