How to benchmark a solver geometry#
This guide shows how to measure the computational throughput of a solver
geometry — how many
forward() and
inverse() operations it can
perform per second — using
hklpy2.utils.benchmark.
Benchmarking is useful when:
evaluating whether a solver is fast enough for a scanning application,
comparing two solvers for the same geometry, or
detecting a performance regression after a code change.
Note
The benchmark is purely computational. It does not move any motors or communicate with hardware, so it is safe to run on a live diffractometer.
Prerequisites#
You will need hklpy2 ≥ 0.6.0 and hklpy2-solvers installed:
pip install "hklpy2>=0.6.0" hklpy2-solvers
Starting from a saved configuration#
The easiest way to benchmark is to restore a simulator from a saved
configuration file using
simulator_from_config().
Ready-to-use configurations are provided for each supported geometry:
Solver |
Geometry |
Configuration file |
|---|---|---|
|
Note
Configuration files for ad_hoc solver geometries are not yet
provided. You can create your own using the How to use the ad_hoc solver
workflow and export().
Download the file for your geometry, save it alongside your script, then run:
import hklpy2
sim = hklpy2.simulator_from_config("diffcalc_4s_2d.yml")
hklpy2.utils.benchmark(sim)
Example output:
Diffractometer benchmark
solver: diffcalc
geometry: diffcalc_4S_2D
mode: 4S+2D bisect_eta_fixed nu_fixed
wavelength: 1.54
calls: 500
operation ops/sec ms/call status
------------ ---------- ----------- ------
forward() 800 1.250 FAIL
inverse() 7300 0.137 PASS
target: 2,000 ops/sec (+/-10%)
The status column compares each operation against a target of
2,000 ops/sec (±10%). A FAIL result means the solver is below that
target for this operation.
Note
Some solvers perform iterative constraint solving and return multiple
candidate solutions per
forward() call. This can
result in a FAIL that reflects an upstream library limitation rather
than a problem with the solver itself. See the
Geometries page for solver-specific notes.
Benchmarking a live diffractometer#
Caution
hklpy2.utils.benchmark runs timing loops directly on the diffractometer object passed to it. Until bluesky/hklpy2#369 is resolved, pass a simulator restored from a snapshot of your live diffractometer’s configuration, rather than the live instrument itself. This guarantees no side effects on motor positions or solver state:
import hklpy2
# Snapshot the live diffractometer, then benchmark the copy.
sim = hklpy2.simulator_from_config(my_diffractometer.configuration)
hklpy2.utils.benchmark(sim)
This page will be updated once the fix is released in hklpy2.
Saving your own configuration#
You can benchmark a diffractometer you have already set up in two ways.
From a file — export the current state using
export(), then create a new
simulator and benchmark:
my_diffractometer.export("my_config.yml", "benchmark configuration")
sim = hklpy2.simulator_from_config("my_config.yml")
hklpy2.utils.benchmark(sim)
Without a file — pass the
configuration property
directly, bypassing the file entirely:
import hklpy2
sim = hklpy2.simulator_from_config(my_diffractometer.configuration)
hklpy2.utils.benchmark(sim)
Adjusting the number of calls#
By default, hklpy2.utils.benchmark
uses 500 calls per operation. Pass n to change this — more calls
give a more stable measurement:
hklpy2.utils.benchmark(sim, n=2000)
Capturing results programmatically#
Pass print=False to suppress the printed report and receive the results
as a dict instead:
results = hklpy2.utils.benchmark(sim, print=False)
print(results["forward_ops_per_sec"])
print(results["inverse_ops_per_sec"])
The dict contains:
Key |
Description |
|---|---|
|
Solver name |
|
Geometry name |
|
Current operating mode |
|
Current wavelength (Å) |
|
Number of calls measured |
|
|
|
|
|
|
|
|
|
Minimum target (2,000 ops/sec) |