Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Tpetra_withLocalAccess.hpp
Go to the documentation of this file.
1 /*
2 // @HEADER
3 // ***********************************************************************
4 //
5 // Tpetra: Templated Linear Algebra Services Package
6 // Copyright (2008) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ************************************************************************
41 // @HEADER
42 */
43 
44 #ifndef TPETRA_WITHLOCALACCESS_HPP
45 #define TPETRA_WITHLOCALACCESS_HPP
46 
47 #include "TpetraCore_config.h"
48 #include <functional>
49 #include <type_traits>
50 
54 
55 namespace Tpetra {
56 
58  // Generic classes needed to implement withLocalAccess
60 
61  namespace Details {
63  enum class AccessMode {
64  ReadOnly,
65  WriteOnly,
66  ReadWrite
67  };
68 
75  template<class GlobalObjectType>
77  using type = typename GlobalObjectType::device_type::memory_space;
78 
79  // Given a global object, get its (default) memory space instance.
80  static type space (const GlobalObjectType& /* G */) {
81  // This stub just assumes that 'type' is default constructible.
82  // In Kokkos, default-constructing a memory space instance just
83  // gives the default memory space.
84  return type ();
85  }
86  };
87 
88 #ifndef DOXYGEN_SHOULD_SKIP_THIS
89  template<class GlobalObjectType,
90  class MemorySpace,
91  const AccessMode am>
92  class LocalAccess; // forward declaration
93 #endif // DOXYGEN_SHOULD_SKIP_THIS
94 
112  template<class LocalAccessType>
114 
133  template<class LocalAccessType>
135  getMasterLocalObject (LocalAccessType LA) {
137  }
138 
163  template<class LocalAccessType>
165 
176  template<class LocalAccessType>
178  nonowning_local_object_type
179  getNonowningLocalObject (LocalAccessType LA,
181  master_local_object_type& master)
182  {
184  }
185  } // namespace Details
186 
201  template<class LocalAccessType>
203  typename Details::GetNonowningLocalObject<LocalAccessType>::
204  nonowning_local_object_type;
205 
207  // Users call readOnly, writeOnly, and readWrite, in order to declare
208  // how they intend to access a global object's local data.
210 
214  template<class GlobalObjectType>
216  GlobalObjectType,
217  typename Details::DefaultMemorySpace<GlobalObjectType>::type,
218  Details::AccessMode::ReadOnly>
219  readOnly (GlobalObjectType&);
220 
224  template<class GlobalObjectType>
226  GlobalObjectType,
227  typename Details::DefaultMemorySpace<GlobalObjectType>::type,
228  Details::AccessMode::ReadOnly>
229  readOnly (const GlobalObjectType&);
230 
234  template<class GlobalObjectType>
236  GlobalObjectType,
237  typename Details::DefaultMemorySpace<GlobalObjectType>::type,
238  Details::AccessMode::WriteOnly>
239  writeOnly (GlobalObjectType&);
240 
244  template<class GlobalObjectType>
246  GlobalObjectType,
247  typename Details::DefaultMemorySpace<GlobalObjectType>::type,
248  Details::AccessMode::ReadWrite>
249  readWrite (GlobalObjectType&);
250 
252  // LocalAccess struct
254 
255  namespace Details {
262  template<class GlobalObjectType,
263  class MemorySpace,
264  const AccessMode am>
265  class LocalAccess {
266  public:
267  using global_object_type = GlobalObjectType;
268  using memory_space = typename MemorySpace::memory_space;
269  static constexpr AccessMode access_mode = am;
270 
271  private:
272  using canonical_this_type = LocalAccess<global_object_type,
273  memory_space,
274  access_mode>;
275  public:
293  LocalAccess (global_object_type& G,
294  memory_space space = memory_space (),
295  const bool isValid = true) :
296  G_ (G),
297  space_ (space),
298  valid_ (isValid)
299  {}
300 
303  using function_argument_type =
305 
306  public:
319  valid (const bool isValid) const {
320  return {this->G_, this->space_, isValid};
321  }
322 
325  template<class NewMemorySpace>
327  on (NewMemorySpace space) const {
328  return {this->G_, space, this->valid_};
329  }
330 
332  bool isValid () const { return this->valid_; }
333 
336  memory_space getSpace () const { return space_; }
337 
338  public:
344  global_object_type& G_;
345 
351  memory_space space_;
353  bool valid_;
354  };
355  } // namespace Details
356 
358  // Implementations of readOnly, writeOnly, and readWrite
360 
361  template<class GOT>
363  GOT,
364  typename Details::DefaultMemorySpace<GOT>::type,
365  Details::AccessMode::ReadOnly>
366  readOnly (GOT& G)
367  {
368  return {G, Details::DefaultMemorySpace<GOT>::space (G), true};
369  }
370 
371  template<class GOT>
372  Details::LocalAccess<
373  GOT,
374  typename Details::DefaultMemorySpace<GOT>::type,
375  Details::AccessMode::ReadOnly>
376  readOnly (const GOT& G)
377  {
378  GOT& G_nc = const_cast<GOT&> (G);
379  return {G_nc, Details::DefaultMemorySpace<GOT>::space (G_nc), true};
380  }
381 
382  template<class GOT>
383  Details::LocalAccess<
384  GOT,
385  typename Details::DefaultMemorySpace<GOT>::type,
386  Details::AccessMode::WriteOnly>
387  writeOnly (GOT& G)
388  {
389  return {G, Details::DefaultMemorySpace<GOT>::space (G), true};
390  }
391 
392  template<class GOT>
393  Details::LocalAccess<
394  GOT,
395  typename Details::DefaultMemorySpace<GOT>::type,
396  Details::AccessMode::ReadWrite>
397  readWrite (GOT& G)
398  {
399  return {G, Details::DefaultMemorySpace<GOT>::space (G), true};
400  }
401 
403  // Implementation of withLocalAccess
405 
406  namespace Details {
407 
409  // Use std::tuple as a compile-time list (Greenspun's 10th Rule)
411 
412  // cons<T, std::tuple<Args...>>::type is std::tuple<T, Args...>.
413  // This is the usual Lisp CONS function, but for std::tuple. I
414  // got the idea from
415  // https://stackoverflow.com/questions/18701798/building-and-accessing-a-list-of-types-at-compile-time
416  // but without "struct Void {};", and with head of new list
417  // ordered first instead of last (hence "cons").
418  template<class ...> struct cons;
419 
420  // (CONS SomeType NIL)
421  template<class T, template <class ...> class List>
422  struct cons<T, List<>> {
423  using type = List<T>;
424  };
425 
426  // (CONS SomeType ListOfTypes)
427  template <class T, template <class ...> class List, class ...Types>
428  struct cons<T, List<Types...>>
429  {
430  typedef List<T, Types...> type;
431  };
432 
434  // Map from std::tuple<Ts...> to std::function<void (Ts...)>.
436 
437  // I got inspiration from
438  // https://stackoverflow.com/questions/15418841/how-do-i-strip-a-tuple-back-into-a-variadic-template-list-of-types
439  //
440  // The only significant change was from "using type = T<Ts...>;",
441  // to "using type = std::function<void (Ts...)>;".
442  template<class T>
443  struct tuple_to_function_type { };
444 
445  template<typename... Ts>
446  struct tuple_to_function_type<std::tuple<Ts...> >
447  {
448  using type = std::function<void (Ts...)>;
449  };
450 
451  // Map from a list of zero or more LocalAccess types, to the
452  // corresponding list of arguments for the user function to give to
453  // withLocalAccess.
454  template<class ... Args>
455  struct ArgsToFunction {};
456 
457  template<>
458  struct ArgsToFunction<> {
459  using arg_list_type = std::tuple<>;
460 
461  // Implementers should only use this.
462  using type = std::function<void ()>;
463  };
464 
465  template<class FirstLocalAccessType, class ... Rest>
466  struct ArgsToFunction<FirstLocalAccessType, Rest...> {
467  using head_arg_type =
468  with_local_access_function_argument_type<FirstLocalAccessType>;
469  using tail_arg_list_type =
470  typename ArgsToFunction<Rest...>::arg_list_type;
471  using arg_list_type =
472  typename cons<head_arg_type, tail_arg_list_type>::type;
473 
474  // Implementers should only use this.
475  using type = typename tuple_to_function_type<arg_list_type>::type;
476  };
477 
482  template<class ... LocalAccessTypes>
484  using current_user_function_type =
485  typename Details::ArgsToFunction<LocalAccessTypes...>::type;
486 
487  static void
488  withLocalAccess (LocalAccessTypes...,
489  typename Details::ArgsToFunction<LocalAccessTypes...>::type);
490  };
491 
495  template<>
496  struct WithLocalAccess<> {
497  using current_user_function_type =
498  typename Details::ArgsToFunction<>::type;
499 
500  static void
501  withLocalAccess (current_user_function_type userFunction)
502  {
503  userFunction ();
504  }
505  };
506 
513  template<class FirstLocalAccessType, class ... Rest>
514  struct WithLocalAccess<FirstLocalAccessType, Rest...> {
515  using current_user_function_type =
516  typename Details::ArgsToFunction<FirstLocalAccessType, Rest...>::type;
517 
518  static void
519  withLocalAccess (current_user_function_type userFunction,
520  FirstLocalAccessType first,
521  Rest... rest)
522  {
523  // The "master" local object is the scope guard for local
524  // data. Its constructor may allocate temporary storage, copy
525  // data to the desired memory space, etc. Its destructor will
526  // put everything back. "Put everything back" could be a
527  // no-op, or it could copy data back so where they need to go
528  // and/or free temporary storage.
529  //
530  // Users define this function and the type it returns by
531  // specializing GetMasterLocalObject for LocalAccess
532  // specializations.
533  auto first_lcl_master = getMasterLocalObject (first);
534 
535  // The "nonowning" local object is a nonowning view of the
536  // "master" local object. This is the only local object that
537  // users see, and they see it as input to their function.
538  // Subsequent slices / subviews view this nonowning local
539  // object. All such nonowning views must have lifetime
540  // contained within the lifetime of the master local object.
541  //
542  // Users define this function and the type it returns by
543  // specializing GetNonowningLocalObject (see above).
544  //
545  // Constraining the nonowning views' lifetime to this scope
546  // means that master local object types may use low-cost
547  // ownership models, like that of std::unique_ptr. There
548  // should be no need for reference counting (in the manner of
549  // std::shared_ptr) or Herb Sutter's deferred_heap.
550  auto first_lcl_view = getNonowningLocalObject (first, first_lcl_master);
551 
552  // Curry the user's function by fixing the first argument.
553 
554  // The commented-out implementation requires C++14, because it
555  // uses a generic lambda (the special case where parameters
556  // are "auto"). We do have the types of the arguments,
557  // though, from ArgsToFunction, so we don't need this feature.
558 
559  // WithLocalAccess<Rest...>::withLocalAccess
560  // (rest...,
561  // [=] (auto ... args) {
562  // userFunction (first_lcl_view, args...);
563  // });
564 
566  ([=] (typename Rest::function_argument_type... args) {
567  userFunction (first_lcl_view, args...);
568  },
569  rest...);
570  }
571  };
572  } // namespace Details
573 
575  // withLocalAccess function declaration and definition
577 
610  template<class ... LocalAccessTypes>
611  void
613  (typename Details::ArgsToFunction<LocalAccessTypes...>::type userFunction,
614  LocalAccessTypes... localAccesses)
615  {
616  using impl_type = Details::WithLocalAccess<LocalAccessTypes...>;
617  impl_type::withLocalAccess (userFunction, localAccesses...);
618  }
619 
620 } // namespace Tpetra
621 
622 #endif // TPETRA_WITHLOCALACCESS_HPP
623 
Mapping from &quot;master&quot; local object type to the nonowning &quot;local view&quot; type that users see (as argumen...
global_object_type & G_
Reference to the global object whose data the user will access.
LocalAccess< GlobalObjectType, NewMemorySpace, am > on(NewMemorySpace space) const
Declare intent to access this object&#39;s local data in a specific (Kokkos) memory space (instance)...
Details::LocalAccess< GlobalObjectType, typename Details::DefaultMemorySpace< GlobalObjectType >::type, Details::AccessMode::WriteOnly > writeOnly(GlobalObjectType &)
Declare that you want to access the given global object&#39;s local data in write-only mode...
Declaration of access intent for a global object.
GetMasterLocalObject< LocalAccessType >::master_local_object_type getMasterLocalObject(LocalAccessType LA)
Given a LocalAccess instance (which has a reference to a global object), get an instance of its maste...
Details::LocalAccess< GlobalObjectType, typename Details::DefaultMemorySpace< GlobalObjectType >::type, Details::AccessMode::ReadWrite > readWrite(GlobalObjectType &)
Declare that you want to access the given global object&#39;s local data in read-and-write mode...
bool isValid() const
Is access supposed to be valid? (See valid() above.)
GetNonowningLocalObject< LocalAccessType >::nonowning_local_object_type getNonowningLocalObject(LocalAccessType LA, const typename GetMasterLocalObject< LocalAccessType >::master_local_object_type &master)
Given a master local object, get an instance of a nonowning local object.
Implementation of withLocalAccess.
with_local_access_function_argument_type< canonical_this_type > function_argument_type
Type that users see, that&#39;s an argument to the function that they give to withLocalAccess.
LocalAccess< GlobalObjectType, MemorySpace, am > valid(const bool isValid) const
Declare at run time whether you actually want to access the object.
void withLocalAccess(typename Details::ArgsToFunction< LocalAccessTypes...>::type userFunction, LocalAccessTypes...localAccesses)
Get access to a Tpetra global object&#39;s local data.
memory_space getSpace() const
Memory space instance in which the user will access local data.
LocalAccess(global_object_type &G, memory_space space=memory_space(), const bool isValid=true)
Constructor.
typename Details::GetNonowningLocalObject< LocalAccessType >::nonowning_local_object_type with_local_access_function_argument_type
Type of the local object, that is an argument to the function the user gives to withLocalAccess.
bool valid_
Will I actually need to access this object?
Given a global object, get its default memory space (both the type and the default instance thereof)...
Details::LocalAccess< GlobalObjectType, typename Details::DefaultMemorySpace< GlobalObjectType >::type, Details::AccessMode::ReadOnly > readOnly(GlobalObjectType &)
Declare that you want to access the given global object&#39;s local data in read-only mode...
Mapping from LocalAccess to the &quot;master&quot; local object type.
memory_space space_
Memory space instance in which the user will access local data.