Skip to content

Commit 13dd2a4

Browse files
author
taras
committed
Optimize ssl performance by invoke SSLProtocol.get_buffer directly
1 parent 79d5dcd commit 13dd2a4

File tree

3 files changed

+39
-15
lines changed

3 files changed

+39
-15
lines changed

uvloop/handles/stream.pyx

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,10 @@ cdef class UVStream(UVBaseTransport):
232232

233233
UVBaseTransport._set_protocol(self, protocol)
234234

235-
if (hasattr(protocol, 'get_buffer') and
235+
if isinstance(protocol, SSLProtocol):
236+
self._protocol_buffer_updated = protocol.buffer_updated
237+
self.__buffered = 1
238+
elif (hasattr(protocol, 'get_buffer') and
236239
not isinstance(protocol, aio_Protocol)):
237240
try:
238241
self._protocol_get_buffer = protocol.get_buffer
@@ -924,9 +927,21 @@ cdef void __uv_stream_buffered_alloc(
924927
"UVStream alloc buffer callback") == 0:
925928
return
926929

930+
cdef UVStream sc = <UVStream>stream.data
931+
932+
# Fast pass for our own SSLProtocol
933+
# avoid python calls, memoryviews, etc
934+
if isinstance(sc._protocol, SSLProtocol):
935+
try:
936+
(<SSLProtocol>sc._protocol).get_buffer_c(
937+
suggested_size, &uvbuf.base, &uvbuf.len)
938+
return
939+
except BaseException as exc:
940+
uvbuf.len = 0
941+
uvbuf.base = NULL
942+
return
943+
927944
cdef:
928-
UVStream sc = <UVStream>stream.data
929-
Loop loop = sc._loop
930945
Py_buffer* pybuf = &sc._read_pybuf
931946
int got_buf = 0
932947

@@ -987,7 +1002,7 @@ cdef void __uv_stream_buffered_on_read(
9871002
return
9881003

9891004
try:
990-
if nread > 0 and not sc._read_pybuf_acquired:
1005+
if nread > 0 and not isinstance(sc._protocol, SSLProtocol) and not sc._read_pybuf_acquired:
9911006
# From libuv docs:
9921007
# nread is > 0 if there is data available or < 0 on error. When
9931008
# we’ve reached EOF, nread will be set to UV_EOF. When
@@ -1015,5 +1030,6 @@ cdef void __uv_stream_buffered_on_read(
10151030

10161031
sc._fatal_error(exc, False)
10171032
finally:
1018-
sc._read_pybuf_acquired = 0
1019-
PyBuffer_Release(pybuf)
1033+
if sc._read_pybuf_acquired:
1034+
sc._read_pybuf_acquired = 0
1035+
PyBuffer_Release(pybuf)

uvloop/sslproto.pxd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ cdef class SSLProtocol:
5959
object _outgoing_read
6060
char* _ssl_buffer
6161
size_t _ssl_buffer_len
62-
object _ssl_buffer_view
6362
SSLProtocolState _state
6463
size_t _conn_lost
6564
AppProtocolState _app_state
@@ -84,6 +83,8 @@ cdef class SSLProtocol:
8483
object _handshake_timeout_handle
8584
object _shutdown_timeout_handle
8685

86+
cdef inline get_buffer_c(self, size_t n, char** buf, size_t* buf_size)
87+
8788
cdef _set_app_protocol(self, app_protocol)
8889
cdef _wakeup_waiter(self, exc=*)
8990
cdef _get_extra_info(self, name, default=*)

uvloop/sslproto.pyx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,8 @@ cdef class SSLProtocol:
204204
self._ssl_buffer = <char*>PyMem_RawMalloc(self._ssl_buffer_len)
205205
if not self._ssl_buffer:
206206
raise MemoryError()
207-
self._ssl_buffer_view = PyMemoryView_FromMemory(
208-
self._ssl_buffer, self._ssl_buffer_len, PyBUF_WRITE)
209207

210208
def __dealloc__(self):
211-
self._ssl_buffer_view = None
212209
PyMem_RawFree(self._ssl_buffer)
213210
self._ssl_buffer = NULL
214211
self._ssl_buffer_len = 0
@@ -358,7 +355,7 @@ cdef class SSLProtocol:
358355
self._handshake_timeout_handle.cancel()
359356
self._handshake_timeout_handle = None
360357

361-
def get_buffer(self, n):
358+
cdef get_buffer_c(self, size_t n, char** buf, size_t* buf_size):
362359
cdef size_t want = n
363360
if want > SSL_READ_MAX_SIZE:
364361
want = SSL_READ_MAX_SIZE
@@ -367,11 +364,21 @@ cdef class SSLProtocol:
367364
if not self._ssl_buffer:
368365
raise MemoryError()
369366
self._ssl_buffer_len = want
370-
self._ssl_buffer_view = PyMemoryView_FromMemory(
371-
self._ssl_buffer, want, PyBUF_WRITE)
372-
return self._ssl_buffer_view
373367

374-
def buffer_updated(self, nbytes):
368+
buf[0] = self._ssl_buffer
369+
buf_size[0] = self._ssl_buffer_len
370+
371+
def get_buffer(self, size_t n):
372+
# This pure python call is still used by some very peculiar test cases
373+
374+
cdef:
375+
char* buf
376+
size_t buf_size
377+
378+
self.get_buffer_c(n, &buf, &buf_size)
379+
return PyMemoryView_FromMemory(buf, buf_size, PyBUF_WRITE)
380+
381+
def buffer_updated(self, size_t nbytes):
375382
self._incoming_write(PyMemoryView_FromMemory(
376383
self._ssl_buffer, nbytes, PyBUF_WRITE))
377384

0 commit comments

Comments
 (0)