/* //@HEADER // ************************************************************************ // // Kokkos v. 2.0 // Copyright (2014) Sandia Corporation // // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // 1. Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the Corporation nor the names of the // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) // // ************************************************************************ //@HEADER */ #include namespace TestAtomic { // Struct for testing arbitrary size atomics template struct SuperScalar { double val[N]; KOKKOS_INLINE_FUNCTION SuperScalar() { for(int i=0; i std::ostream& operator<<(std::ostream& os, const SuperScalar& dt) { os << "{ "; for(int i=0;i struct ZeroFunctor { typedef DEVICE_TYPE execution_space; typedef typename Kokkos::View type; typedef typename Kokkos::View::HostMirror h_type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { data() = 0; } }; //--------------------------------------------------- //--------------atomic_fetch_add--------------------- //--------------------------------------------------- template struct AddFunctor{ typedef DEVICE_TYPE execution_space; typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { Kokkos::atomic_fetch_add(&data(),(T)1); } }; template T AddLoop(int loop) { struct ZeroFunctor f_zero; typename ZeroFunctor::type data("Data"); typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; Kokkos::parallel_for(1,f_zero); execution_space::fence(); struct AddFunctor f_add; f_add.data = data; Kokkos::parallel_for(loop,f_add); execution_space::fence(); Kokkos::deep_copy(h_data,data); T val = h_data(); return val; } template T AddLoopSerial(int loop) { T* data = new T[1]; data[0] = 0; for(int i=0;i struct CASFunctor{ typedef DEVICE_TYPE execution_space; typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { T old = data(); T newval, assumed; do { assumed = old; newval = assumed + (T)1; old = Kokkos::atomic_compare_exchange(&data(), assumed, newval); } while( old != assumed ); } }; template T CASLoop(int loop) { struct ZeroFunctor f_zero; typename ZeroFunctor::type data("Data"); typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; Kokkos::parallel_for(1,f_zero); execution_space::fence(); struct CASFunctor f_cas; f_cas.data = data; Kokkos::parallel_for(loop,f_cas); execution_space::fence(); Kokkos::deep_copy(h_data,data); T val = h_data(); return val; } template T CASLoopSerial(int loop) { T* data = new T[1]; data[0] = 0; for(int i=0;i struct ExchFunctor{ typedef DEVICE_TYPE execution_space; typedef Kokkos::View type; type data, data2; KOKKOS_INLINE_FUNCTION void operator()(int i) const { T old = Kokkos::atomic_exchange(&data(),(T)i); Kokkos::atomic_fetch_add(&data2(),old); } }; template T ExchLoop(int loop) { struct ZeroFunctor f_zero; typename ZeroFunctor::type data("Data"); typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; Kokkos::parallel_for(1,f_zero); execution_space::fence(); typename ZeroFunctor::type data2("Data"); typename ZeroFunctor::h_type h_data2("HData"); f_zero.data = data2; Kokkos::parallel_for(1,f_zero); execution_space::fence(); struct ExchFunctor f_exch; f_exch.data = data; f_exch.data2 = data2; Kokkos::parallel_for(loop,f_exch); execution_space::fence(); Kokkos::deep_copy(h_data,data); Kokkos::deep_copy(h_data2,data2); T val = h_data() + h_data2(); return val; } template T ExchLoopSerial(int loop) { T* data = new T[1]; T* data2 = new T[1]; data[0] = 0; data2[0] = 0; for(int i=0;i T LoopVariant(int loop, int test) { switch (test) { case 1: return AddLoop(loop); case 2: return CASLoop(loop); case 3: return ExchLoop(loop); } return 0; } template T LoopVariantSerial(int loop, int test) { switch (test) { case 1: return AddLoopSerial(loop); case 2: return CASLoopSerial(loop); case 3: return ExchLoopSerial(loop); } return 0; } template bool Loop(int loop, int test) { T res = LoopVariant(loop,test); T resSerial = LoopVariantSerial(loop,test); bool passed = true; if ( resSerial != res ) { passed = false; std::cout << "Loop<" << typeid(T).name() << ">( test = " << test << " FAILED : " << resSerial << " != " << res << std::endl ; } return passed ; } }