Skip to content

Commit

Permalink
Document the pass-through specialization heuristic for Type, Vararg, …
Browse files Browse the repository at this point in the history
…and Function (#32817)
  • Loading branch information
iamed2 authored and timholy committed Oct 30, 2019
1 parent 4e31741 commit 42e9490
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 2 deletions.
2 changes: 1 addition & 1 deletion doc/src/devdocs/ast.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ These symbols appear in the `head` field of [`Expr`](@ref)s in lowered form.
See [Working with LLVM](@ref Working-with-LLVM) for where these are derived from and how they get handled.


### Method
### [Method](@id ast-lowered-method)

A unique'd container describing the shared metadata for a single method.

Expand Down
2 changes: 1 addition & 1 deletion doc/src/devdocs/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ This function further unpacks each *element* of `other`, expecting each one to c
Naturally, a more efficient implementation is available if all splatted arguments are named tuples.
Notice that the original `circle` function is passed through, to handle closures.
## Compiler efficiency issues
## [Compiler efficiency issues](@id compiler-efficiency-issues)
Generating a new type for every function has potentially serious consequences for compiler resource
use when combined with Julia's "specialize on all arguments by default" design. Indeed, the initial
Expand Down
59 changes: 59 additions & 0 deletions doc/src/manual/performance-tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,65 @@ c = (b + 1.0f0)::Complex{T}
does not hinder performance (but does not help either) since the compiler can determine the type of `c`
at the time `k` is compiled.

### Be aware of when Julia avoids specializing

As a heuristic, Julia avoids automatically specializing on argument type parameters in three
specific cases: `Type`, `Function`, and `Vararg`. Julia will always specialize when the argument is
used within the method, but not if the argument is just passed through to another function. This
usually has no performance impact at runtime and
[improves compiler performance](@ref compiler-efficiency-issues). If you find it does have a
performance impact at runtime in your case, you can trigger specialization by adding a type
parameter to the method declaration. Here are some examples:

This will not specialize:

```julia
function f_type(t) # or t::Type
x = ones(t, 10)
return sum(map(sin, x))
end
```

but this will:

```julia
function g_type(t::Type{T}) where T
x = ones(T, 10)
return sum(map(sin, x))
end
```

These will not specialize:

```julia
f_func(f, num) = ntuple(f, div(num, 2))
g_func(g::Function, num) = ntuple(g, div(num, 2))
```

but this will:

```julia
h_func(h::H, num) where {H} = ntuple(h, div(num, 2))
```

This will not specialize:

```julia
f_vararg(x::Int...) = tuple(x...)
```

but this will:

```julia
g_vararg(x::Vararg{Int, N}) where {N} = tuple(x...)
```

Note that [`@code_typed`](@ref) and friends will always show you specialized code, even if Julia
would not normally specialize that method call. You need to check the
[method internals](@ref ast-lowered-method) if you want to see whether specializations are generated
when argument types are changed, i.e., if `(@which f(...)).specializations` contains specializations
for the argument in question.

## Break functions into multiple definitions

Writing a function as many small definitions allows the compiler to directly call the most applicable
Expand Down

0 comments on commit 42e9490

Please sign in to comment.