alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
Platform.hpp
Go to the documentation of this file.
1/* Copyright 2024 René Widera
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5
6#pragma once
7
14
15#if ALPAKA_LANG_CUDA || ALPAKA_LANG_HIP
16
17
18# include <memory>
19# include <mutex>
20# include <sstream>
21# include <vector>
22
23namespace alpaka::onHost
24{
25 namespace unifiedCudaHip
26 {
27 template<typename T_ApiInterface, alpaka::concepts::DeviceKind T_DeviceKind>
28 struct Platform : std::enable_shared_from_this<Platform<T_ApiInterface, T_DeviceKind>>
29 {
30 using ApiInterface = T_ApiInterface;
31
32 public:
33 Platform() = default;
34
35 Platform(Platform const&) = delete;
36 Platform& operator=(Platform const&) = delete;
37
38 Platform(Platform&&) = delete;
39 Platform& operator=(Platform&&) = delete;
40
41 private:
42 void _()
43 {
44 static_assert(internal::concepts::Platform<Platform>);
45 }
46
47 std::vector<std::weak_ptr<unifiedCudaHip::Device<Platform>>> devices;
48 std::mutex deviceGuard;
49
50 std::shared_ptr<Platform> getSharedPtr()
51 {
52 return this->shared_from_this();
53 }
54
55 friend struct alpaka::internal::GetName;
56
57 std::string getName() const
58 {
59 return "unifiedCudaHip::Platform";
60 }
61
62 friend struct onHost::internal::GetDeviceCount;
63
64 uint32_t getDeviceCount()
65 {
67 constexpr bool isSupportedDev = trait::IsDeviceSupportedBy::
68 Op<T_DeviceKind, ALPAKA_TYPEOF(getApi(std::declval<Platform>()))>::value;
69 if constexpr(isSupportedDev)
70 {
71 int numDevices{0};
72 typename ApiInterface::Error_t error = ApiInterface::getDeviceCount(&numDevices);
73 if(error != ApiInterface::success)
74 numDevices = 0;
75
76 if(devices.size() < static_cast<size_t>(numDevices))
77 {
78 std::lock_guard<std::mutex> lk{deviceGuard};
79 devices.resize(numDevices);
80 }
81 return static_cast<uint32_t>(numDevices);
82 }
83
84 return 0;
85 }
86
87 friend struct onHost::internal::MakeDevice;
88
89 Handle<unifiedCudaHip::Device<Platform>> makeDevice(uint32_t const& idx)
90 {
92 uint32_t const numDevices = getDeviceCount();
93 if(idx >= numDevices)
94 {
95 std::stringstream ssErr;
96 ssErr << "Unable to return device handle for GPU (" << T_DeviceKind{}.getName()
97 << ") device with index " << idx << " because there are only " << numDevices << " devices!";
98 throw std::runtime_error(ssErr.str());
99 }
100 std::lock_guard<std::mutex> lk{deviceGuard};
101
102 if(auto sharedPtr = devices[idx].lock())
103 {
104 return sharedPtr;
105 }
106 auto thisHandle = getSharedPtr();
107 auto newDevice = std::make_shared<unifiedCudaHip::Device<Platform>>(std::move(thisHandle), idx);
108 devices[idx] = newDevice;
109 return newDevice;
110 }
111
112 friend struct internal::GetDeviceProperties;
113 };
114 } // namespace unifiedCudaHip
115
116 namespace internal
117 {
118 template<typename T_ApiInterface, alpaka::concepts::DeviceKind T_DeviceKind>
119 struct GetDeviceProperties::Op<unifiedCudaHip::Platform<T_ApiInterface, T_DeviceKind>>
120 {
121 DeviceProperties operator()(
122 unifiedCudaHip::Platform<T_ApiInterface, T_DeviceKind> const&,
123 uint32_t deviceIdx) const
124 {
126 using ApiInterface = typename unifiedCudaHip::Platform<T_ApiInterface, T_DeviceKind>::ApiInterface;
127 typename ApiInterface::DeviceProp_t devProp;
128 ALPAKA_UNIFORM_CUDA_HIP_RT_CHECK(ApiInterface, ApiInterface::getDeviceProperties(&devProp, deviceIdx));
129
130 std::size_t freeGlobalMemBytes(0u);
131 std::size_t globalMemCapacityBytes(0u);
132 ALPAKA_UNIFORM_CUDA_HIP_RT_CHECK(
133 ApiInterface,
134 ApiInterface::memGetInfo(&freeGlobalMemBytes, &globalMemCapacityBytes));
135
136 auto prop = DeviceProperties{};
137 prop.name = devProp.name;
138 prop.warpSize = devProp.warpSize;
139 prop.multiProcessorCount = devProp.multiProcessorCount;
140 prop.globalMemCapacityBytes = globalMemCapacityBytes;
141 prop.sharedMemPerBlockBytes = devProp.sharedMemPerBlock;
142
143 prop.maxThreadsPerBlock = devProp.maxThreadsPerBlock;
144 // will be copied into the lampda and follows cuda index order
145 Vec<uint32_t, 3u> cudaMaxThreadsPerBlock{
146 devProp.maxThreadsDim[0u],
147 devProp.maxThreadsDim[1u],
148 devProp.maxThreadsDim[2u]};
149 prop.fnMaxThreadsPerBlock = [maxThreadsPerBlock = prop.maxThreadsPerBlock,
150 cudaMaxThreadsPerBlock](uint32_t* data, uint32_t numDims)
151 {
152 if(numDims <= 3u)
153 {
154 for(uint32_t d = 0u; d < numDims; ++d)
155 data[numDims - 1u - d] = cudaMaxThreadsPerBlock[d];
156 }
157 else
158 {
159 /* For more than 3 dimensions alpaka is linearizing to one dimension, therefore we use the
160 * maximum for each dimension. */
161 for(uint32_t d = 0u; d < numDims; ++d)
162 data[d] = maxThreadsPerBlock;
163 }
164 };
165
166 prop.maxBlocksPerGrid = std::numeric_limits<uint32_t>::max();
167 // will be copied into the lampda and follows cuda index order
168 Vec<uint32_t, 3u> cudaMaxBlocksPerGrid{
169 devProp.maxGridSize[0u],
170 devProp.maxGridSize[1u],
171 devProp.maxGridSize[2u]};
172 prop.fnMaxBlocksPerGrid =
173 [maxBlocksPerGrid = prop.maxBlocksPerGrid, cudaMaxBlocksPerGrid](uint32_t* data, uint32_t numDims)
174 {
175 if(numDims <= 3u)
176 {
177 for(uint32_t d = 0u; d < numDims; ++d)
178 data[numDims - 1u - d] = cudaMaxBlocksPerGrid[d];
179 }
180 else
181 {
182 /* For more than 3 dimensions alpaka is linearizing to one dimension, therefore we use the
183 * maximum for each dimension. */
184 for(uint32_t d = 0u; d < numDims; ++d)
185 data[d] = maxBlocksPerGrid;
186 }
187 };
188
189 return prop;
190 }
191 };
192 } // namespace internal
193} // namespace alpaka::onHost
194#endif
#define ALPAKA_LOG_FUNCTION(logLvl)
Log the entry and exit of a scope.
Definition logger.hpp:95
constexpr auto device
Definition lvl.hpp:82
Functionality which is usable on the host CPU controller thread.
Definition api.hpp:40
decltype(auto) data(auto &&any)
pointer to data of an object
std::convertible_to< std::string > auto getName(auto &&any)
Runtime name for a given object.
ALPAKA_FN_HOST_ACC Vec(T_1, T_Args...) -> Vec< T_1, uint32_t(sizeof...(T_Args)+1u), ArrayStorage< T_1, uint32_t(sizeof...(T_Args)+1u)> >