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