-
Notifications
You must be signed in to change notification settings - Fork 50
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
libsubprocess: reduce remote input prep/check #6002
libsubprocess: reduce remote input prep/check #6002
Conversation
OK silly question. Could |
Ya know what, i think it can. Lets try that. |
Ahhh I remember now. We allow users to If we wait to call Perhaps a "LOCAL_UNBUF" on the input side is something we could investigate as well, but perhaps not something for this round? |
Ah I didn't think of that. Hmm, could we just set the I can't for the life of me think why the input buffering is ever helpful. |
Yeah, that's certainly a possibility. I hadn't thought about it too much yet mainly because .... I just realized that next Tuesday is not the release deadline, it's in two Tuesdays. So I actually have time to experiment with an alternate approach. I was thinking this would be the approach for the upcoming release. |
Well, it just seems like, in the input case, the buffer isn't helping at all, and in fact impacts scaling in 1:N configs like in job-exec because you have to allocate all the buffers, watchers, etc. So if it's not helping, it seems really tempting to just cut it out! |
As I played around with this more, we also allow users to |
1ea4905
to
3fcf596
Compare
after messing around today I think I got it to work. The only gotcha is that we still need the buffer when the caller writes to the subprocess before the subprocess is running. But we can completely remove the remote input prep/check. I still to test against the reproducer to make sure this works, but it's looking pretty good and passing all tests. |
The reproducer on corona seems to work, and profiling shows exactly what we'd hope for.
|
Nice! Hey, could we just send the exec matchtag instead of the pid in write requests and then get rid of the buffer? That would be a protocol change to RFC 42 (which I would be happy to propose if you think it would work out). |
Ahhh, you mean on the server side, lookup jobs in the hash via exec matchtag vs PID? Yeah, I think that would work, then all the buffering would only be on the server side. Although I think that's a follow up PR to this one as we're changing the protocol. |
Perhaps we can slip the protocol change in before this PR then. I'll get a PR open on the RFC for a start. |
Began looking through code and began wondering about the fallout of removing the local buffer.
|
Well I guess we should check if write/close before start is required in the main sdexec case we care about right now which is job-exec. We may need to add some buffering to sdexec in any case. I had forgotten about that. We won't have line buffering with the UNBUF flag... |
Wait a sec, for local processes, there is an explicit check in So we can't just send to the remote. I guess your create on demand idea may be the best option. If we could delete the buffer after it empties out, even better. But it also makes me wonder why we allow writing/closing before start for remote processes but not for local ones. |
I think the main reason is that
vs
in the latter case, the remote subprocess RPC has probably not even been sent when |
In that example, the exec request definitely is sent before the write request, and the server is guaranteed to receive those messages in order. Thus if fork+exec/spawn really are synchronous, the remote pid will always be assigned to the subprocess before the write request is processed. Unless of course there was a failure but then it doesn't matter. |
I don't think we can be guaranteed this with |
Good point. I guess I was assuming we could fix that. In fact I should tack something on to #6013. For input I was just thinking we could enqueue the write request messages until the unit comes online. |
3fcf596
to
1bf761c
Compare
re-pushed, adding a commit to create the write buffer on demand when it is needed. |
e1d2bd3
to
d83e80d
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.
This is a nice cleanup!
I had a few comments, though nothing very substantial.
One other quick thought - it might not hurt to add a check that flux exec -n --service=sdexec
works. Something like
diff --git a/t/t2409-sdexec.t b/t/t2409-sdexec.t
index cf7ab989c..491ce6717 100755
--- a/t/t2409-sdexec.t
+++ b/t/t2409-sdexec.t
@@ -55,6 +55,9 @@ test_expect_success 'clear broker logs' '
test_expect_success 'sdexec true succeeds' '
$sdexec -r 0 $true
'
+test_expect_success 'sdexec -n cat succeeds' '
+ run_timeout 30 $sdexec -n -r 0 cat
+'
test_expect_success 'sdexec false fails with exit code 1' '
test_expect_code 1 $sdexec -r 0 $false
'
/* if process isn't running, will be sent after process | ||
* converts to running. Or if it has already exited, it | ||
* doesn't matter. |
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.
Maybe say "eof plus any previously writtten data" will be sent?
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.
This code assumes that there is no buffered data if the state is RUNNING. Maybe it would be helpful to mention where that buffer is flushed.
src/common/libsubprocess/remote.c
Outdated
if (c->closed) { | ||
if (subprocess_write (p->h, | ||
p->service_name, | ||
p->rank, | ||
p->pid, | ||
c->name, | ||
NULL, | ||
0, | ||
true) < 0) { |
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.
Could this be combined with the subprocess_write()
call above? E.g.
if (c->closed || fbuf_bytes (c->write_buffer) > 0) {
...
}
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.
ahhh i think you're right. It would have been two calls if the user did it, but we can combine it at this point in the code.
if (send_channel_data (p) < 0) | ||
goto error; |
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.
Should we destroy the fbuf here?
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.
ahhh you mean in the error case if it wasn't destroyed in send_channel_data()
. Hmmm, we certainly could. But since we're goto error
, we're failing the subprocess and going to destroy the subprocess soon. So not super necessary?
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.
Oh, derp! I didn't notice that it was destroyed in send_channel_data()
. NM!
hmm it just seems that isn't covered in general. |
d83e80d
to
793807d
Compare
re-pushed with tweaks per comments above. I also added an extra libsubprocess test that covers only closing stdin early vs write & closing it early. |
793807d
to
629ee0a
Compare
Problem: When starting remote processes, there are no tests to ensure that we can write / close stdin before a process is running. Add tests in libsubprocess/test/remote.c.
629ee0a
to
21ed590
Compare
Problem: The -n option in flux-exec is not covered with the sdexec server. Add coverage in t2409-sdexec.t.
Problem: Profiling shows that a significant amount of time can be spent in the prep/check of remote subprocess input. This is even in the case when the input buffer is empty. It ends up that the prep/check is not necessary for remote input. If the subprocess is already running, it can be written to directly without buffering. Buffering is only needed when a caller attempts to write to the subprocess before the subprocess is running. For remote subprocesses, remove all channel input prep/check. Immediately write to the remote subprocess if the subprocess is running. If the subprocess is not yet running, buffer the input and write it out later.
Problem: Profiling shows that creating the write buffer for remote subprocesses eats up a healthy amount of cycles. However, the buffer is not needed for many circumstances. It is only needed when there is an attempt to write data to the subprocess before the subprocess is running. Create the write buffer only when it is needed.
21ed590
to
b131d32
Compare
setting MWP, thanks! |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #6002 +/- ##
==========================================
+ Coverage 83.27% 83.30% +0.02%
==========================================
Files 519 519
Lines 83680 83637 -43
==========================================
- Hits 69688 69675 -13
+ Misses 13992 13962 -30
|
Problem: Profiling shows that a significant amount of time can be spent in the prep/check of remote subprocess input. This is even in the case when the input buffer is empty.
Enable the remote input prep/check only when the buffer is non-empty.