Skip to content

Commit 178734a

Browse files
committed
Merge branch 'main' into ci_installer
2 parents 4eb8df7 + f8b54ff commit 178734a

File tree

10 files changed

+57
-8
lines changed

10 files changed

+57
-8
lines changed

requirements-tests.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pytest >= 6.2.0
77
requests >= 2.25.1
88
pytest-cov
99
pytest-timeout
10-
filelock >= 3.4, < 3.18
10+
filelock >= 3.4, < 3.19
1111
textual
1212
tree-sitter
1313
tree-sitter-bash

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
psutil >=5.9, <=7.0.0
22
pystache>=0.6.0
33
typeguard>=3.0.1
4-
packaging >= 24.0, <= 24.2
4+
packaging >= 24.0, <= 25.0

src/psij/executors/batch/batch_scheduler_executor.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,21 @@ def __init__(self, launcher_log_file: Optional[Path] = None,
105105
Whether to keep submit files and auxiliary job files (exit code and output files) after
106106
a job has completed.
107107
"""
108-
super().__init__(work_directory, launcher_log_file)
108+
super().__init__(launcher_log_file, work_directory)
109109
self.queue_polling_interval = queue_polling_interval
110110
self.initial_queue_polling_delay = initial_queue_polling_delay
111111
self.queue_polling_error_threshold = queue_polling_error_threshold
112112
self.keep_files = keep_files
113113
if 'PSIJ_BATCH_KEEP_FILES' in os.environ:
114114
self.keep_files = True
115115

116+
@classmethod
117+
def _from_config(cls, config: JobExecutorConfig) -> 'BatchSchedulerExecutorConfig':
118+
new = cls()
119+
new.work_directory = config.work_directory
120+
new.launcher_log_file = config.launcher_log_file
121+
return new
122+
116123

117124
class InvalidJobStateError(Exception):
118125
"""An exception that signals that a job cannot be cancelled due to it being already done."""
@@ -199,14 +206,21 @@ def __init__(self, url: Optional[str] = None,
199206
An configuration for this executor instance; if none is specified, a default
200207
configuration is used.
201208
"""
202-
super().__init__(url=url, config=config if config else BatchSchedulerExecutorConfig())
209+
super().__init__(url=url, config=self._get_config(config))
203210
assert config
204211
self.work_directory = config.work_directory / self.name
205212
self._queue_poll_thread = self._start_queue_poll_thread()
206213

207214
def _ensure_work_dir(self) -> None:
208215
self.work_directory.mkdir(parents=True, exist_ok=True)
209216

217+
def _get_config(self, config: Optional[JobExecutorConfig]) -> BatchSchedulerExecutorConfig:
218+
if config is None:
219+
return BatchSchedulerExecutorConfig()
220+
if isinstance(config, BatchSchedulerExecutorConfig):
221+
return config
222+
return BatchSchedulerExecutorConfig._from_config(config)
223+
210224
def submit(self, job: Job) -> None:
211225
"""See :func:`~psij.JobExecutor.submit`."""
212226
logger.info('Job %s: submitting', job.id)

src/psij/executors/batch/lsf/lsf.mustache

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
#BSUB -gpu num={{.}}/task
3333
{{/gpu_cores_per_process}}
3434

35+
{{#memory}}
36+
#BSUB -M {{memory_kb}}KB
37+
{{/memory}}
38+
3539
{{/job.spec.resources}}
3640

3741

src/psij/executors/batch/pbs/pbs_classic.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{{/job.spec.inherit_environment}}
1111

1212
{{#job.spec.resources}}
13-
#PBS -l nodes={{computed_node_count}}:ppn={{computed_processes_per_node}}{{#gpu_cores_per_process}}:gpus={{.}}{{/gpu_cores_per_process}}
13+
#PBS -l nodes={{computed_node_count}}:ppn={{computed_processes_per_node}}{{#gpu_cores_per_process}}:gpus={{.}}{{/gpu_cores_per_process}}{{#memory}}:mem={{.}}{{/memory}}
1414
{{#exclusive_node_use}}
1515
#PBS -n
1616
{{/exclusive_node_use}}

src/psij/executors/batch/pbs/pbspro.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{{/job.spec.inherit_environment}}
1111

1212
{{#job.spec.resources}}
13-
#PBS -l select={{computed_node_count}}:ncpus={{computed_processes_per_node}}:mpiprocs={{computed_processes_per_node}}
13+
#PBS -l select={{computed_node_count}}:ncpus={{computed_processes_per_node}}:mpiprocs={{computed_processes_per_node}}{{#memory}}:mem={{.}}{{/memory}}
1414
{{#exclusive_node_use}}
1515
#PBS -l place=scatter:exclhost
1616
{{/exclusive_node_use}}

src/psij/executors/batch/slurm/slurm.mustache

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
hyperthreaded CPUs are used) or CPU core (for non-hyperthreaded CPUs).}}
3838
#SBATCH --cpus-per-task={{.}}
3939
{{/cpu_cores_per_process}}
40+
41+
{{#memory}}
42+
#SBATCH --mem={{memory_kb}}K
43+
{{/memory}}
4044
{{/job.spec.resources}}
4145

4246
{{#formatted_job_duration}}

src/psij/job_attributes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ def __init__(self, duration: timedelta = timedelta(minutes=10),
5353
self.account = account
5454
self.duration = duration
5555
self.queue_name = queue_name
56-
self.project_name = project_name
56+
if project_name is not None:
57+
self.project_name = project_name
5758
self.reservation_id = reservation_id
5859
self._custom_attributes = custom_attributes
5960

src/psij/resource_spec.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ def __init__(self, node_count: Optional[int] = None,
5454
processes_per_node: Optional[int] = None,
5555
cpu_cores_per_process: Optional[int] = None,
5656
gpu_cores_per_process: Optional[int] = None,
57-
exclusive_node_use: bool = False) -> None:
57+
exclusive_node_use: bool = False,
58+
memory: Optional[int] = None) -> None:
5859
"""
5960
Some of the properties of this class are constrained. Specifically,
6061
`process_count = node_count * processes_per_node`. Specifying all constrained properties
@@ -79,6 +80,7 @@ def __init__(self, node_count: Optional[int] = None,
7980
set to `False`, which is the default, the LRM is free to co-schedule multiple jobs
8081
on a given node if the number of cores requested by those jobs total less than the
8182
amount available on the node.
83+
:param memory: The total amount, in bytes, of memory requested for the job.
8284
8385
All constructor parameters are accessible as properties.
8486
"""
@@ -88,6 +90,7 @@ def __init__(self, node_count: Optional[int] = None,
8890
self.cpu_cores_per_process = cpu_cores_per_process
8991
self.gpu_cores_per_process = gpu_cores_per_process
9092
self.exclusive_node_use = exclusive_node_use
93+
self.memory = memory
9194
self._check_constraints()
9295

9396
def _check_constraints(self) -> None:
@@ -184,6 +187,19 @@ def computed_processes_per_node(self) -> int:
184187
assert self._computed_ppn is not None
185188
return self._computed_ppn
186189

190+
@property
191+
def memory_kb(self) -> Optional[int]:
192+
"""
193+
Returns the memory limit specified by the `memory` property, but in KB.
194+
195+
:return: If the `memory` property is set on this object, returns `memory // 1024`. If the
196+
`memory` property is `None`, this method returns `None`.
197+
"""
198+
if self.memory:
199+
return self.memory // 1024
200+
else:
201+
return None
202+
187203
@property
188204
def version(self) -> int:
189205
"""Returns the version of this `ResourceSpec`, which is 1 for this class."""

tests/test_resources.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,13 @@ def _supported(ep: ExecutorTestParams) -> bool:
9494
return ep.launcher in ['mpirun', 'srun', 'ibrun']
9595

9696
return False
97+
98+
99+
def test_memory(execparams: ExecutorTestParams) -> None:
100+
job = Job(JobSpec(executable='/bin/hostname', launcher=execparams.launcher))
101+
assert job.spec is not None
102+
job.spec.resources = ResourceSpecV1(memory=1024 * 1024 * 100)
103+
ex = _get_executor_instance(execparams, job)
104+
ex.submit(job)
105+
status = job.wait(timeout=_get_timeout(execparams))
106+
assert_completed(job, status)

0 commit comments

Comments
 (0)