Skip to content

Commit fd1d9b2

Browse files
committed
Add benchmarks for batched versions
1 parent 84907d7 commit fd1d9b2

File tree

4 files changed

+90
-66
lines changed

4 files changed

+90
-66
lines changed

benchmark/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
33
ComplementaritySolve = "b40a91a3-bdaf-4e1c-b965-8c278a33a8d3"
44
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
5+
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
56
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
67
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
78
PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee"
9+
SciMLBenchmarks = "31c91b34-3c75-11e9-0341-95557aab0344"
810
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
911
StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd"
1012
Weave = "44d3d7a6-8a23-5bf8-98c5-b353f8df5ec9"

benchmark/benchmarks.jl

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1-
using Weave
1+
using Weave, SciMLBenchmarks
22

3-
dirs = filter(isdir, joinpath.(@__DIR__, readdir(@__DIR__)))
4-
5-
for dir in dirs
6-
files = filter(x -> endswith(x, ".jmd"), readdir(dir))
7-
for file in files
8-
weave(joinpath(dir, file))
3+
function findall_jmd_files(dir=@__DIR__)
4+
paths = String[]
5+
for p in readdir(dir)
6+
if isdir(joinpath(dir, p))
7+
append!(paths, findall_jmd_files(joinpath(dir, p)))
8+
elseif endswith(p, ".jmd")
9+
push!(paths, joinpath(dir, p))
10+
end
911
end
12+
return paths
1013
end
14+
15+
files = findall_jmd_files()
16+
17+
foreach(f -> SciMLBenchmarks.weave(splitdir(f)..., (:script, :github, :pdf)), files)

benchmark/lcp/solvers.jmd

Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Pkg.activate(joinpath(@__DIR__, ".."))
88
## Load Dependencies
99

1010
```julia
11-
using BenchmarkTools, ComplementaritySolve, DataFrames, PyPlot, StableRNGs
11+
using BenchmarkTools, ComplementaritySolve, DataFrames, NonlinearSolve, PyPlot, StableRNGs
1212
```
1313

1414
## Basic LCP
@@ -27,11 +27,13 @@ SOLVERS = [BokhovenIterativeAlgorithm(),
2727
RPGS(),
2828
InteriorPointMethod(),
2929
NonlinearReformulation(),
30+
NonlinearReformulation(:smooth, Broyden(; batched=true)),
3031
]
3132
times = zeros(length(SOLVERS), 2)
32-
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR"]
33+
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR (Newton)", "NLR (Broyden)"]
3334

3435
for (i, solver) in enumerate(SOLVERS)
36+
@info "Benchmarking $(solvers[i])"
3537
prob_iip = LCP{true}(A₁, q₁, rand(StableRNG(0), 2))
3638
prob_oop = LCP{false}(A₁, q₁, rand(StableRNG(0), 2))
3739
times[i, 1] = @belapsed solve($prob_iip, $solver)
@@ -40,33 +42,34 @@ end
4042
```
4143

4244
```julia
43-
xloc = 1:length(solvers)
44-
width = 0.4 # the width of the bars
45-
multiplier = 0
46-
fig, ax = subplots(layout="constrained")
47-
ax.set_yscale("log")
48-
49-
for (i, group) in enumerate(["Inplace", "Out of Place"])
50-
global multiplier
51-
offset = width * multiplier
52-
rects = ax.bar(xloc .+ offset, times[:, i], width, label=group)
53-
for (j, rect) in enumerate(rects)
54-
height = rect.get_height()
55-
ax.annotate("$(round(times[j, i] * 10^6; digits=2))μs",
56-
xy=(rect.get_x() + rect.get_width() / 2, height),
57-
xytext=(0, 3), # 3 points vertical offset
58-
textcoords="offset points",
59-
ha="center", va="bottom")
45+
let _=plt.xkcd()
46+
xloc = 1:length(solvers)
47+
width = 0.4 # the width of the bars
48+
multiplier = 0
49+
fig, ax = subplots(layout="constrained", figsize=(14, 6))
50+
ax.set_yscale("log")
51+
52+
for (i, group) in enumerate(["Inplace", "Out of Place"])
53+
offset = width * multiplier
54+
rects = ax.bar(xloc .+ offset, times[:, i], width, label=group)
55+
for (j, rect) in enumerate(rects)
56+
height = rect.get_height()
57+
ax.annotate("$(round(times[j, i] * 10^6; digits=2))μs",
58+
xy=(rect.get_x() + rect.get_width() / 2, height),
59+
xytext=(0, 3), # 3 points vertical offset
60+
textcoords="offset points",
61+
ha="center", va="bottom")
62+
end
63+
multiplier += 1
6064
end
61-
multiplier += 1
62-
end
6365

64-
ax.set_ylabel("Times (s)")
65-
ax.set_title("Basic LCP Unbatched")
66-
ax.set_xticks(xloc .+ width ./ 2, solvers)
67-
ax.legend(loc="upper right", ncols=3)
68-
fig.tight_layout()
69-
fig
66+
ax.set_ylabel("Times (s)")
67+
ax.set_title("Basic LCP Unbatched")
68+
ax.set_xticks(xloc .+ width ./ 2, solvers)
69+
ax.legend(ncols=3)
70+
fig.tight_layout()
71+
fig
72+
end
7073
```
7174

7275
### Batched Version
@@ -81,51 +84,63 @@ SOLVERS = [BokhovenIterativeAlgorithm(),
8184
PGS(),
8285
RPGS(),
8386
InteriorPointMethod(),
84-
NonlinearReformulation(),
87+
NonlinearReformulation(:smooth, SimpleNewtonRaphson(; batched=true)),
88+
NonlinearReformulation(:smooth, SimpleDFSane(; batched=true)),
89+
NonlinearReformulation(:smooth, Broyden(; batched=true)),
8590
]
86-
BATCH_SIZES = 2 .^ 1:2:11
91+
BATCH_SIZES = 2 .^ (1:2:11)
8792
times = zeros(length(SOLVERS), length(BATCH_SIZES), 2)
88-
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR"]
93+
solvers = ["Bok.", "RPSOR", "PGS", "RPGS", "IPM", "NLR (Newton)", "NLR (DFSane)", "NLR (Broyden)"]
8994

9095
for (i, solver) in enumerate(SOLVERS)
96+
@info "Benchmarking $(solvers[i])"
9197
for (j, N) in enumerate(BATCH_SIZES)
9298
prob_iip = LCP{true}(A₁, q₁, rand(StableRNG(0), 2, N))
9399
prob_oop = LCP{false}(A₁, q₁, rand(StableRNG(0), 2, N))
94-
times[i, j, 1] = @elapsed solve(prob_iip, solver)
95-
times[i, j, 2] = @elapsed solve(prob_oop, solver)
100+
times[i, j, 2] = @belapsed solve($prob_oop, $solver)
101+
if i == 6
102+
times[i, j, 1] = -1 # SimpleNewtonRaphson is not implemented for inplace
103+
continue
104+
end
105+
times[i, j, 1] = @belapsed solve($prob_iip, $solver)
96106
end
97107
end
98108
```
99109

100-
101110
```julia
102-
xloc = 1:length(solvers)
103-
width = 0.4 # the width of the bars
104-
multiplier = 0
105-
fig, ax = subplots(layout="constrained")
106-
ax.set_yscale("log")
107-
108-
for (i, group) in enumerate(["Inplace", "Out of Place"])
109-
global multiplier
110-
offset = width * multiplier
111-
rects = ax.bar(xloc .+ offset, times[:, i], width, label=group)
112-
for (j, rect) in enumerate(rects)
113-
height = rect.get_height()
114-
ax.annotate("$(round(times[j, i] * 10^6; digits=2))μs",
115-
xy=(rect.get_x() + rect.get_width() / 2, height),
116-
xytext=(0, 3), # 3 points vertical offset
117-
textcoords="offset points",
118-
ha="center", va="bottom")
111+
let _=plt.xkcd()
112+
prop_cycle = plt.rcParams["axes.prop_cycle"]
113+
colors = prop_cycle.by_key()["color"]
114+
fig, (ax1, ax2) = subplots(1, 2; layout="constrained", sharey=true, sharex=true, figsize=(16, 6))
115+
ax1.set_yscale("log")
116+
ax1.set_xscale("log")
117+
118+
fig.suptitle("Basic LCP Batched")
119+
ax1.set_title("In-Place Solvers")
120+
ax2.set_title("Out-Of-Place Solvers")
121+
122+
for (j, solver) in enumerate(solvers)
123+
if !any(times[j, :, 1] .< 0)
124+
ax1.plot(BATCH_SIZES, times[j, :, 1]; label=solver, color=colors[j])
125+
ax1.scatter(BATCH_SIZES, times[j, :, 1]; color=colors[j])
126+
end
127+
if !any(times[j, :, 2] .< 0)
128+
ax2.plot(BATCH_SIZES, times[j, :, 2]; label=solver, color=colors[j])
129+
ax2.scatter(BATCH_SIZES, times[j, :, 2]; color=colors[j])
130+
end
119131
end
120-
multiplier += 1
121-
end
122132

123-
ax.set_ylabel("Times (s)")
124-
ax.set_title("Basic LCP Unbatched")
125-
ax.set_xticks(xloc .+ width ./ 2, solvers)
126-
ax.legend(loc="upper right", ncols=3)
127-
fig.tight_layout()
128-
fig
133+
ax1.set_ylabel("Times (s)")
134+
ax1.set_xlabel("Batch Size")
135+
ax2.set_xlabel("Batch Size")
136+
ax1.legend(ncols=3)
137+
ax2.legend(ncols=3)
138+
fig.tight_layout()
139+
fig
140+
end
129141
```
130142

131-
143+
```julia, echo = false
144+
import SciMLBenchmarks
145+
SciMLBenchmarks.bench_footer(@__DIR__, @__FILE__)
146+
```

benchmark/lcp/solvers.pdf

51.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)