Skip to content

Scheduler#3434

Merged
ioquatix merged 13 commits into
ruby:masterfrom
ioquatix:scheduler
Sep 14, 2020
Merged

Scheduler#3434
ioquatix merged 13 commits into
ruby:masterfrom
ioquatix:scheduler

Conversation

@ioquatix
Copy link
Copy Markdown
Member

@ioquatix ioquatix commented Aug 20, 2020

This is a work in progress.

  • Rename Fiber{} to Fiber.schedule{}.
  • Simplify hooks and improve method name consistency. Format is class_method, e.g. io_wait or kernel_sleep.
  • Expose scheduler callbacks as functions to aid in correctness, documentation and maintainability.
  • Rework wait.c to pass IO instance, and other adjustments where possible.
  • Add support for rescheduling fiber and Mutex support.
  • Expose io_read as a hook for implementing io_uring (Linux) and IOCP (Windows).
  • Add support for ConditionVariable.
  • Add support for Queue.
  • Rework usage of (some) functions which accept file descriptor arguments.

@ioquatix ioquatix marked this pull request as draft August 20, 2020 13:01
@ioquatix
Copy link
Copy Markdown
Member Author

Some notes about io_uring after discussion with @dsh0416 who implemented a scheduler and has started working on a C interface for io_uring.

The most efficient (zero-copy) interface for IO#read must go directly to io_uring. We schedule the full read operation (buffer, offset, length, etc) and it goes to OS. The OS will inform us when the read operation is completed.

This is different from existing Ruby implementation which uses IO#wait_readable in a loop before calling read.

However, in practice both interfaces are critical. For example, libpq for postgres does not expose some way to hook read, just a way to do non-blocking I/O by checking IO#wait_... before calling the libpq functions.

So, we need to support both for high performance I/O.

Therefore, I introduced new optional Scheduler#io_read(io, buffer, offset, length) and Scheduler#io_write(io, buffer, offset, length). This method is experiment and we will try it with io_uring implementation. It should also fit better with Windows IOCP which up until now has been ignored.

Comment thread include/ruby/io.h
#define GetOpenFile RB_IO_POINTER

#define MakeOpenFile(obj, fp) do {\
#define RB_IO_OPEN(obj, fp) do {\
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nobu @shyouhei can I get your feedback on this?

Comment thread scheduler.c
Comment thread include/ruby/io.h
@ioquatix
Copy link
Copy Markdown
Member Author

ioquatix commented Sep 5, 2020

@eregon I have merged your changes into this branch because I want to build on them. Thanks for your effort.

@ioquatix ioquatix force-pushed the scheduler branch 7 times, most recently from 63c453b to 693d725 Compare September 7, 2020 00:16
@ioquatix
Copy link
Copy Markdown
Member Author

ioquatix commented Sep 7, 2020

@jeremyevans do you believe this code is sufficient for your Sequel pool management?

@jeremyevans
Copy link
Copy Markdown
Contributor

I believe Fiber-aware Mutex is a necessary condition for Sequel connection pool management to work correctly with multiple concurrent fibers of the same thread. I'm not sure if ConditionalVariable also needs to be Fiber-aware or not. So I'm not sure if this will be sufficient by itself, but it is definitely a step in the right direction.

@ioquatix
Copy link
Copy Markdown
Member Author

ioquatix commented Sep 7, 2020

ConditionalVariable internally uses mutex to synchronize state, so it should be okay, but I'll check it. Thanks for your thoughts.

@ioquatix
Copy link
Copy Markdown
Member Author

I need to check in thread.c the following functions:

rb_thread_sleep_deadly_allow_spurious_wakeup(void);
rb_thread_wait_for(struct timeval time);

and a few others - some are public interface and should go via the same rb_scheduler_kernel_sleep.

Comment thread ext/io/console/console.c
if (w < 0) rb_eof_error();
if (!(w & RB_WAITFD_IN)) return Qnil;
VALUE result = RB_NUM2INT(rb_io_wait(io, RUBY_IO_READABLE, timeout));
if (result == Qfalse) return Qnil;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nobu what do you think?

@ioquatix ioquatix force-pushed the scheduler branch 2 times, most recently from aea7f4d to 2a50788 Compare September 14, 2020 01:29
eregon and others added 6 commits September 14, 2020 15:49
* Enables Mutex to be used as synchronization between multiple Fibers
  of the same Thread.
* With a Fiber scheduler we can yield to another Fiber on contended
  Mutex#lock instead of blocking the entire thread.
* This also makes the behavior of Mutex consistent across CRuby, JRuby and TruffleRuby.
* [Feature ruby#16792]
@ioquatix ioquatix self-assigned this Sep 14, 2020
@ioquatix ioquatix added this to the v3.0.0 milestone Sep 14, 2020
@ioquatix ioquatix marked this pull request as ready for review September 14, 2020 04:41
@ioquatix ioquatix merged commit 7fca274 into ruby:master Sep 14, 2020
@ioquatix ioquatix deleted the scheduler branch September 17, 2020 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants