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

Improve performance annotation docs #17722

Closed
wants to merge 7 commits into from
Closed
Changes from 3 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
63 changes: 54 additions & 9 deletions doc/manual/performance-tips.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1038,11 +1038,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 @@ -1082,6 +1077,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 the compiler, much like ``:meta`` expressions.
This means they merely give the compiler license to optimize. Whether
it actually does so depends on the compiler. How you 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 @@ -1096,10 +1098,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 the current implementation of :obj:`@simd`, 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 @@ -1114,6 +1114,51 @@ properties:
LLVM auto-vectorization may kick in automatically, leading to no further
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 can be outside of a function
definition is in front of a loop.
Copy link
Contributor

@eschnett eschnett Aug 3, 2016

Choose a reason for hiding this comment

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

This information (outside functions only in front of loops) is news to me. Does this mean that a stand-alone statement

@inbounds a[1] = 0

is malformed?

Copy link
Contributor

Choose a reason for hiding this comment

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

It is not. It just may or may not disable boundscheck depending on many other compiler heuristics.

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, The only place where it can be outside of a function definition is in front of a loop is very misleading....

Copy link
Author

@lopezm94 lopezm94 Aug 3, 2016

Choose a reason for hiding this comment

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

What should it say? What does malformed mean in programming btw?

Copy link
Contributor

Choose a reason for hiding this comment

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

Well, it is also just not true. At global scope it is perfectly fine to write:

x = 1
@inbounds x

But whereas without @inbounds this would print 1, with @inbounds it doesn't print anything. However, I think the inbounds meta information is ignored outside of a function.

I would simplify the description to say that @inbounds can be written in front of any expression, and in some expressions this may be useful to limit the scope of what you are declaring to be "in bounds".

::
Copy link
Contributor

Choose a reason for hiding this comment

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

This double-colon is malformed RST I think, see the sphinx errors

/home/Tony/julia/doc/manual/performance-tips.rst:1122: ERROR: Unexpected indentation.
/home/Tony/julia/doc/manual/performance-tips.rst:1146: ERROR: Unexpected indentation.

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:344

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

julia> f(x)
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like a dangerous example since this should segfault.


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

Be aware that using it before a function declaration will have no effect.
To use :obj:`@inbounds` on a block of code, put it before a ``begin ... end``
statement.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is correct.

::
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:`@fastmath` can be placed in front of most expressions without any problem.

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