File tree Expand file tree Collapse file tree
Misc/NEWS.d/next/Core_and_Builtins Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -69,10 +69,25 @@ struct _qsbr_thread_state {
6969 struct _qsbr_thread_state * freelist_next ;
7070};
7171
72+ // Size used to pad and align the per-thread QSBR states (and the end of
73+ // _PyThreadStateImpl) to avoid false sharing. Apple Silicon has 128-byte cache
74+ // lines:
75+ // $ sysctl -a hw | grep cachelinesize
76+ // hw.cachelinesize: 128
77+ // With 64-byte padding the `seq` fields of two threads share a line and the
78+ // stores in _Py_qsbr_quiescent_state() contend on every eval loop back-edge.
79+ // Use 128 bytes for all AArch64 targets: on cores with 64-byte lines this only
80+ // costs 64 bytes per thread.
81+ #if defined(__aarch64__ ) || defined(_M_ARM64 )
82+ # define _Py_QSBR_CACHE_LINE_SIZE 128
83+ #else
84+ # define _Py_QSBR_CACHE_LINE_SIZE 64
85+ #endif
86+
7287// Padding to avoid false sharing
7388struct _qsbr_pad {
7489 struct _qsbr_thread_state qsbr ;
75- char __padding [64 - sizeof (struct _qsbr_thread_state )];
90+ char __padding [_Py_QSBR_CACHE_LINE_SIZE - sizeof (struct _qsbr_thread_state )];
7691};
7792
7893// Per-interpreter state
@@ -83,7 +98,7 @@ struct _qsbr_shared {
8398 // Minimum observed read sequence of all QSBR thread states
8499 uint64_t rd_seq ;
85100
86- // Array of QSBR thread states (aligned to 64 bytes ).
101+ // Array of QSBR thread states (aligned to _Py_QSBR_CACHE_LINE_SIZE ).
87102 struct _qsbr_pad * array ;
88103 void * array_raw ; // raw allocation pointer (for free)
89104 Py_ssize_t size ;
Original file line number Diff line number Diff line change @@ -109,7 +109,7 @@ typedef struct _PyThreadStateImpl {
109109#ifdef Py_GIL_DISABLED
110110 // gh-144438: Add padding to ensure that the fields above don't share a
111111 // cache line with other allocations.
112- char __padding [64 ];
112+ char __padding [_Py_QSBR_CACHE_LINE_SIZE ];
113113#endif
114114} _PyThreadStateImpl ;
115115
Original file line number Diff line number Diff line change 1+ Fix false sharing between the per-thread QSBR states in the
2+ :term: `free-threaded build ` on AArch64 CPUs with 128-byte cache lines, such
3+ as Apple Silicon. CPU-bound threads that share no objects now scale like
4+ processes there.
Original file line number Diff line number Diff line change @@ -85,10 +85,10 @@ grow_thread_array(struct _qsbr_shared *shared)
8585 new_size = MIN_ARRAY_SIZE ;
8686 }
8787
88- // Overallocate by 63 bytes so we can align to a 64-byte boundary.
88+ // Overallocate so we can align to a cache line boundary.
8989 // This avoids potential false sharing between the first entry and other
9090 // allocations.
91- size_t alignment = 64 ;
91+ size_t alignment = _Py_QSBR_CACHE_LINE_SIZE ;
9292 size_t alloc_size = (size_t )new_size * sizeof (struct _qsbr_pad ) + alignment - 1 ;
9393 void * raw = PyMem_RawCalloc (1 , alloc_size );
9494 if (raw == NULL ) {
You can’t perform that action at this time.
0 commit comments