Skip to content

Commit

Permalink
Add a small class to create a class instance on device.
Browse files Browse the repository at this point in the history
And a unit test for it.  It is not just creating a device
object but a virtual class instance on device and then
invoking a virtual function through the base class on
device.

This is meant to be a simple example and the start of the
discussion on how to structure the code for future
development of GPU enabled Kokkos kernels.
  • Loading branch information
overfelt committed Jun 25, 2018
1 parent 2c1d183 commit bd0d130
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 0 deletions.
5 changes: 5 additions & 0 deletions include/KokkosInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ void kokkos_parallel_reduce(SizeType n, Function loop_body, ReduceType& reduce,
Kokkos::parallel_reduce(debuggingName, Kokkos::RangePolicy<Kokkos::Serial>(0, n), loop_body, reduce);
}

template<typename T>
inline T* kokkos_malloc_on_device(const std::string& debuggingName) {
return static_cast<T*>(Kokkos::kokkos_malloc(debuggingName, sizeof(T)));
}
inline void kokkos_free_on_device(void * ptr) { Kokkos::kokkos_free(ptr); }
}
}

Expand Down
27 changes: 27 additions & 0 deletions include/utils/CreateDeviceExpression.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef CREATEDEVICEEXPRESSION_H
#define CREATEDEVICEEXPRESSION_H

#include <type_traits>

#include <KokkosInterface.h>

namespace sierra {
namespace nalu {

template <typename T>
inline
T* create_device_expression(const T & rhs)
{
const std::string debuggingName(typeid(T).name());
T* t = kokkos_malloc_on_device<T>(debuggingName);
// Bring rhs into local scope for capture to device.
const T RHS(rhs);
kokkos_parallel_for(debuggingName, 1, [&] (const int i) {
new (t) T(RHS);
});
return t;
}
} // namespace nalu
} // namespace sierra

#endif /* CREATEDEVICEEXPRESSION_H */
1 change: 1 addition & 0 deletions unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_sources(GlobalUnitSourceList
UnitTest1ElemCoordCheck.C
UnitTestABLWallFunction.C
UnitTestBasicKokkos.C
UnitTestCreateOnDevice.C
UnitTestElemSuppAlg.C
UnitTestElementDescription.C
UnitTestFieldUtils.C
Expand Down
91 changes: 91 additions & 0 deletions unit_tests/UnitTestCreateOnDevice.C
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#include <gtest/gtest.h>

#include "UnitTestUtils.h"


#include <string>
#include <iostream>
#include <vector>

#include <KokkosInterface.h>
#include "utils/CreateDeviceExpression.h"

class deviceable {
protected :
deviceable *DeviceCopy;
public :
KOKKOS_FORCEINLINE_FUNCTION deviceable() : DeviceCopy(nullptr) {}
virtual ~deviceable() {
if (DeviceCopy) delete_device_copy();
DeviceCopy = nullptr;
}
template <class T> void copy_to_device(const T &t) {
DeviceCopy = sierra::nalu::create_device_expression(t);
}
void delete_device_copy() {
sierra::nalu::kokkos_free_on_device(DeviceCopy);
}
template<class T> T* device_copy() const {return dynamic_cast<T*>(DeviceCopy);}
};

class shape : public deviceable {
public :
KOKKOS_FORCEINLINE_FUNCTION shape() {}
virtual ~shape() {}
virtual double area() const = 0;
};

class rectangle : public shape {
const double L,W;
public :
KOKKOS_FORCEINLINE_FUNCTION rectangle(const double l,const double w):shape(),L(l),W(w) {
copy_to_device(*this);
}
KOKKOS_FORCEINLINE_FUNCTION rectangle(const rectangle &r):shape(),L(r.L),W(r.W) {}
virtual ~rectangle(){}
virtual double area() const final {
return L*W;
}
};

class circle : public shape {
const double R;
public :
KOKKOS_FORCEINLINE_FUNCTION circle(const double r):shape(),R(r) {
copy_to_device(*this);
}
KOKKOS_FORCEINLINE_FUNCTION circle(const circle &c):shape(),R(c.R) {}
virtual ~circle(){}
virtual double area() const final {
return 2*3.14159265*R;
}
};


TEST(CreateDeviceExpression, shapes)
{
// Create a couple of virtual classes on host and device.
shape *r = new rectangle(4,5);
shape *c = new circle(2);
shape *r_dev = r->device_copy<shape>();
shape *c_dev = c->device_copy<shape>();

double r_area;
auto r_on_device = [&] (int i, double &a) {
a = r_dev->area();
};
sierra::nalu::kokkos_parallel_reduce(1, r_on_device, r_area, "Call Rectangle on Device.");

double c_area;
auto c_on_device = [&] (int i, double &a) {
a = c_dev->area();
};
sierra::nalu::kokkos_parallel_reduce(1, c_on_device, c_area, "Call Circle on Device.");

EXPECT_EQ(r_area, r->area()) << "Area of a 4x5 rectangle on device and host";
EXPECT_EQ(c_area, c->area()) << "Area of a radius 2 circle on device and host";

delete r;
delete c;
}

0 comments on commit bd0d130

Please sign in to comment.