metrics: extract mmodule_metrics in its own module
[nit.git] / src / metrics / metrics_base.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 # Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 # Helpers for various statistics tools.
19 module metrics_base
20
21 import model_utils
22 import csv
23 import counter
24
25 redef class ToolContext
26
27 # --all
28 var opt_all = new OptionBool("Compute all metrics", "--all")
29
30 # --mmodules
31 var opt_mmodules = new OptionBool("Compute metrics about mmodules", "--mmodules")
32 # --inheritance
33 var opt_inheritance = new OptionBool("Compute metrics about inheritance usage", "--inheritance")
34 # --genericity
35 var opt_refinement = new OptionBool("Compute metrics about refinement usage", "--refinement")
36 # --self
37 var opt_self = new OptionBool("Compute metrics about the usage of explicit and implicit self", "--self")
38 # --ast
39 var opt_ast = new OptionBool("Compute metrics about the usage of nodes and identifiers in the AST", "--ast")
40 # --nullables
41 var opt_nullables = new OptionBool("Compute metrics on nullables send", "--nullables")
42 # --static-types
43 var opt_static_types = new OptionBool("Compute explicit static types metrics", "--static-types")
44 # --tables
45 var opt_tables = new OptionBool("Compute tables metrics", "--tables")
46 # --rta
47 var opt_rta = new OptionBool("Compute RTA metrics", "--rta")
48 # --generate-csv
49 var opt_generate_csv = new OptionBool("Generate CVS format metrics", "--generate-csv")
50 # --generate_hyperdoc
51 var opt_generate_hyperdoc = new OptionBool("Generate Hyperdoc", "--generate_hyperdoc")
52 # --poset
53 var opt_poset = new OptionBool("Complete metrics on posets", "--poset")
54
55 var opt_dir = new OptionString("Directory where some statistics files are generated", "-d", "--dir")
56 var output_dir: String = "."
57
58 redef init
59 do
60 super
61 self.option_context.add_option(opt_all)
62 self.option_context.add_option(opt_mmodules)
63 self.option_context.add_option(opt_inheritance)
64 self.option_context.add_option(opt_refinement)
65 self.option_context.add_option(opt_self)
66 self.option_context.add_option(opt_ast)
67 self.option_context.add_option(opt_nullables)
68 self.option_context.add_option(opt_static_types)
69 self.option_context.add_option(opt_tables)
70 self.option_context.add_option(opt_rta)
71 self.option_context.add_option(opt_generate_csv)
72 self.option_context.add_option(opt_generate_hyperdoc)
73 self.option_context.add_option(opt_poset)
74 self.option_context.add_option(opt_dir)
75 end
76
77 redef fun process_options
78 do
79 super
80 var val = self.opt_dir.value
81 if val != null then
82 val = val.simplify_path
83 val.mkdir
84 self.output_dir = val
85 end
86 end
87 end
88
89 redef class Model
90
91 # List of modules in std lib
92 # FIXME this is quite ugly, find a dynamic way...
93 fun std_modules: Set[String] do
94 if self.std_modules_cache == null then
95 self.std_modules_cache = new HashSet[String]
96 self.std_modules_cache.add("collection")
97 self.std_modules_cache.add("abstract_collection")
98 self.std_modules_cache.add("array")
99 self.std_modules_cache.add("hash_collection")
100 self.std_modules_cache.add("list")
101 self.std_modules_cache.add("range")
102 self.std_modules_cache.add("sorter")
103 self.std_modules_cache.add("environ")
104 self.std_modules_cache.add("exec")
105 self.std_modules_cache.add("file")
106 self.std_modules_cache.add("gc")
107 self.std_modules_cache.add("hash")
108 self.std_modules_cache.add("kernel")
109 self.std_modules_cache.add("math")
110 self.std_modules_cache.add("standard")
111 self.std_modules_cache.add("stream")
112 self.std_modules_cache.add("string")
113 self.std_modules_cache.add("string_search")
114 self.std_modules_cache.add("time")
115 end
116 return self.std_modules_cache.as(not null)
117 end
118 private var std_modules_cache: nullable Set[String]
119 end
120
121 redef class MClass
122 fun is_user_defined: Bool do
123 return self.intro_mmodule.is_user_defined
124 end
125 end
126
127 redef class MModule
128 fun is_user_defined: Bool do
129 return not self.model.std_modules.has(self.name)
130 end
131 end
132
133 # A Metric is used to collect data about things
134 #
135 # The concept is reified here for a better organization and documentation
136 interface Metric
137 fun name: String is abstract
138 fun desc: String is abstract
139 # clear all results for this metric
140 fun clear is abstract
141 end
142
143 # A Metric that collects integer data
144 #
145 # Used to count things
146 class IntMetric[E: Object]
147 super Metric
148
149 var values = new Counter[E]
150
151 redef fun clear do values.clear
152
153 # Return the couple with the highest value
154 fun max: Couple[E, Int] do
155 assert not values.is_empty
156 var elem = values.max.as(not null)
157 var value = values[elem]
158 return new Couple[E, Int](elem, value)
159 end
160
161 # Return the couple with the lowest value
162 fun min: Couple[E, Int] do
163 assert not values.is_empty
164 var elem = values.min.as(not null)
165 var value = values[elem]
166 return new Couple[E, Int](elem, value)
167 end
168
169 # Values average
170 fun avg: Float do return values.avg
171 end
172
173 # A Metric that collects float datas
174 #
175 # Used sor summarization
176 class FloatMetric[E: Object]
177 super Metric
178
179 var values: Map[E, Float] = new HashMap[E, Float]
180
181 redef fun clear do values.clear
182
183 # Return the couple with the highest value
184 fun max: Couple[E, Float] do
185 assert not values.is_empty
186 var max: nullable Float = null
187 var elem: nullable E = null
188 for e, v in values do
189 if max == null or v > max then
190 max = v
191 elem = e
192 end
193 end
194 return new Couple[E, Float](elem.as(not null), max.as(not null))
195 end
196
197 # Return the couple with the lowest value
198 fun min: Couple[E, Float] do
199 assert not values.is_empty
200 var min: nullable Float = null
201 var elem: nullable E = null
202 for e, v in values do
203 if min == null or v < min then
204 min = v
205 elem = e
206 end
207 end
208 return new Couple[E, Float](elem.as(not null), min.as(not null))
209 end
210
211 # Values average
212 fun avg: Float do
213 if values.is_empty then return 0.0
214 var sum = 0.0
215 for value in values.values do
216 sum += value
217 end
218 return sum / values.length.to_f
219 end
220 end
221
222 # A MetricSet is a metric holder
223 #
224 # It purpose is to be extended with a metric collect service
225 class MetricSet
226 type METRIC: Metric
227
228 # Metrics to compute
229 var metrics: Map[String, METRIC] = new HashMap[String, METRIC]
230
231 # Add a metric to the set
232 fun register(metrics: METRIC...) do for metric in metrics do self.metrics[metric.name] = metric
233
234 # Clear all results for all metrics
235 fun clear do for metric in metrics.values do metric.clear
236 end