Skip to content
Snippets Groups Projects
Commit b0f5de89 authored by Jakub Klinkovský's avatar Jakub Klinkovský
Browse files

Added allocator classes

parent 1849adf2
No related branches found
No related tags found
1 merge request!33Allocators
/***************************************************************************
Cuda.h - description
-------------------
begin : Apr 8, 2019
copyright : (C) 2019 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
// Implemented by: Jakub Klinkovsky
#pragma once
#include <TNL/Devices/Cuda.h>
namespace TNL {
namespace Allocators {
/**
* \brief Allocator for the CUDA device memory space.
*
* The allocation is done using the `cudaMalloc` function and the deallocation
* is done using the `cudaFree` function.
*/
template< class T >
struct Cuda
{
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
Cuda() = default;
Cuda( const Cuda& ) = default;
Cuda( Cuda&& ) = default;
Cuda& operator=( const Cuda& ) = default;
Cuda& operator=( Cuda&& ) = default;
template< class U >
Cuda( const Cuda< U >& )
{}
template< class U >
Cuda( Cuda< U >&& )
{}
template< class U >
Cuda& operator=( const Cuda< U >& )
{
return *this;
}
template< class U >
Cuda& operator=( Cuda< U >&& )
{
return *this;
}
value_type* allocate( size_type n )
{
#ifdef HAVE_CUDA
TNL_CHECK_CUDA_DEVICE;
value_type* result = nullptr;
if( cudaMalloc( (void**) &result, n * sizeof(value_type) ) != cudaSuccess )
throw Exceptions::CudaBadAlloc();
TNL_CHECK_CUDA_DEVICE;
return result;
#else
throw Exceptions::CudaSupportMissing();
#endif
}
void deallocate(value_type* ptr, size_type)
{
#ifdef HAVE_CUDA
TNL_CHECK_CUDA_DEVICE;
cudaFree( ptr );
TNL_CHECK_CUDA_DEVICE;
#else
throw Exceptions::CudaSupportMissing();
#endif
}
};
template<class T1, class T2>
bool operator==(const Cuda<T1>&, const Cuda<T2>&)
{
return true;
}
template<class T1, class T2>
bool operator!=(const Cuda<T1>& lhs, const Cuda<T2>& rhs)
{
return !(lhs == rhs);
}
} // namespace Allocators
} // namespace TNL
/***************************************************************************
CudaHost.h - description
-------------------
begin : Apr 8, 2019
copyright : (C) 2019 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
// Implemented by: Jakub Klinkovsky
#pragma once
#include <TNL/Devices/Cuda.h>
namespace TNL {
namespace Allocators {
/**
* \brief Allocator for page-locked memory on the host.
*
* The allocation is done using the `cudaMallocHost` function and the
* deallocation is done using the `cudaFreeHost` function.
*/
template< class T >
struct CudaHost
{
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
CudaHost() = default;
CudaHost( const CudaHost& ) = default;
CudaHost( CudaHost&& ) = default;
CudaHost& operator=( const CudaHost& ) = default;
CudaHost& operator=( CudaHost&& ) = default;
template< class U >
CudaHost( const CudaHost< U >& )
{}
template< class U >
CudaHost( CudaHost< U >&& )
{}
template< class U >
CudaHost& operator=( const CudaHost< U >& )
{
return *this;
}
template< class U >
CudaHost& operator=( CudaHost< U >&& )
{
return *this;
}
value_type* allocate( size_type n )
{
#ifdef HAVE_CUDA
TNL_CHECK_CUDA_DEVICE;
value_type* result = nullptr;
// cudaHostAllocPortable - The memory returned by this call will be considered as pinned memory by all
// CUDA contexts, not just the one that performed the allocation.
// cudaHostAllocMapped - Maps the allocation into the CUDA address space.
// Also note that we assume that the cudaDevAttrCanUseHostPointerForRegisteredMem attribute is non-zero
// on all devices visible to the application, in which case the pointer returned by cudaMallocHost can
// be used directly by all devices without having to call cudaHostGetDevicePointer. See the reference:
// https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__MEMORY.html#group__CUDART__MEMORY_1gc00502b44e5f1bdc0b424487ebb08db0
if( cudaMallocHost( (void**) &result, n * sizeof(value_type), cudaHostAllocPortable | cudaHostAllocMapped ) != cudaSuccess )
throw Exceptions::CudaBadAlloc();
TNL_CHECK_CUDA_DEVICE;
return result;
#else
throw Exceptions::CudaSupportMissing();
#endif
}
void deallocate(value_type* ptr, size_type)
{
#ifdef HAVE_CUDA
TNL_CHECK_CUDA_DEVICE;
cudaFreeHost( ptr );
TNL_CHECK_CUDA_DEVICE;
#else
throw Exceptions::CudaSupportMissing();
#endif
}
};
template<class T1, class T2>
bool operator==(const CudaHost<T1>&, const CudaHost<T2>&)
{
return true;
}
template<class T1, class T2>
bool operator!=(const CudaHost<T1>& lhs, const CudaHost<T2>& rhs)
{
return !(lhs == rhs);
}
} // namespace Allocators
} // namespace TNL
/***************************************************************************
CudaManaged.h - description
-------------------
begin : Apr 8, 2019
copyright : (C) 2019 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
// Implemented by: Jakub Klinkovsky
#pragma once
#include <TNL/Devices/Cuda.h>
namespace TNL {
namespace Allocators {
/**
* \brief Allocator for the CUDA Unified Memory system.
*
* The memory allocated by this allocator will be automatically managed by the
* CUDA Unified Memory system. The allocation is done using the
* `cudaMallocManaged` function and the deallocation is done using the
* `cudaFree` function.
*/
template< class T >
struct CudaManaged
{
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
CudaManaged() = default;
CudaManaged( const CudaManaged& ) = default;
CudaManaged( CudaManaged&& ) = default;
CudaManaged& operator=( const CudaManaged& ) = default;
CudaManaged& operator=( CudaManaged&& ) = default;
template< class U >
CudaManaged( const CudaManaged< U >& )
{}
template< class U >
CudaManaged( CudaManaged< U >&& )
{}
template< class U >
CudaManaged& operator=( const CudaManaged< U >& )
{
return *this;
}
template< class U >
CudaManaged& operator=( CudaManaged< U >&& )
{
return *this;
}
value_type* allocate( size_type n )
{
#ifdef HAVE_CUDA
TNL_CHECK_CUDA_DEVICE;
value_type* result = nullptr;
if( cudaMallocManaged( &result, n * sizeof(value_type) ) != cudaSuccess )
throw Exceptions::CudaBadAlloc();
TNL_CHECK_CUDA_DEVICE;
return result;
#else
throw Exceptions::CudaSupportMissing();
#endif
}
void deallocate(value_type* ptr, size_type)
{
#ifdef HAVE_CUDA
TNL_CHECK_CUDA_DEVICE;
cudaFree( ptr );
TNL_CHECK_CUDA_DEVICE;
#else
throw Exceptions::CudaSupportMissing();
#endif
}
};
template<class T1, class T2>
bool operator==(const CudaManaged<T1>&, const CudaManaged<T2>&)
{
return true;
}
template<class T1, class T2>
bool operator!=(const CudaManaged<T1>& lhs, const CudaManaged<T2>& rhs)
{
return !(lhs == rhs);
}
} // namespace Allocators
} // namespace TNL
/***************************************************************************
Default.h - description
-------------------
begin : Jul 2, 2019
copyright : (C) 2019 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
// Implemented by: Jakub Klinkovsky
#pragma once
#include <TNL/Allocators/Host.h>
#include <TNL/Allocators/Cuda.h>
#include <TNL/Allocators/MIC.h>
#include <TNL/Devices/Host.h>
#include <TNL/Devices/Cuda.h>
#include <TNL/Devices/MIC.h>
namespace TNL {
namespace Allocators {
/**
* \brief A trait-like class used for the selection of a default allocators for
* given device.
*/
template< typename Device >
struct Default;
//! Sets \ref Allocators::Host as the default allocator for \ref Devices::Host.
template<>
struct Default< Devices::Host >
{
template< typename T >
using Allocator = Allocators::Host< T >;
};
//! Sets \ref Allocators::Cuda as the default allocator for \ref Devices::Cuda.
template<>
struct Default< Devices::Cuda >
{
template< typename T >
using Allocator = Allocators::Cuda< T >;
};
//! Sets \ref Allocators::MIC as the default allocator for \ref Devices::MIC.
template<>
struct Default< Devices::MIC >
{
template< typename T >
using Allocator = Allocators::MIC< T >;
};
} // namespace Allocators
} // namespace TNL
/***************************************************************************
Host.h - description
-------------------
begin : Apr 8, 2019
copyright : (C) 2019 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
// Implemented by: Jakub Klinkovsky
#pragma once
#include <memory>
namespace TNL {
/**
* \brief Namespace for TNL allocators.
*
* All TNL allocators must satisfy the requirements imposed by the
* [Allocator concept](https://en.cppreference.com/w/cpp/named_req/Allocator)
* from STL.
*/
namespace Allocators {
/**
* \brief Allocator for the host memory space -- alias for \ref std::allocator.
*/
template< class T >
using Host = std::allocator< T >;
} // namespace Allocators
} // namespace TNL
/***************************************************************************
MIC.h - description
-------------------
begin : Jul 2, 2019
copyright : (C) 2019 by Tomas Oberhuber et al.
email : tomas.oberhuber@fjfi.cvut.cz
***************************************************************************/
/* See Copyright Notice in tnl/Copyright */
// Implemented by: Jakub Klinkovsky
#pragma once
#include <TNL/Devices/MIC.h>
#include <TNL/Exceptions/MICSupportMissing.h>
namespace TNL {
namespace Allocators {
/**
* \brief Allocator for the MIC device memory space.
*/
template< class T >
struct MIC
{
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
MIC() = default;
MIC( const MIC& ) = default;
MIC( MIC&& ) = default;
MIC& operator=( const MIC& ) = default;
MIC& operator=( MIC&& ) = default;
template< class U >
MIC( const MIC< U >& )
{}
template< class U >
MIC( MIC< U >&& )
{}
template< class U >
MIC& operator=( const MIC< U >& )
{
return *this;
}
template< class U >
MIC& operator=( MIC< U >&& )
{
return *this;
}
value_type* allocate( size_type size )
{
#ifdef HAVE_MIC
Devices::MICHider<void> hide_ptr;
#pragma offload target(mic) out(hide_ptr) in(size)
{
hide_ptr.pointer = malloc(size * sizeof(value_type));
}
return hide_ptr.pointer;
#else
throw Exceptions::MICSupportMissing();
#endif
}
void deallocate(value_type* ptr, size_type)
{
#ifdef HAVE_MIC
Devices::MICHider<void> hide_ptr;
hide_ptr.pointer=ptr;
#pragma offload target(mic) in(hide_ptr)
{
free(hide_ptr.pointer);
}
#else
throw Exceptions::MICSupportMissing();
#endif
}
};
template<class T1, class T2>
bool operator==(const MIC<T1>&, const MIC<T2>&)
{
return true;
}
template<class T1, class T2>
bool operator!=(const MIC<T1>& lhs, const MIC<T2>& rhs)
{
return !(lhs == rhs);
}
} // namespace Allocators
} // namespace TNL
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment