Kokkos Core Kernels Package Version of the Day
Kokkos_LogicalSpaces.hpp
1/*
2//@HEADER
3// ************************************************************************
4//
5// Kokkos v. 3.0
6// Copyright (2020) National Technology & Engineering
7// Solutions of Sandia, LLC (NTESS).
8//
9// Under the terms of Contract DE-NA0003525 with NTESS,
10// the U.S. Government retains certain rights in this software.
11//
12// Redistribution and use in source and binary forms, with or without
13// modification, are permitted provided that the following conditions are
14// met:
15//
16// 1. Redistributions of source code must retain the above copyright
17// notice, this list of conditions and the following disclaimer.
18//
19// 2. Redistributions in binary form must reproduce the above copyright
20// notice, this list of conditions and the following disclaimer in the
21// documentation and/or other materials provided with the distribution.
22//
23// 3. Neither the name of the Corporation nor the names of the
24// contributors may be used to endorse or promote products derived from
25// this software without specific prior written permission.
26//
27// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
28// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
31// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38//
39// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
40//
41// ************************************************************************
42//@HEADER
43*/
44
45#ifndef KOKKOS_LOGICALSPACES_HPP
46#define KOKKOS_LOGICALSPACES_HPP
47
48#include <Kokkos_Macros.hpp>
49#include <Kokkos_Core_fwd.hpp>
50#include <Kokkos_ScratchSpace.hpp>
51#include <impl/Kokkos_MemorySpace.hpp>
52#include <impl/Kokkos_Error.hpp>
53#include <impl/Kokkos_SharedAlloc.hpp>
54#include <impl/Kokkos_Profiling.hpp>
55#include <cstring>
56namespace Kokkos {
57namespace Experimental {
58struct DefaultMemorySpaceNamer {
59 static constexpr const char* get_name() {
60 return "DefaultLogicalMemorySpaceName";
61 }
62};
63
64struct LogicalSpaceSharesAccess {
65 struct shared_access {};
66 struct no_shared_access {};
67};
68
74template <class BaseSpace, class DefaultBaseExecutionSpace = void,
75 class Namer = DefaultMemorySpaceNamer,
76 class SharesAccessWithBase = LogicalSpaceSharesAccess::shared_access>
78#ifdef KOKKOS_ENABLE_OPENMPTARGET
79 // [DZP] For some reason I don't yet know, using LogicalMemorySpaces
80 // inside an OpenMPTarget build causes errors in the
81 // SharedAllocationRecords of other types. This is my way of erroring
82 // a build if we instantiate a LogicalMemSpace in an OMPTarget build
83 static_assert(!std::is_same<BaseSpace, BaseSpace>::value,
84 "Can't use LogicalMemorySpaces in an OpenMPTarget build, we're "
85 "debugging memory issues");
86#endif
87 public:
89 using memory_space = LogicalMemorySpace<BaseSpace, DefaultBaseExecutionSpace,
90 Namer, SharesAccessWithBase>;
91 using size_type = typename BaseSpace::size_type;
92
99
101 typename std::conditional<std::is_void<DefaultBaseExecutionSpace>::value,
102 typename BaseSpace::execution_space,
103 DefaultBaseExecutionSpace>::type;
104
105 using device_type = Kokkos::Device<execution_space, memory_space>;
106
107 LogicalMemorySpace() = default;
108
109 template <typename... Args>
110 LogicalMemorySpace(Args&&... args) : underlying_space((Args &&) args...) {}
111
113 void* allocate(const size_t arg_alloc_size) const {
114 return allocate("[unlabeled]", arg_alloc_size);
115 }
116 void* allocate(const char* arg_label, const size_t arg_alloc_size,
117 const size_t arg_logical_size = 0) const {
118 return impl_allocate(arg_label, arg_alloc_size, arg_logical_size);
119 }
120
122 void deallocate(void* const arg_alloc_ptr,
123 const size_t arg_alloc_size) const {
124 deallocate("[unlabeled]", arg_alloc_ptr, arg_alloc_size);
125 }
126 void deallocate(const char* arg_label, void* const arg_alloc_ptr,
127 const size_t arg_alloc_size,
128 const size_t arg_logical_size = 0) const {
129 impl_deallocate(arg_label, arg_alloc_ptr, arg_alloc_size, arg_logical_size);
130 }
131
133 constexpr static const char* name() { return Namer::get_name(); }
134
135 private:
136 BaseSpace underlying_space;
137 template <class, class, class, class>
138 friend class LogicalMemorySpace;
139 friend class Kokkos::Impl::SharedAllocationRecord<memory_space, void>;
140
141 void* impl_allocate(const char* arg_label, const size_t arg_alloc_size,
142 const size_t arg_logical_size = 0,
143 Kokkos::Tools::SpaceHandle arg_handle =
144 Kokkos::Tools::make_space_handle(name())) const {
145 return underlying_space.impl_allocate(arg_label, arg_alloc_size,
146 arg_logical_size, arg_handle);
147 }
148 void impl_deallocate(const char* arg_label, void* const arg_alloc_ptr,
149 const size_t arg_alloc_size,
150 const size_t arg_logical_size = 0,
151 const Kokkos::Tools::SpaceHandle arg_handle =
152 Kokkos::Tools::make_space_handle(name())) const {
153 underlying_space.impl_deallocate(arg_label, arg_alloc_ptr, arg_alloc_size,
154 arg_logical_size, arg_handle);
155 }
156};
157} // namespace Experimental
158} // namespace Kokkos
159
160//----------------------------------------------------------------------------
161
162namespace Kokkos {
163
164namespace Impl {
165
166template <typename BaseSpace, typename DefaultBaseExecutionSpace, class Namer,
167 typename OtherSpace>
168struct MemorySpaceAccess<
169 Kokkos::Experimental::LogicalMemorySpace<
170 BaseSpace, DefaultBaseExecutionSpace, Namer,
171 Kokkos::Experimental::LogicalSpaceSharesAccess::shared_access>,
172 OtherSpace> {
173 enum { assignable = MemorySpaceAccess<BaseSpace, OtherSpace>::assignable };
174 enum { accessible = MemorySpaceAccess<BaseSpace, OtherSpace>::accessible };
175 enum { deepcopy = MemorySpaceAccess<BaseSpace, OtherSpace>::deepcopy };
176};
177
178template <typename BaseSpace, typename DefaultBaseExecutionSpace, class Namer,
179 typename OtherSpace>
180struct MemorySpaceAccess<
181 OtherSpace,
182 Kokkos::Experimental::LogicalMemorySpace<
183 BaseSpace, DefaultBaseExecutionSpace, Namer,
184 Kokkos::Experimental::LogicalSpaceSharesAccess::shared_access>> {
185 enum { assignable = MemorySpaceAccess<OtherSpace, BaseSpace>::assignable };
186 enum { accessible = MemorySpaceAccess<OtherSpace, BaseSpace>::accessible };
187 enum { deepcopy = MemorySpaceAccess<OtherSpace, BaseSpace>::deepcopy };
188};
189
190template <typename BaseSpace, typename DefaultBaseExecutionSpace, class Namer>
191struct MemorySpaceAccess<
192 Kokkos::Experimental::LogicalMemorySpace<
193 BaseSpace, DefaultBaseExecutionSpace, Namer,
194 Kokkos::Experimental::LogicalSpaceSharesAccess::shared_access>,
196 BaseSpace, DefaultBaseExecutionSpace, Namer,
197 Kokkos::Experimental::LogicalSpaceSharesAccess::shared_access>> {
198 enum { assignable = true };
199 enum { accessible = true };
200 enum { deepcopy = true };
201};
202
203} // namespace Impl
204
205} // namespace Kokkos
206
207//----------------------------------------------------------------------------
208
209namespace Kokkos {
210
211namespace Impl {
212template <class BaseSpace, class DefaultBaseExecutionSpace, class Namer,
213 class SharesAccessSemanticsWithBase>
214class SharedAllocationRecord<Kokkos::Experimental::LogicalMemorySpace<
215 BaseSpace, DefaultBaseExecutionSpace, Namer,
216 SharesAccessSemanticsWithBase>,
217 void> : public SharedAllocationRecord<void, void> {
218 private:
219 using SpaceType =
221 DefaultBaseExecutionSpace, Namer,
222 SharesAccessSemanticsWithBase>;
223 using RecordBase = SharedAllocationRecord<void, void>;
224
225 SharedAllocationRecord(const SharedAllocationRecord&) = delete;
226 SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete;
227
228 static void deallocate(RecordBase* arg_rec) {
229 delete static_cast<SharedAllocationRecord*>(arg_rec);
230 }
231
232#ifdef KOKKOS_ENABLE_DEBUG
235 static RecordBase s_root_record;
236#endif
237
238 const SpaceType m_space;
239
240 protected:
241 ~SharedAllocationRecord() {
242 m_space.deallocate(RecordBase::m_alloc_ptr->m_label,
243 SharedAllocationRecord<void, void>::m_alloc_ptr,
244 SharedAllocationRecord<void, void>::m_alloc_size,
245 (SharedAllocationRecord<void, void>::m_alloc_size -
246 sizeof(SharedAllocationHeader)));
247 }
248 SharedAllocationRecord() = default;
249
250 SharedAllocationRecord(
251 const SpaceType& arg_space, const std::string& arg_label,
252 const size_t arg_alloc_size,
253 const RecordBase::function_type arg_dealloc = &deallocate)
254 : SharedAllocationRecord<void, void>(
255#ifdef KOKKOS_ENABLE_DEBUG
256 &SharedAllocationRecord<SpaceType, void>::s_root_record,
257#endif
258 Impl::checked_allocation_with_header(arg_space, arg_label,
259 arg_alloc_size),
260 sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc),
261 m_space(arg_space) {
262 // Fill in the Header information
263 RecordBase::m_alloc_ptr->m_record =
264 static_cast<SharedAllocationRecord<void, void>*>(this);
265
266 strncpy(RecordBase::m_alloc_ptr->m_label, arg_label.c_str(),
267 SharedAllocationHeader::maximum_label_length - 1);
268 // Set last element zero, in case c_str is too long
269 RecordBase::m_alloc_ptr
270 ->m_label[SharedAllocationHeader::maximum_label_length - 1] = '\0';
271 }
272
273 public:
274 inline std::string get_label() const {
275 return std::string(RecordBase::head()->m_label);
276 }
277 KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate(
278 const SpaceType& arg_space, const std::string& arg_label,
279 const size_t arg_alloc_size) {
280#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST)
281 return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size);
282#else
283 (void)arg_space;
284 (void)arg_label;
285 (void)arg_alloc_size;
286 return (SharedAllocationRecord*)nullptr;
287#endif
288 }
289
291 static void* allocate_tracked(const SpaceType& arg_space,
292 const std::string& arg_label,
293 const size_t arg_alloc_size) {
294 if (!arg_alloc_size) return (void*)nullptr;
295
296 SharedAllocationRecord* const r =
297 allocate(arg_space, arg_label, arg_alloc_size);
298
299 RecordBase::increment(r);
300
301 return r->data();
302 }
303
305 static void* reallocate_tracked(void* const arg_alloc_ptr,
306 const size_t arg_alloc_size) {
307 SharedAllocationRecord* const r_old = get_record(arg_alloc_ptr);
308 SharedAllocationRecord* const r_new =
309 allocate(r_old->m_space, r_old->get_label(), arg_alloc_size);
310
311 Kokkos::Impl::DeepCopy<SpaceType, SpaceType>(
312 r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size()));
313
314 RecordBase::increment(r_new);
315 RecordBase::decrement(r_old);
316
317 return r_new->data();
318 }
320 static void deallocate_tracked(void* const arg_alloc_ptr) {
321 if (arg_alloc_ptr != nullptr) {
322 SharedAllocationRecord* const r = get_record(arg_alloc_ptr);
323
324 RecordBase::decrement(r);
325 }
326 }
327
328 static SharedAllocationRecord* get_record(void* alloc_ptr) {
329 using Header = SharedAllocationHeader;
330 using RecordHost = SharedAllocationRecord<SpaceType, void>;
331
332 SharedAllocationHeader const* const head =
333 alloc_ptr ? Header::get_header(alloc_ptr)
334 : (SharedAllocationHeader*)nullptr;
335 RecordHost* const record =
336 head ? static_cast<RecordHost*>(head->m_record) : (RecordHost*)nullptr;
337
338 if (!alloc_ptr || record->m_alloc_ptr != head) {
339 Kokkos::Impl::throw_runtime_exception(std::string(
340 "Kokkos::Impl::SharedAllocationRecord< LogicalMemorySpace<> , "
341 "void >::get_record ERROR"));
342 }
343
344 return record;
345 }
346#ifdef KOKKOS_ENABLE_DEBUG
347 static void print_records(std::ostream& s, const SpaceType&,
348 bool detail = false) {
349 SharedAllocationRecord<void, void>::print_host_accessible_records(
350 s, "HostSpace", &s_root_record, detail);
351 }
352#else
353 static void print_records(std::ostream&, const SpaceType&,
354 bool detail = false) {
355 (void)detail;
356 throw_runtime_exception(
357 "SharedAllocationRecord<HostSpace>::print_records only works "
358 "with KOKKOS_ENABLE_DEBUG enabled");
359 }
360#endif
361};
362#ifdef KOKKOS_ENABLE_DEBUG
365template <class BaseSpace, class DefaultBaseExecutionSpace, class Namer,
366 class SharesAccessSemanticsWithBase>
367SharedAllocationRecord<void, void>
368 SharedAllocationRecord<Kokkos::Experimental::LogicalMemorySpace<
369 BaseSpace, DefaultBaseExecutionSpace, Namer,
370 SharesAccessSemanticsWithBase>,
371 void>::s_root_record;
372#endif
373
374} // namespace Impl
375
376} // namespace Kokkos
377
378//----------------------------------------------------------------------------
379
380namespace Kokkos {
381
382namespace Impl {
383
384template <class Namer, class BaseSpace, class DefaultBaseExecutionSpace,
385 class SharesAccess, class ExecutionSpace>
386struct DeepCopy<Kokkos::Experimental::LogicalMemorySpace<
387 BaseSpace, DefaultBaseExecutionSpace, Namer, SharesAccess>,
389 BaseSpace, DefaultBaseExecutionSpace, Namer, SharesAccess>,
390 ExecutionSpace> {
391 DeepCopy(void* dst, void* src, size_t n) {
392 DeepCopy<BaseSpace, BaseSpace, ExecutionSpace>(dst, src, n);
393 }
394 DeepCopy(const ExecutionSpace& exec, void* dst, void* src, size_t n) {
395 DeepCopy<BaseSpace, BaseSpace, ExecutionSpace>(exec, dst, src, n);
396 }
397};
398
399template <class Namer, class BaseSpace, class DefaultBaseExecutionSpace,
400 class SharesAccess, class ExecutionSpace, class SourceSpace>
401struct DeepCopy<SourceSpace,
402 Kokkos::Experimental::LogicalMemorySpace<
403 BaseSpace, DefaultBaseExecutionSpace, Namer, SharesAccess>,
404 ExecutionSpace> {
405 DeepCopy(void* dst, void* src, size_t n) {
406 DeepCopy<SourceSpace, BaseSpace, ExecutionSpace>(dst, src, n);
407 }
408 DeepCopy(const ExecutionSpace& exec, void* dst, void* src, size_t n) {
409 DeepCopy<SourceSpace, BaseSpace, ExecutionSpace>(exec, dst, src, n);
410 }
411};
412
413template <class Namer, class BaseSpace, class DefaultBaseExecutionSpace,
414 class SharesAccess, class ExecutionSpace, class DestinationSpace>
415struct DeepCopy<Kokkos::Experimental::LogicalMemorySpace<
416 BaseSpace, DefaultBaseExecutionSpace, Namer, SharesAccess>,
417 DestinationSpace, ExecutionSpace> {
418 DeepCopy(void* dst, void* src, size_t n) {
419 DeepCopy<BaseSpace, DestinationSpace, ExecutionSpace>(dst, src, n);
420 }
421 DeepCopy(const ExecutionSpace& exec, void* dst, void* src, size_t n) {
422 DeepCopy<BaseSpace, DestinationSpace, ExecutionSpace>(exec, dst, src, n);
423 }
424};
425} // namespace Impl
426
427} // namespace Kokkos
428#endif // KOKKOS_LOGICALSPACES_HPP
LogicalMemorySpace is a space that is identical to another space, but differentiable by name and temp...
void * allocate(const size_t arg_alloc_size) const
Allocate untracked memory in the space.
typename std::conditional< std::is_void< DefaultBaseExecutionSpace >::value, typename BaseSpace::execution_space, DefaultBaseExecutionSpace >::type execution_space
Default execution space for this memory space.
static constexpr const char * name()
Return Name of the MemorySpace.
LogicalMemorySpace< BaseSpace, DefaultBaseExecutionSpace, Namer, SharesAccessWithBase > memory_space
Tag this class as a kokkos memory space.
void deallocate(void *const arg_alloc_ptr, const size_t arg_alloc_size) const
Deallocate untracked memory in the space.