Skip to content

streams/xp_socket: eliminate poll() when MSG_DONTWAIT is available #8092

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

Closed
wants to merge 2 commits into from

Conversation

MaxKellermann
Copy link
Contributor

If there is a zero timeout and MSG_DONTWAIT is available (or the
socket is non-blocking), the poll() call is not necessary, and we can
just call recv() right away.

Before this change:

poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
poll([{fd=4, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "HTTP/1.1 301 Moved Permanently\r\n"..., 8192, MSG_DONTWAIT, NULL, NULL) = 348
poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "", 1, MSG_PEEK, NULL, NULL) = 0

After this change:

recvfrom(4, 0x7ffe0cc719a0, 1, MSG_PEEK|MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=4, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=4, revents=POLLIN}])
recvfrom(4, "HTTP/1.1 301 Moved Permanently\r\n"..., 8192, MSG_DONTWAIT, NULL, NULL) = 348
recvfrom(4, "", 1, MSG_PEEK|MSG_DONTWAIT, NULL, NULL) = 0

The first poll() is replaced by recvfrom(), and the third poll() is
omitted completely.

[Splitted from https://github.com//pull/8032]

@MaxKellermann
Copy link
Contributor Author

CI failures unrelated to this PR.

@cmb69
Copy link
Member

cmb69 commented Feb 24, 2022

Please rebase onto current php-src:master and force-push, to re-trigger CI.

@MaxKellermann
Copy link
Contributor Author

Yay, "All checks have passed".

@MaxKellermann MaxKellermann force-pushed the msg_dontwait branch 2 times, most recently from 7758e72 to a81701a Compare March 24, 2022 05:06
@MaxKellermann
Copy link
Contributor Author

I rebased; AppVeyor failure unrelated to this PR.

Copy link
Member

@twose twose left a comment

Choose a reason for hiding this comment

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

LGTM

@bukka
Copy link
Member

bukka commented May 12, 2022

It makes sense to me. Do we actually have any test case covering this path?

@twose
Copy link
Member

twose commented May 15, 2022

@MaxKellermann The same optimization can also be applied to php_openssl_sockop_set_option.

It makes sense to me. Do we actually have any test case covering this path?

@bukka I believe that many socket-stream-related tests have covered this path, such as the most straightforward case for me: echo file_get_contents('http://www.baidu.com');, it also covers this path.

@devnexen
Copy link
Member

devnexen commented Jun 18, 2022

@MaxKellermann do you still want to proceed with your open PRs ? still few weeks left before the feature freeze :-)

@MaxKellermann
Copy link
Contributor Author

@devnexen yes, of course.
I didn't see this was tagged "Waiting on Author" by @ramsey, but what are you waiting for?
(@twose suggested another optimization, but such an idea for an additional optimization shouldn't delay merging this PR, should it?)

@devnexen
Copy link
Member

would it require a lot of changes ? otherwise yes it s mergeable as is.

If there is a zero timeout and MSG_DONTWAIT is available (or the
socket is non-blocking), the poll() call is not necessary, and we can
just call recv() right away.

Before this change:

 poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 0 (Timeout)
 poll([{fd=4, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=4, revents=POLLIN}])
 recvfrom(4, "HTTP/1.1 301 Moved Permanently\r\n"..., 8192, MSG_DONTWAIT, NULL, NULL) = 348
 poll([{fd=4, events=POLLIN|POLLPRI|POLLERR|POLLHUP}], 1, 0) = 1 ([{fd=4, revents=POLLIN}])
 recvfrom(4, "", 1, MSG_PEEK, NULL, NULL) = 0

After this change:

 recvfrom(4, 0x7ffe0cc719a0, 1, MSG_PEEK|MSG_DONTWAIT, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
 poll([{fd=4, events=POLLIN|POLLERR|POLLHUP}], 1, 60000) = 1 ([{fd=4, revents=POLLIN}])
 recvfrom(4, "HTTP/1.1 301 Moved Permanently\r\n"..., 8192, MSG_DONTWAIT, NULL, NULL) = 348
 recvfrom(4, "", 1, MSG_PEEK|MSG_DONTWAIT, NULL, NULL) = 0

The first poll() is replaced by recvfrom(), and the third poll() is
omitted completely.
@MaxKellermann
Copy link
Contributor Author

I've added the same optimization to ext/openssl as suggested by @twose, but only if !ssl_active, because I don't know for sure if the OpenSSL APIs will do non-blocking recv() properly. There may be a way, but that's an optimization for another day.

@MaxKellermann
Copy link
Contributor Author

MACOS_DEBUG_NTS build failure unrelated to this PR.

@cmb69
Copy link
Member

cmb69 commented Jun 18, 2022

The Windows build fails, because MSG_DONTWAIT is not defined there. Not sure how to solve that best; maybe temporarily define it to 0; or maybe introduce platform specifc code (#ifdef PHP_WIN32).

@MaxKellermann
Copy link
Contributor Author

The Windows build fails, because MSG_DONTWAIT is not defined there. Not sure how to solve that best; maybe temporarily define it to 0; or maybe introduce platform specifc code (#ifdef PHP_WIN32).

There's a fallback definition in xp_socket.c but not in xp_ssl.c:

#ifndef MSG_DONTWAIT
# define MSG_DONTWAIT 0
#endif

Will add it.

@MaxKellermann
Copy link
Contributor Author

Interestingly, xp_socket.c has a fallback definition for both MSG_DONTWAIT and MSG_PEEK and uses both; on the other hand, xp_ssl.c does already use MSG_PEEK but has no fallback definition. That MSG_PEEK fallback appears to be not necessary at all.

If there is a zero timeout and MSG_DONTWAIT is available (or the
socket is non-blocking), the poll() call is not necessary, and we can
just call recv() right away.
@MaxKellermann MaxKellermann deleted the msg_dontwait branch June 19, 2022 04:09
@bukka
Copy link
Member

bukka commented Jun 19, 2022

@MaxKellermann I had a proper look at this. All looks reasonable to me. I think there's a possible optimization in xp_ssl that I just did at #8829 . Please take a look and let me know in case there's a specific reason why you haven't done it in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants