Skip to content

Commit d29a6cf

Browse files
Fix --lb-mode=Memory (#275)
## Context lb-mode Memory is failing when no cell_memory_usage.json or memory_per_metype.json commoning from dry_run are present. Fix #243 ## Scope Add dry_run memory files exists check and throw an error if not informing the user he must dry_run first Add test for this situation ## Testing Extent tests/unit/test_dry_run.py ## Review * [ ] PR description is complete * [ ] Coding style (imports, function length, New functions, classes or files) are good * [ ] Unit/Scientific test added * [ ] Updated Readme, in-code, developer documentation
1 parent b309244 commit d29a6cf

File tree

4 files changed

+74
-33
lines changed

4 files changed

+74
-33
lines changed

neurodamus/node.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,17 @@ def compute_load_balance(self):
456456
if file_exists:
457457
alloc = self._dry_run_stats.import_allocation_stats(filename, self._cycle_i)
458458
else:
459+
if not Path(DryRunStats._MEMORY_USAGE_FILENAME).exists():
460+
raise FileNotFoundError(
461+
f"No such file {DryRunStats._MEMORY_USAGE_FILENAME}. "
462+
"Neurodamus must be run with --dry-run mode before proceeding."
463+
)
464+
if not Path(DryRunStats._MEMORY_USAGE_PER_METYPE_FILENAME).exists():
465+
raise FileNotFoundError(
466+
f"No such file {DryRunStats._MEMORY_USAGE_PER_METYPE_FILENAME}. "
467+
"Neurodamus must be run with --dry-run mode before proceeding."
468+
)
469+
459470
logging.warning("Allocation file not found. Generating on-the-fly.")
460471
self._dry_run_stats.try_import_cell_memory_usage()
461472
cell_distributor = CellDistributor(circuit, self._target_manager, self._run_conf)

tests/conftest.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import json
22
import pytest
3-
from pathlib import Path
43
import platform
4+
from pathlib import Path
5+
56
from neurodamus.core._utils import run_only_rank0
67

78
try:
@@ -89,6 +90,20 @@ def change_test_dir(monkeypatch, tmp_path):
8990
monkeypatch.chdir(tmp_path)
9091

9192

93+
@pytest.fixture()
94+
def copy_memory_files(change_test_dir):
95+
# Fix values to ensure allocation memory (0,0)[1, 3] (1,0)[2]
96+
metypes_memory = {
97+
"MTYPE0-ETYPE0": 100.0,
98+
"MTYPE1-ETYPE1": 200.0,
99+
"MTYPE2-ETYPE2": 1000.0,
100+
}
101+
with Path("memory_per_metype.json").open("w") as f:
102+
json.dump(metypes_memory, f, indent=4)
103+
with Path("cell_memory_usage.json").open("w") as f:
104+
json.dump(metypes_memory, f, indent=4)
105+
106+
92107
@run_only_rank0
93108
def _create_simulation_config_file(params, dst_dir, sim_config_data=None) -> str:
94109
"""create simulation config file in dst_dir from

tests/unit-mpi/test_dry_run.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import pytest
22
import tempfile
3-
from pathlib import Path
43
from mpi4py import MPI
54

65

@@ -13,7 +12,7 @@
1312
size = comm.Get_size()
1413

1514

16-
@pytest.fixture(scope="session")
15+
@pytest.fixture(scope="function")
1716
def tmp_folder():
1817
if rank == 0:
1918
path = tempfile.mkdtemp()
@@ -109,17 +108,15 @@ def test_dry_run_distribute_cells(create_tmp_simulation_config_file, mpi_ranks):
109108
}
110109
assert rank_allocation_standard == expected_allocation
111110

112-
Path(("allocation_r1_c1.pkl.gz")).unlink(missing_ok=True)
113-
Path(("allocation_r2_c1.pkl.gz")).unlink(missing_ok=True)
114-
115111

116112
@pytest.mark.parametrize("create_tmp_simulation_config_file", [
117113
{
118114
"simconfig_fixture": "ringtest_baseconfig",
119115
},
120116
], indirect=True)
121117
@pytest.mark.mpi(ranks=2)
122-
def test_dry_run_dynamic_distribute(create_tmp_simulation_config_file, mpi_ranks):
118+
def test_dry_run_dynamic_distribute(create_tmp_simulation_config_file, mpi_ranks,
119+
copy_memory_files):
123120
nd = Neurodamus(create_tmp_simulation_config_file, dry_run=False, lb_mode="Memory",
124121
num_target_ranks=2)
125122
nd.run()
@@ -132,6 +129,7 @@ def test_dry_run_dynamic_distribute(create_tmp_simulation_config_file, mpi_ranks
132129
# RingA neuron 1 always in rank 0, neuron 2 always in rank 1
133130
# but neuron 3 can be in either of the two
134131
if rank == 0:
135-
assert is_subset(rank_allocation_standard['RingA'][(0, 0)], [1, 3])
132+
expected_allocation = {'RingA': {(0, 0): [1, 3]}}
136133
elif rank == 1:
137-
assert is_subset(rank_allocation_standard['RingA'][(1, 0)], [2, 3])
134+
expected_allocation = {'RingA': {(1, 0): [2]}}
135+
assert rank_allocation_standard == expected_allocation

tests/unit/test_dry_run.py

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,21 @@
22
import numpy as np
33
import numpy.testing as npt
44
import unittest.mock
5-
import tempfile
65
from pathlib import Path
76

87
from tests.utils import defaultdict_to_standard_types
9-
from ..conftest import RINGTEST_DIR, NGV_DIR, PLATFORM_SYSTEM
8+
from ..conftest import NGV_DIR, PLATFORM_SYSTEM
109
from neurodamus import Neurodamus
1110

12-
TMP_FOLDER = tempfile.mkdtemp()
13-
14-
15-
@pytest.fixture(autouse=True)
16-
def change_test_dir(monkeypatch):
17-
"""
18-
All tests in this file are using the same working directory, i.e TMP_FOLDER
19-
Because test_dynamic_distribute requires memory_per_metype.json generated in the previous test
20-
"""
21-
monkeypatch.chdir(TMP_FOLDER)
22-
2311

12+
@pytest.mark.parametrize("create_tmp_simulation_config_file", [
13+
{
14+
"simconfig_fixture": "ringtest_baseconfig",
15+
},
16+
], indirect=True)
2417
@pytest.mark.forked
25-
def test_dry_run_memory_use():
26-
nd = Neurodamus(str(RINGTEST_DIR / "simulation_config.json"), dry_run=True, num_target_ranks=2)
27-
18+
def test_dry_run_memory_use(create_tmp_simulation_config_file):
19+
nd = Neurodamus(create_tmp_simulation_config_file, dry_run=True, num_target_ranks=2)
2820
nd.run()
2921

3022
isMacOS = PLATFORM_SYSTEM == "Darwin"
@@ -40,9 +32,14 @@ def test_dry_run_memory_use():
4032
assert nd._dry_run_stats.suggested_nodes > 0
4133

4234

35+
@pytest.mark.parametrize("create_tmp_simulation_config_file", [
36+
{
37+
"simconfig_fixture": "ringtest_baseconfig",
38+
},
39+
], indirect=True)
4340
@pytest.mark.forked
44-
def test_dry_run_distribute_cells():
45-
nd = Neurodamus(str(RINGTEST_DIR / "simulation_config.json"), dry_run=True, num_target_ranks=2)
41+
def test_dry_run_distribute_cells(create_tmp_simulation_config_file):
42+
nd = Neurodamus(create_tmp_simulation_config_file, dry_run=True, num_target_ranks=2)
4643
nd.run()
4744

4845
# Test allocation
@@ -89,31 +86,51 @@ def test_dry_run_distribute_cells():
8986
}
9087
assert rank_allocation_standard == expected_allocation
9188

92-
Path(("allocation_r1_c1.pkl.gz")).unlink(missing_ok=True)
93-
Path(("allocation_r2_c1.pkl.gz")).unlink(missing_ok=True)
94-
9589

9690
@pytest.mark.parametrize("create_tmp_simulation_config_file", [
9791
{
9892
"simconfig_fixture": "ringtest_baseconfig",
9993
},
10094
], indirect=True)
10195
@pytest.mark.forked
102-
def test_dry_run_dynamic_distribute(create_tmp_simulation_config_file):
96+
def test_dry_run_lb_mode_memory(create_tmp_simulation_config_file, copy_memory_files):
10397
nd = Neurodamus(create_tmp_simulation_config_file, dry_run=False, lb_mode="Memory",
10498
num_target_ranks=1)
10599

106100
rank_alloc, _, _ = nd._dry_run_stats.distribute_cells_with_validation(2, 1)
107101
rank_allocation_standard = defaultdict_to_standard_types(rank_alloc)
108102
expected_allocation = {
109103
'RingA': {
110-
(0, 0): [1],
111-
(1, 0): [2, 3]
104+
(0, 0): [1, 3],
105+
(1, 0): [2]
112106
}
113107
}
114108
assert rank_allocation_standard == expected_allocation
115109

116110

111+
@pytest.mark.parametrize("create_tmp_simulation_config_file", [
112+
{
113+
"simconfig_fixture": "ringtest_baseconfig",
114+
},
115+
], indirect=True)
116+
@pytest.mark.forked
117+
def test_dry_run_lb_mode_memory_fail(create_tmp_simulation_config_file):
118+
with pytest.raises(FileNotFoundError,
119+
match="No such file cell_memory_usage.json. "
120+
"Neurodamus must be run with --dry-run mode before proceeding."):
121+
Neurodamus(create_tmp_simulation_config_file, dry_run=False, lb_mode="Memory",
122+
num_target_ranks=1)
123+
124+
with Path("cell_memory_usage.json").open('w'):
125+
pass
126+
127+
with pytest.raises(FileNotFoundError,
128+
match="No such file memory_per_metype.json. "
129+
"Neurodamus must be run with --dry-run mode before proceeding."):
130+
Neurodamus(create_tmp_simulation_config_file, dry_run=False, lb_mode="Memory",
131+
num_target_ranks=1)
132+
133+
117134
@pytest.mark.forked
118135
def test_dry_run_ngv_fail():
119136
with pytest.raises(Exception, match="Dry run not available for ngv circuit"):

0 commit comments

Comments
 (0)