Repository navigation
performance regression in ssl module under free-threading #140795
Description
Activity
- addedperformancePerformance or resource usagePerformance or resource usage
on Oct 30, 2025 cc @ZeroIntensity as author of #124993
Do you have any fixes in mind? I don't know what we could do to speed this up, especially considering critical sections are already pretty fast for single-threaded code.
- We need to be very careful with adding locking to
ssl. If we add it in the wrong place, we get another Regression in ssl module between 3.13.5 and 3.13.6: reading from a TLS-encrypted connection blocks #137583. - Several OpenSSL calls execute callbacks, which can in turn call Python code.
Critical sections solve both of those problems, but something like
PyMutexdoes not.- We need to be very careful with adding locking to
I am looking at
_ssl._SSLSocket.writewhich is called frequently by asyncio. From #124993 critical section was added on it but that function releases the thread state thereby releasing the critical section while callingSSL_write_ex. Doesn't that defeat the purpose of adding critical section if it gets released anyways? While the critical section is released another thread is free to call_ssl._SSLSocket.writeconcurrently so there is no thread safety.Lines 2800 to 2804 in efc37ba
Py_BEGIN_ALLOW_THREADS; retval = SSL_write_ex(self->ssl, b->buf, (size_t)b->len, &count); err = _PySSL_errno(retval == 0, self->ssl, retval); Py_END_ALLOW_THREADS; _PySSL_FIX_ERRNO; - addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or errorextension-modulesC modules in the Modules dirC modules in the Modules dir
on Oct 30, 2025 The critical section is there to protect races on fields like
self->errthat are modified outside thePy_BEGIN_ALLOW_THREADSblock. I think my initial analysis was wrong on that PR; it's not OpenSSL that's thread-unsafe, it's thesslobjects themselves.The critical section is there to protect races on fields like self->err that are modified outside the Py_BEGIN_ALLOW_THREADS block.
I don't think adding critical section just to protect self->err is correct, the bigger problem is that even with critical section
SSL_write_excan be called concurrently which may mutateself->sslinside openssl.FWIW I don't think these APIs are thread safe even in gil enabled build
I just looked at the code briefly, but it looks to me like we can avoid the
self->errmess with a bit of refactoring (just passerrtoPySSL_SetError)self->exclooks trickierFWIW I don't think these APIs are thread safe even in gil enabled build
They should be, I added tests stressing that in #134724. If functions like
SSL_write_exaren't thread-safe, I really don't think there's any sort of synchronization we can add without getting deadlocks.Oh wait, nevermind, I added tests stressing concurrent use of
SSLContext.- added a commit that references this issue
on Nov 21, 2025 - added 6 commits that reference this issue
on Dec 29, 2025
On free-threading there is a large ~20% performance regression under
asyncio_tcp_sslbenchmark. A large part of slowdown is from #124993 which added critical sections and locks for thread safety however 20% is large slowdown for the important single threaded use-case.Critical sections are slow especially for extensions which are dynamically loaded because accessing thread states is slow and there are multiple function calls even for the fastpath of no contention for acquisition of critical section.
Comparing the assembly of
_ssl_RAND_statusin free-threading vs normal build:Linked PRs