-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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
bpo-32221: makeipaddr: remove interface part + speedup #4724
Conversation
Would you add a test for new functionality? |
@asvetlov done |
Doc/library/socket.rst
Outdated
@@ -77,6 +77,11 @@ created. Socket addresses are represented as follows: | |||
backward compatibility. Note, however, omission of *scopeid* can cause problems | |||
in manipulating scoped IPv6 addresses. | |||
|
|||
.. versionchanged:: 3.6 |
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.
I don't know which version to write 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.
3.6 is in bugfix mode.
The PR should land into 3.7 only IMHO
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 3.7 only.
Please add |
Is there anybody who can make a review ? |
@asvetlov could you please speedup review of this PR somehow ? |
Original (not patched) python:
On patched version, times for both cases should be the same exactly (i.e. 532 ns) |
Modules/socketmodule.c
Outdated
{ | ||
char buf[NI_MAXHOST]; | ||
int error; | ||
char buf[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN) + 1]; |
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.
Use Py_MAX
Modules/socketmodule.c
Outdated
ptr = &((const struct sockaddr_in6*) addr)->sin6_addr; | ||
break; | ||
default: | ||
abort(); |
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.
I actually want an error set and NULL returned 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.
this is impossible to trigger. It's part of C logic, so no exception can be imagined here. It should be like assert(0)
. Or, even, I can remove default:
branch.
This function is called (and should be) only from AF_INET and AF_INET6 branches from upper code.
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.
Then rewrite this to:
if (family == AF_INET) {
...
}
else {
assert(family == AF_INET6);
...
}
Overall looks fine, please fix the couple of things I left my comments on. |
I have found two bugs in my patch:
Since it hard to code Please have a look. |
Modules/socketmodule.c
Outdated
@@ -1097,23 +1097,35 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int | |||
|
|||
|
|||
/* Create a string object representing an IP address. |
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.
Remove this comment, it's outdated.
Add a comment to make_ipv4_addr
"Convert IPv4 sockaddr to a Python str." Same for make_ipv6_addr
.
I like it. |
@1st1 done |
After my patch:
|
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.
Second iteration looks much better!
@1st1 please review again |
@asvetlov the pr looks fine, but please don't merge it, I'm still not sure if it's backwards compatible "enough", and I don't have time for research right now. |
Ok, let's wait for a while |
@1st1 ping |
How can I speed up merging ? |
set_gaierror(error); | ||
char buf[INET_ADDRSTRLEN + 1]; | ||
if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) == NULL) { | ||
PyErr_SetFromErrno(PyExc_OSError); | ||
return NULL; | ||
} | ||
return PyUnicode_FromString(buf); |
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.
Will PyUnicode_DecodeASCII
be faster ? Is it better to use it 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.
I think yes.
@@ -5911,14 +5916,11 @@ socket_inet_ntop(PyObject *self, PyObject *args) | |||
Py_buffer packed_ip; | |||
const char* retval; | |||
#ifdef ENABLE_IPV6 | |||
char ip[Py_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; |
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.
It is not related to my issue, but this is a cosmetic fix.
Regarding meltdown vulnerability: this patch will speed up even more! |
Because 3 syscalls per addr serialisation eliminated. |
The pr is good for me but @1st1 explicitly asked for additional time. |
I'll take a look this week. |
@1st1 ping |
i'll take a look today/tomorrow. |
In the meanwhile, can you explain why this patch is important? and what is the speedup? |
@1st1 This patch speeds up all functions that return 4-item tuple with address. Old code uses wrong function to convert binary representation of IPv6 address to textual one. For non-scoped addresses result is exactly the same. But for scoped addresses this wrong function does useless interface index to name resolution. This slows down for example |
…honGH-4724)" This reverts commit 47c0b1f.
https://bugs.python.org/issue32221
recvfrom
from multicast socket is painfull slow. In fact, it returns sender address in form:('fe80::941f:f6ff:fe04:c560%qwe', 42133, 0, 78)
which is superfluous, since interface-name part (
%qwe
) is not actually used. Actually, scopeid (78
) signify interface/scope/zone_id. This tuple can be used for.sendto()
either with this interface-name-part or without.The problem is in the performance. For each
socket.recvrfom()
,libc.getnameinfo()
internally converts interface index to interface name using three syscalls, i.e.socket(), getsockopt()?, close()
, which slows down receiving (I have not measured result, but see additional syscalls instrace
).In order to convert from tuple to string-based full address one may use
socket.getnameinfo()
:As you can see, initial interface is ignored (but without my patch it is also validated uselessly):