diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..d7bd195 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,25 @@ +name: Documentation + +on: + push: + branches: + - main + tags: '*' + pull_request: + +jobs: + build: + env: + PYTHON: conda + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@latest + with: + version: '~1.10.0-0' + - name: Install dependencies + run: julia --project=docs/ -e 'using Pkg; Pkg.add(name="Documenter", rev="master"); Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - name: Build and deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token + run: julia --project=docs/ docs/make.jl diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..a303fff --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +build/ +site/ diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..d341142 --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,17 @@ +using Documenter, AllocCheck + +makedocs( + sitename = "AllocCheck Documentation", + doctest = false, + modules = [AllocCheck], + warnonly = [:missing_docs], + pages = [ + "Home" => "index.md", + "API" => "api.md", + ], + format = Documenter.HTML(prettyurls = haskey(ENV, "CI")), +) + +deploydocs( + repo = "github.com/JuliaComputing/AllocCheck.jl.git", +) diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..f6882c9 --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,11 @@ +# Exported functions and types + +## Index +```@index +``` + +## Docstrings + +```@docs +AllocCheck.check_allocs +``` \ No newline at end of file diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..4d62925 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,49 @@ +# AllocCheck + +[AllocCheck.jl](https://github.com/JuliaComputing/AllocCheck.jl) is a Julia package that statically checks if a function call may allocate, analyzing the generated LLVM IR of it and it's callees using LLVM.jl and GPUCompiler.jl + +AllocCheck operates on _functions_, trying to statically determine wether or not a function _may_ allocate memory, and if so, _where_ that allocation appears. This is different from measuring allocations using, e.g., `@time` or `@allocated`, which measures the allocations that _did_ happen during the execution of a function. + +## Getting started + +The main entry point to check allocations is the function [`check_allocs`](@ref), which takes the function to check as the first argument, and a tuple of argument types as the second argument: +```@example README +using AllocCheck +mymod(x) = mod(x, 2.5) + +check_allocs(mymod, (Float64,)) +``` +This returned an empty array, indicating that the function was proven to not allocate any memory 🎉 + + +When used on a function that may allocate memory +```@example README +linsolve(a, b) = a \ b + +allocs = check_allocs(linsolve, (Matrix{Float64}, Vector{Float64})); +length(allocs) +``` +we get a non-empty array of allocation instances. Each allocation instance contains some useful information, for example + +```@example README +allocs[1] +``` + +we see what type of object was allocated, and where in the code the allocation appeared. + + +### Functions that throw exceptions +Some functions that we do not expect may allocate memory, like `sin`, actually may: +```@example README +length(check_allocs(sin, (Float64,))) +``` +The reason for this is that `sin` may **throw an error**, and the exception object requires some allocations. We can ignore allocations that only happen when throwing errors by passing `ignore_throw=true`: + +```@example README +length(check_allocs(sin, (Float64,); ignore_throw=true)) # ignore allocations that only happen when throwing errors +``` + +## Limitations + + 1. Runtime dispatch + Any runtime dispatch is conservatively assumed to allocate. \ No newline at end of file diff --git a/src/AllocCheck.jl b/src/AllocCheck.jl index f3cdd44..d19fa7e 100644 --- a/src/AllocCheck.jl +++ b/src/AllocCheck.jl @@ -222,7 +222,7 @@ function rename_calls_and_throws!(f::LLVM.Function, job) end """ -check_allocs(func, types; entry_abi=:specfunc, ret_mod=false) + check_allocs(func, types; entry_abi=:specfunc, ret_mod=false) Compiles the given function and types to LLVM IR and checks for allocations. Returns a vector of `AllocInstance` structs, each containing a `CallInst` and a backtrace.