You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
6.4 KiB
239 lines
6.4 KiB
/* |
|
* Copyright 2008-2012 NVIDIA Corporation |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
/*! \file thrust/system/cuda/experimental/pinned_allocator.h |
|
* \brief An allocator which creates new elements in "pinned" memory with \p cudaMallocHost |
|
*/ |
|
|
|
#pragma once |
|
|
|
#include <thrust/detail/config.h> |
|
#include <thrust/system/cuda/detail/guarded_cuda_runtime_api.h> |
|
#include <stdexcept> |
|
#include <limits> |
|
#include <string> |
|
#include <thrust/system/system_error.h> |
|
#include <thrust/system/cuda/error.h> |
|
|
|
namespace thrust |
|
{ |
|
|
|
namespace system |
|
{ |
|
|
|
namespace cuda |
|
{ |
|
|
|
namespace experimental |
|
{ |
|
|
|
/*! \addtogroup memory_management Memory Management |
|
* \addtogroup memory_management_classes |
|
* \ingroup memory_management |
|
* \{ |
|
*/ |
|
|
|
/*! \p pinned_allocator is a CUDA-specific host memory allocator |
|
* that employs \c cudaMallocHost for allocation. |
|
* |
|
* \see http://www.sgi.com/tech/stl/Allocators.html |
|
*/ |
|
template<typename T> class pinned_allocator; |
|
|
|
template<> |
|
class pinned_allocator<void> |
|
{ |
|
public: |
|
typedef void value_type; |
|
typedef void * pointer; |
|
typedef const void * const_pointer; |
|
typedef std::size_t size_type; |
|
typedef std::ptrdiff_t difference_type; |
|
|
|
// convert a pinned_allocator<void> to pinned_allocator<U> |
|
template<typename U> |
|
struct rebind |
|
{ |
|
typedef pinned_allocator<U> other; |
|
}; // end rebind |
|
}; // end pinned_allocator |
|
|
|
|
|
template<typename T> |
|
class pinned_allocator |
|
{ |
|
public: |
|
typedef T value_type; |
|
typedef T* pointer; |
|
typedef const T* const_pointer; |
|
typedef T& reference; |
|
typedef const T& const_reference; |
|
typedef std::size_t size_type; |
|
typedef std::ptrdiff_t difference_type; |
|
|
|
// convert a pinned_allocator<T> to pinned_allocator<U> |
|
template<typename U> |
|
struct rebind |
|
{ |
|
typedef pinned_allocator<U> other; |
|
}; // end rebind |
|
|
|
/*! \p pinned_allocator's null constructor does nothing. |
|
*/ |
|
__host__ __device__ |
|
inline pinned_allocator() {} |
|
|
|
/*! \p pinned_allocator's null destructor does nothing. |
|
*/ |
|
__host__ __device__ |
|
inline ~pinned_allocator() {} |
|
|
|
/*! \p pinned_allocator's copy constructor does nothing. |
|
*/ |
|
__host__ __device__ |
|
inline pinned_allocator(pinned_allocator const &) {} |
|
|
|
/*! This version of \p pinned_allocator's copy constructor |
|
* is templated on the \c value_type of the \p pinned_allocator |
|
* to copy from. It is provided merely for convenience; it |
|
* does nothing. |
|
*/ |
|
template<typename U> |
|
__host__ __device__ |
|
inline pinned_allocator(pinned_allocator<U> const &) {} |
|
|
|
/*! This method returns the address of a \c reference of |
|
* interest. |
|
* |
|
* \p r The \c reference of interest. |
|
* \return \c r's address. |
|
*/ |
|
__host__ __device__ |
|
inline pointer address(reference r) { return &r; } |
|
|
|
/*! This method returns the address of a \c const_reference |
|
* of interest. |
|
* |
|
* \p r The \c const_reference of interest. |
|
* \return \c r's address. |
|
*/ |
|
__host__ __device__ |
|
inline const_pointer address(const_reference r) { return &r; } |
|
|
|
/*! This method allocates storage for objects in pinned host |
|
* memory. |
|
* |
|
* \p cnt The number of objects to allocate. |
|
* \return a \c pointer to the newly allocated objects. |
|
* \note This method does not invoke \p value_type's constructor. |
|
* It is the responsibility of the caller to initialize the |
|
* objects at the returned \c pointer. |
|
*/ |
|
__host__ |
|
inline pointer allocate(size_type cnt, |
|
const_pointer = 0) |
|
{ |
|
if(cnt > this->max_size()) |
|
{ |
|
throw std::bad_alloc(); |
|
} // end if |
|
|
|
pointer result(0); |
|
cudaError_t error = cudaMallocHost(reinterpret_cast<void**>(&result), cnt * sizeof(value_type)); |
|
|
|
if(error) |
|
{ |
|
throw std::bad_alloc(); |
|
} // end if |
|
|
|
return result; |
|
} // end allocate() |
|
|
|
/*! This method deallocates pinned host memory previously allocated |
|
* with this \c pinned_allocator. |
|
* |
|
* \p p A \c pointer to the previously allocated memory. |
|
* \p cnt The number of objects previously allocated at |
|
* \p p. |
|
* \note This method does not invoke \p value_type's destructor. |
|
* It is the responsibility of the caller to destroy |
|
* the objects stored at \p p. |
|
*/ |
|
__host__ |
|
inline void deallocate(pointer p, size_type cnt) |
|
{ |
|
cudaError_t error = cudaFreeHost(p); |
|
|
|
if(error) |
|
{ |
|
throw thrust::system_error(error, thrust::cuda_category()); |
|
} // end if |
|
} // end deallocate() |
|
|
|
/*! This method returns the maximum size of the \c cnt parameter |
|
* accepted by the \p allocate() method. |
|
* |
|
* \return The maximum number of objects that may be allocated |
|
* by a single call to \p allocate(). |
|
*/ |
|
inline size_type max_size() const |
|
{ |
|
return (std::numeric_limits<size_type>::max)() / sizeof(T); |
|
} // end max_size() |
|
|
|
/*! This method tests this \p pinned_allocator for equality to |
|
* another. |
|
* |
|
* \param x The other \p pinned_allocator of interest. |
|
* \return This method always returns \c true. |
|
*/ |
|
__host__ __device__ |
|
inline bool operator==(pinned_allocator const& x) { return true; } |
|
|
|
/*! This method tests this \p pinned_allocator for inequality |
|
* to another. |
|
* |
|
* \param x The other \p pinned_allocator of interest. |
|
* \return This method always returns \c false. |
|
*/ |
|
__host__ __device__ |
|
inline bool operator!=(pinned_allocator const &x) { return !operator==(x); } |
|
}; // end pinned_allocator |
|
|
|
/*! \} |
|
*/ |
|
|
|
} // end experimental |
|
|
|
} // end cuda |
|
|
|
} // end system |
|
|
|
// alias cuda's members at top-level |
|
namespace cuda |
|
{ |
|
|
|
namespace experimental |
|
{ |
|
|
|
using thrust::system::cuda::experimental::pinned_allocator; |
|
|
|
} // end experimental |
|
|
|
} // end cuda |
|
|
|
} // end thrust |
|
|
|
|