Skip to content

Commit a4002f2

Browse files
authored
Merge branch 'main' into frames_average
2 parents ba7d89e + 3cbdf85 commit a4002f2

7 files changed

Lines changed: 76 additions & 28 deletions

File tree

‎docs/source/howto/how_to_run/at_diamond.rst‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,17 @@ This will allow HTTomo to be run on the local machine like so:
3636
Parallel
3737
~~~~~~~~
3838

39-
A parallel run of HTTomo at Diamond would usually be done on a compute cluster.
40-
However, there are cases where a parallel run on a local machine on cropped data
41-
is also useful, so that has also been described below.
39+
Parallel execution of HTTomo at Diamond is typically performed on a compute cluster.
40+
The HTTomo launcher is integrated with the SLURM workload manager via REST APIs and is
41+
configured to submit jobs to the :code:`wilson` compute cluster.
4242

43-
TODO (:code:`httomo_mpi_local`?)
43+
To run HTTomo, either log in to a Wilson compute node directly or load the HTTomo environment on a workstation
44+
with :code:`module load httomo`.
45+
46+
Once the environment is loaded, HTTomo jobs can be submitted and executed in parallel as described below.
47+
48+
.. code-block:: console
49+
50+
$ httomo_mpi IN_FILE YAML_CONFIG OUT_DIR
51+
`
52+
Also look for help with :code:`httomo_mpi --help`.

‎docs/source/howto/run_httomo.rst‎

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -419,18 +419,23 @@ block size happens to improve performance for the CPU-only section(s).
419419
:code:`--max-memory`
420420
~~~~~~~~~~~~~~~~~~~~
421421

422-
HTTomo supports running on both:
422+
HTTomo supports execution on both:
423423

424-
- a compute cluster, where RAM on the host machine is often quite large
425-
- a personal machine, where RAM is not nearly as large
424+
- compute clusters, where large amounts of system RAM are typically available
425+
- personal workstations or laptops, where available RAM is often more limited
426426

427-
This is done by a mechanism within HTTomo to hold data in RAM wherever there is
428-
enough RAM to do the required processing, and write data to a file if there is not
429-
enough RAM.
427+
To accommodate these different environments, HTTomo dynamically manages intermediate
428+
data during pipeline execution. Whenever sufficient RAM is available, data is kept
429+
in memory to maximise performance. If memory requirements exceed the available
430+
RAM, HTTomo automatically stores intermediate data on disk and reloads it as needed.
431+
432+
The :code:`--max-memory` option specifies the amount of RAM available to HTTomo.
433+
It sets the limit in terms of the maximum amount of the CPU memory per process available
434+
on the system. For instance, if you're running HTTomo on 1 process serially, you need
435+
to pass the value of the CPU memory available on your system, e.g., :code:`--max-memory 32G` would
436+
set it to 32 Gigabyte. Providing an accurate value allows HTTomo to optimise memory usage
437+
while avoiding out-of-memory errors.
430438

431-
The :code:`--max-memory` flag is for telling HTTomo how much RAM the machine has,
432-
so then it can switch to using a file during execution of the pipeline if
433-
necessary.
434439

435440
:code:`--save-snapshots`
436441
~~~~~~~~~~~~~~~~~~~~~~~~

‎httomo/cli.py‎

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def check(pipeline: Union[Path, str], in_data_file: Optional[Path] = None):
171171
"--max-memory",
172172
type=click.STRING,
173173
default="0",
174-
help="Limit the amount of memory used by the pipeline to the given memory (supports strings like 3.2G or bytes)",
174+
help="The maximum amount of the CPU memory per process available on the system (supports strings like 3.2G or bytes)",
175175
)
176176
@click.option(
177177
"--save-snapshots",
@@ -324,6 +324,10 @@ def run(
324324
format_enum,
325325
)
326326

327+
for wrapper in pipeline_object:
328+
wrapper.check()
329+
wrapper.prep()
330+
327331
if not does_contain_sweep:
328332
execute_high_throughput_run(
329333
pipeline_object,
@@ -539,7 +543,12 @@ def execute_sweep_run(pipeline: Pipeline, global_comm: MPI.Comm) -> None:
539543
ParamSweepRunner(pipeline, global_comm).execute()
540544

541545

542-
def estimate_cpu_memory(in_data_file: Path, pipeline_file: Path, nprocs: int) -> int:
546+
def estimate_cpu_memory(
547+
in_data_file: Path,
548+
pipeline_file: Path,
549+
nprocs: int,
550+
shape: Optional[tuple[int, int, int]] = None,
551+
) -> int:
543552
pipeline = generate_pipeline(
544553
in_data_file, pipeline_file, False, MPI.COMM_WORLD, PipelineFormat.Yaml
545554
)
@@ -551,14 +560,17 @@ def estimate_cpu_memory(in_data_file: Path, pipeline_file: Path, nprocs: int) ->
551560
dtype = dataset.dtype
552561
full_shape = dataset.shape
553562

554-
preview_config = parse_preview(
555-
config[0]["parameters"].get("preview", None), full_shape
556-
)
557-
previewed_shape = (
558-
preview_config.angles.stop - preview_config.angles.start,
559-
preview_config.detector_y.stop - preview_config.detector_y.start,
560-
preview_config.detector_x.stop - preview_config.detector_x.start,
561-
)
563+
if shape is None:
564+
preview_config = parse_preview(
565+
config[0]["parameters"].get("preview", None), full_shape
566+
)
567+
previewed_shape = (
568+
preview_config.angles.stop - preview_config.angles.start,
569+
preview_config.detector_y.stop - preview_config.detector_y.start,
570+
preview_config.detector_x.stop - preview_config.detector_x.start,
571+
)
572+
else:
573+
previewed_shape = shape
562574

563575
section_memory_peak = 0
564576
for idx in range(len(sections)):

‎httomo/method_wrappers/generic.py‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,21 @@ def __init__(
138138
self._query.save_result_default() if save_result is None else save_result
139139
)
140140

141-
if self.is_gpu and not gpu_enabled:
142-
raise ValueError("GPU is not available, please use only CPU methods")
143-
144141
self._side_output: Dict[str, Any] = dict()
145142

146143
self._gpu_time_info = GpuTimeInfo()
147144

145+
def check(self) -> None:
146+
"""
147+
Raises
148+
------
149+
ValueError
150+
If the method is a GPU method and the machine is not GPU-enabled.
151+
"""
152+
if self.is_gpu and not gpu_enabled:
153+
raise ValueError("GPU is not available, please use only CPU methods")
154+
155+
def prep(self) -> None:
148156
if gpu_enabled:
149157
_id = httomo.globals.gpu_id
150158
self._gpu_id = get_gpu_id() if _id == -1 else _id

‎httomo/runner/method_wrapper.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,17 @@ def calculate_max_slices(
206206
something persists afterwards.
207207
"""
208208
... # pragma: nocover
209+
210+
def check(self) -> None:
211+
"""
212+
Perform any checks necessary to ensure that the method is capable of executing on the
213+
machine (for example, if it's a GPU method, check that execution is on a machine with a
214+
GPU that is accessible).
215+
"""
216+
... # pragma: nocover
217+
218+
def prep(self) -> None:
219+
"""
220+
Perform any preparation needed prior to beginning pipeline execution.
221+
"""
222+
... # pragma: nocover

‎httomo/sweep_runner/param_sweep_runner.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def execute_sweep(self):
233233
unit="value",
234234
ascii=True,
235235
)
236-
for val, _ in zip(self._sweep_values, progress):
236+
for val in progress:
237237
# Blocks are modified in-place by method wrappers, so a new block must be created
238238
# that contains a copy of the input data to the sweep stage
239239
block = ParamSweepBlock(

‎tests/method_wrappers/test_generic.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ def fake_method(data):
213213
"fake_method",
214214
MPI.COMM_WORLD,
215215
make_mock_preview_config(mocker),
216-
)
216+
).check()
217217

218218
assert "GPU is not available" in str(e)
219219

0 commit comments

Comments
 (0)