Skip to content

Conversation

@tarasko
Copy link
Contributor

@tarasko tarasko commented Jan 31, 2026

Calling SSLObject.read(SSL_READ_MAX_SIZE) has a big performance issue. Internally it first allocates bytes object of SSL_READ_MAX_SIZE bytes, then reads into it, then shrinks it down to the actual number of bytes read.
Given that SSL_READ_MAX_SIZE = 256 * 1024,
we allocate 256K every time we call SSLObject.read from SSLProtocol._do_read__copied.
I've fixed it by allocating our own buffer and passing it to SSLObject.read.

I have attached perf output before and after this change.

Other changes:

  • fix cython warning: uvloop/handles/pipe.pyx:159:4: Overriding a c(p)def method with a def method
  • Use bytearray instead of raw memory allocations for the buffer that is provided to UVStream for simplicity
  • Reduce default size of read buffer from 256K to 64K. 64K is actually a default suggested size from libuv. Read buffer can still grow up to 256K if libuv wants more memory.
  • Cache _app_protocol.data_received for performance
  • Cache SSL_READ_MAX_SIZE as a python object, so that cython don't have to create a new object every time we call SSLObject.read.
  • It is ok to call SSLObject.read and pass a buffer that is smaller than the len argument. SSLObject.read will correctly read up to the buffer size, not up to len argument

Before:

30.79%     0.14%            14  python          _ssl.cpython-313-x86_64-linux-gnu.so                  [.] _ssl__SSLSocket_read
        |          
         --30.65%--_ssl__SSLSocket_read
                   |          
                   |--16.98%--PyBytes_FromStringAndSize
                   |          |          
                   |           --13.91%--PyObject_Malloc
                   |                     |          
                   |                      --13.87%--malloc
                   |                                |          
                   |                                 --13.79%--_int_malloc
                   |                                           |          
                   |                                            --13.48%--sysmalloc_mmap.isra.0
                   |                                                      |          
                   |                                                       --7.11%--__mmap
                   |          
                   |--8.66%--_PyBytes_Resize
                   |          |          
                   |           --8.50%--realloc
                   |                     |          
                   |                      --8.43%--__GI___mremap
                   |          
                    --4.37%--SSL_read_ex
                              |          
                               --4.19%--ssl3_read_internal
                                         |          
                                          --4.18%--ssl3_read_bytes
                                                    |          
                                                     --3.24%--ssl3_get_record
                                                               |          
                                                                --2.24%--tls1_enc
                                                                          |          
                                                                          |--1.12%--EVP_DecryptUpdate
                                                                          |          ossl_gcm_stream_update
                                                                          |          |          
                                                                          |           --1.02%--gcm_cipher_internal
                                                                          |                     |          
                                                                          |                      --0.81%--ossl_gcm_one_shot
                                                                          |                                |          
                                                                          |                                 --0.67%--generic_aes_gcm_cipher_update
                                                                          |          
                                                                           --0.78%--EVP_CIPHER_CTX_ctrl

After:

 8.47%     0.21%            19  python          _ssl.cpython-313-x86_64-linux-gnu.so                  [.] _ssl__SSLSocket_read
        |          
         --8.25%--_ssl__SSLSocket_read
                   |          
                   |--6.93%--SSL_read_ex
                   |          |          
                   |           --6.77%--ssl3_read_internal
                   |                     |          
                   |                      --6.68%--ssl3_read_bytes
                   |                                |          
                   |                                |--5.28%--ssl3_get_record
                   |                                |          |          
                   |                                |           --3.81%--tls1_enc
                   |                                |                     |          
                   |                                |                     |--1.92%--EVP_DecryptUpdate
                   |                                |                     |          ossl_gcm_stream_update
                   |                                |                     |          |          
                   |                                |                     |           --1.91%--gcm_cipher_internal
                   |                                |                     |                     |          
                   |                                |                     |                      --1.56%--ossl_gcm_one_shot
                   |                                |                     |                                |          
                   |                                |                     |                                 --1.26%--generic_aes_gcm_cipher_update
                   |                                |                     |                                           |          
                   |                                |                     |                                            --0.50%--CRYPTO_gcm128_decrypt_ctr32
                   |                                |                     |          
                   |                                |                      --1.24%--EVP_CIPHER_CTX_ctrl
                   |                                |          
                   |                                 --0.59%--ssl3_setup_read_buffer
                   |          
                    --0.69%--PyArg_ParseTuple
                              |          
                               --0.60%--vgetargs1_impl

@tarasko tarasko changed the title Optimize non buffered reads in SSLProtocol Optimize non buffered protocol reads in SSLProtocol Jan 31, 2026
@tarasko
Copy link
Contributor Author

tarasko commented Feb 1, 2026

Hi @fantix, would you mind taking a look at this PR as well? It significantly improves SSL read performance in case of non-buffered user protocol

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant