Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template TpetraWrappers::SparseMatrix::vmult on the vector type. #16614

Merged
merged 1 commit into from
Feb 28, 2024

Conversation

kinnewig
Copy link
Contributor

@kinnewig kinnewig commented Feb 9, 2024

Rework from LinearAlgebra::TpetraWrappers::SparseMatrix<Number, MemorySpace>::vmult (and Tvmult, vmult_add, Tvmult_add) such that it takes arbritraty vector types.

Initially, this was part of #16588, but I moved it into a separate pull request because it contains a few points I would like to discuss.

Each function of vmult, Tvmult, vmult_add, and Tvmult_add contains a part that converts the raw data of the input vectors into a Kokkos::DualView. I was thinking about moving that conversion into a separate (internal) function (and marking that function as inline).
And this is the most convenient way to convert the raw data from a vector into a Kokkos::DualView I came up with. But if there is a more elegant way to do that, please let me know!

Furthermore, we need a more elegant way to initialize all templates.

Since some tests include a vmult between a TrilinosWrappers::SparseMatrix and a dealii::Vector, this should help with #16611 as well.

Copy link
Member

@bangerth bangerth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will leave this one to @masterleinad given that it does all of this view magic...

Comment on lines 65 to 137
template <typename Number, typename MemorySpace>
Number *
begin(LinearAlgebra::TpetraWrappers::Vector<Number, MemorySpace> &V)
{
return V.trilinos_vector().getDataNonConst().get();
}

template <typename Number, typename MemorySpace>
const Number *
begin(const LinearAlgebra::TpetraWrappers::Vector<Number, MemorySpace> &V)
{
return V.trilinos_vector().getData().get();
}

template <typename Number, typename MemorySpace>
Number *
end(LinearAlgebra::TpetraWrappers::Vector<Number, MemorySpace> &V)
{
return V.trilinos_vector().getDataNonConst().get() +
V.trilinos_vector().getLocalLength();
}

template <typename Number, typename MemorySpace>
const Number *
end(const LinearAlgebra::TpetraWrappers::Vector<Number, MemorySpace> &V)
{
return V.trilinos_vector().getData().get() +
V.trilinos_vector().getLocalLength();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of providing these overloads here, why not just add begin() and end() functions to the LinearAlgebra::TpetraWrappers::Vector class? Then you won't need any of these functions here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will change this!
But do all other vector classes In deal.II implement begin() and end() ?

I saw, at least dealii::vector<Number> has a begin() and end() method implemented.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I don't actually know whether all vectors have begin() and end(), but even if they did it's not clear what semantics that would follow: Only the locally owned? locally stored? all elements?

Perhaps what you have is better. In fact, perhaps it would be better to call these functions begin_locally_owned() and end_locally_owned() to make this clear.

Comment on lines 902 to 907
Kokkos::View<
typename VectorType::impl_scalar_type **,
Kokkos::LayoutLeft,
Kokkos::Device<typename MemorySpace::kokkos_space::execution_space,
typename MemorySpace::kokkos_space>>
kokkos_view_src(raw_src, src_local_size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need a two-dimensional View here?

Suggested change
Kokkos::View<
typename VectorType::impl_scalar_type **,
Kokkos::LayoutLeft,
Kokkos::Device<typename MemorySpace::kokkos_space::execution_space,
typename MemorySpace::kokkos_space>>
kokkos_view_src(raw_src, src_local_size);
Kokkos::View<
typename VectorType::impl_scalar_type *,
typename MemorySpace::kokkos_space>
kokkos_view_src(raw_src, src_local_size);

How do you know the memory space of InputVectorType?

Copy link
Contributor Author

@kinnewig kinnewig Feb 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you know the memory space of InputVectorType?

Good point!

I thought I had to provide the memory space of the target vector. But you are right; this is not true. We need to provide the memory space of the source vector. So we need to be way more careful here...

For most vector types, the memory space is always Host. The only exceptions I am aware of is the TpetraWrappers::Vector<Number, MemorySpace> and the distributed::Vector<Number, MemorySpace>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need a two-dimensional View here?

How do you know the memory space of InputVectorType?

The Tpetra::Vector always expects a two-dimensional View, as far as I know.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. In this case, you still have to provide extents for both dimensions in the View constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. In this case, you still have to provide extents for both dimensions in the View constructor.

I am not that experienced with Kokkos::View, what constructor should I use here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be

Kokkos::View<
        typename VectorType::impl_scalar_type **,
        Kokkos::LayoutLeft,
        Kokkos::Device<typename MemorySpace::kokkos_space::execution_space,
                       typename MemorySpace::kokkos_space>>
        kokkos_view_src(raw_src, src_local_size, 1);

so that you provide the pointer and an argument for the extent in every dimension. This should be strictly enforced in newer Kokkos versions. Also, there is not much of a point to provide a full Device template argument. In the end, we only need the MemorySpace. For managed Views you could provide an execution space instance as runtime argument to make sure it uses a particular stream (and fences less) or even decide not to initialize the allocation at all. None of that really matters for unmanaged Views like here, of course.

// For the src vector:
// create a Kokkos::View from the src vector
typename VectorType::impl_scalar_type *raw_src =
reinterpret_cast<typename VectorType::impl_scalar_type *>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need a reinterpret_cast here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the Tpetra::Vector expects this type.
Since this is just a complicated alias for Number, I can give it a try and remove this cast.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be very suspicious of any reinterpret_cast we are doing in these classes since we don't really have a buffer that we would use with placement new. Whenever we need a different type we should copy values instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this. x.begin() does not always return a pointer. It could just be an iterator. reinterpret_cast will in such cases not result in anything useful, with no error message. I think there ought to be a better way.

What are the types you're casting here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need the reinterpret_cast here. But at another point, we need a const_cast.
I specialized the function so we know which vector type we are working on, so we can ensure that the cast is working correctly.

@kinnewig
Copy link
Contributor Author

kinnewig commented Feb 15, 2024

I reworked the vmult function.
It now calls an internal function such that one can define specializations more easily. When no specialization for the InputVectorType is provided, it throws an Assert. I guess this is the best approach since it ensures that the memory space is handled correctly

typename SparseMatrix<Number, MemorySpace>::VectorType tpetra_src(
M.trilinos_matrix().getDomainMap(), kokkos_dual_view_src);

M.trilinos_matrix().apply(tpetra_src, tpetra_dst, mode, alpha, beta);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also sync the DualView?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just assumed it does. I just verified it passed the test:

trilinos_tpetra/sparse_matrix_vector_08.cc

Since it passed that test, I assumed it was okay as it was.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is only one memory space, sync doesn't do anything anyway. I think it's reasonable to assume that apply makes sure the two Views are in sync, though.

typename SparseMatrix<Number, MemorySpace>::VectorType tpetra_src(
M.trilinos_matrix().getDomainMap(), kokkos_dual_view_src);

M.trilinos_matrix().apply(tpetra_src, tpetra_dst, mode, alpha, beta);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is only one memory space, sync doesn't do anything anyway. I think it's reasonable to assume that apply makes sure the two Views are in sync, though.

@masterleinad
Copy link
Member

You'll have to fix the indentation.

diff --git a/include/deal.II/lac/trilinos_tpetra_sparse_matrix.templates.h b/include/deal.II/lac/trilinos_tpetra_sparse_matrix.templates.h
index 87a3723e0..6ba2d5613 100644
--- a/include/deal.II/lac/trilinos_tpetra_sparse_matrix.templates.h
+++ b/include/deal.II/lac/trilinos_tpetra_sparse_matrix.templates.h
@@ -83,9 +83,8 @@ namespace LinearAlgebra
           dst.begin(), dst_local_size, 1);
 
         // get a Kokkos::DualView
-        auto mirror_view_dst =
-          Kokkos::create_mirror_view_and_copy(typename MemorySpace::kokkos_space{},
-                                     kokkos_view_dst);
+        auto mirror_view_dst = Kokkos::create_mirror_view_and_copy(
+          typename MemorySpace::kokkos_space{}, kokkos_view_dst);
         typename SparseMatrix<Number, MemorySpace>::VectorType::dual_view_type
           kokkos_dual_view_dst(mirror_view_dst, kokkos_view_dst);
 
@@ -99,9 +98,8 @@ namespace LinearAlgebra
           const_cast<Number *>(src.begin()), src_local_size, 1);
 
         // get a Kokkos::DualView
-        auto mirror_view_src =
-          Kokkos::create_mirror_view_and_copy(typename MemorySpace::kokkos_space{},
-                                     kokkos_view_src);
+        auto mirror_view_src = Kokkos::create_mirror_view_and_copy(
+          typename MemorySpace::kokkos_space{}, kokkos_view_src);
         typename SparseMatrix<Number, MemorySpace>::VectorType::dual_view_type
           kokkos_dual_view_src(mirror_view_src, kokkos_view_src);

Otherwise, this looks good to me now.

@kinnewig
Copy link
Contributor Author

Thank you for all the feedback!

I fixed the indentation and squashed everything into one commit.

@masterleinad
Copy link
Member

/rebuild

@kinnewig
Copy link
Contributor Author

I fixed the failing test.

@masterleinad masterleinad merged commit 1d56f85 into dealii:master Feb 28, 2024
16 checks passed
@kinnewig kinnewig deleted the tpetra_wrappers_vmult branch March 18, 2024 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants