From c8fc56dca7d42025fbe897402335df4870bf8831 Mon Sep 17 00:00:00 2001 From: John Kirkham <jakirkham@gmail.com> Date: Wed, 8 Sep 2021 15:31:57 -0700 Subject: [PATCH 1/5] Queue write only after processing all buffers Allows `writelines` to leverage vectorized IO within uvloop to send multiple buffers in one `sendmsg` call. --- uvloop/handles/stream.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 4757ce7a..67e5e98b 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -446,7 +446,6 @@ cdef class UVStream(UVBaseTransport): return self._maybe_pause_protocol() - self._loop._queue_write(self) cdef inline _exec_write(self): cdef: @@ -680,6 +679,7 @@ cdef class UVStream(UVBaseTransport): self._conn_lost += 1 return self._write(buf) + self._loop._queue_write(self) def writelines(self, bufs): self._ensure_alive() @@ -691,6 +691,7 @@ cdef class UVStream(UVBaseTransport): return for buf in bufs: self._write(buf) + self._loop._queue_write(self) def write_eof(self): self._ensure_alive() From a12214acec8f3f9dc99968e3a820265f4861f304 Mon Sep 17 00:00:00 2001 From: John Kirkham <jakirkham@gmail.com> Date: Fri, 17 Sep 2021 13:18:55 -0700 Subject: [PATCH 2/5] Add copyright header --- uvloop/handles/stream.pyx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 67e5e98b..6aa0fa0d 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -1,3 +1,8 @@ +# MIT and Apache 2.0 +# +# Copyright (c) 2021, NVIDIA CORPORATION. + + DEF __PREALLOCED_BUFS = 4 From 4cd84a31e1df924d413a04082b5a04e4476d1c12 Mon Sep 17 00:00:00 2001 From: John Kirkham <jakirkham@gmail.com> Date: Tue, 5 Oct 2021 11:38:50 -0700 Subject: [PATCH 3/5] Drop file copyright and update license copyright --- LICENSE-APACHE | 2 +- LICENSE-MIT | 2 +- uvloop/handles/stream.pyx | 5 ----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/LICENSE-APACHE b/LICENSE-APACHE index a1de698c..5f66d4ee 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -1,4 +1,4 @@ -Copyright (c) 2015-present MagicStack Inc. http://magic.io +Copyright (C) 2016-present the uvloop authors and contributors. Apache License Version 2.0, January 2004 diff --git a/LICENSE-MIT b/LICENSE-MIT index e6b42c6f..40fd0230 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2015-present MagicStack Inc. http://magic.io +Copyright (C) 2016-present the uvloop authors and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 6aa0fa0d..67e5e98b 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -1,8 +1,3 @@ -# MIT and Apache 2.0 -# -# Copyright (c) 2021, NVIDIA CORPORATION. - - DEF __PREALLOCED_BUFS = 4 From 3e2016f6a2009463127a88bd5a5cfdc846ede737 Mon Sep 17 00:00:00 2001 From: Fantix King <fantix.king@gmail.com> Date: Fri, 9 Sep 2022 13:32:34 -0400 Subject: [PATCH 4/5] Buffer all data first before send in writelines() --- uvloop/handles/stream.pxd | 3 ++- uvloop/handles/stream.pyx | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/uvloop/handles/stream.pxd b/uvloop/handles/stream.pxd index 21ac6279..7c0582fa 100644 --- a/uvloop/handles/stream.pxd +++ b/uvloop/handles/stream.pxd @@ -31,7 +31,8 @@ cdef class UVStream(UVBaseTransport): cdef inline __reading_started(self) cdef inline __reading_stopped(self) - cdef inline _write(self, object data) + cdef inline _buffer_write(self, object data) + cdef inline _write(self) cdef inline _try_write(self, object data) cdef _close(self) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 67e5e98b..13dd9af1 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -162,7 +162,7 @@ cdef class _StreamWriteContext: PyObject_GetBuffer( buf, &p_pybufs[py_bufs_len], PyBUF_SIMPLE) except Exception: - # This shouldn't ever happen, as `UVStream._write` + # This shouldn't ever happen, as `UVStream._buffer_write` # casts non-bytes objects to `memoryviews`. ctx.py_bufs_len = py_bufs_len ctx.free_bufs() @@ -407,7 +407,7 @@ cdef class UVStream(UVBaseTransport): return written - cdef inline _write(self, object data): + cdef inline _buffer_write(self, object data): cdef int dlen if not PyBytes_CheckExact(data): @@ -420,6 +420,7 @@ cdef class UVStream(UVBaseTransport): self._buffer_size += dlen self._buffer.append(data) + cdef inline _write(self): if (not self._protocol_paused and (<uv.uv_stream_t*>self._handle).write_queue_size == 0 and self._buffer_size > self._high_water): @@ -443,9 +444,10 @@ cdef class UVStream(UVBaseTransport): # If not all of the data was sent successfully, # we might need to pause the protocol. self._maybe_pause_protocol() - return - self._maybe_pause_protocol() + elif self._buffer_size > 0: + self._maybe_pause_protocol() + self._loop._queue_write(self) cdef inline _exec_write(self): cdef: @@ -678,8 +680,8 @@ cdef class UVStream(UVBaseTransport): if self._conn_lost: self._conn_lost += 1 return - self._write(buf) - self._loop._queue_write(self) + self._buffer_write(buf) + self._write() def writelines(self, bufs): self._ensure_alive() @@ -690,8 +692,8 @@ cdef class UVStream(UVBaseTransport): self._conn_lost += 1 return for buf in bufs: - self._write(buf) - self._loop._queue_write(self) + self._buffer_write(buf) + self._write() def write_eof(self): self._ensure_alive() From bfe9b8000432b6d1b3834cd4c56e57071bc762a1 Mon Sep 17 00:00:00 2001 From: Fantix King <fantix.king@gmail.com> Date: Fri, 9 Sep 2022 16:44:16 -0400 Subject: [PATCH 5/5] CRF: rename and add comments --- uvloop/handles/stream.pxd | 10 ++++++++-- uvloop/handles/stream.pyx | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/uvloop/handles/stream.pxd b/uvloop/handles/stream.pxd index 7c0582fa..da6b8f67 100644 --- a/uvloop/handles/stream.pxd +++ b/uvloop/handles/stream.pxd @@ -21,7 +21,6 @@ cdef class UVStream(UVBaseTransport): cdef inline _init(self, Loop loop, object protocol, Server server, object waiter, object context) - cdef inline _exec_write(self) cdef inline _shutdown(self) cdef inline _accept(self, UVStream server) @@ -31,8 +30,15 @@ cdef class UVStream(UVBaseTransport): cdef inline __reading_started(self) cdef inline __reading_stopped(self) + # The user API firstly calls _buffer_write() to buffer up user data chunks, + # potentially multiple times in writelines(), and then call _start_write() + # to start writing either immediately or in the next iteration. cdef inline _buffer_write(self, object data) - cdef inline _write(self) + cdef inline _start_write(self) + + # _exec_write() is the method that does the actual send, and _try_write() + # is a fast-path used in _exec_write() to send a single chunk. + cdef inline _exec_write(self) cdef inline _try_write(self, object data) cdef _close(self) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 13dd9af1..d1bb4ced 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -420,7 +420,7 @@ cdef class UVStream(UVBaseTransport): self._buffer_size += dlen self._buffer.append(data) - cdef inline _write(self): + cdef inline _start_write(self): if (not self._protocol_paused and (<uv.uv_stream_t*>self._handle).write_queue_size == 0 and self._buffer_size > self._high_water): @@ -681,7 +681,7 @@ cdef class UVStream(UVBaseTransport): self._conn_lost += 1 return self._buffer_write(buf) - self._write() + self._start_write() def writelines(self, bufs): self._ensure_alive() @@ -693,7 +693,7 @@ cdef class UVStream(UVBaseTransport): return for buf in bufs: self._buffer_write(buf) - self._write() + self._start_write() def write_eof(self): self._ensure_alive()