mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-21 05:34:18 +08:00
144 lines
3.9 KiB
C++
144 lines
3.9 KiB
C++
#include <Python.h>
|
|
|
|
#include "THP.h"
|
|
#include "torch/csrc/utils/auto_gil.h"
|
|
|
|
// Adapted from fblualib
|
|
void* ObjectPtrAllocator::malloc(ptrdiff_t size) {
|
|
return allocator->malloc(allocatorContext, size);
|
|
}
|
|
|
|
|
|
void* ObjectPtrAllocator::realloc(void* ptr, ptrdiff_t size) {
|
|
return allocator->realloc(allocatorContext, ptr, size);
|
|
}
|
|
|
|
void ObjectPtrAllocator::free(void* ptr) {
|
|
{
|
|
AutoGIL gil;
|
|
object = nullptr;
|
|
}
|
|
allocator->free(allocatorContext, ptr);
|
|
delete this;
|
|
}
|
|
|
|
void StorageWeakRefAllocator::free(void* ptr) {
|
|
{
|
|
AutoGIL gil;
|
|
PyObject_SetAttrString(object.get(), "cdata", Py_None);
|
|
object = nullptr;
|
|
}
|
|
allocator->free(allocatorContext, ptr);
|
|
delete this;
|
|
}
|
|
|
|
|
|
#ifdef WITH_NUMPY
|
|
/**
|
|
* Note [Numpy memory management]
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
* For efficiency reasons, when a user converts to/from numpy arrays,
|
|
* we want to share the underlying storage. This means that if we
|
|
* turn a Numpy array into a Torch tensor, the Torch tensor must
|
|
* keep the Numpy array alive, and vice versa for conversions in
|
|
* the other direction.
|
|
*
|
|
* A Torch tensor keeps its backing Numpy array alive using the custom allocator
|
|
* THNumpyArrayAllocator (backed by NumpyArrayAllocator), which holds a
|
|
* THPObjectPointer to the Numpy PyArrayObject, and nulls it out upon free.
|
|
* The relevant code is in torch/csrc/generic/Tensor.cpp.
|
|
*
|
|
* A Numpy array keeps its backing Torch tensor alive using the base object
|
|
* <https://docs.scipy.org/doc/numpy-dev/reference/c-api.array.html#c.PyArray_SetBaseObject>
|
|
* field of Numpy, which is Numpy's hook for allowing an external user to
|
|
* manage memory. The relevant code is in
|
|
* torch/csrc/generic/methods/TensorSerialization.cwrap
|
|
*/
|
|
|
|
// See Note [Numpy memory management]
|
|
void* NumpyArrayAllocator::realloc(void* ptr, ptrdiff_t size) {
|
|
throw std::logic_error("NumpyArrayAllocator::realloc() not supported");
|
|
}
|
|
|
|
// See Note [Numpy memory management]
|
|
void NumpyArrayAllocator::free(void* ptr) {
|
|
PyArrayObject *array_ptr = (PyArrayObject*)object.get();
|
|
if (!array_ptr || ptr != PyArray_DATA(array_ptr))
|
|
throw std::logic_error("invalid call to NumpyArrayAllocator::free()");
|
|
{
|
|
AutoGIL gil;
|
|
object = nullptr;
|
|
}
|
|
delete this;
|
|
}
|
|
#endif
|
|
|
|
template<typename T>
|
|
static void * malloc_wrapper(void *ctx, ptrdiff_t size) {
|
|
return ((T*)ctx)->malloc(size);
|
|
}
|
|
|
|
template<typename T>
|
|
static void * realloc_wrapper(void *ctx, void *ptr, ptrdiff_t size) {
|
|
return ((T*)ctx)->realloc(ptr, size);
|
|
}
|
|
|
|
template<typename T>
|
|
static void free_wrapper(void *ctx, void *ptr) {
|
|
((T*)ctx)->free(ptr);
|
|
}
|
|
|
|
THAllocator THObjectPtrAllocator = {
|
|
malloc_wrapper<ObjectPtrAllocator>,
|
|
realloc_wrapper<ObjectPtrAllocator>,
|
|
free_wrapper<ObjectPtrAllocator>,
|
|
};
|
|
|
|
THAllocator THStorageWeakRefAllocator = {
|
|
malloc_wrapper<StorageWeakRefAllocator>,
|
|
realloc_wrapper<StorageWeakRefAllocator>,
|
|
free_wrapper<StorageWeakRefAllocator>,
|
|
};
|
|
|
|
#ifdef WITH_NUMPY
|
|
// See Note [Numpy memory management]
|
|
THAllocator THNumpyArrayAllocator = {
|
|
malloc_wrapper<NumpyArrayAllocator>,
|
|
realloc_wrapper<NumpyArrayAllocator>,
|
|
free_wrapper<NumpyArrayAllocator>,
|
|
};
|
|
#endif
|
|
|
|
#ifdef WITH_CUDA
|
|
cudaError_t CudaStorageWeakRefAllocator::malloc(void** ptr, size_t size, cudaStream_t stream) {
|
|
THError("CudaStorageWeakRefAllocator: malloc not supported");
|
|
return cudaSuccess;
|
|
}
|
|
|
|
cudaError_t CudaStorageWeakRefAllocator::free(void* ptr) {
|
|
{
|
|
AutoGIL gil;
|
|
PyObject_SetAttrString(object.get(), "cdata", Py_None);
|
|
object = nullptr;
|
|
}
|
|
cudaError_t err = allocator->free(allocatorContext, ptr);
|
|
delete this;
|
|
return err;
|
|
}
|
|
|
|
static cudaError_t cuda_malloc_wrapper(void *ctx, void** ptr, size_t size, cudaStream_t stream) {
|
|
return ((CudaStorageWeakRefAllocator*)ctx)->malloc(ptr, size, stream);
|
|
}
|
|
|
|
static cudaError_t cuda_free_wrapper(void *ctx, void *ptr) {
|
|
return ((CudaStorageWeakRefAllocator*)ctx)->free(ptr);
|
|
}
|
|
|
|
THCDeviceAllocator THCStorageWeakRefAllocator = {
|
|
cuda_malloc_wrapper,
|
|
NULL,
|
|
cuda_free_wrapper,
|
|
NULL,
|
|
};
|
|
#endif
|