rta: store real types in live_cast_type
[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 frontend
24
25 redef class ToolContext
26 var rta_metrics_phase = new RTAMetricsPhase(self, null)
27 end
28
29 private class RTAMetricsPhase
30 super Phase
31 redef fun process_mainmodule(mainmodule)
32 do
33 if not toolcontext.opt_rta.value and not toolcontext.opt_all.value then return
34 compute_rta_metrics(toolcontext.modelbuilder, mainmodule)
35 end
36 end
37
38
39 redef class MType
40 private var nlvt: Int = 0
41 private var nlct: Int = 0
42
43 private fun is_user_defined: Bool do
44 var mtype = self
45 if mtype isa MNullableType then mtype = mtype.mtype
46 return self.as(MClassType).mclass.is_user_defined
47 end
48
49 private fun get_depth: Int do
50 var mtype = self
51 if mtype isa MNullableType then mtype = mtype.mtype
52 if not mtype isa MGenericType then return 0
53
54 var depth = 0
55 for ft in mtype.arguments do
56 if ft.get_depth > depth then depth = ft.get_depth
57 end
58 return depth + 1
59 end
60 end
61
62 redef class MClass
63 private var nlvt: Int = 0
64 private var nlct: Int = 0
65 private var live_types: Set[MType] = new HashSet[MType]
66 private var cast_types: Set[MType] = new HashSet[MType]
67 end
68
69 # Run a runtime type analysis and print metrics
70 fun compute_rta_metrics(modelbuilder: ModelBuilder, mainmodule: MModule)
71 do
72 var analysis = modelbuilder.do_rapid_type_analysis(mainmodule)
73
74 var nlvt = 0 # NLVT Number of Live Type
75 var nlvtg = 0 # NLVTG Number of Generic Live Type
76 var nlvtslud = 0 # NLCTSLUD Number of Live Type defined in SL and init in UD
77 var nlvtgslud = 0 # NLVTGSLUD Number of Generic Live Type defined in SL and init in UD
78 var nlvtudud = 0 # NLVTUDUD Number of Live Type defined in UD and init in UD
79 var nlvtgudud = 0 # NLVTGUDUD Number of Generic Live Type defined in UD and init in UD
80
81 var nlct = 0 # NLCT Number of Live Cast Type
82 var nlctg = 0 # NLCTG Number of Generic Live Cast Type
83 var nlctslud = 0 # NLCTSLUD Number of Live Cast Type defined in SL and init in UD
84 var nlctgslud = 0 # NLCTGSLUD Number of Generic Live Cast Type defined in SL and init in UD
85 var nlctudud = 0 # NLCTUDUD Number of Live Cast Type defined in UD and init in UD
86 var nlctgudud = 0 # NLCTGUDUD Number of Generic Live Cast Type defined in UD and init in UD
87
88 var mtypes = new HashSet[MClassType]
89
90 for mtype in analysis.live_types do
91 mtypes.add(mtype)
92 nlvt += 1
93 mtype.mclass.nlvt += 1
94 mtype.mclass.live_types.add(mtype)
95 if mtype isa MGenericType then nlvtg += 1
96 if mtype.is_user_defined then
97 nlvtudud += 1
98 if mtype isa MGenericType then nlvtgudud += 1
99 else
100 nlvtslud += 1
101 if mtype isa MGenericType then nlvtgslud += 1
102 end
103 end
104
105 for mtype in analysis.live_cast_types do
106 if mtype isa MNullableType then mtype = mtype.mtype
107 if not mtype isa MClassType then continue
108 mtypes.add(mtype)
109 nlct += 1
110 mtype.mclass.nlct += 1
111 mtype.mclass.cast_types.add(mtype)
112 if mtype isa MGenericType then nlctg += 1
113 if mtype.is_user_defined then
114 nlctudud += 1
115 if mtype isa MGenericType then nlctgudud += 1
116 else
117 nlctslud += 1
118 if mtype isa MGenericType then nlctgslud += 1
119 end
120 end
121
122 # CSV generation
123 if modelbuilder.toolcontext.opt_generate_csv.value then
124 var summaryCSV = new CSVDocument(modelbuilder.toolcontext.output_dir.join_path("rta_sum_metrics.csv"))
125 summaryCSV.set_header("scope", "NLVT", "NLVTG", "NLCT", "NLVCTG")
126 summaryCSV.add_line("global", nlvt, nlvtg, nlct, nlctg)
127 summaryCSV.add_line("SLUD", nlvtslud, nlvtgslud, nlctslud, nlctgslud)
128 summaryCSV.add_line("UDUD", nlvtudud, nlvtgudud, nlctudud, nlctgudud)
129 summaryCSV.save
130
131 var scalarCSV = new CSVDocument(modelbuilder.toolcontext.output_dir.join_path("rta_scalar_metrics.csv"))
132 var udscalarCSV = new CSVDocument(modelbuilder.toolcontext.output_dir.join_path("rta_ud_scalar_metrics.csv"))
133 scalarCSV.set_header("Type", "AGS", "DGS", "NLVT", "NLCT")
134 udscalarCSV.set_header("Type", "AGS", "DGS", "NLVT", "NLCT")
135
136 for mtype in mtypes do
137 var arity = 0
138 if mtype isa MGenericType then arity = mtype.arguments.length
139 if mtype.is_user_defined then
140 udscalarCSV.add_line(mtype, arity, mtype.get_depth, mtype.nlvt, mtype.nlct)
141 end
142 scalarCSV.add_line(mtype, arity, mtype.get_depth, mtype.nlvt, mtype.nlct)
143 end
144 scalarCSV.save
145 udscalarCSV.save
146
147 scalarCSV = new CSVDocument(modelbuilder.toolcontext.output_dir.join_path("rta_scalar_class_metrics.csv"))
148 udscalarCSV = new CSVDocument(modelbuilder.toolcontext.output_dir.join_path("rta_ud_scalar_class_metrics.csv"))
149 scalarCSV.set_header("Class", "AGS", "NLVV", "NLVT")
150 udscalarCSV.set_header("Class", "AGS", "NLVV", "inst")
151
152 for mclass in modelbuilder.model.mclasses do
153 if not mclass.is_class or mclass.is_abstract then continue
154 if mclass.is_user_defined then
155 udscalarCSV.add_line(mclass.mclass_type, mclass.arity, mclass.live_types.length, mclass.nlvt)
156 end
157 scalarCSV.add_line(mclass.mclass_type, mclass.arity, mclass.live_types.length, mclass.nlvt)
158 end
159 scalarCSV.save
160 udscalarCSV.save
161 end
162
163 print "--- RTA metrics ---"
164 print "Number of live runtime classes: {analysis.live_classes.length}"
165 if analysis.live_classes.length < 8 then print "\t{analysis.live_classes.join(" ")}"
166 print "Number of live runtime types (instantied resolved type): {analysis.live_types.length}"
167 if analysis.live_types.length < 8 then print "\t{analysis.live_types.join(" ")}"
168 print "Number of live methods: {analysis.live_methods.length}"
169 if analysis.live_methods.length < 8 then print "\t{analysis.live_methods.join(" ")}"
170 print "Number of live method definitions: {analysis.live_methoddefs.length}"
171 if analysis.live_methoddefs.length < 8 then print "\t{analysis.live_methoddefs.join(" ")}"
172 print "Number of live runtime cast types (ie used in as and isa): {analysis.live_cast_types.length}"
173 if analysis.live_cast_types.length < 8 then print "\t{analysis.live_cast_types.join(" ")}"
174
175 var x = 0
176 for p in analysis.live_methods do
177 for d in p.mpropdefs do
178 if analysis.live_methoddefs.has(d) or d.is_abstract then continue
179 x += 1
180 end
181 end
182 print "Number of dead method definitions of live methods: {x}"
183 end