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 #include <Kokkos_Macros.hpp>
46 
47 #if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(_OPENMP)
48 
49 // FIXME_OPENMPTARGET - macro for workaround implementation in UniqueToken
50 // constructor. undef'ed at the end
51 #define KOKKOS_IMPL_OPENMPTARGET_WORKAROUND
52 
53 #include <Kokkos_OpenMPTarget.hpp>
54 #include <OpenMPTarget/Kokkos_OpenMPTarget_UniqueToken.hpp>
55 #include <OpenMPTarget/Kokkos_OpenMPTarget_Instance.hpp>
56 
57 #include <sstream>
58 
59 namespace Kokkos {
60 namespace Experimental {
61 namespace Impl {
fence()62 void OpenMPTargetInternal::fence() {}
concurrency()63 int OpenMPTargetInternal::concurrency() { return 128000; }
name()64 const char* OpenMPTargetInternal::name() { return "OpenMPTarget"; }
print_configuration(std::ostream &,const bool)65 void OpenMPTargetInternal::print_configuration(std::ostream& /*stream*/,
66                                                const bool) {
67   // FIXME_OPENMPTARGET
68   printf("Using OpenMPTarget\n");
69 }
70 
impl_finalize()71 void OpenMPTargetInternal::impl_finalize() {
72   m_is_initialized = false;
73   Kokkos::Impl::OpenMPTargetExec space;
74   if (space.m_lock_array != nullptr) space.clear_lock_array();
75 
76   if (space.m_uniquetoken_ptr != nullptr)
77     Kokkos::kokkos_free<Kokkos::Experimental::OpenMPTargetSpace>(
78         space.m_uniquetoken_ptr);
79 }
impl_initialize()80 void OpenMPTargetInternal::impl_initialize() { m_is_initialized = true; }
impl_is_initialized()81 int OpenMPTargetInternal::impl_is_initialized() {
82   return m_is_initialized ? 1 : 0;
83 }
84 
impl_singleton()85 OpenMPTargetInternal* OpenMPTargetInternal::impl_singleton() {
86   static OpenMPTargetInternal self;
87   return &self;
88 }
89 
90 }  // Namespace Impl
91 
OpenMPTarget()92 OpenMPTarget::OpenMPTarget()
93     : m_space_instance(Impl::OpenMPTargetInternal::impl_singleton()) {}
94 
name()95 const char* OpenMPTarget::name() {
96   return Impl::OpenMPTargetInternal::impl_singleton()->name();
97 }
print_configuration(std::ostream & stream,const bool detail)98 void OpenMPTarget::print_configuration(std::ostream& stream,
99                                        const bool detail) {
100   m_space_instance->print_configuration(stream, detail);
101 }
102 
concurrency()103 int OpenMPTarget::concurrency() {
104   return Impl::OpenMPTargetInternal::impl_singleton()->concurrency();
105 }
fence()106 void OpenMPTarget::fence() {
107   Impl::OpenMPTargetInternal::impl_singleton()->fence();
108 }
109 
impl_initialize()110 void OpenMPTarget::impl_initialize() { m_space_instance->impl_initialize(); }
impl_finalize()111 void OpenMPTarget::impl_finalize() { m_space_instance->impl_finalize(); }
impl_is_initialized()112 int OpenMPTarget::impl_is_initialized() {
113   return Impl::OpenMPTargetInternal::impl_singleton()->impl_is_initialized();
114 }
115 }  // Namespace Experimental
116 
117 namespace Impl {
118 int g_openmptarget_space_factory_initialized =
119     Kokkos::Impl::initialize_space_factory<OpenMPTargetSpaceInitializer>(
120         "160_OpenMPTarget");
121 
initialize(const InitArguments & args)122 void OpenMPTargetSpaceInitializer::initialize(const InitArguments& args) {
123   // Prevent "unused variable" warning for 'args' input struct.  If
124   // Serial::initialize() ever needs to take arguments from the input
125   // struct, you may remove this line of code.
126   (void)args;
127 
128   if (std::is_same<Kokkos::Experimental::OpenMPTarget,
129                    Kokkos::DefaultExecutionSpace>::value) {
130     Kokkos::Experimental::OpenMPTarget().impl_initialize();
131     // std::cout << "Kokkos::initialize() fyi: OpenMP enabled and initialized"
132     // << std::endl ;
133   } else {
134     // std::cout << "Kokkos::initialize() fyi: OpenMP enabled but not
135     // initialized" << std::endl ;
136   }
137 }
138 
finalize(const bool all_spaces)139 void OpenMPTargetSpaceInitializer::finalize(const bool all_spaces) {
140   if (std::is_same<Kokkos::Experimental::OpenMPTarget,
141                    Kokkos::DefaultExecutionSpace>::value ||
142       all_spaces) {
143     if (Kokkos::Experimental::OpenMPTarget().impl_is_initialized())
144       Kokkos::Experimental::OpenMPTarget().impl_finalize();
145   }
146 }
147 
fence()148 void OpenMPTargetSpaceInitializer::fence() {
149   Kokkos::Experimental::OpenMPTarget::fence();
150 }
151 
print_configuration(std::ostream & msg,const bool detail)152 void OpenMPTargetSpaceInitializer::print_configuration(std::ostream& msg,
153                                                        const bool detail) {
154   msg << "OpenMPTarget Execution Space:" << std::endl;
155   msg << "  KOKKOS_ENABLE_OPENMPTARGET: ";
156   msg << "yes" << std::endl;
157 
158   msg << "\nOpenMPTarget Runtime Configuration:" << std::endl;
159   Kokkos::Experimental::OpenMPTarget().print_configuration(msg, detail);
160 }
161 
162 }  // namespace Impl
163 }  // Namespace Kokkos
164 
165 namespace Kokkos {
166 namespace Experimental {
167 
168 UniqueToken<Kokkos::Experimental::OpenMPTarget,
169             Kokkos::Experimental::UniqueTokenScope::Global>::
UniqueToken(Kokkos::Experimental::OpenMPTarget const &)170     UniqueToken(Kokkos::Experimental::OpenMPTarget const&) {
171 #ifdef KOKKOS_IMPL_OPENMPTARGET_WORKAROUND
172   uint32_t* ptr = Kokkos::Impl::OpenMPTargetExec::m_uniquetoken_ptr;
173   int count     = Kokkos::Experimental::OpenMPTarget().concurrency();
174   if (ptr == nullptr) {
175     int size = count * sizeof(uint32_t);
176     ptr      = static_cast<uint32_t*>(
177         Kokkos::kokkos_malloc<Kokkos::Experimental::OpenMPTargetSpace>(
178             "Kokkos::OpenMPTarget::m_uniquetoken_ptr", size));
179     std::vector<uint32_t> h_buf(count, 0);
180     OMPT_SAFE_CALL(omp_target_memcpy(ptr, h_buf.data(), size, 0, 0,
181                                      omp_get_default_device(),
182                                      omp_get_initial_device()));
183 
184     Kokkos::Impl::OpenMPTargetExec::m_uniquetoken_ptr = ptr;
185   }
186 #else
187 // FIXME_OPENMPTARGET - 2 versions of non-working implementations to fill `ptr`
188 // with 0's
189 // Version 1 - Creating a target region and filling the
190 // pointer Error - CUDA error: named symbol not found
191 #pragma omp target teams distribute parallel for is_device_ptr(ptr) \
192     map(to                                                          \
193         : size)
194   for (int i = 0; i < count; ++i) ptr[i] = 0;
195 
196   // Version 2 : Allocating a view on the device and filling it with a scalar
197   // value of 0.
198   Kokkos::View<uint32_t*, Kokkos::Experimental::OpenMPTargetSpace> ptr_view(
199       ptr, count);
200   Kokkos::deep_copy(ptr_view, 0);
201 #endif
202   m_buffer = ptr;
203   m_count  = count;
204 }
205 }  // namespace Experimental
206 }  // namespace Kokkos
207 
208 #undef KOKKOS_IMPL_OPENMPTARGET_WORKAROUND
209 #endif  // defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(_OPENMP)
210