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