Docking step by step: files vs volumes

2026-10-17 · one small docking project, timed step by step against the two storage generations · 3 runs each

Total time per run

Each dot is one full run (all steps). The two methods overlap: the spread between runs of the same method is bigger than the gap between methods.

filesvolumes

Where the time goes (median run)

Docking (Vina's search) is ~95% of the wall time. Storage can only change the thin slice on the right.

Every step except docking

Bar = median of 3 runs; the line across it = slowest to fastest run. Docking is left out so these seconds are visible (it is 149 s files / 148 s volumes).

filesvolumes

Reading results and what is left on disk

Each panel has its own scale. Same results (210 poses) in both; these are what changed.

filesvolumes

How the comparison was done

  1. Two code generations side by side. files = AMDockVS a9a29c6 (main) + ms_flow b371dbe (main, 0.2.0): poses and receptors are files on disk. volumes = AMDockVS 66c9e83 (feat/volumes-integration) + ms_flow 9719c98 (feat/payload-volumes-v7): poses and receptors are payloads inside the project's volumes. The old pair was checked out as detached git worktrees in /tmp/bench_old/; the same conda env (MSDD_312) ran both.
  2. One script, public API only. test/benchmarks/bench_docking_steps.py drives AMDockVSRuntime exactly as a user script would, so the same file runs against either checkout: which one is tested is decided only by which src comes first on PYTHONPATH.
  3. A fresh project per run. Each run makes a temporary HOME (so nothing registers in the real ~/.molsuite), creates the project, runs the steps below, writes one JSON line, and deletes everything.
  4. Each step timed around its job with time.monotonic(), waiting for the job to finish (wait_for_jobs), with the app's default executors:
    • create_project, import_receptors (1iep + 4O71), import_ligands (first 10 Enamine H100K records),
    • generate_3d (the records are 2D, so this is real work), prepare_receptors, prepare_ligands,
    • set_grid (box 22 Å; 1iep at 15.190, 53.903, 16.917; 4O71 at the CPB ligand centroid 24.659, 98.749, 31.691),
    • docking: Vina, exhaustiveness 8, seed 1, 2 × 10 = 20 pairs,
    • read_poses: read every hit's pose plus each receptor once, i.e. what the viewer needs; it also counts the bytes read.
  5. Alternated runs: files, volumes, files, volumes, files, volumes — so drift in the machine (temperature, cache) hits both equally. AMD Ryzen 7 3700X (8 cores / 16 threads), NVMe, nothing else running.
  6. Same answer check: both produce 210 poses and the same three best scores (−10.77, −10.77, −10.74), so the timing compares equal work.
  7. Medians of the 3 runs per method (--summarize); the raw JSON lines are in docking_steps_2026-10-17.jsonl.
Commands
# old pair (files)
git -C AMDockVS worktree add --detach /tmp/bench_old/amdock main
git -C ms_flow  worktree add --detach /tmp/bench_old/ms_flow main

C=~/PycharmProjects
REC="--receptor data/docking/1iep_receptorH.pdb@15.190,53.903,16.917 --receptor /tmp/bench_old/4O71.pdb@24.659,98.749,31.691"
OLD=/tmp/bench_old/amdock/src:/tmp/bench_old/ms_flow/src:$C/ms_components/src:$C/ms_contactmap/src:$C/ms_env/src
NEW=src:$C/ms_flow/src:$C/ms_components/src:$C/ms_contactmap/src:$C/ms_env/src   # ms_flow on feat/payload-volumes-v7

for i in 1 2 3; do
  PYTHONPATH=$OLD python test/benchmarks/bench_docking_steps.py --label files   --out results.jsonl $REC
  PYTHONPATH=$NEW python test/benchmarks/bench_docking_steps.py --label volumes --out results.jsonl $REC
done
python test/benchmarks/bench_docking_steps.py --summarize results.jsonl

Reading it

  • Docking is unaffected. 149.3 s vs 148.3 s median, runs spread 146.8–150.9 s (files) and 145.6–154.3 s (volumes): the difference is noise.
  • import_receptors is the only step that got slower: +0.2 s in 2 of the 3 volume runs, most likely writing the receptors into the volumes.
  • read_poses is 2× faster and reads 6× fewer bytes. With files, each pose was a whole multi-mode SDF read once per mode; each volume payload holds only its own mode.
  • On disk: 100 fewer files and 2.3 MB less at this size. The file gap grows with the number of pairs (bench_project_files.py: 10 files for 100k results).

Table view