OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /// Measurements collected about individual functions. Currently we compute |
| 6 /// data about "sends", to classify whether we know the target or not. |
| 7 library dart2js_info.src.measurements; |
| 8 |
| 9 /// Top-level set of metrics |
| 10 const List<Metric> _topLevelMetrics = const [ |
| 11 Metric.functions, |
| 12 Metric.send, |
| 13 ]; |
| 14 |
| 15 /// 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 |
| 17 /// details on the subtrees. |
| 18 visitAllMetrics(f) { |
| 19 var parentsStack = []; |
| 20 helper(Metric m) { |
| 21 f(m, parentsStack); |
| 22 if (m is GroupedMetric) { |
| 23 parentsStack.add(m); |
| 24 m.submetrics.forEach(helper); |
| 25 parentsStack.removeLast(); |
| 26 } |
| 27 } |
| 28 _topLevelMetrics.forEach(helper); |
| 29 } |
| 30 |
| 31 /// A metric we intend to measure. |
| 32 class Metric { |
| 33 /// Name for the metric. |
| 34 final String name; |
| 35 |
| 36 const Metric(this.name); |
| 37 |
| 38 String toString() => name; |
| 39 |
| 40 /// Total functions in a library/package/program. Parent of |
| 41 /// [reachableFunction]. |
| 42 static const Metric functions = const GroupedMetric('functions', const [ |
| 43 reachableFunctions, |
| 44 ]); |
| 45 |
| 46 /// Subset of the functions that are reachable. |
| 47 static const Metric reachableFunctions = const Metric('reachable functions'); |
| 48 |
| 49 /// Parent of all send metrics. We classify sends as follows: |
| 50 /// |
| 51 /// sends |
| 52 /// |- monomorphic |
| 53 /// | |- static (top-levels, statics) |
| 54 /// | |- super |
| 55 /// | |- local (access to a local var, call local function) |
| 56 /// | |- constructor (like factory ctros) |
| 57 /// | |- type variable (reading a type variable) |
| 58 /// | |- nsm (known no such method exception) |
| 59 /// | |- single-nsm-call (known no such method call, single target) |
| 60 /// | |- instance (non-interceptor, only one possible target) |
| 61 /// | '- interceptor (interceptor, known) |
| 62 /// | |
| 63 /// '- polymorphic |
| 64 /// |- multi-nsm (known to be nSM, but not sure if error, or call, or |
| 65 /// which call) |
| 66 /// |- virtual (traditional virtual call, polymorphic equivalent of |
| 67 /// | `instance`, no-interceptor) |
| 68 /// |- multi-interceptor (1 of n possible interceptors) |
| 69 /// '- dynamic (any combination of the above) |
| 70 /// |
| 71 static const Metric send = const GroupedMetric('send', const [ |
| 72 monomorphicSend, |
| 73 polymorphicSend, |
| 74 ]); |
| 75 |
| 76 /// Parent of monomorphic sends, see [send] for details. |
| 77 static const Metric monomorphicSend = const GroupedMetric('monomorphic', |
| 78 const [ |
| 79 staticSend, |
| 80 superSend, |
| 81 localSend, |
| 82 constructorSend, |
| 83 typeVariableSend, |
| 84 nsmErrorSend, |
| 85 singleNsmCallSend, |
| 86 instanceSend, |
| 87 interceptorSend, |
| 88 ]); |
| 89 |
| 90 /// Metric for static calls, see [send] for details. |
| 91 static const Metric staticSend = const Metric('static'); |
| 92 |
| 93 /// Metric for super calls, see [send] for details. |
| 94 static const Metric superSend = const Metric('super'); |
| 95 |
| 96 /// Metric for local variable sends, see [send] for details. |
| 97 static const Metric localSend = const Metric('local'); |
| 98 |
| 99 /// Metric for constructor sends, see [send] for details. |
| 100 static const Metric constructorSend = const Metric('constructor'); |
| 101 |
| 102 /// Metric for type-variable sends, see [send] for details. |
| 103 // TODO(sigmund): delete? is mainly associated with compile-time errors |
| 104 static const Metric typeVariableSend = const Metric('type variable'); |
| 105 |
| 106 /// Metric for no-such-method errors, see [send] for details. |
| 107 static const Metric nsmErrorSend = const Metric('nSM error'); |
| 108 |
| 109 /// Metric for calls to noSuchMethod methods with a known target, see [send] |
| 110 /// for details. |
| 111 static const Metric singleNsmCallSend = const Metric('nSM call single'); |
| 112 |
| 113 /// Metric for calls to a precisely known instance method, see [send] for |
| 114 /// details. |
| 115 static const Metric instanceSend = const Metric('instance'); |
| 116 |
| 117 /// Metric for calls to a precisely known interceptor method, see [send] for |
| 118 /// details. |
| 119 static const Metric interceptorSend = const Metric('interceptor'); |
| 120 |
| 121 /// Parent of polymorphic sends, see [send] for details. |
| 122 static const Metric polymorphicSend = const GroupedMetric('polymorphic', |
| 123 const [ |
| 124 multiNsmCallSend, |
| 125 virtualSend, |
| 126 multiInterceptorSend, |
| 127 dynamicSend, |
| 128 ]); |
| 129 |
| 130 /// Metric for calls to noSuchMethod methods with more than one possible |
| 131 /// target, see [send] for details. |
| 132 static const Metric multiNsmCallSend = const Metric('nSM call multi'); |
| 133 |
| 134 /// Metric for calls that are dispatched virtually ar runtime, see [send] for |
| 135 /// details. |
| 136 static const Metric virtualSend = const Metric('virtual'); |
| 137 |
| 138 /// Metyric for calls to more than one possible interceptor, see [send] for |
| 139 /// details. |
| 140 static const Metric multiInterceptorSend = const Metric('interceptor multi'); |
| 141 |
| 142 /// Metyric for dynamic calls for which we know nothing about the target |
| 143 /// method. See [send] for details. |
| 144 static const Metric dynamicSend = const Metric('dynamic'); |
| 145 |
| 146 String toJson() => name; |
| 147 static Map<String, Metric> _nameToMetricMap = () { |
| 148 var res = {}; |
| 149 visitAllMetrics((m, _) => res[m.name] = m); |
| 150 return res; |
| 151 }(); |
| 152 |
| 153 static Metric fromJson(String name) => _nameToMetricMap[name]; |
| 154 } |
| 155 |
| 156 /// A metric that is subdivided in smaller metrics. |
| 157 class GroupedMetric extends Metric { |
| 158 final List<Metric> submetrics; |
| 159 |
| 160 const GroupedMetric(String name, this.submetrics) : super(name); |
| 161 } |
| 162 |
| 163 /// A measurement entry (practically a source-span location where the |
| 164 /// measurement was seen). |
| 165 class Entry { |
| 166 final int begin; |
| 167 final int end; |
| 168 Entry(this.begin, this.end); |
| 169 } |
| 170 |
| 171 /// A collection of data points for each metric. Used to summarize a single |
| 172 /// function, a library, a package, or an entire program. |
| 173 class Measurements { |
| 174 final Uri uri; |
| 175 final Map<Metric, List<Entry>> entries; |
| 176 final Map<Metric, int> counters; |
| 177 |
| 178 Measurements([this.uri]) |
| 179 : entries = <Metric, List<Entry>>{}, |
| 180 counters = <Metric, int>{}; |
| 181 |
| 182 const Measurements.unreachableFunction() |
| 183 : counters = const { Metric.functions: 1}, entries = const {}, uri = null; |
| 184 |
| 185 Measurements.reachableFunction([this.uri]) |
| 186 : counters = { Metric.functions: 1, Metric.reachableFunctions: 1}, |
| 187 entries = {}; |
| 188 |
| 189 /// Record [metric] was seen. The optional [begin] and [end] offsets are |
| 190 /// included for metrics that correspond to a source range. Intended to be |
| 191 /// used by `StatsBuilder`. |
| 192 record(Metric metric, [int begin, int end]) { |
| 193 if (begin != null && end != null) { |
| 194 assert(uri != null); |
| 195 entries.putIfAbsent(metric, () => []).add(new Entry(begin, end)); |
| 196 } |
| 197 counters.putIfAbsent(metric, () => 0); |
| 198 counters[metric]++; |
| 199 } |
| 200 |
| 201 /// Removes a previously added entry. Intended only to be used by |
| 202 /// `StatsBuilder`. Internally `StatsBuilder` computes redundant information |
| 203 /// in order to check for coverage and validate invariants with |
| 204 /// [checkInvariant]. This is used to adjust some of the redundant |
| 205 /// information. |
| 206 popLast(Metric metric) { |
| 207 assert(entries[metric] != null && entries[metric].isNotEmpty); |
| 208 entries[metric].removeLast(); |
| 209 counters[metric]--; |
| 210 } |
| 211 |
| 212 /// Add the counters from [other] into this set of measurements. |
| 213 addFrom(Measurements other) { |
| 214 other.counters.forEach((metric, value) { |
| 215 var current = counters[metric]; |
| 216 counters[metric] = current == null ? value : current + value; |
| 217 }); |
| 218 } |
| 219 |
| 220 /// Check that every grouped metric totals the individual counts of it's |
| 221 /// submetric. |
| 222 bool checkInvariant(GroupedMetric key) { |
| 223 int total = counters[key] ?? 0; |
| 224 int submetricTotal = 0; |
| 225 for (var metric in key.submetrics) { |
| 226 var n = counters[metric]; |
| 227 if (n != null) submetricTotal += n; |
| 228 } |
| 229 return total == submetricTotal; |
| 230 } |
| 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 } |
OLD | NEW |