Skip to content

Commit

Permalink
Merge Copy [device_]matrix_data into arrays
Browse files Browse the repository at this point in the history
This merge changes the behavior for the read(const T&) overloads for Coo and Csr.

Now, the `const T&` overloads will copy the passed in [device_]matrix_data into the internal arrays directly, instead of using move assignments.
This also introduces the array copy assignment from const_array_view.
  • Loading branch information
MarcelKoch authored Dec 8, 2023
2 parents c67dc10 + c99bce3 commit a206ab6
Show file tree
Hide file tree
Showing 6 changed files with 499 additions and 9 deletions.
32 changes: 29 additions & 3 deletions core/matrix/coo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <ginkgo/core/matrix/dense.hpp>


#include "core/base/device_matrix_data_kernels.hpp"
#include "core/components/absolute_array_kernels.hpp"
#include "core/components/fill_array_kernels.hpp"
#include "core/components/format_conversion_kernels.hpp"
Expand All @@ -43,6 +44,7 @@ GKO_REGISTER_OPERATION(inplace_absolute_array,
components::inplace_absolute_array);
GKO_REGISTER_OPERATION(outplace_absolute_array,
components::outplace_absolute_array);
GKO_REGISTER_OPERATION(aos_to_soa, components::aos_to_soa);


} // anonymous namespace
Expand Down Expand Up @@ -180,15 +182,39 @@ void Coo<ValueType, IndexType>::resize(dim<2> new_size, size_type nnz)
template <typename ValueType, typename IndexType>
void Coo<ValueType, IndexType>::read(const mat_data& data)
{
this->read(device_mat_data::create_from_host(this->get_executor(), data));
auto size = data.size;
auto exec = this->get_executor();
this->set_size(size);
this->row_idxs_.resize_and_reset(data.nonzeros.size());
this->col_idxs_.resize_and_reset(data.nonzeros.size());
this->values_.resize_and_reset(data.nonzeros.size());
device_mat_data view{exec, size, this->row_idxs_.as_view(),
this->col_idxs_.as_view(), this->values_.as_view()};
const auto host_data =
make_array_view(exec->get_master(), data.nonzeros.size(),
const_cast<matrix_data_entry<ValueType, IndexType>*>(
data.nonzeros.data()));
exec->run(
coo::make_aos_to_soa(*make_temporary_clone(exec, &host_data), view));
}


template <typename ValueType, typename IndexType>
void Coo<ValueType, IndexType>::read(const device_mat_data& data)
{
// make a copy, read the data in
this->read(device_mat_data{this->get_executor(), data});
this->set_size(data.get_size());
// copy the arrays from device matrix data into the arrays of
// this. Compared to the read(device_mat_data&&) version, the internal
// arrays keep their current ownership status
this->values_ = make_const_array_view(data.get_executor(),
data.get_num_stored_elements(),
data.get_const_values());
this->col_idxs_ = make_const_array_view(data.get_executor(),
data.get_num_stored_elements(),
data.get_const_col_idxs());
this->row_idxs_ = make_const_array_view(data.get_executor(),
data.get_num_stored_elements(),
data.get_const_row_idxs());
}


Expand Down
48 changes: 45 additions & 3 deletions core/matrix/csr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ GKO_REGISTER_OPERATION(inv_scale, csr::inv_scale);
GKO_REGISTER_OPERATION(add_scaled_identity, csr::add_scaled_identity);
GKO_REGISTER_OPERATION(check_diagonal_entries,
csr::check_diagonal_entries_exist);
GKO_REGISTER_OPERATION(aos_to_soa, components::aos_to_soa);


} // anonymous namespace
Expand Down Expand Up @@ -423,15 +424,56 @@ void Csr<ValueType, IndexType>::move_to(Fbcsr<ValueType, IndexType>* result)
template <typename ValueType, typename IndexType>
void Csr<ValueType, IndexType>::read(const mat_data& data)
{
this->read(device_mat_data::create_from_host(this->get_executor(), data));
auto size = data.size;
auto exec = this->get_executor();
this->set_size(size);
this->row_ptrs_.resize_and_reset(size[0] + 1);
this->col_idxs_.resize_and_reset(data.nonzeros.size());
this->values_.resize_and_reset(data.nonzeros.size());
// the device matrix data contains views on the column indices
// and values array of this matrix, and an owning array for the
// row indices (which doesn't exist in this matrix)
device_mat_data view{exec, size,
array<IndexType>{exec, data.nonzeros.size()},
this->col_idxs_.as_view(), this->values_.as_view()};
const auto host_data =
make_array_view(exec->get_master(), data.nonzeros.size(),
const_cast<matrix_data_entry<ValueType, IndexType>*>(
data.nonzeros.data()));
exec->run(
csr::make_aos_to_soa(*make_temporary_clone(exec, &host_data), view));
exec->run(csr::make_convert_idxs_to_ptrs(view.get_const_row_idxs(),
view.get_num_stored_elements(),
size[0], this->get_row_ptrs()));
this->make_srow();
}


template <typename ValueType, typename IndexType>
void Csr<ValueType, IndexType>::read(const device_mat_data& data)
{
// make a copy, read the data in
this->read(device_mat_data{this->get_executor(), data});
auto size = data.get_size();
auto exec = this->get_executor();
this->row_ptrs_.resize_and_reset(size[0] + 1);
this->set_size(size);
// copy the column indices and values array from the device matrix data
// into this. Compared to the read(device_mat_data&&) version, the internal
// arrays keep their current ownership status.
this->values_ = make_const_array_view(data.get_executor(),
data.get_num_stored_elements(),
data.get_const_values());
this->col_idxs_ = make_const_array_view(data.get_executor(),
data.get_num_stored_elements(),
data.get_const_col_idxs());
const auto row_idxs = make_const_array_view(data.get_executor(),
data.get_num_stored_elements(),
data.get_const_row_idxs())
.copy_to_array();
auto local_row_idxs = make_temporary_clone(exec, &row_idxs);
exec->run(csr::make_convert_idxs_to_ptrs(local_row_idxs->get_const_data(),
local_row_idxs->get_size(),
size[0], this->get_row_ptrs()));
this->make_srow();
}


Expand Down
42 changes: 39 additions & 3 deletions core/test/base/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -523,21 +523,57 @@ TYPED_TEST(Array, CopyViewToArray)
TYPED_TEST(Array, CopyArrayToView)
{
TypeParam data[] = {1, 2, 3};
auto view = gko::make_array_view(this->exec, 3, data);
auto view = gko::make_array_view(this->exec, 2, data);
gko::array<TypeParam> array_size2(this->exec, {5, 4});
gko::array<TypeParam> array_size4(this->exec, {5, 4, 2, 1});

view = array_size2;

EXPECT_EQ(data[0], TypeParam{5});
EXPECT_EQ(data[1], TypeParam{4});
EXPECT_EQ(data[2], TypeParam{3});
EXPECT_EQ(view.get_size(), 3);
EXPECT_EQ(view.get_size(), 2);
EXPECT_EQ(array_size2.get_size(), 2);
ASSERT_THROW(view = array_size4, gko::OutOfBoundsError);
}


TYPED_TEST(Array, CopyConstViewToArray)
{
TypeParam data[] = {1, 2, 3, 4};
auto const_view = gko::make_const_array_view(this->exec, 4, data);
gko::array<TypeParam> array(this->exec, {5, 4, 2});

array = const_view;
data[1] = 7;

EXPECT_EQ(array.get_data()[0], TypeParam{1});
EXPECT_EQ(array.get_data()[1], TypeParam{2});
EXPECT_EQ(array.get_data()[2], TypeParam{3});
EXPECT_EQ(array.get_data()[3], TypeParam{4});
EXPECT_EQ(array.get_size(), 4);
ASSERT_EQ(const_view.get_size(), 4);
}


TYPED_TEST(Array, CopyConstViewToView)
{
TypeParam data1[] = {1, 2, 3, 4};
TypeParam data2[] = {5, 4, 2};
auto view = gko::make_array_view(this->exec, 3, data2);
auto const_view3 = gko::make_const_array_view(this->exec, 3, data1);
auto const_view4 = gko::make_const_array_view(this->exec, 4, data1);

view = const_view3;
data1[1] = 7;

EXPECT_EQ(view.get_data()[0], TypeParam{1});
EXPECT_EQ(view.get_data()[1], TypeParam{2});
EXPECT_EQ(view.get_data()[2], TypeParam{3});
EXPECT_EQ(view.get_size(), 3);
EXPECT_EQ(const_view3.get_size(), 3);
ASSERT_THROW(view = const_view4, gko::OutOfBoundsError);
}

TYPED_TEST(Array, MoveArrayToArray)
{
gko::array<TypeParam> array(this->exec, {1, 2, 3});
Expand Down
166 changes: 166 additions & 0 deletions core/test/matrix/coo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,42 @@ TYPED_TEST(Coo, CanBeReadFromMatrixData)
}


TYPED_TEST(Coo, CanBeReadFromMatrixDataIntoViews)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto row_idxs = gko::array<index_type>(this->exec, 4);
auto col_idxs = gko::array<index_type>(this->exec, 4);
auto values = gko::array<value_type>(this->exec, 4);
auto m = Mtx::create(this->exec, gko::dim<2>{2, 3}, values.as_view(),
col_idxs.as_view(), row_idxs.as_view());

m->read({{2, 3}, {{0, 0, 1.0}, {0, 1, 3.0}, {0, 2, 2.0}, {1, 1, 5.0}}});

this->assert_equal_to_original_mtx(m);
ASSERT_EQ(row_idxs.get_data(), m->get_row_idxs());
ASSERT_EQ(col_idxs.get_data(), m->get_col_idxs());
ASSERT_EQ(values.get_data(), m->get_values());
}


TYPED_TEST(Coo, ThrowsOnIncompatibleReadFromMatrixDataIntoViews)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto row_idxs = gko::array<index_type>(this->exec, 1);
auto col_idxs = gko::array<index_type>(this->exec, 1);
auto values = gko::array<value_type>(this->exec, 1);
auto m = Mtx::create(this->exec, gko::dim<2>{2, 3}, values.as_view(),
col_idxs.as_view(), row_idxs.as_view());

ASSERT_THROW(m->read({{2, 3}, {{0, 0, 1.0}, {0, 1, 3.0}}}),
gko::NotSupported);
}


TYPED_TEST(Coo, CanBeReadFromMatrixAssemblyData)
{
using Mtx = typename TestFixture::Mtx;
Expand All @@ -215,6 +251,136 @@ TYPED_TEST(Coo, CanBeReadFromMatrixAssemblyData)
}


TYPED_TEST(Coo, CanBeReadFromDeviceMatrixData)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto m = Mtx::create(this->exec);
gko::matrix_assembly_data<value_type, index_type> data(gko::dim<2>{2, 3});
data.set_value(0, 0, 1.0);
data.set_value(0, 1, 3.0);
data.set_value(0, 2, 2.0);
data.set_value(1, 1, 5.0);
auto device_data =
gko::device_matrix_data<value_type, index_type>::create_from_host(
this->exec, data.get_ordered_data());

m->read(device_data);

this->assert_equal_to_original_mtx(m);
ASSERT_EQ(device_data.get_num_stored_elements(),
m->get_num_stored_elements());
ASSERT_EQ(device_data.get_size(), m->get_size());
}


TYPED_TEST(Coo, CanBeReadFromDeviceMatrixDataIntoViews)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto row_idxs = gko::array<index_type>(this->exec, 4);
auto col_idxs = gko::array<index_type>(this->exec, 4);
auto values = gko::array<value_type>(this->exec, 4);
auto m = Mtx::create(this->exec, gko::dim<2>{2, 3}, values.as_view(),
col_idxs.as_view(), row_idxs.as_view());
gko::matrix_assembly_data<value_type, index_type> data(gko::dim<2>{2, 3});
data.set_value(0, 0, 1.0);
data.set_value(0, 1, 3.0);
data.set_value(0, 2, 2.0);
data.set_value(1, 1, 5.0);
auto device_data =
gko::device_matrix_data<value_type, index_type>::create_from_host(
this->exec, data.get_ordered_data());

m->read(device_data);

this->assert_equal_to_original_mtx(m);
ASSERT_EQ(row_idxs.get_data(), m->get_row_idxs());
ASSERT_EQ(col_idxs.get_data(), m->get_col_idxs());
ASSERT_EQ(values.get_data(), m->get_values());
}


TYPED_TEST(Coo, ThrowsOnIncompatibleReadFromDeviceMatrixDataIntoViews)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto row_idxs = gko::array<index_type>(this->exec, 1);
auto col_idxs = gko::array<index_type>(this->exec, 1);
auto values = gko::array<value_type>(this->exec, 1);
auto m = Mtx::create(this->exec, gko::dim<2>{2, 3}, values.as_view(),
col_idxs.as_view(), row_idxs.as_view());
gko::matrix_assembly_data<value_type, index_type> data(gko::dim<2>{2, 3});
data.set_value(0, 0, 1.0);
data.set_value(0, 1, 3.0);
auto device_data =
gko::device_matrix_data<value_type, index_type>::create_from_host(
this->exec, data.get_ordered_data());

ASSERT_THROW(m->read(device_data), gko::OutOfBoundsError);
}


TYPED_TEST(Coo, CanBeReadFromMovedDeviceMatrixData)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto m = Mtx::create(this->exec);
gko::matrix_assembly_data<value_type, index_type> data(gko::dim<2>{2, 3});
data.set_value(0, 0, 1.0);
data.set_value(0, 1, 3.0);
data.set_value(0, 2, 2.0);
data.set_value(1, 1, 5.0);
auto device_data =
gko::device_matrix_data<value_type, index_type>::create_from_host(
this->exec, data.get_ordered_data());

m->read(std::move(device_data));

this->assert_equal_to_original_mtx(m);
ASSERT_EQ(device_data.get_size(), gko::dim<2>{});
ASSERT_EQ(device_data.get_num_stored_elements(), 0);
}


TYPED_TEST(Coo, CanBeReadFromMovedDeviceMatrixDataIntoViews)
{
using Mtx = typename TestFixture::Mtx;
using value_type = typename TestFixture::value_type;
using index_type = typename TestFixture::index_type;
auto row_idxs = gko::array<index_type>(this->exec, 2);
auto col_idxs = gko::array<index_type>(this->exec, 2);
auto values = gko::array<value_type>(this->exec, 2);
row_idxs.fill(0);
col_idxs.fill(0);
values.fill(gko::zero<value_type>());
auto m = Mtx::create(this->exec, gko::dim<2>{2, 3}, values.as_view(),
col_idxs.as_view(), row_idxs.as_view());
gko::matrix_assembly_data<value_type, index_type> data(gko::dim<2>{2, 3});
data.set_value(0, 0, 1.0);
data.set_value(0, 1, 3.0);
data.set_value(0, 2, 2.0);
data.set_value(1, 1, 5.0);
auto device_data =
gko::device_matrix_data<value_type, index_type>::create_from_host(
this->exec, data.get_ordered_data());
auto orig_row_idxs = device_data.get_row_idxs();
auto orig_col_idxs = device_data.get_col_idxs();
auto orig_values = device_data.get_values();

m->read(std::move(device_data));

this->assert_equal_to_original_mtx(m);
ASSERT_EQ(orig_row_idxs, m->get_row_idxs());
ASSERT_EQ(orig_col_idxs, m->get_col_idxs());
ASSERT_EQ(orig_values, m->get_values());
}


TYPED_TEST(Coo, GeneratesCorrectMatrixData)
{
using Mtx = typename TestFixture::Mtx;
Expand Down
Loading

0 comments on commit a206ab6

Please sign in to comment.