oracle / truffleruby

A high performance implementation of the Ruby programming language, built on GraalVM.
https://www.graalvm.org/ruby/
Other
3.02k stars 185 forks source link

Multi-thread access to fastR #2035

Closed rbotafogo closed 1 year ago

rbotafogo commented 4 years ago

Hello,

I have the following line in a file in ruby:

# g2_pry.rb

Polyglot.eval("R", "print(c(1, 2, 3))")

Running the following command:

# ruby --polyglot --jvm -S irb -r ./g2_pry.rb

prints to the console: [1] 1 2 3 and starts an irb section, as expected.

However if I do:

# ruby --polyglot --jvm -S pry -r ./g2_pry.rb

I get the error:

`eval': Multi threaded access requested by thread Thread[Ruby Thread id=16 from Ruby-reference-processor,5,main] but is not allowed for language(s) R. (ArgumentError)
    from /home/rbotafogo/desenv/galaaz/bin/g2_pry.rb:1:in `<top (required)>'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/mri/rubygems/core_ext/kernel_require.rb:54:in `gem_original_require'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/mri/rubygems/core_ext/kernel_require.rb:54:in `require'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/gems/gems/pry-0.13.1/lib/pry/pry_class.rb:105:in `block in load_requires'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/gems/gems/pry-0.13.1/lib/pry/pry_class.rb:104:in `each'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/gems/gems/pry-0.13.1/lib/pry/pry_class.rb:104:in `load_requires'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/gems/gems/pry-0.13.1/lib/pry/pry_class.rb:146:in `final_session_setup'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/gems/gems/pry-0.13.1/lib/pry/cli.rb:89:in `parse_options'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/lib/gems/gems/pry-0.13.1/bin/pry:12:in `<top (required)>'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/bin/pry:23:in `load'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/bin/pry:23:in `load'
    from /usr/local/lib/graalvm-ce-java11-20.1.0/languages/ruby/bin/pry:23:in `<main>'

Is there any way to fix this and have a multi-threaded ruby script call a fastR script?

I know that if I do:

ruby --polyglot --jvm --experimental-options --single-threaded -S pry -r ./g2_pry.rb

everything works fine. But I don't want to limit pry to a single thread. I tried protecting the Polyglot code in a semaphore, but it didn't do any good.

# g2_pry.rb

semaphore = Mutex.new

semaphore.synchronize {
  Polyglot.eval("R", "print(c(1, 2, 3))")
}
eregon commented 4 years ago

Thanks for the report. It seems FastR doesn't support multi-threaded access currently.

Maybe we could detect --polyglot is given, and in such a case not use a thread for Ruby-reference-processor, which runs finalizers in Ruby.

Currently, there is no solution to actually use multiple Ruby threads and interop with a language which doesn't support multi-threaded access, although we're looking into what could be done there.

But I don't want to limit pry to a single thread.

Do you want to create Ruby Threads explicitly? Or does pry not behave well with --single-threaded?

rbotafogo commented 4 years ago

Pry behaves fine with --single-threaded.

If possible, I would like to create Ruby Threads explicitly.

Also, I'm not sure what would happen if trying to run RoR calling fastR through Galaaz. I don't want to run RoR single threaded because of fastR. It would be great if I could protect all calls to fastR in a Mutex and have the rest multi-threaded.

Em seg., 15 de jun. de 2020 às 14:18, Benoit Daloze < notifications@github.com> escreveu:

Thanks for the report. It seems FastR doesn't support multi-threaded access currently.

Maybe we could detect --polyglot is given, and in such a case not use a thread for Ruby-reference-processor, which runs finalizers in Ruby.

Currently, there is no solution to actually use multiple Ruby threads and interop with a language which doesn't support multi-threaded access, although we're looking into what could be done there.

But I don't want to limit pry to a single thread.

Do you want to create Ruby Threads explicitly? Or does pry not behave well with --single-threaded?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/oracle/truffleruby/issues/2035#issuecomment-644262986, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6QP4KDDVPJTOX2OOZJI3LRWZJWTANCNFSM4N6LZL4A .

-- Rodrigo Botafogo

eregon commented 4 years ago

Relates to #1538, which was suggesting a R context per Ruby thread.

Supporting multiple Ruby threads + interop in general, whether it's with multiple inner contexts (e.g., multiple R contexts), a global lock when doing interop with single-threaded languages, or just checking single-threaded languages are not accessed concurrently, is tracked internally as GR-6371.

rbotafogo commented 4 years ago

I don't think that an R context per Ruby thread is a good solution. I think that a global lock when doing interop should be better.

Em ter., 16 de jun. de 2020 às 12:11, Benoit Daloze < notifications@github.com> escreveu:

Relates to #1538 https://github.com/oracle/truffleruby/issues/1538, which was suggesting a R context per Ruby thread.

Supporting multiple Ruby threads + interop in general, whether it's with multiple contexts, a global lock when doing interop with single-threaded languages, or just checking single-threaded languages are not accessed concurrently, is tracked internally as GR-6371.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/oracle/truffleruby/issues/2035#issuecomment-644827596, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6QP4IIFCO3K6JU5TRVBE3RW6DTVANCNFSM4N6LZL4A .

-- Rodrigo Botafogo

eregon commented 4 years ago

With 3ba925112206c78496b54c284449ac7d501c9110 the "Ruby-reference-processor" Thread will no longer be created when using other languages (such as when using --polyglot). So you should be able to use pry + Polyglot.eval() without extra flags. It will still not allow to create Ruby Threads, but at least it shouldn't to create Ruby Threads without an explicit Thread.new {} in Ruby code.

I don't think that an R context per Ruby thread is a good solution. I think that a global lock when doing interop should be better.

Should we close #1538 in favor of this issue then?

rbotafogo commented 4 years ago

Not sure I understand what happens if you create a new thread explicitly. Will it raise an exception?

If you run RoR or any other multithreaded program, will it be single-threaded? This is a huge impact on performance.

I might be saying something stupid, but wouldn't it be possible that if you had multiple threads and they wanted to access a single threaded language, the single threaded language would be protected by a semaphore or any other guard that would suspend the calling thread?

Em qua., 17 de jun. de 2020 às 06:11, Benoit Daloze < notifications@github.com> escreveu:

With 3ba9251 https://github.com/oracle/truffleruby/commit/3ba925112206c78496b54c284449ac7d501c9110 the "Ruby-reference-processor" Thread will no longer be created when using other languages (such as when using --polyglot). So you should be able to use pry + Polyglot.eval() without extra flags. It will still not allow to create Ruby Threads, but at least it shouldn't to create Ruby Threads without an explicit Thread.new {} in Ruby code.

I don't think that an R context per Ruby thread is a good solution. I think that a global lock when doing interop should be better.

Should we close #1538 https://github.com/oracle/truffleruby/issues/1538 in favor of this issue then?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/oracle/truffleruby/issues/2035#issuecomment-645254638, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6QP4KRSKE5JZ6D6S65S6TRXCCC3ANCNFSM4N6LZL4A .

-- Rodrigo Botafogo

eregon commented 4 years ago

I think I wasn't clear in the previous comment, sorry about that. 3ba925112206c78496b54c284449ac7d501c9110 avoids the error shown above with pry, by not creating the finalizer Thread. Interop with R is not yet changed, it still raises an error when creating a Ruby Thread (but at least it shouldn't be from that "internal" finalizer Thread).

Yes, we're looking into ways to indeed lock around calls to single-threaded languages like R and JS, without affecting the performance of other cases.

rbotafogo commented 4 years ago

OK... sounds good. Thanks! So, yes, I think you can close #1538.

Em qua., 17 de jun. de 2020 às 13:54, Benoit Daloze < notifications@github.com> escreveu:

I think I wasn't clear in the previous comment, sorry about that. 3ba9251 https://github.com/oracle/truffleruby/commit/3ba925112206c78496b54c284449ac7d501c9110 avoids the error shown above with pry, by not creating the finalizer Thread. Interop with R is not yet changed, it still raises an error when creating a Ruby Thread (but at least it shouldn't be from that "internal" finalizer Thread).

Yes, we're looking into ways to indeed lock around calls to single-threaded languages like R and JS, without affecting the performance of other cases.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/oracle/truffleruby/issues/2035#issuecomment-645494804, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6QP4PAY3ED6IZ44WW5BJDRXDYNJANCNFSM4N6LZL4A .

-- Rodrigo Botafogo

eregon commented 1 year ago

One solution for this is to use inner contexts, i.e.,

    Polyglot::InnerContext.new do |context|
      context.eval('R', '6 * 7')
    end

That doesn't have the threading issue.