Fix some circular imports + Cleanup + Bugfixes

This commit is contained in:
Abraham Gonzalez 2022-04-25 16:42:55 +00:00
parent 8dcb1271a9
commit f2887d39d8
18 changed files with 164 additions and 178 deletions

View File

@ -1,5 +1,7 @@
""" Tools to help manage afis. """
from __future__ import annotations
import logging
import boto3
from awstools.awstools import depaginated_boto_query

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python3
from __future__ import annotations
""" This script configures your AWS account to run FireSim. """
import boto3

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from __future__ import print_function
from __future__ import print_function, annotations
import random
import logging

View File

@ -1,4 +1,5 @@
from __future__ import with_statement
from __future__ import with_statement, annotations
import json
import time
import random
@ -9,14 +10,15 @@ from fabric.api import prefix, local, run, env, lcd, parallel # type: ignore
from fabric.contrib.console import confirm # type: ignore
from fabric.contrib.project import rsync_project # type: ignore
from awstools.afitools import *
from awstools.afitools import firesim_tags_to_description, copy_afi_to_all_regions
from awstools.awstools import send_firesim_notification
from util.streamlogger import StreamLogger, InfoStreamLogger
# imports needed for python type checking
from typing import Optional
from buildtools.buildconfig import BuildConfig
from buildtools.buildconfigfile import BuildConfigFile
from typing import Optional, TYPE_CHECKING
if TYPE_CHECKING:
from buildtools.buildconfig import BuildConfig
from buildtools.buildconfigfile import BuildConfigFile
rootLogger = logging.getLogger()

View File

@ -1,18 +1,14 @@
from __future__ import annotations
from time import strftime, gmtime
import pprint
from importlib import import_module
from awstools.awstools import *
from awstools.awstools import valid_aws_configure_creds, aws_resource_names
# imports needed for python type checking
from typing import Set, Any, Optional, Dict, TYPE_CHECKING
# needed to avoid type-hint circular dependencies
# TODO: Solved in 3.7.+ by "from __future__ import annotations" (see https://stackoverflow.com/questions/33837918/type-hints-solve-circular-dependency)
# and normal "import <module> as ..." syntax (see https://www.reddit.com/r/Python/comments/cug90e/how_to_not_create_circular_dependencies_when/)
if TYPE_CHECKING:
from buildtools.buildconfigfile import BuildConfigFile
else:
BuildConfigFile = object
class BuildConfig:
"""Represents a single build configuration used to build RTL, drivers, and bitstreams.

View File

@ -1,10 +1,10 @@
from __future__ import annotations
from time import strftime, gmtime
import pprint
import logging
import sys
import yaml
from collections import defaultdict
from importlib import import_module
from runtools.runtime_config import RuntimeHWDB
from buildtools.buildconfig import BuildConfig
@ -13,7 +13,7 @@ from buildtools.buildfarm import BuildFarm
# imports needed for python type checking
from typing import Dict, Optional, List, Set, Type, Any, TYPE_CHECKING
from argparse import Namespace
import argparse # this is not within a if TYPE_CHECKING: scope so the `register_task` in FireSim can evaluate it's annotation
rootLogger = logging.getLogger()
@ -50,7 +50,7 @@ class BuildConfigFile:
num_builds: Number of builds to run.
build_farm: Build farm used to host builds.
"""
args: Namespace
args: argparse.Namespace
agfistoshare: List[str]
acctids_to_sharewith: List[str]
hwdb: RuntimeHWDB
@ -59,7 +59,7 @@ class BuildConfigFile:
num_builds: int
build_farm: BuildFarm
def __init__(self, args: Namespace) -> None:
def __init__(self, args: argparse.Namespace) -> None:
"""
Args:
args: Object holding arg attributes.

View File

@ -1,20 +1,16 @@
from __future__ import annotations
import logging
import sys
import abc
import pprint
from awstools.awstools import *
from awstools.awstools import aws_resource_names, launch_instances, wait_on_instance_launches, get_instance_ids_for_instances, terminate_instances
# imports needed for python type checking
from typing import cast, Any, Dict, Optional, Sequence, List, TYPE_CHECKING
from mypy_boto3_ec2.service_resource import Instance as EC2InstanceResource
# needed to avoid type-hint circular dependencies
# TODO: Solved in 3.7.+ by "from __future__ import annotations" (see https://stackoverflow.com/questions/33837918/type-hints-solve-circular-dependency)
# and normal "import <module> as ..." syntax (see https://www.reddit.com/r/Python/comments/cug90e/how_to_not_create_circular_dependencies_when/)
if TYPE_CHECKING:
from buildtools.buildconfig import BuildConfig
else:
BuildConfig = object
from mypy_boto3_ec2.service_resource import Instance as EC2InstanceResource
rootLogger = logging.getLogger()

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3
# PYTHON_ARGCOMPLETE_OK
from __future__ import annotations
import sys
import os
@ -11,18 +12,12 @@ import random
import argcomplete # type: ignore
from fabric.api import local, hide, warn_only, env, execute # type: ignore
import string
from typing import Dict, Callable, Type, Optional
try:
# added in 3.8
from typing import TypedDict
except ImportError:
TypedDict = dict
from inspect import signature
from runtools.runtime_config import RuntimeConfig
from awstools.awstools import valid_aws_configure_creds, get_aws_userid, subscribe_to_firesim_topic
from awstools.afitools import *
from awstools.afitools import share_agfi_in_all_regions
from buildtools.buildafi import replace_rtl, build_driver, aws_build, aws_create_afi
from buildtools.buildconfigfile import BuildConfigFile
@ -30,6 +25,8 @@ from buildtools.buildconfig import BuildConfig
from util.streamlogger import StreamLogger
from typing import Dict, Callable, Type, Optional, TypedDict, get_type_hints
class Task(TypedDict):
task: Callable
config: Optional[Callable]
@ -59,6 +56,9 @@ def register_task(task: Callable) -> Callable:
config_class = None
# resolve str type hints
task.__annotations__ = get_type_hints(task)
# introspect the type of config that this task takes (it's first param)
sig = signature(task)
if sig.parameters:
@ -68,6 +68,9 @@ def register_task(task: Callable) -> Callable:
else:
config_class = first.annotation
# resolve str type hints
config_class.__init__.__annotations__ = get_type_hints(config_class.__init__)
# check that the first parameter takes a Namespace passed to its constructor
csig = signature(config_class)
if csig.parameters:

View File

@ -1,10 +1,13 @@
""" These are the base components that make up a FireSim simulation target
topology. """
from runtools.firesim_topology_elements import *
from __future__ import annotations
from runtools.user_topology import UserTopologies
from typing import List, Callable, Optional, Union
from typing import List, Callable, Optional, Union, TYPE_CHECKING
if TYPE_CHECKING:
from runtools.firesim_topology_elements import FireSimSwitchNode, FireSimServerNode, FireSimNode
class FireSimTopology(UserTopologies):
""" A FireSim Topology consists of a list of root FireSimNodes, which

View File

@ -1,5 +1,7 @@
""" Node types necessary to construct a FireSimTopology. """
from __future__ import annotations
import logging
import abc
from fabric.contrib.project import rsync_project # type: ignore
@ -8,12 +10,13 @@ from fabric.api import run, local, warn_only, get # type: ignore
from runtools.switch_model_config import AbstractSwitchToSwitchConfig
from runtools.utils import get_local_shared_libraries
from util.streamlogger import StreamLogger
from runtools.workload import WorkloadConfig, JobConfig
from runtools.run_farm import EC2Inst
from runtools.runtime_config import RuntimeHWConfig
from runtools.utils import MacAddress
from typing import Optional, List, Tuple, Sequence, Union
from typing import Optional, List, Tuple, Sequence, Union, TYPE_CHECKING
if TYPE_CHECKING:
from runtools.workload import JobConfig
from runtools.run_farm import EC2Inst
from runtools.runtime_config import RuntimeHWConfig
from runtools.utils import MacAddress
rootLogger = logging.getLogger()
@ -73,25 +76,21 @@ class FireSimLink:
""" Get the port used for this Link. This should only be called for
links implemented with SocketPorts. """
if self.port is None:
uplink_side = self.get_uplink_side()
self.port = uplink_side.get_host_instance().allocate_host_port()
self.port = self.get_uplink_side().get_host_instance().allocate_host_port()
return self.port
def link_hostserver_ip(self) -> str:
""" Get the IP address used for this Link. This should only be called for
links implemented with SocketPorts. """
uplink_side = self.get_uplink_side()
return uplink_side.get_host_instance().get_private_ip()
return self.get_uplink_side().get_host_instance().get_private_ip()
def link_crosses_hosts(self) -> bool:
""" Return True if the user has mapped the two endpoints of this link to
separate hosts. This implies a SocketServerPort / SocketClientPort will be used
to implement the Link. If False, use a sharedmem port to implement the link. """
if type(self.get_downlink_side()) == FireSimDummyServerNode:
if isinstance(self.get_downlink_side(), FireSimDummyServerNode):
return False
uplink_side = self.get_uplink_side()
downlink_side = self.get_downlink_side()
return uplink_side.get_host_instance() != downlink_side.get_host_instance()
return self.get_uplink_side().get_host_instance() != self.get_downlink_side().get_host_instance()
def get_global_link_id(self) -> str:
""" Return the globally unique link id, used for naming shmem ports. """
@ -224,6 +223,10 @@ class FireSimServerNode(FireSimNode):
def get_server_hardware_config(self) -> Optional[Union[RuntimeHWConfig, str]]:
return self.server_hardware_config
def get_resolved_server_hardware_config(self) -> RuntimeHWConfig:
assert self.server_hardware_config is not None and isinstance(self.server_hardware_config, RuntimeHWConfig)
return self.server_hardware_config
def assign_mac_address(self, macaddr: MacAddress) -> None:
self.mac_address = macaddr
@ -244,9 +247,7 @@ class FireSimServerNode(FireSimNode):
result_list = []
for rootfsname in rootfses_list:
if rootfsname is not None and rootfsname.endswith(".qcow2"):
host_inst = self.get_host_instance()
assert isinstance(host_inst, EC2Inst)
allocd_device = host_inst.nbd_tracker.get_nbd_for_imagename(rootfsname)
allocd_device = self.get_host_instance().nbd_tracker.get_nbd_for_imagename(rootfsname)
# connect the /dev/nbdX device to the rootfs
run("""sudo qemu-nbd -c {devname} {rootfs}""".format(devname=allocd_device, rootfs=rootfsname))
@ -259,10 +260,8 @@ class FireSimServerNode(FireSimNode):
"""
rootfses_list = [self.get_rootfs_name()]
for rootfsname in rootfses_list:
if rootfsname and rootfsname.endswith(".qcow2"):
host_inst = self.get_host_instance()
assert isinstance(host_inst, EC2Inst)
allocd_device = host_inst.nbd_tracker.get_nbd_for_imagename(rootfsname)
if rootfsname is not None and rootfsname.endswith(".qcow2"):
allocd_device = self.get_host_instance().nbd_tracker.get_nbd_for_imagename(rootfsname)
def diagramstr(self) -> str:
@ -288,13 +287,12 @@ class FireSimServerNode(FireSimNode):
all_bootbins = [self.get_bootbin_name()]
all_shmemportnames = [shmemportname]
assert self.server_hardware_config is not None and isinstance(self.server_hardware_config, RuntimeHWConfig)
assert (self.server_profile_interval is not None and all_bootbins is not None and self.trace_enable is not None and
self.trace_select is not None and self.trace_start is not None and self.trace_end is not None and self.trace_output_format is not None and
self.autocounter_readrate is not None and all_shmemportnames is not None and self.zerooutdram is not None and self.disable_asserts is not None and
self.print_start is not None and self.print_end is not None and self.print_cycle_prefix is not None)
runcommand = self.server_hardware_config.get_boot_simulation_command(
runcommand = self.get_resolved_server_hardware_config().get_boot_simulation_command(
slotno, all_macs, all_rootfses, all_linklatencies, all_maxbws,
self.server_profile_interval, all_bootbins, self.trace_enable,
self.trace_select, self.trace_start, self.trace_end, self.trace_output_format,
@ -452,6 +450,9 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
call out to dummy server nodes to get all the info to launch the one
command line to run the FPGA sim that has N > 1 sims on one fpga."""
def __init__(self) -> None:
super().__init__()
def copy_back_job_results_from_run(self, slotno: int) -> None:
""" This override is to call copy back job results for all the dummy nodes too. """
# first call the original
@ -475,17 +476,10 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
"""
num_siblings = self.supernode_get_num_siblings_plus_one()
assert self.get_rootfs_name() is not None
rootfses_list = [self.get_rootfs_name()]
for x in range(1, num_siblings):
sibling = self.supernode_get_sibling(x)
rootfses_list.append(sibling.get_rootfs_name())
rootfses_list = [self.get_rootfs_name()] + [self.supernode_get_sibling(x).get_rootfs_name() for x in range(1, num_siblings)]
for rootfsname in rootfses_list:
assert rootfsname is not None
if rootfsname.endswith(".qcow2"):
if rootfsname is not None and rootfsname.endswith(".qcow2"):
allocd_device = self.get_host_instance().nbd_tracker.get_nbd_for_imagename(rootfsname)
@ -496,8 +490,7 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
"""
siblings = 1
count = False
uplink_side = self.uplinks[0].get_uplink_side()
for index, servernode in enumerate(map(lambda x : x.get_downlink_side(), uplink_side.downlinks)):
for index, servernode in enumerate(map(lambda x : x.get_downlink_side(), self.uplinks[0].get_uplink_side().downlinks)):
if count:
if isinstance(servernode, FireSimDummyServerNode):
siblings += 1
@ -510,10 +503,9 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
def supernode_get_sibling(self, siblingindex: int) -> FireSimDummyServerNode:
""" return the sibling for supernode mode.
siblingindex = 1 -> next sibling, 2 = second, 3 = last one."""
uplink_side = self.uplinks[0].get_uplink_side()
for index, servernode in enumerate(map(lambda x : x.get_downlink_side(), uplink_side.downlinks)):
for index, servernode in enumerate(map(lambda x : x.get_downlink_side(), self.uplinks[0].get_uplink_side().downlinks)):
if self == servernode:
node = uplink_side.downlinks[index+siblingindex].get_downlink_side()
node = self.uplinks[0].get_uplink_side().downlinks[index+siblingindex].get_downlink_side()
assert isinstance(node, FireSimDummyServerNode)
return node
assert False, "Should return supernode sibling"
@ -524,38 +516,22 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
num_siblings = self.supernode_get_num_siblings_plus_one()
all_macs = [self.get_mac_address()]
all_rootfses = [self.get_rootfs_name()]
all_bootbins = [self.get_bootbin_name()]
all_linklatencies = [self.server_link_latency]
all_maxbws = [self.server_bw_max]
for x in range(1, num_siblings):
sibling = self.supernode_get_sibling(x)
all_macs.append(sibling.get_mac_address())
all_rootfses.append(sibling.get_rootfs_name())
all_bootbins.append(sibling.get_bootbin_name())
all_linklatencies.append(sibling.server_link_latency)
all_maxbws.append(sibling.server_bw_max)
all_rootfses = self.process_qcow2_rootfses(all_rootfses)
all_macs = [self.get_mac_address()] + [self.supernode_get_sibling(x).get_mac_address() for x in range(1, num_siblings)]
all_rootfses = self.process_qcow2_rootfses([self.get_rootfs_name()] + [self.supernode_get_sibling(x).get_rootfs_name() for x in range(1, num_siblings)])
all_bootbins = [self.get_bootbin_name()] + [self.supernode_get_sibling(x).get_bootbin_name() for x in range(1, num_siblings)]
all_linklatencies = [self.server_link_latency] + [self.supernode_get_sibling(x).server_link_latency for x in range(1, num_siblings)]
all_maxbws = [self.server_bw_max] + [self.supernode_get_sibling(x).server_bw_max for x in range(1, num_siblings)]
all_shmemportnames = ["default" for x in range(num_siblings)]
if self.uplinks:
all_shmemportnames = [self.uplinks[0].get_global_link_id()]
for x in range(1, num_siblings):
sibling = self.supernode_get_sibling(x)
all_shmemportnames = [self.uplinks[0].get_global_link_id()] + [self.supernode_get_sibling(x).uplinks[0].get_global_link_id() for x in range(1, num_siblings)]
all_shmemportnames.append(sibling.uplinks[0].get_global_link_id())
assert self.server_hardware_config is not None and isinstance(self.server_hardware_config, RuntimeHWConfig)
assert (self.server_profile_interval is not None and all_bootbins is not None and self.trace_enable is not None and
self.trace_select is not None and self.trace_start is not None and self.trace_end is not None and self.trace_output_format is not None and
self.autocounter_readrate is not None and all_shmemportnames is not None and self.zerooutdram is not None and self.disable_asserts is not None and
self.print_start is not None and self.print_end is not None and self.print_cycle_prefix is not None)
runcommand = self.server_hardware_config.get_boot_simulation_command(
runcommand = self.get_resolved_server_hardware_config().get_boot_simulation_command(
slotno, all_macs, all_rootfses, all_linklatencies, all_maxbws,
self.server_profile_interval, all_bootbins, self.trace_enable,
self.trace_select, self.trace_start, self.trace_end, self.trace_output_format,
@ -573,7 +549,7 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
def local_and_remote(filepath, index):
return [filepath, get_path_trailing(filepath) + str(index)]
assert self.server_hardware_config is not None and isinstance(self.server_hardware_config, RuntimeHWConfig)
hw_cfg = self.get_resolved_server_hardware_config()
all_paths = []
job_rootfs_path = self.get_job().rootfs_path()
@ -582,7 +558,7 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
assert self_rootfs_name is not None
all_paths.append((job_rootfs_path, self_rootfs_name))
driver_path = self.server_hardware_config.get_local_driver_path()
driver_path = hw_cfg.get_local_driver_path()
all_paths.append((driver_path, ''))
# shared libraries
@ -605,12 +581,12 @@ class FireSimSuperNodeServerNode(FireSimServerNode):
all_paths.append((self.get_job().bootbinary_path(),
self.get_bootbin_name()))
all_paths.append((self.server_hardware_config.get_local_runtime_conf_path(), ''))
all_paths.append((hw_cfg.get_local_runtime_conf_path(), ''))
return all_paths
class FireSimDummyServerNode(FireSimServerNode):
""" This is a dummy server node for supernode mode. """
def __init__(self, server_hardware_config: Optional[RuntimeHWConfig] = None, server_link_latency: Optional[int] = None,
def __init__(self, server_hardware_config: Optional[Union[RuntimeHWConfig, str]] = None, server_link_latency: Optional[int] = None,
server_bw_max: Optional[int] = None):
super().__init__(server_hardware_config, server_link_latency, server_bw_max)

View File

@ -1,23 +1,27 @@
""" This constructs a topology and performs a series of passes on it. """
from __future__ import annotations
import time
import os
import pprint
import logging
import datetime
from fabric.api import env, parallel, execute # type: ignore
from fabric.api import env, parallel, execute, run, local, warn_only # type: ignore
from colorama import Fore, Style # type: ignore
import types
from functools import reduce
from runtools.switch_model_config import *
from runtools.firesim_topology_core import *
from runtools.firesim_topology_elements import FireSimServerNode, FireSimDummyServerNode, FireSimSwitchNode
from runtools.firesim_topology_core import FireSimTopology
from runtools.utils import MacAddress
from runtools.run_farm import RunFarm
from runtools.runtime_config import RuntimeHWDB
from util.streamlogger import StreamLogger
from typing import Dict, Any, cast
from typing import Dict, Any, cast, List, TYPE_CHECKING
if TYPE_CHECKING:
from runtools.run_farm import RunFarm
from runtools.runtime_config import RuntimeHWDB
from runtools.workload import WorkloadConfig
rootLogger = logging.getLogger()
@ -135,9 +139,7 @@ class FireSimTopologyWithPasses:
else:
childdownlinkmacs: List[List[MacAddress]] = []
for x in node.downlinks:
downlink_side = x.get_downlink_side()
if downlink_side is not None:
childdownlinkmacs.append(downlink_side.downlinkmacs)
childdownlinkmacs.append(x.get_downlink_side().downlinkmacs)
# flatten
node.downlinkmacs = reduce(lambda x, y: x + y, childdownlinkmacs)
@ -150,9 +152,7 @@ class FireSimTopologyWithPasses:
# prepopulate the table with the last port, which will be
switchtab = [uplinkportno for x in range(MacAddress.next_mac_to_allocate())]
for port_no in range(len(switch.downlinks)):
downlink_side = switch.downlinks[port_no].get_downlink_side()
assert downlink_side is not None
portmacs = downlink_side.downlinkmacs
portmacs = switch.downlinks[port_no].get_downlink_side().downlinkmacs
for mac in portmacs:
switchtab[mac.as_int_no_prefix()] = port_no
@ -320,9 +320,10 @@ class FireSimTopologyWithPasses:
defaulthwconfig_obj = self.hwdb.get_runtimehwconfig_from_name(self.defaulthwconfig)
hw_cfg = defaulthwconfig_obj
else:
if not isinstance(hw_cfg, RuntimeHWConfig):
# 1)
if isinstance(hw_cfg, str):
# 1) str
hw_cfg = self.hwdb.get_runtimehwconfig_from_name(hw_cfg)
# 1) hwcfg
# 3)
hw_cfg.get_deploytriplet_for_config()
server.set_server_hardware_config(hw_cfg)
@ -408,9 +409,7 @@ class FireSimTopologyWithPasses:
servers = self.firesimtopol.get_dfs_order_servers()
for server in servers:
hw_cfg = server.get_server_hardware_config()
assert hw_cfg is not None and isinstance(hw_cfg, RuntimeHWConfig)
hw_cfg.build_fpga_driver()
server.get_resolved_server_hardware_config().build_fpga_driver()
def pass_build_required_switches(self) -> None:
""" Build all the switches required for this simulation. """

View File

@ -1,19 +1,22 @@
""" Run Farm management. """
from __future__ import annotations
import re
import logging
import time
from datetime import timedelta
from fabric.api import run, env, prefix, put, cd, warn_only # type: ignore
from fabric.api import run, env, prefix, put, cd, warn_only, local, settings, hide # type: ignore
from fabric.contrib.project import rsync_project # type: ignore
from os.path import join as pjoin
from runtools.firesim_topology_elements import FireSimSwitchNode, FireSimServerNode
from awstools.awstools import *
from awstools.awstools import instances_sorted_by_avail_ip, get_run_instances_by_tag_type, get_private_ips_for_instances, launch_run_instances, wait_on_instance_launches, terminate_instances, get_instance_ids_for_instances
from util.streamlogger import StreamLogger
from typing import Dict, Optional, List, Union
from mypy_boto3_ec2.service_resource import Instance as EC2InstanceResource
from typing import Dict, Optional, List, Union, TYPE_CHECKING
if TYPE_CHECKING:
from mypy_boto3_ec2.service_resource import Instance as EC2InstanceResource
from runtools.firesim_topology_elements import FireSimSwitchNode, FireSimServerNode
rootLogger = logging.getLogger()
@ -75,7 +78,6 @@ class EC2Inst:
SWITCH_SLOTS: int = 100000
boto3_instance_object: Optional[Union[EC2InstanceResource, MockBoto3Instance]]
switch_slots: List[FireSimSwitchNode]
switch_slots_consumed: int
instance_deploy_manager: InstanceDeployManager
_next_port: int
nbd_tracker: NBDTracker
@ -83,7 +85,6 @@ class EC2Inst:
def __init__(self) -> None:
self.boto3_instance_object = None
self.switch_slots = []
self.switch_slots_consumed = 0
self.instance_deploy_manager = InstanceDeployManager(self)
self._next_port = 10000 # track ports to allocate for server switch model ports
self.nbd_tracker = NBDTracker()
@ -100,15 +101,10 @@ class EC2Inst:
def add_switch(self, firesimswitchnode: FireSimSwitchNode) -> None:
""" Add a switch to the next available switch slot. """
assert self.switch_slots_consumed < self.SWITCH_SLOTS
assert len(self.switch_slots) < self.SWITCH_SLOTS
self.switch_slots.append(firesimswitchnode)
self.switch_slots_consumed += 1
assert len(self.switch_slots) == self.switch_slots_consumed
firesimswitchnode.assign_host_instance(self)
def get_num_switch_slots_consumed(self) -> int:
return self.switch_slots_consumed
def allocate_host_port(self) -> int:
""" Allocate a port to use for something on the host. Successive calls
will return a new port. """
@ -120,27 +116,19 @@ class EC2Inst:
class F1_Instance(EC2Inst):
FPGA_SLOTS: int = 0
fpga_slots: List[FireSimServerNode]
fpga_slots_consumed: int
def __init__(self) -> None:
super().__init__()
self.fpga_slots = []
self.fpga_slots_consumed = 0
def get_num_fpga_slots_max(self) -> int:
""" Get the number of fpga slots. """
return self.FPGA_SLOTS
def get_num_fpga_slots_consumed(self) -> int:
""" Get the number of fpga slots. """
return self.fpga_slots_consumed
def add_simulation(self, firesimservernode: FireSimServerNode) -> None:
""" Add a simulation to the next available slot. """
assert self.fpga_slots_consumed < self.FPGA_SLOTS
assert len(self.fpga_slots) < self.FPGA_SLOTS
self.fpga_slots.append(firesimservernode)
self.fpga_slots_consumed += 1
assert len(self.fpga_slots) == self.fpga_slots_consumed
firesimservernode.assign_host_instance(self)
class F1_16(F1_Instance):
@ -536,7 +524,7 @@ class InstanceDeployManager:
def flash_fpgas(self) -> None:
dummyagfi = None
assert isinstance(self.parentnode, F1_Instance)
for firesimservernode, slotno in zip(self.parentnode.fpga_slots, range(self.parentnode.get_num_fpga_slots_consumed())):
for slotno, firesimservernode in enumerate(self.parentnode.fpga_slots):
agfi = firesimservernode.get_agfi()
dummyagfi = agfi
self.instance_logger("""Flashing FPGA Slot: {} with agfi: {}.""".format(slotno, agfi))
@ -550,18 +538,18 @@ class InstanceDeployManager:
# anyway. Since the only interaction we have with an FPGA right now
# is over PCIe where the software component is mastering, this can't
# break anything.
for slotno in range(self.parentnode.get_num_fpga_slots_consumed(), self.parentnode.get_num_fpga_slots_max()):
for slotno in range(len(self.parentnode.fpga_slots), self.parentnode.get_num_fpga_slots_max()):
self.instance_logger("""Flashing FPGA Slot: {} with dummy agfi: {}.""".format(slotno, dummyagfi))
with StreamLogger('stdout'), StreamLogger('stderr'):
run("""sudo fpga-load-local-image -S {} -I {} -A""".format(
slotno, dummyagfi))
for firesimservernode, slotno in zip(self.parentnode.fpga_slots, range(self.parentnode.get_num_fpga_slots_consumed())):
for slotno, firesimservernode in enumerate(self.parentnode.fpga_slots):
self.instance_logger("""Checking for Flashed FPGA Slot: {} with agfi: {}.""".format(slotno, agfi))
with StreamLogger('stdout'), StreamLogger('stderr'):
run("""until sudo fpga-describe-local-image -S {} -R -H | grep -q "loaded"; do sleep 1; done""".format(slotno))
for slotno in range(self.parentnode.get_num_fpga_slots_consumed(), self.parentnode.get_num_fpga_slots_max()):
for slotno in range(len(self.parentnode.fpga_slots), self.parentnode.get_num_fpga_slots_max()):
self.instance_logger("""Checking for Flashed FPGA Slot: {} with agfi: {}.""".format(slotno, dummyagfi))
with StreamLogger('stdout'), StreamLogger('stderr'):
run("""until sudo fpga-describe-local-image -S {} -R -H | grep -q "loaded"; do sleep 1; done""".format(slotno))
@ -695,7 +683,7 @@ class InstanceDeployManager:
assert isinstance(self.parentnode, F1_Instance)
# copy fpga sim infrastructure
for slotno in range(self.parentnode.get_num_fpga_slots_consumed()):
for slotno in range(len(self.parentnode.fpga_slots)):
self.copy_sim_slot_infrastructure(slotno)
self.get_and_install_aws_fpga_sdk()
@ -724,7 +712,7 @@ class InstanceDeployManager:
if self.instance_assigned_switches():
# all nodes could have a switch
for slotno in range(self.parentnode.get_num_switch_slots_consumed()):
for slotno in range(len(self.parentnode.switch_slots)):
self.copy_switch_slot_infrastructure(slotno)
@ -735,7 +723,7 @@ class InstanceDeployManager:
with StreamLogger('stdout'), StreamLogger('stderr'):
run("sudo rm -rf /dev/shm/*")
for slotno in range(self.parentnode.get_num_switch_slots_consumed()):
for slotno in range(len(self.parentnode.switch_slots)):
self.start_switch_slot(slotno)
def start_simulations_instance(self) -> None:
@ -744,13 +732,13 @@ class InstanceDeployManager:
assert isinstance(self.parentnode, F1_Instance)
# only on sim nodes
for slotno in range(self.parentnode.get_num_fpga_slots_consumed()):
for slotno in range(len(self.parentnode.fpga_slots)):
self.start_sim_slot(slotno)
def kill_switches_instance(self) -> None:
""" Kill all the switches on this instance. """
if self.instance_assigned_switches():
for slotno in range(self.parentnode.get_num_switch_slots_consumed()):
for slotno in range(len(self.parentnode.switch_slots)):
self.kill_switch_slot(slotno)
with StreamLogger('stdout'), StreamLogger('stderr'):
run("sudo rm -rf /dev/shm/*")
@ -760,7 +748,7 @@ class InstanceDeployManager:
if self.instance_assigned_simulations():
assert isinstance(self.parentnode, F1_Instance)
# only on sim nodes
for slotno in range(self.parentnode.get_num_fpga_slots_consumed()):
for slotno in range(len(self.parentnode.fpga_slots)):
self.kill_sim_slot(slotno)
if disconnect_all_nbds:
# disconnect all NBDs
@ -805,8 +793,7 @@ class InstanceDeployManager:
if teardown:
# handle the case where we're just tearing down nodes that have
# ONLY switches
numswitchesused = self.parentnode.get_num_switch_slots_consumed()
for counter in range(numswitchesused):
for counter in range(len(self.parentnode.switch_slots)):
switchsim = self.parentnode.switch_slots[counter]
switchsim.copy_back_switchlog_from_run(job_results_dir, counter)
@ -822,7 +809,7 @@ class InstanceDeployManager:
# not teardown - just get the status of the switch sims
switchescompleteddict = {k: False for k in self.running_simulations()['switches']}
for switchsim in self.parentnode.switch_slots[:self.parentnode.get_num_switch_slots_consumed()]:
for switchsim in self.parentnode.switch_slots:
swname = switchsim.switch_builder.switch_binary_name()
if swname not in switchescompleteddict.keys():
switchescompleteddict[swname] = True
@ -837,8 +824,7 @@ class InstanceDeployManager:
# ON THE INSTANCE.
parentslots = self.parentnode.fpga_slots
rootLogger.debug("parentslots " + str(parentslots))
num_parentslots_used = self.parentnode.fpga_slots_consumed
jobnames = [slot.get_job_name() for slot in parentslots[0:num_parentslots_used]]
jobnames = [slot.get_job_name() for slot in parentslots]
rootLogger.debug("jobnames " + str(jobnames))
already_done = all([job in completed_jobs for job in jobnames])
rootLogger.debug("already done? " + str(already_done))
@ -855,7 +841,7 @@ class InstanceDeployManager:
if self.instance_assigned_switches():
# fill in whether switches have terminated for some reason
for switchsim in self.parentnode.switch_slots[:self.parentnode.get_num_switch_slots_consumed()]:
for switchsim in self.parentnode.switch_slots:
swname = switchsim.switch_builder.switch_binary_name()
if swname not in switchescompleteddict.keys():
switchescompleteddict[swname] = True
@ -868,6 +854,7 @@ class InstanceDeployManager:
if str(slotno) not in slotsrunning and jobname not in completed_jobs:
self.instance_logger("Slot " + str(slotno) + " completed! copying results.")
# NOW, we must copy off the results of this sim, since it just exited
assert slotno < len(parentslots)
parentslots[slotno].copy_back_job_results_from_run(slotno)
# add our job to our copy of completed_jobs, so that next,
# we can test again to see if this instance is "done" and
@ -894,7 +881,7 @@ class InstanceDeployManager:
self.kill_switches_instance()
for counter, switchsim in enumerate(self.parentnode.switch_slots[:self.parentnode.get_num_switch_slots_consumed()]):
for counter, switchsim in enumerate(self.parentnode.switch_slots):
switchsim.copy_back_switchlog_from_run(job_results_dir, counter)
if now_done and terminateoncompletion:

View File

@ -1,9 +1,8 @@
""" This file manages the overall configuration of the system for running
simulation tasks. """
from __future__ import print_function
from __future__ import print_function, annotations
import argparse
from datetime import timedelta
from time import strftime, gmtime
import pprint
@ -11,17 +10,19 @@ import logging
import yaml
import os
import sys
from fabric.api import prefix # type: ignore
from fabric.api import prefix, settings, local # type: ignore
from awstools.awstools import *
from awstools.afitools import *
from awstools.awstools import aws_resource_names
from awstools.afitools import get_firesim_tagval_for_agfi
from runtools.firesim_topology_with_passes import FireSimTopologyWithPasses
from runtools.workload import WorkloadConfig
from runtools.run_farm import RunFarm
from util.streamlogger import StreamLogger
from runtools.utils import MacAddress
from typing import Optional, Dict, Any, List, Sequence
from typing import Optional, Dict, Any, List, Sequence, TYPE_CHECKING
import argparse # this is not within a if TYPE_CHECKING: scope so the `register_task` in FireSim can evaluate it's annotation
if TYPE_CHECKING:
from runtools.utils import MacAddress
LOCAL_DRIVERS_BASE = "../sim/output/f1/"
CUSTOM_RUNTIMECONFS_BASE = "../sim/custom-runtime-configs/"

View File

@ -1,6 +1,8 @@
""" This file contains components that tie closely with the FireSim switch
models that live in target-design/switch/ """
from __future__ import annotations
import subprocess
import random
import string
@ -8,7 +10,9 @@ import logging
from fabric.api import local # type: ignore
from util.streamlogger import StreamLogger
from runtools.firesim_topology_elements import FireSimSwitchNode
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from runtools.firesim_topology_elements import FireSimSwitchNode
rootLogger = logging.getLogger()

View File

@ -1,10 +1,13 @@
""" Define your additional topologies here. The FireSimTopology class inherits
from UserToplogies and thus can instantiate your topology. """
from runtools.firesim_topology_elements import *
from runtools.firesim_topology_with_passes import FireSimTopologyWithPasses
from __future__ import annotations
from typing import Optional, Union, Callable, Sequence
from runtools.firesim_topology_elements import FireSimSwitchNode, FireSimServerNode, FireSimSuperNodeServerNode, FireSimDummyServerNode, FireSimNode
from typing import Optional, Union, Callable, Sequence, TYPE_CHECKING
if TYPE_CHECKING:
from runtools.firesim_topology_with_passes import FireSimTopologyWithPasses
class UserTopologies:
""" A class that just separates out user-defined/configurable topologies

View File

@ -1,5 +1,7 @@
""" Miscellaneous utils used by other buildtools pieces. """
from __future__ import annotations
import lddwrap
import logging
from os import fspath

View File

@ -1,5 +1,7 @@
""" Workload configuration information. """
from __future__ import annotations
import json
import os

View File

@ -1,16 +1,18 @@
"""\
See `StreamLogger`.
"""See `StreamLogger`.
This is taken from https://gist.github.com/pmuller/2376336
which has no license associated with it.
"""
from __future__ import annotations
import sys
import logging
import io
from typing import Any, Optional, Tuple
class StreamLogger(object):
class StreamLogger:
"""
A helper which intercepts what's written to an output stream
then sends it, line by line, to a `logging.Logger` instance.
@ -22,9 +24,15 @@ class StreamLogger(object):
with StreamLogger('stdout'):
print 'foo'
"""
__name: str
__stream: Any
__logger: Optional[logging.Logger]
__buffer: io.StringIO
__unbuffered: bool
__flush_on_new_line: bool
def __init__(self, name, logger=None, unbuffered=False,
flush_on_new_line=True):
def __init__(self, name: str, logger: logging.Logger = None, unbuffered: bool = False,
flush_on_new_line: bool = True) -> None:
"""
``name``: The stream name to incercept ('stdout' or 'stderr')
``logger``: The logger that will receive what's written to the stream.
@ -41,7 +49,7 @@ class StreamLogger(object):
self.__unbuffered = unbuffered
self.__flush_on_new_line = flush_on_new_line
def write(self, data):
def write(self, data: str) -> None:
"""Write data to the stream.
"""
self.__buffer.write(data)
@ -49,7 +57,7 @@ class StreamLogger(object):
(self.__flush_on_new_line is True and '\n' in data):
self.flush()
def flush(self):
def flush(self) -> None:
"""Flush the stream.
"""
self.__buffer.seek(0)
@ -72,22 +80,22 @@ class StreamLogger(object):
self.__buffer.truncate()
break
def parse(self, data):
def parse(self, data: str) -> Tuple[str, str]:
"""Override me!
"""
return 'debug', data
def isatty(self):
def isatty(self) -> bool:
"""I'm not a tty.
"""
return False
def __enter__(self):
def __enter__(self) -> None:
"""Enter the context manager.
"""
setattr(sys, self.__name, self)
def __exit__(self, exc_type, exc_value, traceback):
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
"""Leave the context manager.
"""
setattr(sys, self.__name, self.__stream)
@ -96,5 +104,5 @@ class StreamLogger(object):
class InfoStreamLogger(StreamLogger):
""" StreamLogger, but write to info log instead of debug. """
def parse(self, data):
def parse(self, data: str) -> Tuple[str, str]:
return 'info', data