Skip to content

Commit 42e9490

Browse files
iamed2timholy
authored andcommitted
Document the pass-through specialization heuristic for Type, Vararg, and Function (#32817)
1 parent 4e31741 commit 42e9490

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

doc/src/devdocs/ast.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ These symbols appear in the `head` field of [`Expr`](@ref)s in lowered form.
503503
See [Working with LLVM](@ref Working-with-LLVM) for where these are derived from and how they get handled.
504504

505505

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

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

doc/src/devdocs/functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ This function further unpacks each *element* of `other`, expecting each one to c
210210
Naturally, a more efficient implementation is available if all splatted arguments are named tuples.
211211
Notice that the original `circle` function is passed through, to handle closures.
212212
213-
## Compiler efficiency issues
213+
## [Compiler efficiency issues](@id compiler-efficiency-issues)
214214
215215
Generating a new type for every function has potentially serious consequences for compiler resource
216216
use when combined with Julia's "specialize on all arguments by default" design. Indeed, the initial

doc/src/manual/performance-tips.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,65 @@ c = (b + 1.0f0)::Complex{T}
481481
does not hinder performance (but does not help either) since the compiler can determine the type of `c`
482482
at the time `k` is compiled.
483483

484+
### Be aware of when Julia avoids specializing
485+
486+
As a heuristic, Julia avoids automatically specializing on argument type parameters in three
487+
specific cases: `Type`, `Function`, and `Vararg`. Julia will always specialize when the argument is
488+
used within the method, but not if the argument is just passed through to another function. This
489+
usually has no performance impact at runtime and
490+
[improves compiler performance](@ref compiler-efficiency-issues). If you find it does have a
491+
performance impact at runtime in your case, you can trigger specialization by adding a type
492+
parameter to the method declaration. Here are some examples:
493+
494+
This will not specialize:
495+
496+
```julia
497+
function f_type(t) # or t::Type
498+
x = ones(t, 10)
499+
return sum(map(sin, x))
500+
end
501+
```
502+
503+
but this will:
504+
505+
```julia
506+
function g_type(t::Type{T}) where T
507+
x = ones(T, 10)
508+
return sum(map(sin, x))
509+
end
510+
```
511+
512+
These will not specialize:
513+
514+
```julia
515+
f_func(f, num) = ntuple(f, div(num, 2))
516+
g_func(g::Function, num) = ntuple(g, div(num, 2))
517+
```
518+
519+
but this will:
520+
521+
```julia
522+
h_func(h::H, num) where {H} = ntuple(h, div(num, 2))
523+
```
524+
525+
This will not specialize:
526+
527+
```julia
528+
f_vararg(x::Int...) = tuple(x...)
529+
```
530+
531+
but this will:
532+
533+
```julia
534+
g_vararg(x::Vararg{Int, N}) where {N} = tuple(x...)
535+
```
536+
537+
Note that [`@code_typed`](@ref) and friends will always show you specialized code, even if Julia
538+
would not normally specialize that method call. You need to check the
539+
[method internals](@ref ast-lowered-method) if you want to see whether specializations are generated
540+
when argument types are changed, i.e., if `(@which f(...)).specializations` contains specializations
541+
for the argument in question.
542+
484543
## Break functions into multiple definitions
485544

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

0 commit comments

Comments
 (0)