-
-
Notifications
You must be signed in to change notification settings - Fork 925
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
JRuby+Truffle: Keyword Arguments Optimization #2588
Conversation
We're working on it! Thanks for taking a look. |
This is great news. One general comment though, please replace all tab characters with 4 spaces. We should try to keep the formatting consistent with the rest of the code. |
Thanks for the feedback, @nirvdrum. We'll fix the indent asap. |
@@ -34,21 +29,12 @@ | |||
|
|||
@Child private RubyNode receiver; | |||
@Child private ProcOrNullNode block; | |||
@Children private final RubyNode[] arguments; | |||
private final RubyNode[] arguments; |
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.
Why removing the @Children
annotation here?
Looks good, I had a quick look through the code. |
We use We removed the |
return new Marker(); | ||
} | ||
|
||
public static class Marker {} |
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.
What are the pros/cons of using the singleton pattern here?
I see, having the (second) marker at the end seems natural as it would be where the Hash is in the non-optimized case. I don't know what is best in case of rest arguments. |
…kwargs Conflicts: truffle/src/main/java/org/jruby/truffle/nodes/dispatch/CachedBoxedMethodMissingDispatchNode.java truffle/src/main/java/org/jruby/truffle/nodes/dispatch/UncachedDispatchNode.java
eb78a89
to
8a7083a
Compare
@chrisseaton All tests are passing now. Feel free to give more feedback |
} | ||
|
||
@ExplodeLoop | ||
protected Object executeArguments(VirtualFrame frame, Object argumentOverride) { |
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.
I am wondering whether there's a better way to implement this. Argument nodes for calls are now stored in DispatchNode
, but there are still places where argument objects (no nodes, but objects) are passed when calling the dispatch head node (e.g. ArrayNodes.inject
). That's why we are keeping this option (not storing the argument nodes in DispatchNode
but passing objects as before) still open.
Still a few tabs, but I'll merge it now so we can get on and run our CI benchmarks. Can you go back and fix the tabs and submit a new PR for that? |
JRuby+Truffle: Keyword Arguments Optimization
@chrisseaton sure, will do. Thanks! |
I'm afraid I had to revert these merges temporarily. We've got some regressions on our benchmarks after pulling your branch in, and we don't want to leave any regressions in if we can't fix them in a day as it may mask other regressions. I've made a branch |
Hey @chrisseaton, |
I'm going to wait a few days, as we are changing how the PE works in Truffle and probably doing a new release of Graal. It makes sense to wait for those before exploring the problem here. I don't anticipate it taking long to fix. Do you need it to be merged into master as part of the requirements of your project? |
No, I don't think so. The code is already in the repository which should be enough I guess. |
Yeah we won't leave it more than a week max. |
No worries. Let us know if we can be of any help. Otherwise, we will leave this with you if that's ok :) |
Did you have any benchmarks for testing that keyword arguments were properly optimised? |
Yes, sure we did, but they were very simple. Here's one: def m(foo:, bar:)
foo + bar
end
200.times.each do |times|
beginning_time = Time.now
(1..1000000).each do |i|
m(foo: 1, bar: 2)
end
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"
end and here's a more complex one: def m(foo:, bar:)
foo + bar
end
def n(foo = 1, bar = 2)
foo + bar
end
def o(foo, bar:)
foo + bar
end
def p(a, b=2, c:)
a + b + c
end
def q(foo:1, bar:2)
foo + bar
end
def r(a, b=2, c=3, d:, e:5, f:)
a+b+c+d+e+f
end
def s(a, b=2, c:, d:, **rest)
a+b+c+d+rest[:e]
#rest[:e]
end
def t(**r)
r[:a]+r[:b]
end
def u(a, b)
a + b[:a] + b[:b]
end
def assert(a, b)
if a != b
puts "error: " + a.to_s + "!=" + b.to_s
end
end
200.times.each do |times|
beginning_time = Time.now
(1..1000000).each do |i|
assert(n(1, 2), 3)
assert(m(foo: 1, bar: 2), 3)
assert(m({foo: 1, bar:2}), 3)
assert(o(1, bar: 2), 3)
assert(o(1, {bar:2}), 3)
assert(p(1, c:3), 6)
assert(q(foo:1, bar:2), 3)
assert(q(foo:1), 3)
#assert(q(), 3)
assert(r(1,f:6,d:4), 21)
assert(s(1,e:5, f:6,d:4,c:3), 15)
assert(t(a:1, b:2, c:3), 3)
assert(u(1, {a: 2, b: 3}), 6)
end
end_time = Time.now
puts "Time elapsed #{(end_time - beginning_time)*1000} milliseconds"
end |
Maybe I'll just convert some of the existing benchmarks to use kwargs. |
Haha, you probably should! |
Hi @chrisseaton ,
this PR speeds up keyword arguments in JRuby+Truffle as discussed earlier (#2567).
RubyCallNode
toDispatchNode
MarkerNode
andMarkerNode.Marker
to indicate that a method call with keyword arguments is optimized, i.e., theHashLiteralNode
is expanded (removed and values extracted into the array)Feedback and thorough review would be appreciated (and necessary).
Regards,
@matthias-springer, @jgraichen, @mswart and @fniephaus
More details can be found here: