|
7 | 7 | import io
|
8 | 8 | import logging
|
9 | 9 | import mimetypes
|
10 |
| -import multiprocessing |
11 | 10 | import numpy as np
|
12 | 11 | import sys
|
13 | 12 | import json
|
|
35 | 34 | get_L5Pyr_params_default)
|
36 | 35 | from hnn_core.hnn_io import dict_to_network, write_network_configuration
|
37 | 36 | from hnn_core.cells_default import _exp_g_at_dist
|
| 37 | +from hnn_core.parallel_backends import (_determine_cores_hwthreading, |
| 38 | + _has_mpi4py, |
| 39 | + _has_psutil) |
38 | 40 |
|
39 | 41 | hnn_core_root = Path(hnn_core.__file__).parent
|
40 | 42 | default_network_configuration = (hnn_core_root / 'param' /
|
@@ -344,6 +346,12 @@ def __init__(self, theme_color="#802989",
|
344 | 346 | # load default parameters
|
345 | 347 | self.params = self.load_parameters(network_configuration)
|
346 | 348 |
|
| 349 | + # Number of available cores |
| 350 | + [self.n_cores, _] = _determine_cores_hwthreading( |
| 351 | + use_hwthreading_if_found=False, |
| 352 | + sensible_default_cores=True, |
| 353 | + ) |
| 354 | + |
347 | 355 | # In-memory storage of all simulation and visualization related data
|
348 | 356 | self.simulation_data = defaultdict(lambda: dict(net=None, dpls=list()))
|
349 | 357 |
|
@@ -394,15 +402,17 @@ def __init__(self, theme_color="#802989",
|
394 | 402 | placeholder='ID of your simulation',
|
395 | 403 | description='Name:',
|
396 | 404 | disabled=False)
|
397 |
| - self.widget_backend_selection = Dropdown(options=[('Joblib', 'Joblib'), |
398 |
| - ('MPI', 'MPI')], |
399 |
| - value='Joblib', |
400 |
| - description='Backend:') |
| 405 | + self.widget_backend_selection = ( |
| 406 | + Dropdown(options=[('Joblib', 'Joblib'), |
| 407 | + ('MPI', 'MPI')], |
| 408 | + value=self._check_backend(), |
| 409 | + description='Backend:')) |
401 | 410 | self.widget_mpi_cmd = Text(value='mpiexec',
|
402 | 411 | placeholder='Fill if applies',
|
403 | 412 | description='MPI cmd:', disabled=False)
|
404 |
| - self.widget_n_jobs = BoundedIntText(value=1, min=1, |
405 |
| - max=multiprocessing.cpu_count(), |
| 413 | + self.widget_n_jobs = BoundedIntText(value=1, |
| 414 | + min=1, |
| 415 | + max=self.n_cores, |
406 | 416 | description='Cores:',
|
407 | 417 | disabled=False)
|
408 | 418 | self.load_data_button = FileUpload(
|
@@ -490,6 +500,14 @@ def __init__(self, theme_color="#802989",
|
490 | 500 | self._init_ui_components()
|
491 | 501 | self.add_logging_window_logger()
|
492 | 502 |
|
| 503 | + @staticmethod |
| 504 | + def _check_backend(): |
| 505 | + """Checks for MPI and returns the default backend name""" |
| 506 | + default_backend = 'Joblib' |
| 507 | + if _has_mpi4py() and _has_psutil(): |
| 508 | + default_backend = 'MPI' |
| 509 | + return default_backend |
| 510 | + |
493 | 511 | def get_cell_parameters_dict(self):
|
494 | 512 | """Returns the number of elements in the
|
495 | 513 | cell_parameters_dict dictionary.
|
@@ -632,8 +650,9 @@ def _run_button_clicked(b):
|
632 | 650 | self.fig_default_params, self.widget_default_smoothing,
|
633 | 651 | self.widget_min_frequency, self.widget_max_frequency,
|
634 | 652 | self.widget_ntrials, self.widget_backend_selection,
|
635 |
| - self.widget_mpi_cmd, self.widget_n_jobs, self.params, |
636 |
| - self._simulation_status_bar, self._simulation_status_contents, |
| 653 | + self.widget_mpi_cmd, self.widget_n_jobs, |
| 654 | + self.params, self._simulation_status_bar, |
| 655 | + self._simulation_status_contents, |
637 | 656 | self.connectivity_widgets, self.viz_manager,
|
638 | 657 | self.simulation_list_widget, self.cell_pameters_widgets)
|
639 | 658 |
|
@@ -758,6 +777,10 @@ def compose(self, return_layout=True):
|
758 | 777 | self.widget_max_frequency,
|
759 | 778 | ])
|
760 | 779 | ], layout=self.layout['config_box'])
|
| 780 | + # Displays the default backend options |
| 781 | + handle_backend_change(self.widget_backend_selection.value, |
| 782 | + self._backend_config_out, self.widget_mpi_cmd, |
| 783 | + self.widget_n_jobs) |
761 | 784 |
|
762 | 785 | connectivity_configuration = Tab()
|
763 | 786 |
|
@@ -2071,8 +2094,16 @@ def run_button_clicked(widget_simulation_name, log_out, drive_widgets,
|
2071 | 2094 |
|
2072 | 2095 | print("start simulation")
|
2073 | 2096 | if backend_selection.value == "MPI":
|
| 2097 | + # 'use_hwthreading_if_found' and 'sensible_default_cores' have |
| 2098 | + # already been set elsewhere, and do not need to be re-set here. |
| 2099 | + # Hardware-threading and oversubscription will always be disabled |
| 2100 | + # to prevent edge cases in the GUI. |
2074 | 2101 | backend = MPIBackend(
|
2075 |
| - n_procs=multiprocessing.cpu_count() - 1, mpi_cmd=mpi_cmd.value) |
| 2102 | + n_procs=n_jobs.value, |
| 2103 | + mpi_cmd=mpi_cmd.value, |
| 2104 | + override_hwthreading_option=False, |
| 2105 | + override_oversubscribe_option=False, |
| 2106 | + ) |
2076 | 2107 | else:
|
2077 | 2108 | backend = JoblibBackend(n_jobs=n_jobs.value)
|
2078 | 2109 | print(f"Using Joblib with {n_jobs.value} core(s).")
|
@@ -2379,7 +2410,7 @@ def handle_backend_change(backend_type, backend_config, mpi_cmd, n_jobs):
|
2379 | 2410 | backend_config.clear_output()
|
2380 | 2411 | with backend_config:
|
2381 | 2412 | if backend_type == "MPI":
|
2382 |
| - display(mpi_cmd) |
| 2413 | + display(VBox(children=[n_jobs, mpi_cmd])) |
2383 | 2414 | elif backend_type == "Joblib":
|
2384 | 2415 | display(n_jobs)
|
2385 | 2416 |
|
|
0 commit comments