Skip to content

Commit 6dc2eef

Browse files
authored
Add benchmark for simplify to runtests.jl (#251)
- add bench_simplify.jl to runtests.jl - report the results nicely - fail if the performance dropped below 80% of the reference performance - different performance of Julia 1.11 and 1.12 is taken into account - CPU speed is taken into account - assumption: Windows 25% slower than Linux
1 parent d6111b0 commit 6dc2eef

File tree

2 files changed

+99
-78
lines changed

2 files changed

+99
-78
lines changed

test/bench_simplify.jl

Lines changed: 96 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ T_REF = 48.0 # AMD Ryzen 7840U, Julia 1.11, no sys image [s]
77
if VERSION.minor==12
88
T_REF /= 0.85 # Julia 1.12 is about 15% slower on AMD Ryzen 7 7840U
99
end
10-
11-
using Pkg
12-
if ! ("Test" keys(Pkg.project().dependencies))
13-
using TestEnv; TestEnv.activate()
10+
if Sys.iswindows()
11+
T_REF /= 0.75 # Windows is about 25% slower than Linux on same hardware
1412
end
15-
using KiteModels, LinearAlgebra, Statistics, Test, Distributed
13+
msg = String[]
14+
15+
# TestEnv was previously used to activate the test environment dynamically.
16+
# All required test dependencies are now listed under [targets] test in Project.toml,
17+
# so we can rely on the active project without pulling in TestEnv.
18+
using KiteModels, LinearAlgebra, Statistics, Test
1619
include("bench_ref.jl")
1720

21+
# Repository root for subprocess scripts
22+
const REPO_ROOT = normpath(@__DIR__, "..")
23+
1824
# Simulation parameters
1925
dt = 0.05
2026
total_time = 10.0 # Longer simulation to see oscillations
@@ -27,86 +33,98 @@ steering_magnitude = 10.0 # Magnitude of steering input [Nm]
2733

2834
# Function to run benchmark in separate Julia process
2935
function run_benchmark_subprocess()
30-
# Create a temporary script file for the benchmark
31-
benchmark_script = """
32-
using Pkg
33-
if ! ("Test" ∈ keys(Pkg.project().dependencies))
34-
using TestEnv; TestEnv.activate()
35-
end
36-
using KiteModels, LinearAlgebra, Statistics
37-
include("test/bench_ref.jl")
38-
39-
SIMPLE = $SIMPLE
40-
T_REF = $T_REF
41-
42-
# Initialize model
43-
set = load_settings("system_ram.yaml")
44-
set.segments = 3
45-
set_values = [-50, 0.0, 0.0] # Set values of the torques of the three winches. [Nm]
46-
set.quasi_static = false
47-
set.physical_model = SIMPLE ? "simple_ram" : "ram"
48-
49-
sam = SymbolicAWEModel(set)
50-
sam.set.abs_tol = 1e-2
51-
sam.set.rel_tol = 1e-2
52-
rm("data/model_1.11_ram_dynamic_3_seg.bin"; force=true)
53-
54-
# Initialize at elevation
55-
set.l_tethers[2] += 0.2
56-
set.l_tethers[3] += 0.2
57-
time_ = init!(sam; remake=false, reload=true, bench=true)
58-
@info "Simplify took \$time_ seconds"
59-
rel_performance = (T_REF / rel_cpu_performance())/time_
60-
61-
# Write results to file for parent process to read
62-
open("benchmark_results.tmp", "w") do f
63-
println(f, time_)
64-
println(f, rel_performance)
65-
end
66-
"""
67-
68-
# Write the script to a temporary file
69-
temp_script = "temp_benchmark.jl"
70-
open(temp_script, "w") do f
71-
write(f, benchmark_script)
72-
end
73-
74-
try
75-
# Run the benchmark in a separate Julia process
76-
result = run(`julia --project=. $temp_script`)
77-
78-
if result.exitcode == 0
79-
# Read results from temporary file
80-
if isfile("benchmark_results.tmp")
81-
lines = readlines("benchmark_results.tmp")
36+
# Use an isolated temporary directory for all intermediate files
37+
mktempdir() do tmpdir
38+
results_file = joinpath(tmpdir, "benchmark_results.tmp")
39+
temp_script = joinpath(tmpdir, "temp_benchmark.jl")
40+
41+
# Create benchmark script with absolute results path embedded
42+
benchmark_script = """
43+
const REPO_ROOT = $(repr(REPO_ROOT))
44+
const RESULTS_FILE = $(repr(results_file))
45+
cd(REPO_ROOT) # ensure consistent base directory
46+
using Pkg
47+
using KiteModels, LinearAlgebra, Statistics
48+
include(joinpath(REPO_ROOT, "test", "bench_ref.jl"))
49+
50+
SIMPLE = $SIMPLE
51+
T_REF = $T_REF
52+
53+
# Initialize model
54+
set = load_settings("system_ram.yaml")
55+
set.segments = 3
56+
set_values = [-50, 0.0, 0.0] # Set values of the torques of the three winches. [Nm]
57+
set.quasi_static = false
58+
set.physical_model = SIMPLE ? "simple_ram" : "ram"
59+
60+
sam = SymbolicAWEModel(set)
61+
sam.set.abs_tol = 1e-2
62+
sam.set.rel_tol = 1e-2
63+
rm("data/model_1.11_ram_dynamic_3_seg.bin"; force=true)
64+
65+
# Initialize at elevation
66+
set.l_tethers[2] += 0.2
67+
set.l_tethers[3] += 0.2
68+
time_ = init!(sam; remake=false, reload=true, bench=true)
69+
rel_performance = (T_REF / rel_cpu_performance())/time_
70+
71+
# Write results to file for parent process to read
72+
open(RESULTS_FILE, "w") do f
73+
println(f, time_)
74+
println(f, rel_performance)
75+
end
76+
"""
77+
78+
# Write the script to the temporary directory
79+
open(temp_script, "w") do f
80+
write(f, benchmark_script)
81+
end
82+
83+
success = false
84+
time_ = NaN
85+
relp = NaN
86+
msg = nothing
87+
try
88+
result = run(`julia --project=. $temp_script`)
89+
if result.exitcode == 0 && isfile(results_file)
90+
lines = readlines(results_file)
8291
time_ = parse(Float64, lines[1])
83-
rel_performance = parse(Float64, lines[2])
84-
85-
@info "Simplify took $time_ seconds"
86-
@info "Relative performance: $rel_performance"
87-
@test rel_performance > 0.8
88-
89-
# Clean up temporary files
90-
rm("benchmark_results.tmp", force=true)
91-
rm(temp_script, force=true)
92-
93-
return time_, rel_performance
92+
relp = parse(Float64, lines[2])
93+
success = true
9494
else
95-
error("Benchmark results file not found")
95+
msg = "Benchmark subprocess exit=$(result.exitcode) file_exists=$(isfile(results_file))"
9696
end
97-
else
98-
error("Benchmark process failed with exit code $(result.exitcode)")
97+
catch e
98+
io = IOBuffer(); showerror(io, e); msg = String(take!(io))
99+
finally
100+
# temp dir and contents auto-removed after mktempdir do-block
99101
end
100-
catch e
101-
# Clean up temporary files in case of error
102-
rm("benchmark_results.tmp", force=true)
103-
rm(temp_script, force=true)
104-
rethrow(e)
102+
return success, time_, relp, msg
105103
end
106104
end
107105

108-
# Run the benchmark in a separate process
109-
time_, rel_performance = run_benchmark_subprocess()
106+
ok, time_, rel_performance, err_msg = run_benchmark_subprocess()
107+
if ! isnan(rel_performance)
108+
push!(msg, ("Rel performance of simplify: $(round(rel_performance, digits=2))"))
109+
else
110+
push!(msg, ("Error in simplify benchmark: $(err_msg)"))
111+
end
112+
113+
@testset "Testing performance of simplify..." begin
114+
if ok
115+
push!(msg, ("Simplify took: $(round(time_, digits=3)) s"))
116+
@test rel_performance > 0.8
117+
else
118+
@error "Simplify benchmark failed" err_msg
119+
@test ok # will fail in strict mode
120+
end
121+
end
122+
123+
printstyled("\nBenchmark results for simplify:\n"; bold = true)
124+
for i in eachindex(msg)
125+
println(msg[i])
126+
end
127+
println()
110128

111129
# Note: sys object is not available when running in separate process
112130
# If you need sys, you would need to serialize it or run parts in the main process

test/runtests.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ KiteUtils.set_data_path("")
2929
if build_is_production_build
3030
include("bench3.jl")
3131
include("bench4.jl")
32+
if ! haskey(ENV, "NO_MTK")
33+
include("bench_simplify.jl")
34+
end
3235
end
3336
if ! haskey(ENV, "NO_MTK")
3437
include("test_ram_air_kite.jl")

0 commit comments

Comments
 (0)