Description
- uvloop version: 0.11.3 and 0.12.0rc2
- Python version: 3.7
- Platform: Linux
I have been trying to optimize the performance of aiortc
, an asyncio-based WebRTC implementation. aiortc
uses aioice
(an Interactive Connectivity Establishment library) for its network access. Using uvloop
provides some performance improvement, but not as much as I had hoped.
During my optimization work I noticed that when called with an address, UDPTransport.sendto spends a noticeable amount of time calling into Python code, looking up the socket's family
and type
properties. Looking at the code, this corresponds to validation checks on the destination address which are run on every single packet (which involves a call to getaddrinfo whose result is ultimately discarded):
Line 146 in df0e543
I am aware that specifying a remote address when calling create_datagram_endpoint
would probably work around this issue, but in the case of ICE this is not practical as the remote party may have multiple addresses, which are not known in advance and may change over time.
To assess the impact of the validation code I tried a basic patch which stores the last validated address and skips the validation if sendto
is called for the same address again. I then ran the following test:
import asyncio
import socket
import time
import uvloop
class DummyProtocol(asyncio.DatagramProtocol):
pass
async def run(loop):
addr = ('127.0.0.1', 1234)
data = b'M' * 1500
transport, protocol = await loop.create_datagram_endpoint(
lambda: DummyProtocol(),
family=socket.AF_INET)
start = time.process_time()
for i in range(1000000):
transport.sendto(data, addr)
print('elapsed', time.process_time() - start)
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.get_event_loop()
loop.run_until_complete(run(loop))
On my laptop the results of sending out a million packets:
- without the patch: 7.8s
- with the patch: 3.0s
Questions:
- do we need the validation code at all?
- if we do, would you consider a patch which caches the last successfully validated address and skips the validation if
sendto
is called again with the same address? - alternatively, could we at the very least store the socket type and family to avoid the call into Python to fetch these two properties?