Skip to content

Conversation

@spencerpatty
Copy link
Contributor

I am concerned about the operation_state_t complexity with regards to SpGEMM C matrix_handle_t is stored in operation_state_t that keeps the continuity between compute/fill. There is a matrix_opt restriction on C right now, but it seems it would be important to let C be a matrix_opt, that way it isn't stored in the operation_state_t indefinitely... lifetime is complicated

@spencerpatty
Copy link
Contributor Author

@BenBrock any thoughts about integrating the matrix_opt into our solutions now that we have CSC and transpose objects merged to main branch ?

I seem to recall there were some open questions we had discussed a while ago:

  1. should matrix_opt be a base_view ? I think we decided it should not, but there should be another request which gives the usable_view (name to be refined) which is either a base xyz_view or a matrix_opt containing an xyz_view object.
  2. should the matrix_opt be created with an execution_policy, so that when appropriate, a queue/stream can also be available for destruction, or should we add a member function to matrix_opt like clean(ExecutionPolicy & policy) that enqueues (if appropriate) the deletion of any internals stored...
  3. Separate topic, but might fit here while modifying the base stuff like we will need to do about handling "const" data types more appropriately, with our tensor_index_t<A> etc functions, to have some with const and others with const removal for internals before we get too far along with backend impls :) See 68a4e3b for test case where @YvanMokwinski and I were able to succeed at SpMV with partially const csr_view data (and onemkl needed to const_cast since we don't have a const matrix operator construct...)

BenBrock
BenBrock previously approved these changes Apr 17, 2025
Copy link
Collaborator

@BenBrock BenBrock left a comment

Choose a reason for hiding this comment

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

Hi @spencerpatty—I've merged this PR with main to get it up-to-date and then made a couple of small tweaks. (Actually some of the changes are to pre-existing code to make it more consistent.)

The main change is switching to get_matrix_handle, which will handle (no pun intended) the cases where you do and don't have a matrix_opt.

I think the design as-is is pretty reasonable.

The one thing I might consider changing is how we store the matrix handles inside of operation_state. Currently, we store a nullptr handle if there is a matrix_opt and a non-nullptr handle if there isn't. We could update this to store a wrapper object inside the operation_state. The wrapper object could then keep track of whether it ought to delete itself or not, which would simplify things considerably.

Still, I think this is fine as-is. I'm approving this and will send you a review request right back to review my changes/the current state.

O* c_rowptr = (O*) info.state_.c_rowptr;

I* c_rowptr = (I*) info.state_.c_rowptr;
auto a_handle = __mkl::get_matrix_handle(q, a, info.state_.a_handle);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is the main update I made—instead of calling get_ultimate_base, I re-worked get_matrix_handle to work directly on a stack of views. It will iterate through and grab the matrix_opt if available, or else create a new view.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

aha, I see. And it is an MKL specific api (instead of a general one) since we are returning an MKL specific object... this is good. Others can add their handlers as well for their objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so in here, I guess we don't ever interact with the ultimate_base of a or b, but rather we always get an mkl matrix handle from a or info.state including extracting the xyz_view and creating a matrix_handle from it, in thus get_matrix_handle ...

index<>{__backend::shape(c)[0], __backend::shape(c)[1]}, nnz,
__mkl::operation_state_t{a_handle, b_handle, c_handle, nullptr, descr,
(void*) c_rowptr, q}};
__mkl::operation_state_t{__detail::has_matrix_opt(a) ? nullptr : a_handle,
Copy link
Collaborator

Choose a reason for hiding this comment

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

The function has_matrix_opt will return whether or not a stack of views has a matrix_opt, which you can then use to handle those two cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nice :)

@BenBrock BenBrock marked this pull request as ready for review April 17, 2025 22:34
@BenBrock
Copy link
Collaborator

@spencerpatty GitHub won't allow me to request a review, so please take a look and let me know what you think.

Comment on lines 86 to 94
if constexpr (has_base<T>) {
if constexpr (is_matrix_opt_view_v<T>) {
return t;
} else {
return t;
return get_ultimate_base(t.base());
}
} else {
return t;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

so get_ultimate_base still returns not the ultimate base but either a matrix_opt or the bottom xyz_view now ? do we want to keep that as is ? or should we return it back to ignoring matrix_opt_view_v ?


template <typename M>
requires(__detail::is_matrix_instantiation_of_mdspan_v<M>)
requires(__detail::is_matrix_mdspan_v<M>)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

nice, I like this shortened names

Comment on lines +20 to +21
concept matrix = __detail::is_csr_view_v<M> || __detail::is_csc_view_v<M> ||
__detail::is_matrix_mdspan_v<M> || __detail::matrix<M>;
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 am guessing the "is_xyz_view_v" look through the matrix_opt to see the xyz_view underneath so a matrix_opt would also be classified properly here ...

Comment on lines +93 to +103
template <tensor T>
bool has_matrix_opt(T&& t) {
if constexpr (is_matrix_opt_v<T>) {
return true;
} else if constexpr (has_base<T>) {
return has_matrix_opt(t.base());
} else {
return false;
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nice checker

Copy link
Contributor Author

Choose a reason for hiding this comment

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

aha, get_ultimate_base was returned to it's previous state and we use has_matrix_opt() and the custom __mkl::get_matrix_handle() to get matrix handle now, instead of having ultimate_base return it . I like this much more. Good changes!


return m.matrix_handle_;
} else if constexpr (__detail::has_base<M>) {
return get_matrix_handle(q, m.base(), handle);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh, so line 29 and 30 will iterate through the stack and keep looking until we either find a matrix_handle, or we run out of bases and check either handle or create_matrix_handle on ultimate base of m ...

Comment on lines +50 to +56
auto base() {
return matrix_;
}

auto base() const {
return matrix_;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

why do we need both const (accessor) and nonconst(mutator) functions for base() ? can we really guarantee that the accessor won't modify matrix_ ?

Comment on lines +56 to +58
if (!__detail::has_matrix_opt(a)) {
oneapi::mkl::sparse::release_matrix_handle(q, &a_handle).wait();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

aha, this is good to enable a_handle to persist in matrix_opt ... good

Comment on lines +49 to +51
if (!__detail::has_matrix_opt(a)) {
oneapi::mkl::sparse::release_matrix_handle(q, &a_handle).wait();
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

so we turned on matrix_opt for spmv/spmm and spgemm ... but it looks like there is still some work to add it to triangular_solve. @BenBrock do you have opinion about whether we do that in a separate PR or in this one ?

Copy link
Contributor Author

@spencerpatty spencerpatty left a comment

Choose a reason for hiding this comment

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

As this was originally my PR, I am not able to approve it, but I have reviewed the changes that @BenBrock made and approve of the PR now for merge. (There may be some thigns listed below that we want to add to this PR, or it is stable right now, so is fine to merge)

Summary: We add in the matrix_opt handling to spmv/spmm/spgemm, though it is not in TRSV yet. We added a new has_matrix_opt() function and a custom _mkl::get_matrix_handle() in these functions to isolate the interaction between matrix M and getting a vendor matrix object for calling the vendor APIs.

TODOs:

  1. add matrix_opt support to triangular_solve
  2. Add use of matrix_opt into examples or testing

@BenBrock
Copy link
Collaborator

@spencerpatty Good point about testing and triangular_solve. I think we can wait for another PR to support triangular_solve.

I want to implement some more comprehensive testing that will test with every possible combination of arguments (raw view, scaled, matrix_opt, scaled matrix_opt, etc.), but I think that will have to wait. We already have one SpMM test that uses matrix_opt, so I'll add an SpGEMM one and merge for now.

@BenBrock BenBrock self-requested a review April 24, 2025 18:53
Copy link
Collaborator

@BenBrock BenBrock left a comment

Choose a reason for hiding this comment

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

Approving to merge based on @spencerpatty's comments.

@BenBrock BenBrock merged commit 7f9de98 into main Apr 24, 2025
20 of 22 checks passed
@BenBrock BenBrock deleted the dev/spatty/integrate_matrix_opt_to_mkl_sycl branch April 24, 2025 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants