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

make performancetips code consistent with offset arrays #23565

Merged
merged 7 commits into from
Sep 16, 2017

Conversation

mkborregaard
Copy link
Contributor

As remarked on Discourse (https://discourse.julialang.org/t/is-inbounds-really-necessary/5654/12) the performance tips code for inbounds is not consistent with recommended style.

The performance tips e.g. use 1:n to iterate over an array to demonstrate a case where it is safe to use @inbounds. But that very example is used here: https://docs.julialang.org/en/latest/devdocs/offset-arrays/#Background-1 to describe a situation where it is NOT safe to use @inbounds because the array could be an offsetarray.

When used as in the context here it is still safe, because the array is initialized in the previous line, but it is possibly misleading.

I updated the code examples on the page to be consistent with the generalized-array syntax as I understand it.

@timholy
Copy link
Member

timholy commented Sep 2, 2017

Thanks! LGTM.

Anything that specifies Vector or Array in its argument types will predictably start indexing at 1, nevertheless 👍 for demonstrating more generalizable coding practices.

n = size(x, 1)
out = Array{T}(n, n)
for i = 1:n
n = indices(x, 1)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe change the name of the variable to e.g. inds.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, good point. I made the change.

@fastmath @inbounds @simd for i in 2:n-1
inds = linearindices(u)
dx = 1.0 / (length(inds)-1)
@fastmath @inbounds du[inds[1]] = (u[inds[2]] - u[inds[1]]) / dx
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In most cases the more general style is at least as clear - but in this one case it isn't, and I'm unsure whether this might confuse readers? I tried to be as clear as possible.

@KristofferC
Copy link
Member

I think this might just detract from the point of the examples. I rather just have a ::Array annotation on the input variable or a statement saying that we assume Arrays in this section and a link to the general indices section. Thoughts?

@mkborregaard
Copy link
Contributor Author

I think that could be true for the line I highlighted above - that's why I highlighted it. I was thinking to suggest annotating that with ::Array. In the other examples I think the style is at least as clear and might be said to be a preferred style anyway, at least it does not detract from clarity IMHO.

I'd say it is an issue that the very first example for inbounds here https://docs.julialang.org/en/latest/manual/performance-tips/#man-performance-annotations-1 is exactly a case that this part https://docs.julialang.org/en/latest/devdocs/offset-arrays/#Background-1 highlights as unsafe.

In the end I guess it depends how much you'd like the generalized array interface to permeate the language and ecosystem. We're now editing Plots to conform with the generalized syntax and it does require a slightly different thinking.

@timholy
Copy link
Member

timholy commented Sep 5, 2017

In places where it's awkward, I'm fine with restricting it to Arrays.

But overall I agree that we should demo code that uses the generic interface. When I get some time again I plan to "take off the training wheels" and submit a PR to OffsetArrays that allows @inbounds to work and supports size and length again (and submit a PR to the devdocs updating the recommendations). At that point one is back in segfault-land for code that hasn't been updated.

Replaces generalized indexing syntax with an ::Vector assertion where that improved clarity of the code.
@mkborregaard
Copy link
Contributor Author

I've 1. inserted an ::Vector assertion in the place where the code was awkward, and 2. mentioned the concern with unconventional indexing when using inbounds. This should meet the concerns.

@@ -1094,6 +1094,10 @@ Sometimes you can enable better optimization by promising certain program proper
* Write `@simd` in front of `for` loops that are amenable to vectorization. **This feature is experimental**
and could change or disappear in future versions of Julia.

The common ideom of using 1:n to index into an AbstractArray is not safe if the Array uses unconventional indexing,
Copy link
Member

Choose a reason for hiding this comment

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

idiom

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@@ -601,7 +601,7 @@ This should be written as:

```jldoctest
julia> function fill_twos!(a)
for i=1:length(a)
for i=linearindices(a)
Copy link
Member

Choose a reason for hiding this comment

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

Would it make more sense to use eachindex(a)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed that eachindex is more intuitive. But the offset-arrays doc recommend linearindices (https://docs.julialang.org/en/latest/devdocs/offset-arrays) so I chose that for consistency.
Should I

  1. keep linearindices both places for consistency
  2. change linearindices->eachindex both places for consistency (for this use - iterating linearly over a container)
  3. change linearindices->eachindex here and not worry about the small discrepancy
    ?
    I have no clear preference.

Copy link
Member

Choose a reason for hiding this comment

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

Use linearindices if you really want to index with an integer. If you don't care what you index with, use eachindex.

Copy link
Member

Choose a reason for hiding this comment

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

I see what you mean about it being ambiguous in the devdocs.

Copy link
Contributor Author

@mkborregaard mkborregaard Sep 10, 2017

Choose a reason for hiding this comment

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

I've updated to eachindex here. I don't mind including some changes to the devdocs here, or we could leave as it is.

Copy link
Member

Choose a reason for hiding this comment

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

If you're willing I'd be grateful, but feel free to say "your job, Tim." 😄

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've tried here: #23731 . Can't say I'm completely happy with the result at this point, but possibly after some feedback that could work.

@timholy
Copy link
Member

timholy commented Sep 16, 2017

Thanks so much, @mkborregaard!

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.

6 participants