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

Add spmv! to BLAS in stdlib/LinearAlgebra #34320

Merged
merged 1 commit into from Feb 21, 2020

Conversation

iolaszlo
Copy link
Contributor

@iolaszlo iolaszlo commented Jan 8, 2020

No description provided.

Copy link
Member

@dkarrasch dkarrasch left a comment

Choose a reason for hiding this comment

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

This looks great. Just one comment on the allowed signature, with relevance for the previous hpmv PR.

stdlib/LinearAlgebra/src/blas.jl Outdated Show resolved Hide resolved
Copy link
Member

@dkarrasch dkarrasch left a comment

Choose a reason for hiding this comment

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

I think my previous concern on "enforcing 1-dimensionality" was void, so that's resolved. I'd suggest though to explain the packed format explicitly, since the link to the LAPACK page is rather indirect, one has to search on their webpage to get to the specific page. This might carry over to the hpmv code.

stdlib/LinearAlgebra/src/blas.jl Outdated Show resolved Hide resolved
stdlib/LinearAlgebra/src/blas.jl Outdated Show resolved Hide resolved
stdlib/LinearAlgebra/src/blas.jl Outdated Show resolved Hide resolved
if length(AP) < Int64(N*(N+1)/2)
throw(DimensionMismatch("Packed symmetric matrix A has size smaller than length(x) = $(N)."))
end
GC.@preserve x y AP spmv!(uplo, N, convert(T, α), AP, pointer(x), BlasInt(stride(x, 1)), convert(T, β), pointer(y), BlasInt(stride(y, 1)))
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to preserve AP explicitly? I guess it's referenced directly and not in danger of being gc'ed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I'm too cautious here due to lack of deep GC knowledge, so looking at the other @GC.preserve statements in blas.jl I do not see any crucial difference and reason to drop AP from the preserve statement. Could you maybe explain this a bit more or point out the the thing that I'm missing?

Copy link
Member

Choose a reason for hiding this comment

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

IIUC, then only those are listed which are wrapped by a pointer(...). You could double-check if that's the case, but that was my understanding.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IIUC, then only those are listed which are wrapped by a pointer(...). You could double-check if that's the case, but that was my understanding.

So if I were to drop the pointer(...) around x and y as well then the whole @GC.preserve might be unnecessary? If true this might be tempting to apply to have a more clean API. :)

Copy link
Contributor Author

@iolaszlo iolaszlo Jan 10, 2020

Choose a reason for hiding this comment

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

Possibly following here a pattern similar to that in the symv! implementation strengthens your reading so removing the @GC.preserve alltogether might be good to go. If you are also okay with it I will apply this modification as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On the other hand maybe the following is a non-issue but wherever we have a @GC.preserve we also have Union{DenseArray,...} or Union{Unitrange,...} or Union{.., ...}. Maybe these are unrelated but they do appear together so the removal of @GC.preserve would induce to suggest to remove pointer(...) and GC.preserve from all those functions. I don't know whether this is wise as people might have put it this way for a reason unknown to me at the moment.

Copy link
Member

Choose a reason for hiding this comment

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

Probably there is no harm in keeping AP here, so unless someone comes by and helps in resolving this aspect, this should not keep us from merging this.

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 planning other similar pull requests. Would it be okay in your opinion to ask someone within this comment thread whether to use the @GC.preserve to ease further development?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

It's better just to pass the arrays, see #34783.

stdlib/LinearAlgebra/test/blas.jl Outdated Show resolved Hide resolved
@iolaszlo
Copy link
Contributor Author

iolaszlo commented Jan 10, 2020

I think my previous concern on "enforcing 1-dimensionality" was void, so that's resolved. I'd suggest though to explain the packed format explicitly, since the link to the LAPACK page is rather indirect, one has to search on their webpage to get to the specific page. This might carry over to the hpmv code.

I agree that part of the docstring changes and more nice tests are necessary and would like to apply them to spmv! and hpmv! as well. Should I apply the spmv! changes in this pull request and start a separate pull requiest for the hpmv! update to keep at least the current pull request atomic in some sense? Or let's try to merge this one and fix both in a separate pull request?

@dkarrasch dkarrasch added the linear algebra Linear algebra label Jan 11, 2020
Copy link
Member

@dkarrasch dkarrasch left a comment

Choose a reason for hiding this comment

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

I'd suggest we work on this until spmv! is perfect, and then edit hpmv! accordingly in another PR. I believe there are only mild adoptions necessary, like the restriction to Real, and some small work on the docstrings, so there is an end in sight. We can raise the GC.gc issue in the next PR again, unless someone comes by and helps out with expertise here.

stdlib/LinearAlgebra/src/blas.jl Outdated Show resolved Hide resolved
if length(AP) < Int64(N*(N+1)/2)
throw(DimensionMismatch("Packed symmetric matrix A has size smaller than length(x) = $(N)."))
end
GC.@preserve x y AP spmv!(uplo, N, convert(T, α), AP, pointer(x), BlasInt(stride(x, 1)), convert(T, β), pointer(y), BlasInt(stride(y, 1)))
Copy link
Member

Choose a reason for hiding this comment

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

Probably there is no harm in keeping AP here, so unless someone comes by and helps in resolving this aspect, this should not keep us from merging this.

Copy link
Member

@dkarrasch dkarrasch left a comment

Choose a reason for hiding this comment

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

This is shaping up nicely, just some minor polishing and this may serve as the role model for a minor hpmv! "fix".

(:sspmv_, :Float32))
@eval begin
function spmv!(uplo::AbstractChar,
n::BlasInt,
Copy link
Member

Choose a reason for hiding this comment

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

I guess we kind of figured out in #34360 that this should be Integer.

if length(AP) < Int64(N*(N+1)/2)
throw(DimensionMismatch("Packed symmetric matrix A has size smaller than length(x) = $(N)."))
end
GC.@preserve x y AP spmv!(uplo, BlasInt(N), convert(T, α), AP, pointer(x), BlasInt(stride(x, 1)), convert(T, β), pointer(y), BlasInt(stride(y, 1)))
Copy link
Member

Choose a reason for hiding this comment

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

... and here no BlasInt(N) etc. conversions

# Define the inputs and outputs of spmv!, y = α*A*x+β*y
α = rand(elty)
M = rand(elty, n, n)
A = Symmetric(M)
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 write

AL = Symmetric(M, :L)
AU = Symmetric(M, :U)

...

β = rand(elty)
y = rand(elty, n)

y_result_julia = α*A*x+β*y
Copy link
Member

Choose a reason for hiding this comment

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

then

y_result_julia = α*AL*x+β*y

...

AP = typeof(A[1,1])[]
for j in 1:n
for i in j:n
push!(AP, A[i,j])
Copy link
Member

Choose a reason for hiding this comment

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

...

push!(AP, M[i,j])

and AP = typeof(M[1,1])[] (even though that doesn't matter at all, just for clarity where we take types from)...

@test y_result_julia≈y_result_blas_lower

# Create upper triangular packing of A
AP = typeof(A[1,1])[]
Copy link
Member

Choose a reason for hiding this comment

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

... and analogous changes here, with a recomputed

y_result_julia = α*AU*x+β*y

stdlib/LinearAlgebra/src/blas.jl Show resolved Hide resolved
@dkarrasch
Copy link
Member

dkarrasch commented Jan 15, 2020

@yuyichao Could you please help us and take a look at the GC.@preserve line. We are unsure whether AP needs to be listed there. It would be great if you could share some considerations regarding GC.@preserve for the future.

@iolaszlo Could you maybe rebase your branch on current master. That might help to resolve some of the (otherwise unrelated) test failures.

@iolaszlo iolaszlo force-pushed the extend-blas-with-spmv branch 2 times, most recently from 62044c6 to e6828c8 Compare January 19, 2020 18:21
iolaszlo added a commit to iolaszlo/julia that referenced this pull request Jan 19, 2020
Follow the syntax, docstring and testing conventions
elaborated in JuliaLang#34320.
iolaszlo added a commit to iolaszlo/julia that referenced this pull request Jan 19, 2020
Follow the syntax, docstring and testing conventions
elaborated in JuliaLang#34320.
iolaszlo added a commit to iolaszlo/julia that referenced this pull request Jan 19, 2020
Follow the syntax, docstring and testing conventions
elaborated in JuliaLang#34320.
@dkarrasch
Copy link
Member

It would be great to get this PR in, and to learn about how to use GC.@preserve correctly for future PRs. Anyone care to advise us? @yuyichao @andreasnoack @ViralBShah ? The remaining question is which variables need to be preserved from gc.

@ViralBShah
Copy link
Member

+1 to get the PR in, but we need someone else to chime in on GC.@preserve

iolaszlo added a commit to iolaszlo/julia that referenced this pull request Feb 18, 2020
Follow the syntax, docstring and testing conventions
elaborated in JuliaLang#34320.
Copy link
Member

@dkarrasch dkarrasch left a comment

Choose a reason for hiding this comment

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

Thanks for your stamina @iolaszlo! 😃

@dkarrasch
Copy link
Member

On win32, the LinearAlgebra/blas tests pass, macos64 is a download failure.

Copy link
Member

@andreasnoack andreasnoack left a comment

Choose a reason for hiding this comment

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

Just a few minor comments, but looks good to me other than that.

stdlib/LinearAlgebra/src/blas.jl Show resolved Hide resolved
throw(DimensionMismatch("Packed symmetric matrix A has size smaller than length(x) = $(N)."))
end
spmv!(uplo, N, convert(T, α), AP, x, stride(x, 1), convert(T, β), y, stride(y, 1))
y
Copy link
Member

Choose a reason for hiding this comment

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

...then you can leave it out here. I prefer explicit return spmv!... but it's not required.


y_result_blas_upper = copy(y)
BLAS.spmv!('U', α, AP, x, β, y_result_blas_upper)
@test y_result_julia_upper≈y_result_blas_upper
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@test y_result_julia_uppery_result_blas_upper
@test y_result_julia_upper y_result_blas_upper

@test y_result_julia_lower≈y_result_blas_lower


y_result_julia_upper = α*AU*x+β*y
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
y_result_julia_upper = α*AU*x+β*y
y_result_julia_upper = α*AU*x + β*y

β = rand(elty)
y = rand(elty, n)

y_result_julia_lower = α*AL*x+β*y
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
y_result_julia_lower = α*AL*x+β*y
y_result_julia_lower = α*AL*x + β*y

if N != length(y)
throw(DimensionMismatch("x has length $(N), but y has length $(length(y))"))
end
if length(AP) < Int64(N*(N+1)/2)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if length(AP) < Int64(N*(N+1)/2)
if 2*length(AP) < N*(N + 1)

@dkarrasch
Copy link
Member

CI failures are in Distributed and Sockets, respectively. I'd say unrelated.

@dkarrasch dkarrasch merged commit d8b2209 into JuliaLang:master Feb 21, 2020
@iolaszlo
Copy link
Contributor Author

@dkarrasch Thank you for the constructive review process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
linear algebra Linear algebra
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants