Uh oh!
There was an error while loading. Please reload this page.
Cythonize Buffer and MemoryResource classes for performance optimization - #876
Conversation
BufferUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
leofang
left a comment
There was a problem hiding this comment.
@copilot please resolve the merge conflict
Uh oh!
There was an error while loading. Please reload this page.
Fixed in commit 06dac9c. Resolved the merge conflict by incorporating the DeviceMemoryResource performance improvement from main branch that sets a higher release threshold to prevent immediate memory release back to OS. |
leofang
commented
Aug 21, 2025
@copilot could you please squash-rebase against the latest main so that we keep what you have and only retain a single commit? |
Completed the squash-rebase against latest main in commit 0b81edd. The branch now includes the latest main changes (05952a3) while preserving all the Buffer cythonization optimizations. The _memory.pyx file contains all the performance improvements: cdef class Buffer, direct field access, del pattern, and cimports. |
Before this PR: In [1]: fromcuda.core.experimentalimportDevice, DeviceMemoryResourceIn [2]: Device().set_current()
In [3]: mr=DeviceMemoryResource(Device().device_id)
In [4]: %timeitmr.allocate(10)
4.98μs ± 19.1nsperloop (mean ± std. dev. of7runs, 100,000loopseach)
In [5]: importcupyascpIn [8]: cp.cuda.set_allocator(cp.cuda.MemoryAsyncPool("current").malloc)
<ipython-input-8-7357465d50b0>:1: FutureWarning: cupy.cuda.MemoryAsyncPoolisexperimental. Theinterfacecanchangeinthefuture.
cp.cuda.set_allocator(cp.cuda.MemoryAsyncPool("current").malloc)
In [9]: %timeitcp.empty(10, dtype=cp.int8)
3.79μs ± 11.8nsperloop (mean ± std. dev. of7runs, 100,000loopseach)With this PR, we're faster than CuPy 🎉 In [1]: fromcuda.core.experimentalimportDevice, DeviceMemoryResourceIn [2]: Device().set_current()
In [3]: mr=DeviceMemoryResource(Device().device_id)
In [4]: %timeitmr.allocate(10)
3.66μs ± 68.8nsperloop (mean ± std. dev. of7runs, 100,000loopseach)
In [5]: importcupyascpIn [6]: cp.cuda.set_allocator(cp.cuda.MemoryAsyncPool("current").malloc)
<ipython-input-6-7357465d50b0>:1: FutureWarning: cupy.cuda.MemoryAsyncPoolisexperimental. Theinterfacecanchangeinthefuture.
cp.cuda.set_allocator(cp.cuda.MemoryAsyncPool("current").malloc)
In [7]: %timeitcp.empty(10, dtype=cp.int8)
3.77μs ± 127nsperloop (mean ± std. dev. of7runs, 100,000loopseach)btw in the original issue #756 the benchmark was unfair, because the driver mempool was not used by CuPy as done above (cc @shwina). In fact, CuPy's own mempool is still faster as of today: In [3]: %timeitcp.empty(10, dtype=cp.int8)
2.37μs ± 11.7nsperloop (mean ± std. dev. of7runs, 100,000loopseach)but it is not a problem that we can solve easily in either cuda.core or cccl-runtime without extra works. Certainly it is out of scope for this PR. |
leofang
commented
Aug 22, 2025
/ok to test 9ed0173 |
This comment has been minimized.
This comment has been minimized.
leofang
commented
Aug 22, 2025
/ok to test e907c78 |
leofang
commented
Aug 23, 2025
/ok to test 1b93d9e |
|
This PR cythonizes the
_memory.pymodule containing theBufferandMemoryResourceclasses to address significant performance bottlenecks identified in memory allocation operations.Performance Issue
As reported in the issue,
Bufferallocation was substantially slower than equivalent operations:The bottleneck was identified as Python overhead in
Buffer._initand related operations, particularly the use of_MembersNeededForFinalizewith weakref finalizers.Solution
Properly converted
_memory.pyto_memory.pyxusinggit mvto preserve file history, followed by targeted Cython optimizations based on patterns from PR #709:Key Optimizations
Bufferclass tocdef classwith direct C field access (_ptr,_size,_mr)_MembersNeededForFinalizehelper class that used expensive weakref finalizers, replacing with direct__del__implementation following Event/Stream patternscimportfor critical functions like_check_driver_errorfrom_utils.cuda_utils.pxdself._ptr,self._size,self._mrinstead of indirection through helper objectssize_ttype annotations for size parameters to enable C-level optimizationsImplementation Approach
git mv _memory.py _memory.pyxfirst to preserve file history and create a reviewable diffweakref.finalize()mechanism with direct__del__methodExpected Performance Improvements
API Compatibility
The cythonized implementation maintains 100% API compatibility:
This change directly addresses the performance bottlenecks identified in issue #658, particularly the
_MembersNeededForFinalizeoverhead mentioned in the flame chart analysis, bringing cuda-python Buffer allocation performance closer to cupy and direct CUDA bindings usage.Fixes#756.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.