-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Fire fewer homing missiles #10070
Fire fewer homing missiles #10070
Conversation
The invariants here are really hard to follow. I wish that we weren't playing this dance of swapping out If we can get this to work though I don't mind leaving the complexity for now. |
This optimizes the `home_for_io` code path by requiring fewer scheduler operations in some situtations. When moving to your home scheduler, this no longer forces a context switch if you're already on the home scheduler. Instead, the homing code now simply pins you to your current scheduler (making it so you can't be stolen away). If you're not on your home scheduler, then we context switch away, sending you to your home scheduler. When the I/O operation is done, then we also no longer forcibly trigger a context switch. Instead, the action is cased on whether the task is homed or not. If a task does not have a home, then the task is re-flagged as not having a home and no context switch is performed. If a task is homed to the current scheduler, then we don't do anything, and if the task is homed to a foreign scheduler, then it's sent along its merry way. I verified that there are about a third as many `write` syscalls done in print operations now. Libuv uses write to implement async handles, and the homing before and after each I/O operation was triggering a write on these async handles. Additionally, using the terrible benchmark of printing 10k times in a loop, this drives the runtime from 0.6s down to 0.3s (yay!).
I've updated this with your suggestions and what we talked about on IRC, it's a lot simpler now, and it seems to achieve the same goal (all tests passed locally). |
This optimizes the `home_for_io` code path by requiring fewer scheduler operations in some situtations. When moving to your home scheduler, this no longer forces a context switch if you're already on the home scheduler. Instead, the homing code now simply pins you to your current scheduler (making it so you can't be stolen away). If you're not on your home scheduler, then we context switch away, sending you to your home scheduler. When the I/O operation is done, then we also no longer forcibly trigger a context switch. Instead, the action is cased on whether the task is homed or not. If a task does not have a home, then the task is re-flagged as not having a home and no context switch is performed. If a task is homed to the current scheduler, then we don't do anything, and if the task is homed to a foreign scheduler, then it's sent along its merry way. I verified that there are about a third as many `write` syscalls done in print operations now. Libuv uses write to implement async handles, and the homing before and after each I/O operation was triggering a write on these async handles. Additionally, using the terrible benchmark of printing 10k times in a loop, this drives the runtime from 0.6s down to 0.3s (yay!).
I don't think this change maintains thread safety. As far as I can tell, this doesn't change the home of the task to be the I/O home, which means that you can get this sequence of events:
In the original version:
Temporarily setting the task's home to the I/O home is necessary for thread safety in I/O or else the scheduler will happily execute I/O on the wrong thread. |
I can see how this would be a problem if the task is ever placed on a work queue, but I don't think that it's ever found in a work queue. During the homing operation, it's found in a specific scheduler's message queue. After the homing operation, it will get descheduled and won't be on any queue. When the task is reawoken, it's awoken with I agree that if the task resumption didn't happen with the "immediately" function we would have problems, but so long as the uv bindings all resume immediately, I don't think that a task is on a work queue at any point in time during an I/O operation. Although you are probably more familiar with the scheduler than I am, so am I missing something? |
…check, r=y21 Extend `implicit_saturating_sub` lint Fixes rust-lang#10070. It can serve as base if we want to add equivalent checks for other arithmetic operations. Also one important note: when writing this lint, I realized that I could check for wrong conditions performed beforehand on subtraction and added another part in the lint. Considering they both rely on the same checks, I kept both in the same place. Not sure if it makes sense though... changelog: Extend `implicit_saturating_sub` lint
This optimizes the
home_for_io
code path by requiring fewer scheduleroperations in some situtations.
When moving to your home scheduler, this no longer forces a context switch if
you're already on the home scheduler. Instead, the homing code now simply pins
you to your current scheduler (making it so you can't be stolen away). If you're
not on your home scheduler, then we context switch away, sending you to your
home scheduler.
When the I/O operation is done, then we also no longer forcibly trigger a
context switch. Instead, the action is cased on whether the task is homed or
not. If a task does not have a home, then the task is re-flagged as not having a
home and no context switch is performed. If a task is homed to the current
scheduler, then we don't do anything, and if the task is homed to a foreign
scheduler, then it's sent along its merry way.
I verified that there are about a third as many
write
syscalls done in printoperations now. Libuv uses write to implement async handles, and the homing
before and after each I/O operation was triggering a write on these async
handles. Additionally, using the terrible benchmark of printing 10k times in a
loop, this drives the runtime from 0.6s down to 0.3s (yay!).