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

Better documentation for performance annotations #17700

Closed
wants to merge 6 commits into from
Closed
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 58 additions & 10 deletions doc/manual/performance-tips.rst
Original file line number Diff line number Diff line change
Expand Up @@ -888,11 +888,6 @@ properties.
**This feature is experimental** and could change or disappear in future
versions of Julia.

Note: While :obj:`@simd` needs to be placed directly in front of a
loop, both :obj:`@inbounds` and :obj:`@fastmath` can be applied to
several statements at once, e.g. using ``begin`` ... ``end``, or even
to a whole function.

Here is an example with both :obj:`@inbounds` and :obj:`@simd` markup::

function inner( x, y )
Expand Down Expand Up @@ -932,6 +927,13 @@ On a computer with a 2.4GHz Intel Core i5 processor, this produces::
GFlop = 1.9467069505224963
GFlop (SIMD) = 17.578554163920018

Certain preconditions need to be met before using some of these macros.
Both :obj:`@simd` and :obj:`@inbounds` do a simple rewrite of the expression
and delegate the optimizations to compiler, much like ``:meta`` expressions.
Copy link
Contributor

Choose a reason for hiding this comment

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

delegate the optimizations to the compiler

This means they merely give the compiler license to optimize. Whether
it actually does so depends on the compiler. As consequence how you
Copy link
Member

Choose a reason for hiding this comment

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

"As consequence" is not grammatical. Actually, I think you can just delete the "As consequence..." sentence.

write the expressions will have a final say on the output.

The range for a ``@simd for`` loop should be a one-dimensional range.
A variable used for accumulating, such as ``s`` in the example, is called
a *reduction variable*. By using :obj:`@simd`, you are asserting several
Expand All @@ -946,10 +948,8 @@ properties of the loop:
A loop containing ``break``, ``continue``, or :obj:`@goto` will cause a
compile-time error.

Using :obj:`@simd` merely gives the compiler license to vectorize. Whether
it actually does so depends on the compiler. To actually benefit from the
current implementation, your loop should have the following additional
properties:
To actually benefit from :obj:`@simd` current implementation, your loop
should have the following additional properties:

- The loop must be an innermost loop.
- The loop body must be straight-line code. This is why :obj:`@inbounds` is
Expand All @@ -962,7 +962,55 @@ properties:
- The stride should be unit stride.
- In some simple cases, for example with 2-3 arrays accessed in a loop, the
LLVM auto-vectorization may kick in automatically, leading to no further
speedup with :obj:`@simd`.
speedup with :obj:`@simd``.

While :obj:`@simd` needs to be placed in front of a loop, that is not the case
for :obj:`@inbounds`. It can be placed in front of any expression as long as it
is inside a function, the only place where it could be outside of a function
Copy link
Member

Choose a reason for hiding this comment

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

Semicolon, not comma, before "the only place where it can be" (not "could")

definition is in front of a loop.

julia> x = [1]

julia> @inbounds if true
x[2]
end
ERROR: BoundsError: attempt to access 1-element Array{Int64,1} at index [2]
in getindex(::Array{Int64,1}, ::Int64) at ./array.jl:309
in eval(::Module, ::Any) at ./boot.jl:225
in macro expansion at ./REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:46

julia> function f(x)
@inbounds if true
x[2]
end
end

julia> f(x)

julia> @inbounds for i in 1:10
x[2]
end

Beware using it before a function declaration will have no effect, the
Copy link
Member

Choose a reason for hiding this comment

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

Beware -> Be aware that. Start a new sentence, and rephrase "To use @inbounds on a block of code, put it before a begin ... end statement.

correct way to encapsule a function or block of code is inside a
``begin`` ``end`` statement.

julia> @inbounds function g(x) #Won't remove bound checks nor warn you
for i in 1:10
x[i] = x[i]^2
end
end

julia> function g(x)
@inbounds begin
for i in 1:10
x[i] = x[i]^2
end
end
end

:obj:`@simd` can be placed in front of any expression without problems.

Here is an example with all three kinds of markup. This program first
calculates the finite difference of a one-dimensional array, and then
Expand Down