Skip to content

Commit 3fc23d3

Browse files
authored
remove array from cli (#107)
1 parent 4a86cf1 commit 3fc23d3

File tree

3 files changed

+0
-187
lines changed

3 files changed

+0
-187
lines changed

clusterscope/cli.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -243,42 +243,6 @@ def slurm(
243243
click.echo(format_methods[output_format]())
244244

245245

246-
@job_gen.command()
247-
@click.option(
248-
"--gpus-per-task", type=int, required=True, help="Number of GPUs per task"
249-
)
250-
@click.option(
251-
"--format",
252-
"output_format",
253-
type=click.Choice(["json", "sbatch", "srun", "submitit", "salloc"]),
254-
default="json",
255-
help="Format to output the job requirements in",
256-
)
257-
@click.option(
258-
"--partition",
259-
type=str,
260-
default=None,
261-
help="Slurm partition name to filter queries (optional)",
262-
)
263-
def array(gpus_per_task: int, output_format: str, partition: str):
264-
"""Generate job requirements for an array job."""
265-
unified_info = UnifiedInfo(partition=partition)
266-
job_requirements = unified_info.get_array_job_requirements(
267-
partition=partition,
268-
gpus_per_task=gpus_per_task,
269-
)
270-
271-
# Route to the correct format method based on CLI option
272-
format_methods = {
273-
"json": job_requirements.to_json,
274-
"sbatch": job_requirements.to_sbatch,
275-
"srun": job_requirements.to_srun,
276-
"salloc": job_requirements.to_salloc,
277-
"submitit": job_requirements.to_submitit,
278-
}
279-
click.echo(format_methods[output_format]())
280-
281-
282246
def main():
283247
"""Main entry point for the Slurm information CLI."""
284248
cli()

clusterscope/cluster_info.py

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -335,62 +335,6 @@ def get_task_resource_requirements(
335335
tasks_per_node=tasks_per_node,
336336
)
337337

338-
def get_array_job_requirements(
339-
self, partition: str, gpus_per_task: int
340-
) -> ResourceShape:
341-
"""Calculate resource requirements for array jobs with optimal GPU packing.
342-
343-
For array jobs, each array element gets its own resource allocation.
344-
This method calculates per-array-element resources based on proportional
345-
allocation of node resources per GPU. For maximum GPUs, returns all
346-
available node resources.
347-
348-
Args:
349-
gpus_per_task (int): Number of GPUs required per array task (1 to max available)
350-
351-
Returns:
352-
ResourceShape: Tuple containing CPU cores per array element (int),
353-
memory per array element (str), and tasks_per_node=1
354-
e.g., ResourceShape(cpu_cores=24, memory="225G", tasks_per_node=1)
355-
356-
Raises:
357-
ValueError: If gpus_per_task is not between 1 and max available GPUs
358-
"""
359-
# Get the total number of GPUs available per node
360-
max_gpus_per_node = self.get_total_gpus_per_node()
361-
362-
if not (1 <= gpus_per_task <= max_gpus_per_node):
363-
raise ValueError(f"gpus_per_task must be between 1 and {max_gpus_per_node}")
364-
365-
# Get total resources per node
366-
total_cpu_cores = self.get_cpus_per_node()
367-
total_ram_mb = self.get_mem_per_node_MB()
368-
369-
if gpus_per_task == max_gpus_per_node:
370-
# For max GPUs, use all available resources
371-
required_cpu_cores = math.floor(total_cpu_cores)
372-
required_ram_mb = math.floor(total_ram_mb)
373-
else:
374-
# Calculate per-GPU allocation based on actual GPU count per node
375-
cpu_cores_per_gpu = total_cpu_cores / max_gpus_per_node
376-
ram_mb_per_gpu = total_ram_mb / max_gpus_per_node
377-
378-
# Calculate requirements per array element
379-
required_cpu_cores = math.floor(cpu_cores_per_gpu * gpus_per_task)
380-
required_ram_mb = math.floor(ram_mb_per_gpu * gpus_per_task)
381-
382-
# Memory: Convert MB to GB and format for Slurm
383-
required_ram_gb = required_ram_mb / 1024
384-
sbatch_memory = f"{required_ram_gb:.0f}G"
385-
386-
return ResourceShape(
387-
slurm_partition=partition,
388-
cpus_per_task=required_cpu_cores,
389-
memory=sbatch_memory,
390-
tasks_per_node=1,
391-
gpus_per_task=gpus_per_task,
392-
)
393-
394338

395339
class DarwinInfo:
396340
def get_cpu_count(self, timeout: int = 60) -> int:

tests/test_cluster_info.py

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -902,101 +902,6 @@ def test_getResRequirements_invalid_tasks_per_node(self, mock_total_gpus):
902902
)
903903
self.assertIn("tasks_per_node must be at least 1", str(context.exception))
904904

905-
@patch.object(UnifiedInfo, "get_total_gpus_per_node")
906-
@patch.object(UnifiedInfo, "get_cpus_per_node")
907-
@patch.object(UnifiedInfo, "get_mem_per_node_MB")
908-
def test_getArrayJobRequirements_single_gpu(
909-
self, mock_mem, mock_cpus, mock_total_gpus
910-
):
911-
"""Test getArrayJobRequirements with 1 GPU per task."""
912-
mock_total_gpus.return_value = 8
913-
mock_cpus.return_value = 192
914-
mock_mem.return_value = 1843200
915-
916-
result = self.unified_info.get_array_job_requirements(
917-
partition="test_partition", gpus_per_task=1
918-
)
919-
920-
self.assertEqual(result.cpus_per_task, 24) # 192/8 = 24
921-
self.assertEqual(result.memory, "225G") # 1843200/8/1024 = 225GB
922-
self.assertEqual(result.tasks_per_node, 1) # Always 1 for array jobs
923-
924-
@patch.object(UnifiedInfo, "get_total_gpus_per_node")
925-
@patch.object(UnifiedInfo, "get_cpus_per_node")
926-
@patch.object(UnifiedInfo, "get_mem_per_node_MB")
927-
def test_getArrayJobRequirements_multiple_gpus(
928-
self, mock_mem, mock_cpus, mock_total_gpus
929-
):
930-
"""Test getArrayJobRequirements with multiple GPUs per task."""
931-
mock_total_gpus.return_value = 8
932-
mock_cpus.return_value = 192
933-
mock_mem.return_value = 1843200
934-
935-
result = self.unified_info.get_array_job_requirements(
936-
partition="test_partition", gpus_per_task=4
937-
)
938-
939-
self.assertEqual(result.cpus_per_task, 96) # 192/8*4 = 96
940-
self.assertEqual(result.memory, "900G") # 1843200/8*4/1024 = 900GB
941-
self.assertEqual(result.tasks_per_node, 1)
942-
943-
@patch.object(UnifiedInfo, "get_total_gpus_per_node")
944-
@patch.object(UnifiedInfo, "get_cpus_per_node")
945-
@patch.object(UnifiedInfo, "get_mem_per_node_MB")
946-
def test_getArrayJobRequirements_full_node(
947-
self, mock_mem, mock_cpus, mock_total_gpus
948-
):
949-
"""Test getArrayJobRequirements with all GPUs (full node per task)."""
950-
mock_total_gpus.return_value = 8
951-
mock_cpus.return_value = 192
952-
mock_mem.return_value = 1843200
953-
954-
result = self.unified_info.get_array_job_requirements(
955-
partition="test_partition", gpus_per_task=8
956-
)
957-
958-
self.assertEqual(result.cpus_per_task, 192) # All CPUs
959-
self.assertEqual(result.memory, "1800G") # All memory: 1843200/1024 = 1800GB
960-
self.assertEqual(result.tasks_per_node, 1)
961-
962-
@patch.object(UnifiedInfo, "get_total_gpus_per_node")
963-
@patch.object(UnifiedInfo, "get_cpus_per_node")
964-
@patch.object(UnifiedInfo, "get_mem_per_node_MB")
965-
def test_getArrayJobRequirements_4gpu_node(
966-
self, mock_mem, mock_cpus, mock_total_gpus
967-
):
968-
"""Test getArrayJobRequirements on a 4-GPU node configuration."""
969-
mock_total_gpus.return_value = 4
970-
mock_cpus.return_value = 64
971-
mock_mem.return_value = 524288
972-
973-
result = self.unified_info.get_array_job_requirements(
974-
partition="test_partition", gpus_per_task=2
975-
)
976-
977-
self.assertEqual(result.cpus_per_task, 32) # 64/4*2 = 32
978-
self.assertEqual(result.memory, "256G") # 524288/4*2/1024 = 256GB
979-
self.assertEqual(result.tasks_per_node, 1)
980-
981-
@patch.object(UnifiedInfo, "get_total_gpus_per_node")
982-
def test_getArrayJobRequirements_invalid_gpus_per_task(self, mock_total_gpus):
983-
"""Test getArrayJobRequirements raises ValueError for invalid gpus_per_task."""
984-
mock_total_gpus.return_value = 8
985-
986-
# Test zero GPUs
987-
with self.assertRaises(ValueError) as context:
988-
self.unified_info.get_array_job_requirements(
989-
partition="test_partition", gpus_per_task=0
990-
)
991-
self.assertIn("gpus_per_task must be between 1 and 8", str(context.exception))
992-
993-
# Test more than max GPUs
994-
with self.assertRaises(ValueError) as context:
995-
self.unified_info.get_array_job_requirements(
996-
partition="test_partition", gpus_per_task=9
997-
)
998-
self.assertIn("gpus_per_task must be between 1 and 8", str(context.exception))
999-
1000905
@patch.object(UnifiedInfo, "get_gpu_generation_and_count")
1001906
def test_get_total_gpus_per_node_with_gpus(self, mock_gpu_info):
1002907
"""Test get_total_gpus_per_node with actual GPU detection."""

0 commit comments

Comments
 (0)