classification
Title: asyncio debug mode is very slow
Type: behavior Stage: resolved
Components: asyncio, Library (Lib) Versions: Python 3.7, Python 3.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: asvetlov, giampaolo.rodola, pitrou, vstinner, yselivanov
Priority: normal Keywords: patch

Created on 2017-11-07 13:15 by pitrou, last changed 2017-11-08 13:45 by pitrou. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 4314 merged pitrou, 2017-11-07 13:21
PR 4322 merged pitrou, 2017-11-07 16:27
Messages (13)
msg305752 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-07 13:15
Each time a new future, handle or task is created, asyncio with debug mode enabled will parse the whole call stack and create a StackSummary object for it.  Imagine a recursive coroutine: with N nested calls, you get O(N**2) performance.

Ideally debug mode wouldn't slow things too much, at least for development and testing setups.
msg305757 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-07 13:32
If this is accepted on the principle, it would be great to also patch 3.6.
msg305777 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-07 16:23
New changeset 921e9432a1461bbf312c9c6dcc2b916be6c05fa0 by Antoine Pitrou in branch 'master':
bpo-31970: Reduce performance overhead of asyncio debug mode. (#4314)
https://github.com/python/cpython/commit/921e9432a1461bbf312c9c6dcc2b916be6c05fa0
msg305780 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-07 16:50
New changeset d8d218ffda6b7569625ff9edadbbc9a2b1055e32 by Antoine Pitrou in branch '3.6':
[3.6] bpo-31970: Reduce performance overhead of asyncio debug mode. (GH-4314) (#4322)
https://github.com/python/cpython/commit/d8d218ffda6b7569625ff9edadbbc9a2b1055e32
msg305781 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-07 16:51
Thank you for the quick reviews!
msg305784 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2017-11-07 16:55
Thank you for helping with asyncio!  I'll try to get to that transport performance issues you found sometime this week.  I've a few ideas how to add 0-copy support to protocols.
msg305834 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-08 13:12
> I've a few ideas how to add 0-copy support to protocols.

I'd be interesting to hear about them.  The main challenge IMHO is to find a way to allow a readinto()-like functionality.
msg305836 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2017-11-08 13:40
>> I've a few ideas how to add 0-copy support to protocols.

> I'd be interesting to hear about them.  The main challenge IMHO is to find a way to allow a readinto()-like functionality.

Exposing sendfile() should be straightforward. I started implementing it years ago but I gave up pretty soon because asyncio had no solid test framework for testing an actual data transfer between two sockets and that basically represented a blocker. Basically back then all recv() / send() related tests were mocks. Not sure about the current situation but if that has changed I would be happy to contribute a PR (I was the one who contributed socket.sendfile()).

As for a readinto()-like functionality: the only thing I'm aware of is splice() syscall but it's Linux only. It must be noted that also sendfile() is UNIX only. Windows achieve the same via TransmitFile.
msg305837 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-08 13:42
Le 08/11/2017 à 14:40, Giampaolo Rodola' a écrit :
> Exposing sendfile() should be straightforward.

sendfile() is not useful for data that's read from (or written to) memory.

> As for a readinto()-like functionality: the only thing I'm aware of is splice() syscall but it's Linux only.

This is not the abstraction level we are talking about.  The problem is
the Protocol API imposes copies by default (data_received() gives you an
arbitrarily-sized bytes object that doesn't match how your protocol
chunks data).
msg305838 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2017-11-08 13:44
Sorry. It looks like I completely misunderstood. =)
msg305839 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2017-11-08 13:44
> The problem is the Protocol API imposes copies by default (...)

IMHO performance is a good motivation to enhance the asyncio API ;-) The tricky part is to keep the backward compatibility.
msg305840 - (view) Author: Yury Selivanov (yselivanov) * (Python committer) Date: 2017-11-08 13:44
> IMHO performance is a good motivation to enhance the asyncio API ;-) The tricky part is to keep the backward compatibility.

Let's stop the discussion in this ticket :)
msg305841 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-11-08 13:45
In any case, I think this is better discussed on async-sig (where I already started a discussion thread some weeks ago -- see """APIs for high-bandwidth large I/O?""").
History
Date User Action Args
2017-11-08 13:45:41pitrousetmessages: + msg305841
2017-11-08 13:44:56yselivanovsetmessages: + msg305840
2017-11-08 13:44:11vstinnersetmessages: + msg305839
2017-11-08 13:44:04giampaolo.rodolasetmessages: + msg305838
2017-11-08 13:42:29pitrousetmessages: + msg305837
2017-11-08 13:40:21giampaolo.rodolasetmessages: + msg305836
2017-11-08 13:12:29pitrousetmessages: + msg305834
2017-11-07 16:55:33yselivanovsetmessages: + msg305784
2017-11-07 16:51:22pitrousetstatus: open -> closed
resolution: fixed
messages: + msg305781

stage: patch review -> resolved
2017-11-07 16:50:52pitrousetmessages: + msg305780
2017-11-07 16:27:21pitrousetpull_requests: + pull_request4280
2017-11-07 16:23:33pitrousetmessages: + msg305777
2017-11-07 13:32:01pitrousetmessages: + msg305757
2017-11-07 13:29:53pitrousetnosy: + asvetlov
2017-11-07 13:21:46pitrousetkeywords: + patch
stage: patch review
pull_requests: + pull_request4273
2017-11-07 13:15:04pitroucreate