-
Notifications
You must be signed in to change notification settings - Fork 321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use Vector.new
for fill
and tuning...
#3744
Conversation
b8581ca
to
f54ebdf
Compare
f54ebdf
to
f732be7
Compare
5c8b660
to
5c8a394
Compare
This change stems from the investigation into ellusive performance degradation that became visible when implementing `Builder.to_vector` with `slice` to not copy the store in #3744. We were seeing about 40% drop for a simple `filter` method calls without any reason. IGV debugging was fun, but didn't reveal much. Profiling with VisualVM revealed that we were previously inlining most of nodes, while with the new version that was no longer the case. Still, it was hard to figure out why. Decided to use ``` -Dpolyglot.engine.TraceDeoptimizeFrame=true -Dpolyglot.engine.BackgroundCompilation=false -Dpolyglot.engine.TraceCompilation=true -Dpolyglot.engine.TraceInlining=true ``` which revealed a more than expected number of deoptimizations. With ``` -Dpolyglot.engine.TraceTransferToInterpreter=true ``` we were able to see the source of it: ``` [info] [2022-10-07T13:13:12.98Z] [engine] transferToInterpreter at Builder.to_vector<arg-2>(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:1091) <split-c6d56df> Builder.to_vector(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:1091) <split-6500912a> Vector.filter(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:347) <split-660ff9b4> ... ... org.graalvm.truffle/com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate(CompilerDirectives.java:90) org.enso.interpreter.node.callable.resolver.MethodResolverNodeGen.execute(MethodResolverNodeGen.java:47) org.enso.interpreter.node.callable.resolver.HostMethodCallNode.getPolyglotCallType(HostMethodCallNode.java:146) org.enso.interpreter.node.callable.InvokeMethodNodeGen.execute(InvokeMethodNodeGen.java:86) org.enso.interpreter.node.callable.InvokeCallableNode.invokeDynamicSymbol(InvokeCallableNode.java:254) org.enso.interpreter.node.callable.InvokeCallableNodeGen.execute(InvokeCallableNodeGen.java:54) org.enso.interpreter.node.callable.ApplicationNode.executeGeneric(ApplicationNode.java:99) org.enso.interpreter.node.ClosureRootNode.execute(ClosureRootNode.java:90) ``` So the problem was in the new implementation of `to_vector` but not in `slice`, as we expected, but in `list.size`. Problem was that `MethodResolver` would always deoptimize for polyglot array method calls because newly created `UnresolvedSymbol` in [HostMethodCallNode](https://github.com/enso-org/enso/blob/ea60cd5fab48d9f6b16923cea21620b97216a898/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java#L145) wouldn't `==` to the cached one in [MethodResolver](https://github.com/enso-org/enso/blob/ea60cd5fab48d9f6b16923cea21620b97216a898/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java#L38). Fixed by providing a custom `equals` implementation for `UnresolvedSymbol` and `s/==/equals` in `MethodResolverNode` cache check.
This change stems from the investigation into elusive performance degradation that became visible when implementing `Builder.to_vector` with `slice` to not copy the store in #3744. We were seeing about 40% drop for a simple `filter` method calls without any reason. IGV debugging was fun, but didn't reveal much. Profiling with VisualVM revealed that we were previously inlining most of nodes, while with the new version that was no longer the case. Still, it was hard to figure out why. Decided to use ``` -Dpolyglot.engine.TraceDeoptimizeFrame=true -Dpolyglot.engine.BackgroundCompilation=false -Dpolyglot.engine.TraceCompilation=true -Dpolyglot.engine.TraceInlining=true ``` which revealed a more than expected number of deoptimizations. With ``` -Dpolyglot.engine.TraceTransferToInterpreter=true ``` we were able to see the source of it: ``` [info] [2022-10-07T13:13:12.98Z] [engine] transferToInterpreter at Builder.to_vector<arg-2>(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:1091) <split-c6d56df> Builder.to_vector(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:1091) <split-6500912a> Vector.filter(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:347) <split-660ff9b4> ... ... org.graalvm.truffle/com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate(CompilerDirectives.java:90) org.enso.interpreter.node.callable.resolver.MethodResolverNodeGen.execute(MethodResolverNodeGen.java:47) org.enso.interpreter.node.callable.resolver.HostMethodCallNode.getPolyglotCallType(HostMethodCallNode.java:146) org.enso.interpreter.node.callable.InvokeMethodNodeGen.execute(InvokeMethodNodeGen.java:86) org.enso.interpreter.node.callable.InvokeCallableNode.invokeDynamicSymbol(InvokeCallableNode.java:254) org.enso.interpreter.node.callable.InvokeCallableNodeGen.execute(InvokeCallableNodeGen.java:54) org.enso.interpreter.node.callable.ApplicationNode.executeGeneric(ApplicationNode.java:99) org.enso.interpreter.node.ClosureRootNode.execute(ClosureRootNode.java:90) ``` So the problem was in the new implementation of `to_vector` but not in `slice`, as we expected, but in `list.size`. Problem was that `MethodResolver` would always deoptimize for polyglot array method calls because newly created `UnresolvedSymbol` in [HostMethodCallNode](https://github.com/enso-org/enso/blob/ea60cd5fab48d9f6b16923cea21620b97216a898/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java#L145) wouldn't `==` to the cached one in [MethodResolver](https://github.com/enso-org/enso/blob/ea60cd5fab48d9f6b16923cea21620b97216a898/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java#L38). Fixed by providing a custom `equals` implementation for `UnresolvedSymbol` and `s/==/equals` in `MethodResolverNode` cache check.
This change stems from the investigation into elusive performance degradation that became visible when implementing `Builder.to_vector` with `slice` to not copy the store in #3744. We were seeing about 40% drop for a simple `filter` method calls without any reason. IGV debugging was fun, but didn't reveal much. Profiling with VisualVM revealed that we were previously inlining most of nodes, while with the new version that was no longer the case. Still, it was hard to figure out why. Decided to use ``` -Dpolyglot.engine.TraceDeoptimizeFrame=true -Dpolyglot.engine.BackgroundCompilation=false -Dpolyglot.engine.TraceCompilation=true -Dpolyglot.engine.TraceInlining=true ``` which revealed a more than expected number of deoptimizations. With ``` -Dpolyglot.engine.TraceTransferToInterpreter=true ``` we were able to see the source of it: ``` [info] [2022-10-07T13:13:12.98Z] [engine] transferToInterpreter at Builder.to_vector<arg-2>(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:1091) <split-c6d56df> Builder.to_vector(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:1091) <split-6500912a> Vector.filter(built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/src/Data/Vector.enso:347) <split-660ff9b4> ... ... org.graalvm.truffle/com.oracle.truffle.api.CompilerDirectives.transferToInterpreterAndInvalidate(CompilerDirectives.java:90) org.enso.interpreter.node.callable.resolver.MethodResolverNodeGen.execute(MethodResolverNodeGen.java:47) org.enso.interpreter.node.callable.resolver.HostMethodCallNode.getPolyglotCallType(HostMethodCallNode.java:146) org.enso.interpreter.node.callable.InvokeMethodNodeGen.execute(InvokeMethodNodeGen.java:86) org.enso.interpreter.node.callable.InvokeCallableNode.invokeDynamicSymbol(InvokeCallableNode.java:254) org.enso.interpreter.node.callable.InvokeCallableNodeGen.execute(InvokeCallableNodeGen.java:54) org.enso.interpreter.node.callable.ApplicationNode.executeGeneric(ApplicationNode.java:99) org.enso.interpreter.node.ClosureRootNode.execute(ClosureRootNode.java:90) ``` So the problem was in the new implementation of `to_vector` but not in `slice`, as we expected, but in `list.size`. Problem was that `MethodResolver` would always deoptimize for polyglot array method calls because newly created `UnresolvedSymbol` in [HostMethodCallNode](https://github.com/enso-org/enso/blob/ea60cd5fab48d9f6b16923cea21620b97216a898/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/HostMethodCallNode.java#L145) wouldn't `==` to the cached one in [MethodResolver](https://github.com/enso-org/enso/blob/ea60cd5fab48d9f6b16923cea21620b97216a898/engine/runtime/src/main/java/org/enso/interpreter/node/callable/resolver/MethodResolverNode.java#L38). Fixed by providing a custom `equals` implementation for `UnresolvedSymbol` and `s/==/equals` in `MethodResolverNode` cache check.
0fd1030
to
b2bfae0
Compare
b2bfae0
to
116ca71
Compare
Vector.Builder
and Vector.fill
Vector.new
for fill
and tuning...
fba70e4
to
a6cddc3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
While we are at it - seems that Vector.fill
docs are completely out of date. Can we update them?
Oops... Oops... Try using Range for Vector loops. Before trying to sort Range... Update Fold and Reduce... Update Fold and Reduce... Doh! Release snapshot. Don't use slice for builder Allow slice to be whole Vector and then avoid copies for builder. Use new instead of a Builder. Add a fill test 2. Add a fill test.
13f119e
to
f09a0fe
Compare
@@ -87,10 +87,8 @@ type Vector a | |||
|
|||
Vector.fill length=50 item=42 | |||
fill : Integer -> Any -> Vector Any | |||
fill length ~item = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out removing ~
caused this regression #10142 (comment), CCing @radeusgd and @jdunkerley
Previously the ~item
was evaluated again and again for each element of the array. Now it is evaluated just once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I find the new fill
semantic better. Use Vector.new
if you want to create vector with different values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I find the new
fill
semantic better. UseVector.new
if you want to create vector with different values.
Yes, I too think that current semantics is better.
Pull Request Description
Vector.fill
use theVector.new
method.Checklist
Please include the following checklist in your PR:
Scala,
Java,
and
Rust
style guides.
./run ide build
and./run ide watch
.