Skip to content

Commit

Permalink
Update documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobjpeters committed Dec 28, 2024
1 parent 14b00dd commit 52a6626
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 51 deletions.
20 changes: 20 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,23 @@
# News

## v0.1.0

- `speculate(predicate, value; parameters...)`: Search for compilation directives
- `predicate`: Filter values found in a `Module`
- `value`: The initial value to search
- `parameters`
- `background`: Whether to search in a background process
- `dry`: Whether to call `precompile` on generated methods
- `limit`:
The maximum number of compilable methods that may be generated from a generic method
- `path`: A file to write compilation directives to
- `verbosity`: Specifies which logging statements to show
- Input Speculators
- `install_speculator`: Automatically calls `speculate` on values input to the REPL
- `uninstall_speculator`: Removes the automatic input speculator
- `Verbosity`: A set used to specify which logging statements to show
- `debug`: Shows each successful compilation directive
- `review`: Summarizes the generated compilation directives
- `silent`: Shows no logging statements
- `warn`: Shows each unsuccessful compilation directive
- `all_modules::AllModules`: A value used to `speculate` each loaded module
38 changes: 19 additions & 19 deletions docs/source/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@

## Introduction

Speculator.jl is a tool to reduce latency by automatically
generating and running compilation workloads.

Code needs to be compiled, either upon the installation of a package or as needed during runtime.
In the former case, this can be used in a package as a supplement or alternative to
[PrecompileTools.jl](https://github.com/JuliaLang/PrecompileTools.jl).
In the latter case, it can be used in a `startup.jl` file or interactively in the REPL.
Speculator.jl reduces latency by automatically searching for compilation directives.

## Usage

Expand All @@ -18,7 +12,7 @@ In the latter case, it can be used in a `startup.jl` file or interactively in th
```julia-repl
julia> using Pkg: add
julia> add(; url = "https://github.com/jakobjpeters/Speculator.jl")
julia> add("Speculator")
julia> using Speculator
```
Expand Down Expand Up @@ -57,23 +51,18 @@ julia> i(::Union{String, Symbol}, ::Union{String, Symbol}) = nothing;

## Features

- Automatically generate a compilation workload from modules and callable objects.
- Configurable to run in the background, select precompilation targets, and write to a file.
- Can be ran in the REPL after each input.
- Filter values
- Run in the background
- Handle abstractly typed methods
- Save compilation directives to a file
- Show logging statements
- Run in REPL after each input

### Planned

- Disable during development using Preferences.jl?
- Support for `UnionAll` types?

## Acknowledgements

Credit to [Cameron Pfiffer](https://github.com/cpfiffer) for the initial idea.

The preexisting package PrecompileSignatures.jl implements similar functionality,
notably that `PrecompileSignatures.@precompile_signatures ::Module`
is roughly equivalent to `Speculator.speculate(::Module)`.

## Similar Packages

- [Cthulhu.jl](https://github.com/JuliaDebug/Cthulhu.jl)
Expand All @@ -86,3 +75,14 @@ is roughly equivalent to `Speculator.speculate(::Module)`.
- [PrecompileTools.jl](https://github.com/JuliaLang/PrecompileTools.jl)
- [SnoopCompile.jl](https://github.com/timholy/SnoopCompile.jl)
- [SnoopCompileCore.jl](https://github.com/timholy/SnoopCompile.jl/tree/master/SnoopCompileCore)

## Acknowledgements

Credit to [Cameron Pfiffer](https://github.com/cpfiffer) for the initial idea.

The preexisting package PrecompileSignatures.jl implements similar functionality,
notably that `PrecompileSignatures.@precompile_signatures ::Module`
is roughly equivalent to `Speculator.speculate(::Module)`.

The idea to compile concrete method signatures has also been brought up in
[PrecompileTools.jl #28](https://github.com/JuliaLang/PrecompileTools.jl/issues/28).
4 changes: 2 additions & 2 deletions src/Speculator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ TODO: tutorial to create a system image?
TODO: benchmark with `PrecompileSignatures.jl` and `MethodAnalysis.jl`:
- `speculate(all_modules; dry = true)`
- `length(PrecompileSignatures.precompilables(Base.loaded_modules_array()))`
TODO: benchmark time to search for every possible method:
`speculate(all_modules; verbosity = review)`
TODO: does `f(; (@nospecialize xs...))` work?
TODO: does `f(@nospecialize _)` work?
TODO: remove closures, because they can't be precompiled?
Expand All @@ -21,6 +19,8 @@ TODO: document that some methods aren't skipped
`f(::String)`, `f(::Union{String, Symbol})`, `speculate(f; verbosity = debug)`
TODO: implement `Base.symdiff(::Verbosity, ::Verbosity...)`
TODO: remove dependency on InteractiveUtils.jl
TODO: https://github.com/JuliaLang/julia/issues/28808
TODO: https://github.com/JuliaLang/julia/issues/52677
=#

import Base: isdisjoint, isempty, issetequal, issubset, iterate, show
Expand Down
1 change: 0 additions & 1 deletion src/all_modules.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@


"""
AllModules
Expand Down
4 changes: 2 additions & 2 deletions src/input_speculators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ function install_speculator!(
(@nospecialize predicate), ast_transforms::Vector{Any}, is_background::Bool;
(@nospecialize parameters...))
push!(ast_transforms, InputSpeculator(parameters, predicate))
log_background_repl(log_input_speculator, is_background)
log_repl(log_input_speculator, is_background)
end

"""
install_speculator(predicate = $default_predicate; background::Bool = true, parameters...)
install_speculator(predicate = Returns(true); background::Bool = true, parameters...)
Install an input speculator that calls
`speculate(predicate,\u00A0value;\u00A0background,\u00A0parameters...)`
Expand Down
32 changes: 17 additions & 15 deletions src/speculate.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

function log_warn(p::Parameters, caller_type::Type, (@nospecialize compilable_types))
function log_warn(p::Parameters, caller_type::Type, compilable_types::Vector{Type})
if warn p.verbosity
_signature = signature(caller_type, compilable_types)
p.counters[warned] += 1

log_background_repl(() -> (
log_repl(() -> (
@warn "Compilation failed, please file a bug report in Speculator.jl for:\n`$_signature`"
), p.background_repl)
end
Expand Down Expand Up @@ -150,7 +150,7 @@ function initialize_parameters(
elapsed = @elapsed search_all_modules(x, _parameters)

if review _parameters.verbosity
log_background_repl(_parameters.background_repl) do
log_repl(_parameters.background_repl) do
_counters = _parameters.counters
_compiled, _generic, _skipped, _warned = map(s -> _counters[s], counters)
generated = _compiled + _skipped + _warned
Expand All @@ -170,12 +170,12 @@ end
speculate(predicate, value; parameters...)
speculate(value; parameters...)
Generate a compilation a workload.
Search for compilation directives.
See also [`install_speculator`](@ref).
!!! tip
Use this in a package to reduce latency for its users.
Use this in a package to reduce latency.
!!! note
Speculation only runs when called during precompilation or an interactive session,
Expand All @@ -191,15 +191,16 @@ See also [`install_speculator`](@ref).
given module and name satisfy `isdefined` and `!isdeprecated`.
The default predicate `Returns(true)` will search everything possible,
up to the generic `limit`, whereas the predicate
`Returns(false)` will not generate any methods.
Some useful predicates include `Base.isexported`, `Base.ispublic`,
checking properties of the value itself, and a combination thereof.
`Returns(false)` will only generate methods from
callable values passed directly to `speculate`.
Some useful predicates include `Base.isexported`,
`Base.ispublic`, and checking properties of the value itself.
- `value`:
When given a `Module`, `speculate` will recursively search its contents
using `names(::Module;\u00A0all\u00A0=\u00A0true)`, for each name that is
not deprecated, is not an external module, and satisifes the `predicate`.
For other values, each of their generic `methods`
are searched for corresponding compilable signatures.
are searched for corresponding compilable methods.
# Keyword parameters
Expand All @@ -210,21 +211,22 @@ See also [`install_speculator`](@ref).
Specifies whether to run `precompile` on generated method signatures.
This is useful for testing workloads with `verbosity\u00A0=\u00A0debug\u00A0∪\u00A0review`.
Methods that are known to be specialized are skipped.
Note that `dry` must be `false` to save the workload to a file with the `path` parameter.
Note that `dry` must be `false` to save the directives to a file with the `path` parameter.
- `limit::Int = $default_limit`:
Specifies the maximum number of compilable methods that are generated from a generic method.
Values less than `1` will throw an error.
Otherwise, method signatures will be generated from the Cartesian product each parameter type.
Types marked with `@nospecialize` are used directly.
Otherwise, compilable types are obtained from the subtypes of `DataType` and `Union`.
This prevents spending too much time precompiling a single generic method.
Setting an appropriate value prevents spending too
much time precompiling a single generic method.
- `path::String = ""`:
Saves a workload by writing each successful precompilation directive
to a file if the `path` is not empty and it is not a `dry` run.
Saves successful precompilation directives to a file
if the `path` is not empty and it is not a `dry` run.
Note that these directives may require loading additional modules to run.
- `verbosity::Verbosity = warn`:
Specifies what logging statements to show.
If this function is used in a package as a precompilation workload,
If this function is used to precompile methods in a package,
this should be set to [`silent`](@ref) or [`warn`](@ref).
See also [`Verbosity`](@ref).
Expand Down Expand Up @@ -276,7 +278,7 @@ function speculate(predicate, value;
)
end
else
@warn "Skipping speculation because it is not being ran during precompilation, an interactive session, or to save a workload"
@warn "Skipping speculation because it is not being ran during precompilation, an interactive session, or to save compilation directives"
end
end
function speculate(x; parameters...)
Expand Down
15 changes: 4 additions & 11 deletions src/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
@enum Counter compiled generic skipped warned

const counters = instances(Counter)

const default_limit = 1
const default_predicate = Returns(true)
const searched_callables = IdSet{DataType}

const searched_functions = IdSet{Function}

const searched_types = IdSet{Type}

@kwdef struct Parameters
Expand All @@ -28,12 +27,6 @@ const searched_types = IdSet{Type}
searched_methods::IdSet{Method} = IdSet{Method}()
end

const default_limit = 1

const default_predicate = Returns(true)

const default_trials = 8

is_repl_ready() = (
isdefined(Base, :active_repl_backend) &&
isdefined(Base, :active_repl) &&
Expand All @@ -52,11 +45,11 @@ function log_debug(p::Parameters, c::Counter, caller_type::Type, caller_types::V
_signature = signature(caller_type, caller_types)
statement = uppercasefirst(string(c))

log_background_repl(() -> (@info "$statement `$_signature`"), p.background_repl)
log_repl(() -> (@info "$statement `$_signature`"), p.background_repl)
end
end

function log_background_repl(f, background_repl::Bool)
function log_repl(f, background_repl::Bool)
if background_repl
active_repl = Base.active_repl
refresh_line = typeof(active_repl).name.module.LineEdit.refresh_line
Expand Down
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ visit(count_method_analysis)

path = "precompile.jl"
rm(path; force = true)
s = "Skipping speculation because it is not being ran during precompilation, an interactive session, or to save a workload"
s = "Skipping speculation because it is not being ran during precompilation, an interactive session, or to save compilation directives"
@test_warn "$s" speculate(X; path, dry = true)
@test !isfile(path)
speculate(X; path)
Expand Down

0 comments on commit 52a6626

Please sign in to comment.