Tpetra parallel linear algebra  Version of the Day
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>
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 
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 
Declaration of access intent for a global object.
bool valid_
Will I actually need to access this object?
LocalAccess< GlobalObjectType, NewMemorySpace, am > on(NewMemorySpace space) const
Declare intent to access this object's local data in a specific (Kokkos) memory space (instance).
global_object_type & G_
Reference to the global object whose data the user will access.
bool isValid() const
Is access supposed to be valid? (See valid() above.)
LocalAccess(global_object_type &G, memory_space space=memory_space(), const bool isValid=true)
Constructor.
memory_space space_
Memory space instance in which the user will access local data.
memory_space getSpace() const
Memory space instance in which the user will access local data.
with_local_access_function_argument_type< canonical_this_type > function_argument_type
Type that users see, that'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.
Implementation details of Tpetra.
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...
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.
Namespace Tpetra contains the class and methods constituting the Tpetra library.
Details::LocalAccess< GlobalObjectType, typename Details::DefaultMemorySpace< GlobalObjectType >::type, Details::AccessMode::ReadOnly > readOnly(GlobalObjectType &)
Declare that you want to access the given global object's local data in read-only mode,...
void withLocalAccess(typename Details::ArgsToFunction< LocalAccessTypes... >::type userFunction, LocalAccessTypes... localAccesses)
Get access to a Tpetra global object's local data.
Details::LocalAccess< GlobalObjectType, typename Details::DefaultMemorySpace< GlobalObjectType >::type, Details::AccessMode::ReadWrite > readWrite(GlobalObjectType &)
Declare that you want to access the given global object's local data in read-and-write mode,...
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.
Details::LocalAccess< GlobalObjectType, typename Details::DefaultMemorySpace< GlobalObjectType >::type, Details::AccessMode::WriteOnly > writeOnly(GlobalObjectType &)
Declare that you want to access the given global object's local data in write-only mode,...
Given a global object, get its default memory space (both the type and the default instance thereof).
Mapping from LocalAccess to the "master" local object type.
Mapping from "master" local object type to the nonowning "local view" type that users see (as argumen...
Implementation of withLocalAccess.