| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /// Measurements collected about individual functions. Currently we compute | 5 /// Measurements collected about individual functions. Currently we compute |
| 6 /// data about "sends", to classify whether we know the target or not. | 6 /// data about "sends", to classify whether we know the target or not. |
| 7 library dart2js_info.src.measurements; | 7 library dart2js_info.src.measurements; |
| 8 | 8 |
| 9 /// Top-level set of metrics | 9 /// Top-level set of metrics |
| 10 const List<Metric> _topLevelMetrics = const [ | 10 const List<Metric> _topLevelMetrics = const [Metric.functions, Metric.send]; |
| 11 Metric.functions, | |
| 12 Metric.send, | |
| 13 ]; | |
| 14 | 11 |
| 15 /// Apply `f` on each metric in DFS order on the metric tree. [Metric.functions] | 12 /// Apply `f` on each metric in DFS order on the metric tree. [Metric.functions] |
| 16 /// and [Metric.send] are the top level metrics. See those declarations for | 13 /// and [Metric.send] are the top level metrics. See those declarations for |
| 17 /// details on the subtrees. | 14 /// details on the subtrees. |
| 18 visitAllMetrics(f) { | 15 visitAllMetrics(f) { |
| 19 var parentsStack = []; | 16 var parentsStack = []; |
| 20 helper(Metric m) { | 17 helper(Metric m) { |
| 21 f(m, parentsStack); | 18 f(m, parentsStack); |
| 22 if (m is GroupedMetric) { | 19 if (m is GroupedMetric) { |
| 23 parentsStack.add(m); | 20 parentsStack.add(m); |
| 24 m.submetrics.forEach(helper); | 21 m.submetrics.forEach(helper); |
| 25 parentsStack.removeLast(); | 22 parentsStack.removeLast(); |
| 26 } | 23 } |
| 27 } | 24 } |
| 28 _topLevelMetrics.forEach(helper); | 25 _topLevelMetrics.forEach(helper); |
| 29 } | 26 } |
| 30 | 27 |
| 31 /// A metric we intend to measure. | 28 /// A metric we intend to measure. |
| 32 class Metric { | 29 class Metric { |
| 33 /// Name for the metric. | 30 /// Name for the metric. |
| 34 final String name; | 31 final String name; |
| 35 | 32 |
| 36 const Metric(this.name); | 33 const Metric(this.name); |
| 37 | 34 |
| 35 factory Metric.fromName(String name) => _nameToMetricMap[name]; |
| 36 |
| 38 String toString() => name; | 37 String toString() => name; |
| 39 | 38 |
| 40 /// Total functions in a library/package/program. Parent of | 39 /// Total functions in a library/package/program. Parent of |
| 41 /// [reachableFunction]. | 40 /// [reachableFunction]. |
| 42 static const Metric functions = const GroupedMetric('functions', const [ | 41 static const Metric functions = |
| 43 reachableFunctions, | 42 const GroupedMetric('functions', const [reachableFunctions]); |
| 44 ]); | |
| 45 | 43 |
| 46 /// Subset of the functions that are reachable. | 44 /// Subset of the functions that are reachable. |
| 47 static const Metric reachableFunctions = const Metric('reachable functions'); | 45 static const Metric reachableFunctions = const Metric('reachable functions'); |
| 48 | 46 |
| 49 /// Parent of all send metrics. We classify sends as follows: | 47 /// Parent of all send metrics. We classify sends as follows: |
| 50 /// | 48 /// |
| 51 /// sends | 49 /// sends |
| 52 /// |- monomorphic | 50 /// |- monomorphic |
| 53 /// | |- static (top-levels, statics) | 51 /// | |- static (top-levels, statics) |
| 54 /// | |- super | 52 /// | |- super |
| 55 /// | |- local (access to a local var, call local function) | 53 /// | |- local (access to a local var, call local function) |
| 56 /// | |- constructor (like factory ctros) | 54 /// | |- constructor (like factory ctros) |
| 57 /// | |- type variable (reading a type variable) | 55 /// | |- type variable (reading a type variable) |
| 58 /// | |- nsm (known no such method exception) | 56 /// | |- nsm (known no such method exception) |
| 59 /// | |- single-nsm-call (known no such method call, single target) | 57 /// | |- single-nsm-call (known no such method call, single target) |
| 60 /// | |- instance (non-interceptor, only one possible target) | 58 /// | |- instance (non-interceptor, only one possible target) |
| 61 /// | '- interceptor (interceptor, known) | 59 /// | '- interceptor (interceptor, known) |
| 62 /// | | 60 /// | |
| 63 /// '- polymorphic | 61 /// '- polymorphic |
| 64 /// |- multi-nsm (known to be nSM, but not sure if error, or call, or | 62 /// |- multi-nsm (known to be nSM, but not sure if error, or call, or |
| 65 /// which call) | 63 /// which call) |
| 66 /// |- virtual (traditional virtual call, polymorphic equivalent of | 64 /// |- virtual (traditional virtual call, polymorphic equivalent of |
| 67 /// | `instance`, no-interceptor) | 65 /// | `instance`, no-interceptor) |
| 68 /// |- multi-interceptor (1 of n possible interceptors) | 66 /// |- multi-interceptor (1 of n possible interceptors) |
| 69 /// '- dynamic (any combination of the above) | 67 /// '- dynamic (any combination of the above) |
| 70 /// | 68 /// |
| 71 static const Metric send = const GroupedMetric('send', const [ | 69 static const Metric send = |
| 72 monomorphicSend, | 70 const GroupedMetric('send', const [monomorphicSend, polymorphicSend]); |
| 73 polymorphicSend, | |
| 74 ]); | |
| 75 | 71 |
| 76 /// Parent of monomorphic sends, see [send] for details. | 72 /// Parent of monomorphic sends, see [send] for details. |
| 77 static const Metric monomorphicSend = const GroupedMetric('monomorphic', | 73 static const Metric monomorphicSend = |
| 78 const [ | 74 const GroupedMetric('monomorphic', const [ |
| 79 staticSend, | 75 staticSend, |
| 80 superSend, | 76 superSend, |
| 81 localSend, | 77 localSend, |
| 82 constructorSend, | 78 constructorSend, |
| 83 typeVariableSend, | 79 typeVariableSend, |
| 84 nsmErrorSend, | 80 nsmErrorSend, |
| 85 singleNsmCallSend, | 81 singleNsmCallSend, |
| 86 instanceSend, | 82 instanceSend, |
| 87 interceptorSend, | 83 interceptorSend |
| 88 ]); | 84 ]); |
| 89 | 85 |
| 90 /// Metric for static calls, see [send] for details. | 86 /// Metric for static calls, see [send] for details. |
| 91 static const Metric staticSend = const Metric('static'); | 87 static const Metric staticSend = const Metric('static'); |
| 92 | 88 |
| 93 /// Metric for super calls, see [send] for details. | 89 /// Metric for super calls, see [send] for details. |
| 94 static const Metric superSend = const Metric('super'); | 90 static const Metric superSend = const Metric('super'); |
| 95 | 91 |
| 96 /// Metric for local variable sends, see [send] for details. | 92 /// Metric for local variable sends, see [send] for details. |
| 97 static const Metric localSend = const Metric('local'); | 93 static const Metric localSend = const Metric('local'); |
| 98 | 94 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 113 /// Metric for calls to a precisely known instance method, see [send] for | 109 /// Metric for calls to a precisely known instance method, see [send] for |
| 114 /// details. | 110 /// details. |
| 115 static const Metric instanceSend = const Metric('instance'); | 111 static const Metric instanceSend = const Metric('instance'); |
| 116 | 112 |
| 117 /// Metric for calls to a precisely known interceptor method, see [send] for | 113 /// Metric for calls to a precisely known interceptor method, see [send] for |
| 118 /// details. | 114 /// details. |
| 119 static const Metric interceptorSend = const Metric('interceptor'); | 115 static const Metric interceptorSend = const Metric('interceptor'); |
| 120 | 116 |
| 121 /// Parent of polymorphic sends, see [send] for details. | 117 /// Parent of polymorphic sends, see [send] for details. |
| 122 static const Metric polymorphicSend = const GroupedMetric('polymorphic', | 118 static const Metric polymorphicSend = const GroupedMetric('polymorphic', |
| 123 const [ | 119 const [multiNsmCallSend, virtualSend, multiInterceptorSend, dynamicSend]); |
| 124 multiNsmCallSend, | |
| 125 virtualSend, | |
| 126 multiInterceptorSend, | |
| 127 dynamicSend, | |
| 128 ]); | |
| 129 | 120 |
| 130 /// Metric for calls to noSuchMethod methods with more than one possible | 121 /// Metric for calls to noSuchMethod methods with more than one possible |
| 131 /// target, see [send] for details. | 122 /// target, see [send] for details. |
| 132 static const Metric multiNsmCallSend = const Metric('nSM call multi'); | 123 static const Metric multiNsmCallSend = const Metric('nSM call multi'); |
| 133 | 124 |
| 134 /// Metric for calls that are dispatched virtually ar runtime, see [send] for | 125 /// Metric for calls that are dispatched virtually ar runtime, see [send] for |
| 135 /// details. | 126 /// details. |
| 136 static const Metric virtualSend = const Metric('virtual'); | 127 static const Metric virtualSend = const Metric('virtual'); |
| 137 | 128 |
| 138 /// Metyric for calls to more than one possible interceptor, see [send] for | 129 /// Metyric for calls to more than one possible interceptor, see [send] for |
| 139 /// details. | 130 /// details. |
| 140 static const Metric multiInterceptorSend = const Metric('interceptor multi'); | 131 static const Metric multiInterceptorSend = const Metric('interceptor multi'); |
| 141 | 132 |
| 142 /// Metyric for dynamic calls for which we know nothing about the target | 133 /// Metyric for dynamic calls for which we know nothing about the target |
| 143 /// method. See [send] for details. | 134 /// method. See [send] for details. |
| 144 static const Metric dynamicSend = const Metric('dynamic'); | 135 static const Metric dynamicSend = const Metric('dynamic'); |
| 145 | 136 |
| 146 String toJson() => name; | |
| 147 static Map<String, Metric> _nameToMetricMap = () { | 137 static Map<String, Metric> _nameToMetricMap = () { |
| 148 var res = {}; | 138 var res = {}; |
| 149 visitAllMetrics((m, _) => res[m.name] = m); | 139 visitAllMetrics((m, _) => res[m.name] = m); |
| 150 return res; | 140 return res; |
| 151 }(); | 141 }(); |
| 152 | |
| 153 static Metric fromJson(String name) => _nameToMetricMap[name]; | |
| 154 } | 142 } |
| 155 | 143 |
| 156 /// A metric that is subdivided in smaller metrics. | 144 /// A metric that is subdivided in smaller metrics. |
| 157 class GroupedMetric extends Metric { | 145 class GroupedMetric extends Metric { |
| 158 final List<Metric> submetrics; | 146 final List<Metric> submetrics; |
| 159 | 147 |
| 160 const GroupedMetric(String name, this.submetrics) : super(name); | 148 const GroupedMetric(String name, this.submetrics) : super(name); |
| 161 } | 149 } |
| 162 | 150 |
| 163 /// A measurement entry (practically a source-span location where the | 151 /// A measurement entry (practically a source-span location where the |
| 164 /// measurement was seen). | 152 /// measurement was seen). |
| 165 class Entry { | 153 class Entry { |
| 166 final int begin; | 154 final int begin; |
| 167 final int end; | 155 final int end; |
| 168 Entry(this.begin, this.end); | 156 Entry(this.begin, this.end); |
| 169 } | 157 } |
| 170 | 158 |
| 171 /// A collection of data points for each metric. Used to summarize a single | 159 /// A collection of data points for each metric. Used to summarize a single |
| 172 /// function, a library, a package, or an entire program. | 160 /// function, a library, a package, or an entire program. |
| 173 class Measurements { | 161 class Measurements { |
| 174 final Uri uri; | 162 final Uri uri; |
| 175 final Map<Metric, List<Entry>> entries; | 163 final Map<Metric, List<Entry>> entries; |
| 176 final Map<Metric, int> counters; | 164 final Map<Metric, int> counters; |
| 177 | 165 |
| 178 Measurements([this.uri]) | 166 Measurements([this.uri]) |
| 179 : entries = <Metric, List<Entry>>{}, | 167 : entries = <Metric, List<Entry>>{}, |
| 180 counters = <Metric, int>{}; | 168 counters = <Metric, int>{}; |
| 181 | 169 |
| 182 const Measurements.unreachableFunction() | 170 const Measurements.unreachableFunction() |
| 183 : counters = const { Metric.functions: 1}, entries = const {}, uri = null; | 171 : counters = const {Metric.functions: 1}, |
| 172 entries = const {}, |
| 173 uri = null; |
| 184 | 174 |
| 185 Measurements.reachableFunction([this.uri]) | 175 Measurements.reachableFunction([this.uri]) |
| 186 : counters = { Metric.functions: 1, Metric.reachableFunctions: 1}, | 176 : counters = {Metric.functions: 1, Metric.reachableFunctions: 1}, |
| 187 entries = {}; | 177 entries = {}; |
| 188 | 178 |
| 189 /// Record [metric] was seen. The optional [begin] and [end] offsets are | 179 /// Record [metric] was seen. The optional [begin] and [end] offsets are |
| 190 /// included for metrics that correspond to a source range. Intended to be | 180 /// included for metrics that correspond to a source range. Intended to be |
| 191 /// used by `StatsBuilder`. | 181 /// used by `StatsBuilder`. |
| 192 record(Metric metric, [int begin, int end]) { | 182 record(Metric metric, [int begin, int end]) { |
| 193 if (begin != null && end != null) { | 183 if (begin != null && end != null) { |
| 194 assert(uri != null); | 184 assert(uri != null); |
| 195 entries.putIfAbsent(metric, () => []).add(new Entry(begin, end)); | 185 entries.putIfAbsent(metric, () => []).add(new Entry(begin, end)); |
| 196 } | 186 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 221 /// submetric. | 211 /// submetric. |
| 222 bool checkInvariant(GroupedMetric key) { | 212 bool checkInvariant(GroupedMetric key) { |
| 223 int total = counters[key] ?? 0; | 213 int total = counters[key] ?? 0; |
| 224 int submetricTotal = 0; | 214 int submetricTotal = 0; |
| 225 for (var metric in key.submetrics) { | 215 for (var metric in key.submetrics) { |
| 226 var n = counters[metric]; | 216 var n = counters[metric]; |
| 227 if (n != null) submetricTotal += n; | 217 if (n != null) submetricTotal += n; |
| 228 } | 218 } |
| 229 return total == submetricTotal; | 219 return total == submetricTotal; |
| 230 } | 220 } |
| 231 | |
| 232 Map toJson() { | |
| 233 var jsonEntries = <String, List<Map>>{}; | |
| 234 entries.forEach((metric, values) { | |
| 235 jsonEntries[metric.toJson()] = | |
| 236 values.expand((e) => [e.begin, e.end]).toList(); | |
| 237 }); | |
| 238 var json = {'entries': jsonEntries}; | |
| 239 // TODO(sigmund): encode uri as an offset of the URIs available in the parts | |
| 240 // of the library info. | |
| 241 if (uri != null) json['sourceFile'] = '$uri'; | |
| 242 if (counters[Metric.functions] != null) { | |
| 243 json[Metric.functions.toJson()] = counters[Metric.functions]; | |
| 244 } | |
| 245 if (counters[Metric.reachableFunctions] != null) { | |
| 246 json[Metric.reachableFunctions.toJson()] = | |
| 247 counters[Metric.reachableFunctions]; | |
| 248 } | |
| 249 return json; | |
| 250 } | |
| 251 } | 221 } |
| OLD | NEW |