Skip to content

Commit 4113f13

Browse files
committed
[GR-2737] Various performance improvements.
PullRequest: fastr/1984
2 parents 0eac9c8 + 5807097 commit 4113f13

File tree

12 files changed

+318
-87
lines changed

12 files changed

+318
-87
lines changed

ci_common/common.hocon

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ common : ${java8Downloads} {
101101
logs: ${logfiles}
102102
catch_files : [
103103
"Graal diagnostic output saved in (?P<filename>.+\.zip)",
104-
"output mismatch file: (?P<filename>.+\.Rout)"
104+
"output mismatch file: (?P<filename>.+\.Rout)",
105+
"test had .fail outputs: \['(?P<filename>.+)'\]"
105106
]
106107
timelimit : "1:00:00"
107108
environment : {

com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.oracle.truffle.api.frame.FrameDescriptor;
3636
import com.oracle.truffle.api.frame.FrameSlot;
3737
import com.oracle.truffle.api.frame.MaterializedFrame;
38+
import com.oracle.truffle.api.profiles.ValueProfile;
3839
import com.oracle.truffle.r.library.methods.MethodsListDispatchFactory.GetGenericInternalNodeGen;
3940
import com.oracle.truffle.r.nodes.access.AccessSlotNode;
4041
import com.oracle.truffle.r.nodes.access.AccessSlotNodeGen;
@@ -68,6 +69,7 @@
6869
import com.oracle.truffle.r.runtime.data.RNull;
6970
import com.oracle.truffle.r.runtime.data.RPromise;
7071
import com.oracle.truffle.r.runtime.data.RS4Object;
72+
import com.oracle.truffle.r.runtime.data.RStringVector;
7173
import com.oracle.truffle.r.runtime.data.RSymbol;
7274
import com.oracle.truffle.r.runtime.data.RTypedValue;
7375
import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
@@ -343,17 +345,27 @@ public abstract static class R_identC extends RExternalBuiltinNode.Arg2 {
343345
}
344346

345347
@Specialization
346-
protected Object identC(RAbstractStringVector e1, RAbstractStringVector e2) {
347-
if (e1.getLength() == 1 && e2.getLength() == 1 && e1.getDataAt(0).equals(e2.getDataAt(0))) {
348-
return RRuntime.LOGICAL_TRUE;
349-
} else {
350-
return RRuntime.LOGICAL_FALSE;
351-
}
348+
protected byte identC(String e1, String e2) {
349+
return RRuntime.asLogical(e1.equals(e2));
350+
}
351+
352+
@Specialization
353+
protected byte identC(RStringVector e1, RStringVector e2) {
354+
return RRuntime.asLogical(e1.getLength() == 1 && e2.getLength() == 1 && e1.getDataAt(0).equals(e2.getDataAt(0)));
355+
}
356+
357+
@Specialization
358+
protected byte identC(RAbstractStringVector e1In, RAbstractStringVector e2In,
359+
@Cached("createClassProfile()") ValueProfile e1Profile,
360+
@Cached("createClassProfile()") ValueProfile e2Profile) {
361+
RAbstractStringVector e1 = e1Profile.profile(e1In);
362+
RAbstractStringVector e2 = e2Profile.profile(e2In);
363+
return RRuntime.asLogical(e1.getLength() == 1 && e2.getLength() == 1 && e1.getDataAt(0).equals(e2.getDataAt(0)));
352364
}
353365

354366
@SuppressWarnings("unused")
355367
@Fallback
356-
protected Object identC(Object e1, Object e2) {
368+
protected byte identC(Object e1, Object e2) {
357369
return RRuntime.LOGICAL_FALSE;
358370
}
359371
}

com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Attr.java

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,30 @@
2828
import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
2929
import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
3030

31+
import com.oracle.truffle.api.CompilerDirectives;
3132
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
33+
import com.oracle.truffle.api.dsl.Cached;
3234
import com.oracle.truffle.api.dsl.Fallback;
35+
import com.oracle.truffle.api.dsl.ImportStatic;
3336
import com.oracle.truffle.api.dsl.Specialization;
37+
import com.oracle.truffle.api.nodes.Node;
3438
import com.oracle.truffle.api.object.DynamicObject;
39+
import com.oracle.truffle.api.object.Shape;
3540
import com.oracle.truffle.api.profiles.ConditionProfile;
41+
import com.oracle.truffle.r.nodes.attributes.ForEachAttributeNode;
42+
import com.oracle.truffle.r.nodes.attributes.ForEachAttributeNode.AttributeAction;
43+
import com.oracle.truffle.r.nodes.attributes.ForEachAttributeNode.Context;
3644
import com.oracle.truffle.r.nodes.attributes.GetAttributeNode;
37-
import com.oracle.truffle.r.nodes.attributes.IterableAttributeNode;
3845
import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
46+
import com.oracle.truffle.r.nodes.builtin.base.AttrNodeGen.PartialSearchCacheNodeGen;
3947
import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode;
4048
import com.oracle.truffle.r.nodes.unary.InternStringNode;
49+
import com.oracle.truffle.r.runtime.DSLConfig;
4150
import com.oracle.truffle.r.runtime.RError;
4251
import com.oracle.truffle.r.runtime.RError.Message;
4352
import com.oracle.truffle.r.runtime.RRuntime;
4453
import com.oracle.truffle.r.runtime.builtins.RBuiltin;
4554
import com.oracle.truffle.r.runtime.data.RAttributable;
46-
import com.oracle.truffle.r.runtime.data.RAttributesLayout;
4755
import com.oracle.truffle.r.runtime.data.RMissing;
4856
import com.oracle.truffle.r.runtime.data.RNull;
4957
import com.oracle.truffle.r.runtime.data.model.RAbstractContainer;
@@ -57,7 +65,7 @@ public abstract class Attr extends RBuiltinNode.Arg3 {
5765
@Child private InternStringNode intern = InternStringNode.create();
5866

5967
@Child private GetAttributeNode attrAccess = GetAttributeNode.create();
60-
@Child private IterableAttributeNode iterAttrAccess = IterableAttributeNode.create();
68+
@Child private PartialSearchCache partialSearchCache;
6169

6270
@Override
6371
public Object[] getDefaultParameterValues() {
@@ -73,19 +81,11 @@ public Object[] getDefaultParameterValues() {
7381
}
7482

7583
private Object searchKeyPartial(DynamicObject attributes, String name) {
76-
Object val = RNull.instance;
77-
78-
for (RAttributesLayout.RAttribute e : iterAttrAccess.execute(attributes)) {
79-
if (e.getName().startsWith(name)) {
80-
if (val == RNull.instance) {
81-
val = e.getValue();
82-
} else {
83-
// non-unique match
84-
return RNull.instance;
85-
}
86-
}
84+
if (partialSearchCache == null) {
85+
CompilerDirectives.transferToInterpreterAndInvalidate();
86+
partialSearchCache = insert(PartialSearchCacheNodeGen.create());
8787
}
88-
return val;
88+
return partialSearchCache.execute(attributes, name);
8989
}
9090

9191
private Object attrRA(RAttributable attributable, String name, boolean exact) {
@@ -125,4 +125,45 @@ protected Object attr(Object object, Object name, Object exact) {
125125
throw RError.nyi(this, "object cannot be attributed");
126126
}
127127
}
128+
129+
@ImportStatic(DSLConfig.class)
130+
protected abstract static class PartialSearchCache extends Node {
131+
@Child protected ForEachAttributeNode iterAttrAccess = ForEachAttributeNode.create(new PartialAttrSearchAction());
132+
133+
public abstract Object execute(DynamicObject attributes, String name);
134+
135+
@Specialization(guards = {"attrs.getShape() == cachedShape", "name.equals(cachedName)"}, limit = "getCacheSize(8)")
136+
protected Object doCached(@SuppressWarnings("unused") DynamicObject attrs, @SuppressWarnings("unused") String name,
137+
@SuppressWarnings("unused") @Cached("attrs.getShape()") Shape cachedShape,
138+
@SuppressWarnings("unused") @Cached("name") String cachedName,
139+
@Cached("iterAttrAccess.execute(attrs,name)") Object result) {
140+
return result;
141+
}
142+
143+
@Specialization(replaces = "doCached")
144+
protected Object doUncached(DynamicObject attrs, String name) {
145+
return iterAttrAccess.execute(attrs, name);
146+
}
147+
}
148+
149+
private static final class PartialAttrSearchAction extends AttributeAction {
150+
@Override
151+
public void init(Context context) {
152+
context.result = RNull.instance;
153+
}
154+
155+
@Override
156+
public boolean action(String name, Object value, Context ctx) {
157+
if (name.startsWith((String) ctx.param)) {
158+
if (ctx.result == RNull.instance) {
159+
ctx.result = value;
160+
} else {
161+
// non-unique match
162+
ctx.result = RNull.instance;
163+
return false;
164+
}
165+
}
166+
return true;
167+
}
168+
}
128169
}

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@
2828
import com.oracle.truffle.api.frame.Frame;
2929
import com.oracle.truffle.api.frame.FrameDescriptor;
3030
import com.oracle.truffle.api.frame.FrameSlot;
31-
import com.oracle.truffle.api.frame.FrameSlotKind;
3231
import com.oracle.truffle.api.frame.VirtualFrame;
3332
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
34-
import com.oracle.truffle.api.nodes.Node;
3533
import com.oracle.truffle.api.nodes.UnexpectedResultException;
3634
import com.oracle.truffle.api.profiles.ConditionProfile;
3735
import com.oracle.truffle.api.profiles.ValueProfile;
@@ -45,15 +43,14 @@
4543
import com.oracle.truffle.r.runtime.env.frame.ActiveBinding;
4644
import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
4745

48-
public final class LocalReadVariableNode extends Node {
46+
public final class LocalReadVariableNode extends ReadVariableNodeBase {
4947

5048
@Child private PromiseHelperNode promiseHelper;
5149
@Child private RExplicitCallNode readActiveBinding;
5250

5351
private final Object identifier;
5452
private final boolean forceResult;
5553

56-
@CompilationFinal(dimensions = 1) private boolean[] seenValueKinds;
5754
@CompilationFinal private ValueProfile valueProfile;
5855
@CompilationFinal private ConditionProfile isNullProfile;
5956
@CompilationFinal private ConditionProfile isMissingProfile;
@@ -110,12 +107,11 @@ public Object execute(VirtualFrame frame, Frame variableFrame) {
110107
Object result = null;
111108
if (isMissingProfile == null) {
112109
CompilerDirectives.transferToInterpreterAndInvalidate();
113-
seenValueKinds = new boolean[FrameSlotKind.values().length];
114110
valueProfile = ValueProfile.createClassProfile();
115111
isNullProfile = ConditionProfile.createBinaryProfile();
116112
isMissingProfile = ConditionProfile.createBinaryProfile();
117113
}
118-
result = valueProfile.profile(ReadVariableNode.profiledGetValue(seenValueKinds, profiledVariableFrame, frameSlot));
114+
result = valueProfile.profile(profiledGetValue(profiledVariableFrame, frameSlot));
119115
if (isNullProfile.profile(result == null) || isMissingProfile.profile(result == RMissing.instance)) {
120116
return null;
121117
}

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/ReadVariableNode.java

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import com.oracle.truffle.api.frame.Frame;
3737
import com.oracle.truffle.api.frame.FrameDescriptor;
3838
import com.oracle.truffle.api.frame.FrameSlot;
39-
import com.oracle.truffle.api.frame.FrameSlotKind;
4039
import com.oracle.truffle.api.frame.FrameSlotTypeException;
4140
import com.oracle.truffle.api.frame.MaterializedFrame;
4241
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -138,7 +137,7 @@ LookupNode copyAsSilenMissing() {
138137
* a particular layout of frame descriptors and enclosing environments, and re-specializes in case
139138
* the layout changes.
140139
*/
141-
public final class ReadVariableNode extends RBaseNode {
140+
public final class ReadVariableNode extends ReadVariableNodeBase {
142141

143142
private static final int MAX_INVALIDATION_COUNT = 8;
144143

@@ -210,8 +209,8 @@ private static RNode wrapAsSilentMissing(LookupNode node) {
210209
private final ConditionProfile isPromiseProfile = ConditionProfile.createBinaryProfile();
211210
private final ConditionProfile isActiveBindingProfile = ConditionProfile.createBinaryProfile();
212211
private final ConditionProfile copyProfile;
213-
private final BranchProfile unexpectedMissingProfile = BranchProfile.create();
214-
private final ValueProfile superEnclosingFrameProfile = ValueProfile.createClassProfile();
212+
private final BranchProfile unexpectedMissingProfile;
213+
private final ValueProfile superEnclosingFrameProfile;
215214

216215
private final Object identifier;
217216
private final String identifierAsString;
@@ -222,8 +221,6 @@ private static RNode wrapAsSilentMissing(LookupNode node) {
222221
// inlined varargs, which should not show missing value error
223222
private final boolean silentMissing;
224223

225-
@CompilationFinal(dimensions = 1) private final boolean[] seenValueKinds = new boolean[FrameSlotKind.values().length];
226-
227224
ReadVariableNode(ReadVariableNode node, boolean silentMissing) {
228225
this(node.identifier, node.mode, node.kind, silentMissing);
229226
}
@@ -238,6 +235,8 @@ private ReadVariableNode(Object identifier, RType mode, ReadKind kind, boolean s
238235
this.mode = mode;
239236
this.kind = kind;
240237
this.silentMissing = silentMissing;
238+
unexpectedMissingProfile = silentMissing ? null : BranchProfile.create();
239+
superEnclosingFrameProfile = kind == ReadKind.Super ? ValueProfile.createClassProfile() : null;
241240

242241
this.copyProfile = kind != ReadKind.Copying ? null : ConditionProfile.createBinaryProfile();
243242
}
@@ -359,7 +358,7 @@ private Mismatch(FrameLevel next, FrameSlot slot) {
359358
@Override
360359
public Object execute(VirtualFrame frame, Frame variableFrame) throws InvalidAssumptionException, LayoutChangedException, FrameSlotTypeException {
361360
Frame profiledVariableFrame = frameProfile.profile(variableFrame);
362-
Object value = profiledGetValue(seenValueKinds, profiledVariableFrame, slot);
361+
Object value = profiledGetValue(profiledVariableFrame, slot);
363362
if (checkType(frame, value, isNullProfile)) {
364363
CompilerDirectives.transferToInterpreterAndInvalidate();
365364
throw new LayoutChangedException();
@@ -408,7 +407,7 @@ private Match(FrameSlot slot) {
408407

409408
@Override
410409
public Object execute(VirtualFrame frame, Frame variableFrame) throws LayoutChangedException, FrameSlotTypeException {
411-
Object value = valueProfile.profile(profiledGetValue(seenValueKinds, frameProfile.profile(variableFrame), slot));
410+
Object value = valueProfile.profile(profiledGetValue(frameProfile.profile(variableFrame), slot));
412411
if (!checkType(frame, value, isNullProfile)) {
413412
throw new LayoutChangedException();
414413
}
@@ -613,7 +612,7 @@ private FrameAndSlotLookupLevel(FrameAndSlotLookupResult lookup) {
613612

614613
@Override
615614
public Object execute(VirtualFrame frame) throws InvalidAssumptionException, LayoutChangedException, FrameSlotTypeException {
616-
Object value = profiledGetValue(seenValueKinds, frameProfile.profile(lookup.getFrame()), lookup.getSlot());
615+
Object value = profiledGetValue(frameProfile.profile(lookup.getFrame()), lookup.getSlot());
617616
if (!checkType(frame, value, isNullProfile)) {
618617
CompilerDirectives.transferToInterpreterAndInvalidate();
619618
throw new LayoutChangedException();
@@ -648,7 +647,7 @@ private FrameLevel initialize(VirtualFrame frame, Frame variableFrame) {
648647
FrameSlot localSlot = variableFrame.getFrameDescriptor().findFrameSlot(identifier);
649648
// non-local reads can only be handled in a simple way if they are successful
650649
if (localSlot != null) {
651-
Object val = getValue(seenValueKinds, variableFrame, localSlot);
650+
Object val = getValue(variableFrame, localSlot);
652651
if (checkTypeSlowPath(frame, val)) {
653652
if (val instanceof MultiSlotData) {
654653
RError.performanceWarning("polymorphic (slow path) lookup of symbol \"" + identifier + "\" from a multi slot");
@@ -721,7 +720,7 @@ private FrameLevel createLevels(VirtualFrame frame, Frame variableFrame, ArrayLi
721720
FrameDescriptor currentDescriptor = variableFrame.getFrameDescriptor();
722721
FrameSlot frameSlot = currentDescriptor.findFrameSlot(identifier);
723722
if (frameSlot != null) {
724-
Object value = getValue(seenValueKinds, variableFrame, frameSlot);
723+
Object value = getValue(variableFrame, frameSlot);
725724
if (checkTypeSlowPath(frame, value)) {
726725
StableValue<Object> valueAssumption = FrameSlotChangeMonitor.getStableValueAssumption(currentDescriptor, frameSlot, value);
727726
if (valueAssumption != null) {
@@ -768,7 +767,7 @@ private FrameLevel createLevels(VirtualFrame frame, Frame variableFrame, ArrayLi
768767
if (frameSlot == null) {
769768
assumptions.add(currentDescriptor.getNotInFrameAssumption(identifier));
770769
} else {
771-
StableValue<Object> valueAssumption = FrameSlotChangeMonitor.getStableValueAssumption(currentDescriptor, frameSlot, getValue(seenValueKinds, variableFrame, frameSlot));
770+
StableValue<Object> valueAssumption = FrameSlotChangeMonitor.getStableValueAssumption(currentDescriptor, frameSlot, getValue(variableFrame, frameSlot));
772771
if (valueAssumption != null && lastLevel instanceof DescriptorLevel) {
773772
assumptions.add(valueAssumption.getAssumption());
774773
} else {
@@ -873,44 +872,6 @@ public static RArgsValuesAndNames lookupVarArgs(Frame variableFrame) {
873872
return null;
874873
}
875874

876-
private static Object getValue(boolean[] seenValueKinds, Frame variableFrame, FrameSlot frameSlot) {
877-
assert variableFrame.getFrameDescriptor().getSlots().contains(frameSlot) : frameSlot.getIdentifier();
878-
Object value = variableFrame.getValue(frameSlot);
879-
if (variableFrame.isObject(frameSlot)) {
880-
value = FrameSlotChangeMonitor.getValue(frameSlot, variableFrame);
881-
seenValueKinds[FrameSlotKind.Object.ordinal()] = true;
882-
} else if (variableFrame.isByte(frameSlot)) {
883-
seenValueKinds[FrameSlotKind.Byte.ordinal()] = true;
884-
} else if (variableFrame.isInt(frameSlot)) {
885-
seenValueKinds[FrameSlotKind.Int.ordinal()] = true;
886-
} else if (variableFrame.isDouble(frameSlot)) {
887-
seenValueKinds[FrameSlotKind.Double.ordinal()] = true;
888-
}
889-
return value;
890-
}
891-
892-
static Object profiledGetValue(boolean[] seenValueKinds, Frame variableFrame, FrameSlot frameSlot) {
893-
assert variableFrame.getFrameDescriptor().getSlots().contains(frameSlot) : frameSlot.getIdentifier();
894-
try {
895-
if (seenValueKinds[FrameSlotKind.Object.ordinal()] && variableFrame.isObject(frameSlot)) {
896-
return FrameSlotChangeMonitor.getObject(frameSlot, variableFrame);
897-
} else if (seenValueKinds[FrameSlotKind.Byte.ordinal()] && variableFrame.isByte(frameSlot)) {
898-
return variableFrame.getByte(frameSlot);
899-
} else if (seenValueKinds[FrameSlotKind.Int.ordinal()] && variableFrame.isInt(frameSlot)) {
900-
return variableFrame.getInt(frameSlot);
901-
} else if (seenValueKinds[FrameSlotKind.Double.ordinal()] && variableFrame.isDouble(frameSlot)) {
902-
return variableFrame.getDouble(frameSlot);
903-
} else {
904-
CompilerDirectives.transferToInterpreterAndInvalidate();
905-
// re-profile to widen the set of expected types
906-
return getValue(seenValueKinds, variableFrame, frameSlot);
907-
}
908-
} catch (FrameSlotTypeException e) {
909-
CompilerDirectives.transferToInterpreter();
910-
throw new RInternalError(e, "unexpected frame slot type mismatch");
911-
}
912-
}
913-
914875
/**
915876
* This method checks the value a RVN just read. It is used to determine whether the value just
916877
* read matches the expected type or if we have to look in a frame up the lexical chain. It

0 commit comments

Comments
 (0)