[dart2js] Update SSA/Codegen inlining metrics.
Add several more inlining metrics to SSA:
- getters (ellisions vs. inlines)
- setters (ellisions vs. inlines)
- intercepted length calls
- if conditions
- is checks
- late sentinel checks
After digging these are all the opportunities for optimization that I saw that I thought might be affected by changes in global inference. Open to feedback on whether any of these are unnecessary or if there's any other things worth tracking.
Change-Id: I70ff279a797f71b39b2bc02c00fbb3f6e149cb2a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255202
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 7fdd154..3b1632d 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5137,9 +5137,11 @@
_typeInferenceMap.resultTypeOfSelector(selector, receiverType);
HInvokeDynamic invoke;
if (selector.isGetter) {
+ _metrics.countGettersTotal.add();
invoke = HInvokeDynamicGetter(selector, receiverType, element, inputs,
isIntercepted, resultType, sourceInformation);
} else if (selector.isSetter) {
+ _metrics.countSettersTotal.add();
invoke = HInvokeDynamicSetter(selector, receiverType, element, inputs,
isIntercepted, resultType, sourceInformation);
} else if (selector.isClosureCall) {
@@ -5840,9 +5842,9 @@
providedArguments, typeArguments, currentNode, sourceInformation,
instanceType: instanceType);
if (inlined) {
- _metrics.countInlinesDone.add();
+ _metrics.countMethodInlined.add();
} else {
- _metrics.countInlinesSkipped.add();
+ _metrics.countMethodNotInlined.add();
}
return inlined;
}
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 3e7e544..c2cd1ce 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -175,6 +175,13 @@
class _CodegenMetrics extends MetricsBase {
int countHIf = 0;
int countHIfConstant = 0;
+ int countHIsTest = 0;
+ int countHIsTestSimple = 0;
+ int countHIsLateSentinel = 0;
+ int countHGetLength = 0;
+ int countHIndex = 0;
+ int countHFieldGet = 0;
+ int countSingleTargetInstanceCalls = 0;
final countHInterceptor = CountMetric('count.HInterceptor');
final countHInterceptorGet = CountMetric('count.HInterceptor.getInterceptor');
final countHInterceptorOneshot = CountMetric('count.HInterceptor.oneShot');
@@ -193,6 +200,14 @@
Iterable<Metric> get secondary => [
CountMetric('count.HIf')..add(countHIf),
CountMetric('count.HIf.constant')..add(countHIfConstant),
+ CountMetric('count.HIsTest')..add(countHIsTest),
+ CountMetric('count.HIsTestSimple')..add(countHIsTestSimple),
+ CountMetric('count.HIsLateSentinel')..add(countHIsLateSentinel),
+ CountMetric('count.HGetLength')..add(countHGetLength),
+ CountMetric('count.HIndex')..add(countHIndex),
+ CountMetric('count.HFieldGet')..add(countHFieldGet),
+ CountMetric('count.SingleTargetInstance')
+ ..add(countSingleTargetInstanceCalls),
countHInterceptor,
countHInterceptorGet,
countHInterceptorConditionalConstant,
@@ -1884,6 +1899,7 @@
@override
visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
+ _updateInvokeMetrics(node);
use(node.receiver);
js.Expression object = pop();
String methodName;
@@ -2074,8 +2090,13 @@
}
}
+ void _updateInvokeMetrics(HInvokeDynamic node) {
+ if (node.element != null) _metrics.countSingleTargetInstanceCalls++;
+ }
+
@override
visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
+ _updateInvokeMetrics(node);
use(node.receiver);
js.Name name = _namer.invocationName(node.selector);
push(js
@@ -2086,6 +2107,7 @@
@override
visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
+ _updateInvokeMetrics(node);
use(node.receiver);
js.Name name = _namer.invocationName(node.selector);
push(js
@@ -2260,6 +2282,7 @@
@override
visitFieldGet(HFieldGet node) {
+ _metrics.countHFieldGet++;
use(node.receiver);
push(_loadField(pop(), node.element, node.sourceInformation));
}
@@ -2281,6 +2304,7 @@
@override
visitGetLength(HGetLength node) {
+ _metrics.countHGetLength++;
use(node.receiver);
push(js.PropertyAccess.field(pop(), 'length')
.withSourceInformation(node.sourceInformation));
@@ -2908,6 +2932,7 @@
@override
void visitIndex(HIndex node) {
+ _metrics.countHIndex++;
use(node.receiver);
js.Expression receiver = pop();
use(node.index);
@@ -3119,6 +3144,7 @@
@override
visitIsTest(HIsTest node) {
+ _metrics.countHIsTest++;
_registry.registerTypeUse(TypeUse.isCheck(node.dartType));
use(node.typeInput);
@@ -3135,6 +3161,7 @@
@override
visitIsTestSimple(HIsTestSimple node) {
+ _metrics.countHIsTestSimple++;
_emitIsTestSimple(node);
}
@@ -3400,6 +3427,8 @@
}
@override
- visitIsLateSentinel(HIsLateSentinel node) =>
- _emitIsLateSentinel(node.inputs.single, node.sourceInformation);
+ visitIsLateSentinel(HIsLateSentinel node) {
+ _metrics.countHIsLateSentinel;
+ _emitIsLateSentinel(node.inputs.single, node.sourceInformation);
+ }
}
diff --git a/pkg/compiler/lib/src/ssa/metrics.dart b/pkg/compiler/lib/src/ssa/metrics.dart
index 2cdf618..8ef1158 100644
--- a/pkg/compiler/lib/src/ssa/metrics.dart
+++ b/pkg/compiler/lib/src/ssa/metrics.dart
@@ -1,11 +1,25 @@
import '../common/metrics.dart';
class SsaMetrics extends MetricsBase {
- final countInlinesDone = CountMetric('count.inlines.done');
- final countInlinesSkipped = CountMetric('count.inlines.skipped');
- final countInlineConstantsDone = CountMetric('count.inlineConstants.done');
- final countInlineConstantsSkipped =
- CountMetric('count.inlineConstants.skipped');
+ final countMethodInlined = CountMetric('count.method.inlined');
+ final countMethodNotInlined = CountMetric('count.method.notInlined');
+ final countSpecializations = CountMetric('count.specializations');
+ final countOperationFolded = CountMetric('count.operation.folded');
+ final countLengthOptimized = CountMetric('count.length.optimized');
+ final countFieldGetFolded = CountMetric('count.fieldGet.folded');
+ final countIndexFolded = CountMetric('count.index.folded');
+ final countGetLengthFolded = CountMetric('count.getLength.folded');
+ final countGettersTotal = CountMetric('count.getters.total');
+ final countGettersInlined = CountMetric('count.getters.inlined');
+ final countGettersElided = CountMetric('count.getters.elided');
+ final countSettersTotal = CountMetric('count.setters.total');
+ final countSettersInlined = CountMetric('count.setters.inlined');
+ final countSettersElided = CountMetric('count.setters.elided');
+ final countConditionDecided = CountMetric('count.if.decided');
+ final countIsTestDecided = CountMetric('count.isTest.decided');
+ final countIsTestSimplified = CountMetric('count.isTest.simplified');
+ final countLateSentinelCheckDecided =
+ CountMetric('count.lateSentinel.decided');
@override
String get namespace => 'ssa';
@@ -15,9 +29,22 @@
@override
Iterable<Metric> get secondary => [
- countInlinesDone,
- countInlinesSkipped,
- countInlineConstantsDone,
- countInlineConstantsSkipped
+ countMethodInlined,
+ countMethodNotInlined,
+ countSpecializations,
+ countLengthOptimized,
+ countFieldGetFolded,
+ countIndexFolded,
+ countGetLengthFolded,
+ countGettersTotal,
+ countGettersInlined,
+ countGettersElided,
+ countSettersTotal,
+ countSettersInlined,
+ countSettersElided,
+ countConditionDecided,
+ countIsTestDecided,
+ countIsTestSimplified,
+ countLateSentinelCheckDecided
];
}
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index faad0f8..a8b11e0 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -656,13 +656,17 @@
HInstruction instruction = node.inputs.length == 2
? foldUnary(operation, node.inputs[1])
: foldBinary(operation, node.inputs[1], node.inputs[2]);
- if (instruction != null) return instruction;
+ if (instruction != null) {
+ _metrics.countOperationFolded.add();
+ return instruction;
+ }
}
// Try converting the instruction to a builtin instruction.
HInstruction instruction = node.specializer.tryConvertToBuiltin(node,
_graph, _globalInferenceResults, commonElements, _closedWorld, _log);
if (instruction != null) {
+ _metrics.countSpecializations.add();
return instruction;
}
@@ -736,7 +740,10 @@
} else if (selector.isGetter) {
if (commonElements.appliesToJsIndexableLength(selector)) {
HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
- if (optimized != null) return optimized;
+ if (optimized != null) {
+ _metrics.countLengthOptimized.add();
+ return optimized;
+ }
}
}
@@ -1274,8 +1281,10 @@
HInstruction value = node.inputs[0];
AbstractBool isLateSentinel = value.isLateSentinel(_abstractValueDomain);
if (isLateSentinel.isDefinitelyTrue) {
+ _metrics.countLateSentinelCheckDecided.add();
return _graph.addConstantBool(true, _closedWorld);
} else if (isLateSentinel.isDefinitelyFalse) {
+ _metrics.countLateSentinelCheckDecided.add();
return _graph.addConstantBool(false, _closedWorld);
}
@@ -1320,9 +1329,11 @@
AbstractBool isTruthy =
_abstractValueDomain.isTruthy(condition.instructionType);
if (isTruthy.isDefinitelyTrue) {
+ _metrics.countConditionDecided.add();
return _replaceHIfCondition(
node, _graph.addConstantBool(true, _closedWorld));
} else if (isTruthy.isDefinitelyFalse) {
+ _metrics.countConditionDecided.add();
return _replaceHIfCondition(
node, _graph.addConstantBool(false, _closedWorld));
}
@@ -1443,12 +1454,11 @@
if (constant is ConstructedConstantValue) {
ConstantValue value = constant.fields[node.element];
if (value != null) {
- _metrics.countInlineConstantsDone.add();
+ _metrics.countFieldGetFolded.add();
return _graph.addConstant(value, _closedWorld);
}
}
}
- _metrics.countInlineConstantsSkipped.add();
return node;
}
@@ -1460,12 +1470,14 @@
if (receiver.isConstantList()) {
HConstant constantReceiver = receiver;
ListConstantValue constant = constantReceiver.constant;
+ _metrics.countGetLengthFolded.add();
return _graph.addConstantInt(constant.length, _closedWorld);
}
if (receiver.isConstantString()) {
HConstant constantReceiver = receiver;
StringConstantValue constant = constantReceiver.constant;
+ _metrics.countGetLengthFolded.add();
return _graph.addConstantInt(constant.length, _closedWorld);
}
@@ -1474,6 +1486,7 @@
int /*?*/ length = _abstractValueDomain.getContainerLength(receiverType);
if (length != null) {
HInstruction constant = _graph.addConstantInt(length, _closedWorld);
+ _metrics.countGetLengthFolded.add();
if (_abstractValueDomain.isNull(receiverType).isPotentiallyTrue) {
// If the container can be null, we update all uses of the length
// access to use the constant instead, but keep the length access in
@@ -1510,6 +1523,7 @@
// be able to do with the broader type of [lengthInput]. We should
// insert a HTypeKnown witnessed by the allocation to narrow the
// lengthInput.
+ _metrics.countGetLengthFolded.add();
return lengthInput;
}
}
@@ -1518,6 +1532,7 @@
isFixedLength(receiver.instructionType, _closedWorld)) {
// The input type has changed to fixed-length so change to an unassignable
// HGetLength to allow more GVN optimizations.
+ _metrics.countGetLengthFolded.add();
return HGetLength(receiver, node.instructionType, isAssignable: false);
}
return node;
@@ -1532,6 +1547,7 @@
ConstantValue foldedValue =
constant_system.index.fold(receiver.constant, index.constant);
if (foldedValue != null) {
+ _metrics.countIndexFolded.add();
return _graph.addConstant(foldedValue, _closedWorld);
}
}
@@ -1581,11 +1597,13 @@
ConstantValue constant = fieldData.constantValue;
HConstant result = _graph.addConstant(constant, _closedWorld,
sourceInformation: node.sourceInformation);
+ _metrics.countGettersElided.add();
_log?.registerConstantFieldGet(node, field, result);
return result;
} else {
receiver = maybeGuardWithNullCheck(receiver, node, field);
HFieldGet result = _directFieldGet(receiver, field, node);
+ _metrics.countGettersInlined.add();
_log?.registerFieldGet(node, result);
return result;
}
@@ -1658,12 +1676,14 @@
HInstruction assignField() {
if (_closedWorld.fieldAnalysis.getFieldData(field).isElided) {
_log?.registerFieldSet(node);
+ _metrics.countSettersElided.add();
return value;
} else {
HFieldSet result =
HFieldSet(_abstractValueDomain, field, receiver, value)
..sourceInformation = node.sourceInformation;
_log?.registerFieldSet(node, result);
+ _metrics.countSettersInlined.add();
return result;
}
}
@@ -2101,9 +2121,11 @@
AbstractBool result = node.evaluate(_closedWorld, _options);
if (result.isDefinitelyFalse) {
+ _metrics.countIsTestDecided.add();
return _graph.addConstantBool(false, _closedWorld);
}
if (result.isDefinitelyTrue) {
+ _metrics.countIsTestDecided.add();
return _graph.addConstantBool(true, _closedWorld);
}
@@ -2124,6 +2146,7 @@
if (specialization != null) {
AbstractValueWithPrecision checkedType = _abstractValueDomain
.createFromStaticType(node.dartType, nullable: false);
+ _metrics.countIsTestSimplified.add();
return HIsTestSimple(node.dartType, checkedType, specialization,
node.checkedInput, _abstractValueDomain.boolType);
}
@@ -2137,9 +2160,11 @@
HInstruction visitIsTestSimple(HIsTestSimple node) {
AbstractBool result = node.evaluate(_closedWorld, _options);
if (result.isDefinitelyFalse) {
+ _metrics.countIsTestDecided.add();
return _graph.addConstantBool(false, _closedWorld);
}
if (result.isDefinitelyTrue) {
+ _metrics.countIsTestDecided.add();
return _graph.addConstantBool(true, _closedWorld);
}
return node;