diff --git a/BenchmarkPlots/src/BenchmarkPlots.jl b/BenchmarkPlots/src/BenchmarkPlots.jl index 54f26b4f..2d00c715 100644 --- a/BenchmarkPlots/src/BenchmarkPlots.jl +++ b/BenchmarkPlots/src/BenchmarkPlots.jl @@ -1,6 +1,6 @@ module BenchmarkPlots using RecipesBase -using BenchmarkTools: Trial, BenchmarkGroup +using BenchmarkTools: Trial, BenchmarkGroup, mean @recipe function f(::Type{Trial}, t::Trial) seriestype --> :violin @@ -10,16 +10,31 @@ using BenchmarkTools: Trial, BenchmarkGroup t.times end -@recipe function f(g::BenchmarkGroup, keys=keys(g)) - legend --> false +@recipe function f(g::BenchmarkGroup, keyset=keys(g)) yguide --> "t / ns" - for k in keys - @series begin - label --> string(k) - xticks --> true - [string(k)], g[k] + if all(isa.(keyset, Number)) + keyvec = sort([keyset...]) + fillrange := [mean(g[key]).time for key in keyvec] + seriestype --> :path + fillalpha --> 0.5 + keyvec, [minimum(g[key]).time for key in keyvec] + else + legend --> false + for key in keyset + @series begin + label --> string(key) + xticks --> true + [string(key)], g[key] + end end end end +# If a BenchmarkGroup has BenchmarkGroups for elements, ignore the xtick string given by +# parent, just run BenchmarkGroup recipe again +@recipe function f(::AbstractVector{String}, g::BenchmarkGroup) + legend --> true + return g +end + end diff --git a/docs/generate_plots.jl b/docs/generate_plots.jl new file mode 100644 index 00000000..21a05e72 --- /dev/null +++ b/docs/generate_plots.jl @@ -0,0 +1,28 @@ +using BenchmarkTools, Plots, BenchmarkPlots, StatsPlots + +function runalgorithm(x, alg) + alg == :default && return sort(x) + alg == :insertion && return sort(x; alg=InsertionSort) + alg == :quick && return sort(x; alg=QuickSort) + alg == :merge && return sort(x; alg=MergeSort) +end + +g = BenchmarkGroup() +for key in [:default, :insertion, :quick, :merge] + g[key] = @benchmarkable runalgorithm(x, $key) setup=(x=randn(1000)) +end +res = run(g) +plot(res; yscale=:log10) +savefig("$(pkgdir(BenchmarkTools))/docs/src/assets/violins.png") + +g = BenchmarkGroup() +for key in [:default, :insertion, :quick, :merge] + g[key] = BenchmarkGroup() + for size in 2 .^ (1:15) + g[key][size] = @benchmarkable runalgorithm(x, $key) setup=(x=randn($size)) + end +end +res = run(g) +plot(res; scale=:log10, xguide=:size, legendposition=:topleft) +savefig("$(pkgdir(BenchmarkTools))/docs/src/assets/algorithms.png") + diff --git a/docs/src/assets/algorithms.png b/docs/src/assets/algorithms.png new file mode 100644 index 00000000..ca6d9c4b Binary files /dev/null and b/docs/src/assets/algorithms.png differ diff --git a/docs/src/assets/violins.png b/docs/src/assets/violins.png new file mode 100644 index 00000000..4d96f297 Binary files /dev/null and b/docs/src/assets/violins.png differ diff --git a/docs/src/manual.md b/docs/src/manual.md index d0c732b0..188e7c69 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -974,19 +974,52 @@ plot(t) ``` This will show the timing results of the trial as a violin plot. You can use -all the keyword arguments from `Plots.jl`, for instance `st=:box` or -`yaxis=:log10`. +all the keyword arguments from `Plots.jl`, for instance `seriestype=:box` or +`yscale=:log10`. If a `BenchmarkGroup` contains (only) `Trial`s, its results can be visualized simply by ```julia using BenchmarkPlots, StatsPlots +g = BenchmarkGroup() +for alg in algorithm_symbols + g[alg] = @benchmarkable runalgorithm(x, $alg) setup=(x=randn(1000)) +end t = run(g) -plot(t) +plot(t; yscale=:log10) +``` + +This will display each `Trial` as a violin plot. + +![Violin plots of BenchmarkGroup](./assets/violins.png) + +A `BenchmarkGroup` whose +elements are `BenchmarkGroup`s can be visualized the same way, but no separation +will be made between the element groups - shared keys will get several violins, +and there is no visual indication that a result belongs to one group or the +other. + +The exception is `BenchmarkGroup`s whose keys are `Number`s. These keys will be +interpreted as a size parameter, and the violin plots will be replaced by a line +plot showing the minimum time, with a shaded region up to the mean time. If you +want to bypass this, to still get violin (or similar) plots for the numeric +keys, explicitly make them strings. + +```julia +g = BenchmarkGroup() +for alg in algorithm_symbols + g[alg] = BenchmarkGroup() + for size in 2 .^ [1:15] + g[alg][size] = @benchmarkable runalgorithm(x, $alg) +setup=(x=randn($size)) + end +end +t = run(g) +plot(t; scale=:log10, xguide="size", legendposition=:topleft) ``` -This will display each `Trial` as a violin plot. +![Plot of a BenchmarkGroup containing BenchmarkGroups with numerical keys](./assets/algorithms.png) ## Miscellaneous tips and info