Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions src/feelpp/benchmarking/reframe/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ def validate(self, rfm_test):
class TaskAndTaskPerNodeStrategy(ResourceStrategy):
""" Resource Strategy to configure the resources for the test with tasks and tasks per node """
def configure(self, resources, rfm_test):
if resources.cpus_per_task:
rfm_test.num_cpus_per_task = int(resources.cpus_per_task)

rfm_test.num_tasks_per_node = int(resources.tasks_per_node)
rfm_test.num_tasks = int(resources.tasks)
rfm_test.num_nodes = int(np.ceil(rfm_test.num_tasks / rfm_test.num_tasks_per_node))
Expand All @@ -28,27 +31,35 @@ def validate(self, rfm_test):
super().validate(rfm_test)
assert rfm_test.num_tasks % rfm_test.num_tasks_per_node == 0, 'Number of tasks should be divisible by tasks per node'
assert rfm_test.num_tasks >= rfm_test.num_tasks_per_node > 0, 'Number of tasks should be greater than tasks per node'
assert rfm_test.num_tasks_per_node <= rfm_test.current_partition.processor.num_cpus, f"A node has not enough capacity ({rfm_test.current_partition.processor.num_cpus}, {rfm_test.num_tasks_per_node})"
assert rfm_test.num_tasks_per_node * (rfm_test.num_cpus_per_task or 1) <= rfm_test.current_partition.processor.num_cpus, f"A node has not enough capacity ({rfm_test.current_partition.processor.num_cpus} cpus, {rfm_test.num_tasks_per_node} tasks per node, {rfm_test.num_cpus_per_task} cpus per task)"

class NodesAndTasksPerNodeStrategy(ResourceStrategy):
""" Resource Strategy to configure the resources for the test with nodes and tasks per node
The number of tasks is calculated as the number of nodes multiplied by the number of tasks per node
"""
def configure(self, resources, rfm_test):
if resources.cpus_per_task:
rfm_test.num_cpus_per_task = int(resources.cpus_per_task)

rfm_test.num_tasks_per_node = int(resources.tasks_per_node)
rfm_test.num_nodes = int(resources.nodes)
rfm_test.num_tasks = int(rfm_test.num_tasks_per_node * rfm_test.num_nodes)

def validate(self, rfm_test):
super().validate(rfm_test)
assert rfm_test.num_tasks_per_node <= rfm_test.current_partition.processor.num_cpus, f"A node has not enough capacity ({rfm_test.current_partition.processor.num_cpus}, {rfm_test.num_tasks_per_node})"
assert rfm_test.num_nodes > 0, "Number of nodes should be strictly positive."
assert rfm_test.num_tasks_per_node * (rfm_test.num_cpus_per_task or 1) <= rfm_test.current_partition.processor.num_cpus, f"A node has not enough capacity ({rfm_test.current_partition.processor.num_cpus} cpus, {rfm_test.num_tasks_per_node} tasks per node, {rfm_test.num_cpus_per_task} cpus per task)"



class TasksAndNodesStrategy(ResourceStrategy):
""" Resource Strategy to configure the resources for the test with tasks and nodes
The number of tasks per node is calculated as the euclidean quotient of the number of tasks divided by the number of nodes
"""
def configure(self, resources, rfm_test):
if resources.cpus_per_task:
rfm_test.num_cpus_per_task = int(resources.cpus_per_task)

rfm_test.num_tasks = int(resources.tasks)
rfm_test.num_nodes = int(resources.nodes)
rfm_test.num_tasks_per_node = rfm_test.num_tasks // rfm_test.num_nodes
Expand All @@ -64,6 +75,10 @@ class TasksStrategy(ResourceStrategy):
The number of tasks per node is calculated as the minimum between the number of tasks and the number of CPUs per node
"""
def configure(self, resources, rfm_test):

if resources.cpus_per_task:
rfm_test.num_cpus_per_task = int(resources.cpus_per_task)

rfm_test.num_tasks = int(resources.tasks)
rfm_test.num_nodes = int(np.ceil(rfm_test.num_tasks / rfm_test.current_partition.processor.num_cpus))
rfm_test.num_tasks_per_node = min(rfm_test.num_tasks, rfm_test.current_partition.processor.num_cpus)
Expand Down Expand Up @@ -118,6 +133,20 @@ def __init__(self, exclusive_access):
def enforceExclusiveAccess(self, rfm_test):
rfm_test.exclusive_access = self.exclusive_access

class HyperthreadingEnforcer:
""" Plugin to enforce hyperthreading value to the nodes
The hyperthreading value is set to 1 by default
"""
def __init__(self, threads_per_core):
"""Args:
threads_per_core (int): The hyperthreading value
"""
self.threads_per_core = int(threads_per_core) if threads_per_core is not None else 1

def enforceHyperthreading(self, rfm_test):
rfm_test.job.options += [f'--threads-per-core={self.threads_per_core}']
rfm_test.multithreading = self.threads_per_core > 1

class ResourceHandler:
""" Resource Handler to set the resources for the test, based on the resources model """
@staticmethod
Expand Down Expand Up @@ -155,6 +184,8 @@ def setResources(resources, rfm_test):
if resources.memory:
MemoryEnforcer(resources.memory).enforceMemory(rfm_test)



ExclusiveAccessEnforcer(resources.exclusive_access).enforceExclusiveAccess(rfm_test)

strategy.validate(rfm_test)
Expand Down
3 changes: 3 additions & 0 deletions src/feelpp/benchmarking/reframe/schemas/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Resources(BaseModel):
memory: Optional[Union[str,int]] = 0
exclusive_access: Optional[Union[str,bool]] = True

cpus_per_task: Optional[Union[str,int]] = 1
threads_per_core: Optional[Union[str,int]] = 1 #Hyperthreading

@model_validator(mode="after")
def validateResources(self):
assert (
Expand Down
1 change: 0 additions & 1 deletion src/feelpp/benchmarking/reframe/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ def setSchedOptions(self):
""" Sets the necessary pre-run configurations"""
self.job.launcher.options += self.current_partition.get_resource('launcher_options')
self.job.options += self.machine_reader.config.access
self.job.options += ['--threads-per-core=1']

@run_before('run')
def addPrepareCmds(self):
Expand Down
4 changes: 3 additions & 1 deletion tests/parameters/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@

class ResourcesMocker:
""" Mocks the resources object """
def __init__(self, tasks = None, tasks_per_node = None, nodes = None, memory = None, exclusive_access = None, gpus_per_node = None):
def __init__(self, tasks = None, tasks_per_node = None, nodes = None, memory = None, exclusive_access = None, gpus_per_node = None, cpus_per_task = None ):
self.tasks = tasks
self.tasks_per_node = tasks_per_node
self.nodes = nodes
self.memory = memory
self.exclusive_access = exclusive_access
self.gpus_per_node = gpus_per_node
self.cpus_per_task = cpus_per_task


class RfmTestMocker:
""" Mocks the rfm_test object (a ReFrame Test) """
def __init__(self, num_cpus, memory_per_node):
self.current_partition = self.Partition(num_cpus=num_cpus, memory_per_node=memory_per_node)
self.job = self.Job()
self.num_cpus_per_task = None #Because the resource strategy does not set it if none.

class Job:
def __init__(self):
Expand Down
Loading