Merge branch 'dev' into fs-sw-docs
This commit is contained in:
commit
df975d50d3
|
@ -20,9 +20,11 @@ class FireSimTopology(UserTopologies):
|
|||
if nextup in visitedonce:
|
||||
if nextup not in retlist:
|
||||
retlist.append(stack.pop(0))
|
||||
else:
|
||||
stack.pop(0)
|
||||
else:
|
||||
visitedonce.add(nextup)
|
||||
stack = nextup.downlinks + stack
|
||||
stack = list(map(lambda x: x.get_downlink_side(), nextup.downlinks)) + stack
|
||||
return retlist
|
||||
|
||||
def get_dfs_order_switches(self):
|
||||
|
@ -41,6 +43,10 @@ class FireSimTopology(UserTopologies):
|
|||
def __init__(self, user_topology_name, no_net_num_nodes):
|
||||
# This just constructs the user topology. an upper level pass manager
|
||||
# will apply passes to it.
|
||||
|
||||
# a topology can specify a custom target -> host mapping. if left as None,
|
||||
# the default mapper is used, which handles no network and simple networked cases.
|
||||
self.custom_mapper = None
|
||||
self.no_net_num_nodes = no_net_num_nodes
|
||||
configfunc = getattr(self, user_topology_name)
|
||||
configfunc()
|
||||
|
|
|
@ -8,6 +8,77 @@ from fabric.api import *
|
|||
|
||||
rootLogger = logging.getLogger()
|
||||
|
||||
|
||||
class FireSimLink(object):
|
||||
""" This represents a link that connects different FireSimNodes.
|
||||
|
||||
Terms:
|
||||
Naming assumes a tree-ish topology, with roots at the top, leaves at the
|
||||
bottom. So in a topology like:
|
||||
RootSwitch
|
||||
/ \
|
||||
Link A / \ Link B
|
||||
/ \
|
||||
Sim X Sim Y
|
||||
|
||||
"Uplink side" of Link A is RootSwitch.
|
||||
"Downlink side" of Link A is Sim X.
|
||||
Sim X has an uplink connected to RootSwitch.
|
||||
RootSwitch has a downlink to Sim X.
|
||||
|
||||
"""
|
||||
|
||||
# links have a globally unique identifier, currently used for naming
|
||||
# shmem regions for Shmem Links
|
||||
next_unique_link_identifier = 0
|
||||
|
||||
def __init__(self, uplink_side, downlink_side):
|
||||
self.id = FireSimLink.next_unique_link_identifier
|
||||
FireSimLink.next_unique_link_identifier += 1
|
||||
# format as 100 char hex string padded with zeroes
|
||||
self.id_as_str = format(self.id, '0100X')
|
||||
self.uplink_side = None
|
||||
self.downlink_side = None
|
||||
self.port = None
|
||||
self.set_uplink_side(uplink_side)
|
||||
self.set_downlink_side(downlink_side)
|
||||
|
||||
def set_uplink_side(self, fsimnode):
|
||||
self.uplink_side = fsimnode
|
||||
|
||||
def set_downlink_side(self, fsimnode):
|
||||
self.downlink_side = fsimnode
|
||||
|
||||
def get_uplink_side(self):
|
||||
return self.uplink_side
|
||||
|
||||
def get_downlink_side(self):
|
||||
return self.downlink_side
|
||||
|
||||
def link_hostserver_port(self):
|
||||
""" Get the port used for this Link. This should only be called for
|
||||
links implemented with SocketPorts. """
|
||||
if self.port is None:
|
||||
self.port = self.get_uplink_side().host_instance.allocate_host_port()
|
||||
return self.port
|
||||
|
||||
def link_hostserver_ip(self):
|
||||
""" Get the IP address used for this Link. This should only be called for
|
||||
links implemented with SocketPorts. """
|
||||
assert self.get_uplink_side().host_instance.is_bound_to_real_instance(), "Instances must be bound to private IP to emit switches with uplinks. i.e. you must have a running Run Farm."
|
||||
return self.get_uplink_side().host_instance.get_private_ip()
|
||||
|
||||
def link_crosses_hosts(self):
|
||||
""" 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. """
|
||||
return self.get_uplink_side().host_instance != self.get_downlink_side().host_instance
|
||||
|
||||
def get_global_link_id(self):
|
||||
""" Return the globally unique link id, used for naming shmem ports. """
|
||||
return self.id_as_str
|
||||
|
||||
|
||||
class FireSimNode(object):
|
||||
""" This represents a node in the high-level FireSim Simulation Topology
|
||||
Graph. These nodes are either
|
||||
|
@ -28,6 +99,8 @@ class FireSimNode(object):
|
|||
|
||||
def __init__(self):
|
||||
self.downlinks = []
|
||||
# used when there are multiple links between switches to disambiguate
|
||||
#self.downlinks_consumed = []
|
||||
self.uplinks = []
|
||||
self.host_instance = None
|
||||
|
||||
|
@ -35,21 +108,23 @@ class FireSimNode(object):
|
|||
""" A "downlink" is a link that will take you further from the root
|
||||
of the tree. Users define a tree topology by specifying "downlinks".
|
||||
Uplinks are automatically inferred. """
|
||||
firesimnode.add_uplink(self)
|
||||
self.downlinks.append(firesimnode)
|
||||
linkobj = FireSimLink(self, firesimnode)
|
||||
firesimnode.add_uplink(linkobj)
|
||||
self.downlinks.append(linkobj)
|
||||
#self.downlinks_consumed.append(False)
|
||||
|
||||
def add_downlinks(self, firesimnodes):
|
||||
""" Just a convenience function to add multiple downlinks at once.
|
||||
Assumes downlinks in the supplied list are ordered. """
|
||||
[self.add_downlink(node) for node in firesimnodes]
|
||||
|
||||
def add_uplink(self, firesimnode):
|
||||
def add_uplink(self, firesimlink):
|
||||
""" This is only for internal use - uplinks are automatically populated
|
||||
when a node is specified as the downlink of another.
|
||||
|
||||
An "uplink" is a link that takes you towards one of the roots of the
|
||||
tree."""
|
||||
self.uplinks.append(firesimnode)
|
||||
self.uplinks.append(firesimlink)
|
||||
|
||||
def num_links(self):
|
||||
""" Return the total number of nodes. """
|
||||
|
@ -112,10 +187,15 @@ class FireSimServerNode(FireSimNode):
|
|||
""" return the command to start the simulation. assumes it will be
|
||||
called in a directory where its required_files are already located.
|
||||
"""
|
||||
shmemportname = "default"
|
||||
if self.uplinks:
|
||||
shmemportname = self.uplinks[0].get_global_link_id()
|
||||
|
||||
return self.server_hardware_config.get_boot_simulation_command(
|
||||
self.get_mac_address(), self.get_rootfs_name(), slotno,
|
||||
self.server_link_latency, self.server_bw_max, self.get_bootbin_name(),
|
||||
self.trace_enable, self.trace_start, self.trace_end)
|
||||
self.trace_enable, self.trace_start, self.trace_end, shmemportname)
|
||||
|
||||
|
||||
def copy_back_job_results_from_run(self, slotno):
|
||||
"""
|
||||
|
|
|
@ -11,11 +11,10 @@ from firesim_topology_core import *
|
|||
from utils import MacAddress
|
||||
from fabric.api import *
|
||||
from colorama import Fore, Style
|
||||
import types
|
||||
|
||||
from util.streamlogger import StreamLogger
|
||||
|
||||
#BASEPORT = 10000
|
||||
|
||||
rootLogger = logging.getLogger()
|
||||
|
||||
@parallel
|
||||
|
@ -96,7 +95,7 @@ class FireSimTopologyWithPasses:
|
|||
if isinstance(node, FireSimServerNode):
|
||||
node.downlinkmacs = [node.get_mac_address()]
|
||||
else:
|
||||
childdownlinkmacs = [x.downlinkmacs for x in node.downlinks]
|
||||
childdownlinkmacs = [x.get_downlink_side().downlinkmacs for x in node.downlinks]
|
||||
node.downlinkmacs = reduce(lambda x, y: x + y, childdownlinkmacs)
|
||||
|
||||
switches_dfs_order = self.firesimtopol.get_dfs_order_switches()
|
||||
|
@ -107,7 +106,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)):
|
||||
portmacs = switch.downlinks[port_no].downlinkmacs
|
||||
portmacs = switch.downlinks[port_no].get_downlink_side().downlinkmacs
|
||||
for mac in portmacs:
|
||||
switchtab[mac.as_int_no_prefix()] = port_no
|
||||
|
||||
|
@ -136,6 +135,7 @@ class FireSimTopologyWithPasses:
|
|||
switches_dfs_order = self.firesimtopol.get_dfs_order_switches()
|
||||
for node in switches_dfs_order:
|
||||
for downlink in node.downlinks:
|
||||
downlink = downlink.get_downlink_side()
|
||||
gviz_graph.edge(str(node), str(downlink))
|
||||
|
||||
gviz_graph.render(view=False)
|
||||
|
@ -169,24 +169,41 @@ class FireSimTopologyWithPasses:
|
|||
m4_16s_used = 0
|
||||
|
||||
for switch in switches:
|
||||
if all([isinstance(x, FireSimSwitchNode) for x in switch.downlinks]):
|
||||
downlinknodes = map(lambda x: x.get_downlink_side(), switch.downlinks)
|
||||
if all([isinstance(x, FireSimSwitchNode) for x in downlinknodes]):
|
||||
# all downlinks are switches
|
||||
self.run_farm.m4_16s[m4_16s_used].add_switch(switch)
|
||||
m4_16s_used += 1
|
||||
elif all([isinstance(x, FireSimServerNode) for x in switch.downlinks]):
|
||||
elif all([isinstance(x, FireSimServerNode) for x in downlinknodes]):
|
||||
# all downlinks are simulations
|
||||
if (len(switch.downlinks) == 1) and (f1_2s_used < len(self.run_farm.f1_2s)):
|
||||
self.run_farm.f1_2s[f1_2s_used].add_switch(switch)
|
||||
self.run_farm.f1_2s[f1_2s_used].add_simulation(switch.downlinks[0])
|
||||
self.run_farm.f1_2s[f1_2s_used].add_simulation(downlinknodes[0])
|
||||
f1_2s_used += 1
|
||||
else:
|
||||
self.run_farm.f1_16s[f1_16s_used].add_switch(switch)
|
||||
for server in switch.downlinks:
|
||||
for server in downlinknodes:
|
||||
self.run_farm.f1_16s[f1_16s_used].add_simulation(server)
|
||||
f1_16s_used += 1
|
||||
else:
|
||||
assert False, "Mixed downlinks currently not supported."""
|
||||
|
||||
def mapping_use_one_f1_16xlarge(self):
|
||||
""" Just put everything on one f1.16xlarge """
|
||||
switches = self.firesimtopol.get_dfs_order_switches()
|
||||
f1_2s_used = 0
|
||||
f1_16s_used = 0
|
||||
m4_16s_used = 0
|
||||
|
||||
for switch in switches:
|
||||
self.run_farm.f1_16s[f1_16s_used].add_switch(switch)
|
||||
downlinknodes = map(lambda x: x.get_downlink_side(), switch.downlinks)
|
||||
if all([isinstance(x, FireSimServerNode) for x in downlinknodes]):
|
||||
for server in downlinknodes:
|
||||
self.run_farm.f1_16s[f1_16s_used].add_simulation(server)
|
||||
elif any([isinstance(x, FireSimServerNode) for x in downlinknodes]):
|
||||
assert False, "MIXED DOWNLINKS NOT SUPPORTED."
|
||||
f1_16s_used += 1
|
||||
|
||||
def pass_perform_host_node_mapping(self):
|
||||
""" This pass assigns host nodes to nodes in the abstract FireSim
|
||||
|
@ -197,18 +214,30 @@ class FireSimTopologyWithPasses:
|
|||
top level elements are switches, it will assume you're simulating a
|
||||
networked config, """
|
||||
|
||||
# if your roots are servers, just pack as tightly as possible, since
|
||||
# you have no_net_config
|
||||
if all([isinstance(x, FireSimServerNode) for x in self.firesimtopol.roots]):
|
||||
# all roots are servers, so we're in no_net_config
|
||||
# if the user has specified any 16xlarges, we assign to them first
|
||||
self.pass_no_net_host_mapping()
|
||||
return
|
||||
|
||||
# now, we're handling the cycle-accurate networked simulation case
|
||||
# currently, we only handle the case where
|
||||
self.pass_simple_networked_host_node_mapping()
|
||||
|
||||
if self.firesimtopol.custom_mapper is None:
|
||||
""" Use default mapping strategy. The topol has not specified a
|
||||
special one. """
|
||||
# if your roots are servers, just pack as tightly as possible, since
|
||||
# you have no_net_config
|
||||
if all([isinstance(x, FireSimServerNode) for x in self.firesimtopol.roots]):
|
||||
# all roots are servers, so we're in no_net_config
|
||||
# if the user has specified any 16xlarges, we assign to them first
|
||||
self.pass_no_net_host_mapping()
|
||||
return
|
||||
else:
|
||||
# now, we're handling the cycle-accurate networked simulation case
|
||||
# currently, we only handle the case where
|
||||
self.pass_simple_networked_host_node_mapping()
|
||||
elif type(self.firesimtopol.custom_mapper) == types.FunctionType:
|
||||
""" call the mapper fn defined in the topology itself. """
|
||||
self.firesimtopol.custom_mapper(self)
|
||||
elif type(self.firesimtopol.custom_mapper) == str:
|
||||
""" assume that the mapping strategy is a custom pre-defined strategy
|
||||
given in this class, supplied as a string in the topology """
|
||||
mapperfunc = getattr(self, self.firesimtopol.custom_mapper)
|
||||
mapperfunc()
|
||||
else:
|
||||
assert False, "IMPROPER MAPPING CONFIGURATION"
|
||||
|
||||
def pass_apply_default_hwconfig(self):
|
||||
""" This is the default mapping pass for hardware configurations - it
|
||||
|
@ -270,7 +299,7 @@ class FireSimTopologyWithPasses:
|
|||
automatically when creating this object. """
|
||||
self.pass_assign_mac_addresses()
|
||||
self.pass_compute_switching_tables()
|
||||
self.pass_perform_host_node_mapping()
|
||||
self.pass_perform_host_node_mapping() # TODO: we can know ports here?
|
||||
self.pass_apply_default_hwconfig()
|
||||
self.pass_apply_default_network_params()
|
||||
self.pass_assign_jobs()
|
||||
|
|
|
@ -22,15 +22,17 @@ class MockBoto3Instance:
|
|||
self.private_ip_address = ".".join([str((self.ip_addr_int >> (8*x)) & 0xFF) for x in [3, 2, 1, 0]])
|
||||
|
||||
class EC2Inst(object):
|
||||
# for now, we require that only one switch is mapped to each host
|
||||
# this could be overridden based on instance type later
|
||||
SWITCH_SLOTS = 1
|
||||
# TODO: this is leftover from when we could only support switch slots.
|
||||
# This can be removed once self.switch_slots is dynamically allocated.
|
||||
# Just make it arbitrarily large for now.
|
||||
SWITCH_SLOTS = 100000
|
||||
|
||||
def __init__(self):
|
||||
self.boto3_instance_object = None
|
||||
self.switch_slots = [None for x in range(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
|
||||
|
||||
def assign_boto3_instance_object(self, boto3obj):
|
||||
self.boto3_instance_object = boto3obj
|
||||
|
@ -48,8 +50,16 @@ class EC2Inst(object):
|
|||
firesimswitchnode.assign_host_instance(self)
|
||||
self.switch_slots_consumed += 1
|
||||
|
||||
def get_num_switch_slots(self):
|
||||
return self.SWITCH_SLOTS
|
||||
def get_num_switch_slots_consumed(self):
|
||||
return self.switch_slots_consumed
|
||||
|
||||
def allocate_host_port(self):
|
||||
""" Allocate a port to use for something on the host. Successive calls
|
||||
will return a new port. """
|
||||
retport = self._next_port
|
||||
assert retport < 11000, "Exceeded number of ports used on host. You will need to modify your security groups to increase this value."
|
||||
self._next_port += 1
|
||||
return retport
|
||||
|
||||
class F1_Instance(EC2Inst):
|
||||
FPGA_SLOTS = 0
|
||||
|
@ -327,7 +337,11 @@ class InstanceDeployManager:
|
|||
for slotno in range(self.parentnode.get_num_fpga_slots_max()):
|
||||
self.instance_logger("""Clearing FPGA Slot {}.""".format(slotno))
|
||||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run("""sudo fpga-clear-local-image -S {}""".format(slotno))
|
||||
run("""sudo fpga-clear-local-image -S {} -A""".format(slotno))
|
||||
for slotno in range(self.parentnode.get_num_fpga_slots_max()):
|
||||
self.instance_logger("""Checking for Cleared FPGA Slot {}.""".format(slotno))
|
||||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run("""until sudo fpga-describe-local-image -S {} -R -H | grep -q "cleared"; do sleep 1; done""".format(slotno))
|
||||
|
||||
def flash_fpgas(self):
|
||||
for firesimservernode, slotno in zip(self.parentnode.fpga_slots, range(self.parentnode.get_num_fpga_slots_consumed())):
|
||||
|
@ -335,8 +349,13 @@ class InstanceDeployManager:
|
|||
agfi = firesimservernode.get_agfi()
|
||||
self.instance_logger("""Flashing FPGA Slot: {} with agfi: {}.""".format(slotno, agfi))
|
||||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run("""sudo fpga-load-local-image -S {} -I {}""".format(
|
||||
run("""sudo fpga-load-local-image -S {} -I {} -A""".format(
|
||||
slotno, agfi))
|
||||
for firesimservernode, slotno in zip(self.parentnode.fpga_slots, range(self.parentnode.get_num_fpga_slots_consumed())):
|
||||
if firesimservernode is not None:
|
||||
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))
|
||||
|
||||
def load_edma(self):
|
||||
""" load the edma kernel module. """
|
||||
|
@ -378,6 +397,7 @@ class InstanceDeployManager:
|
|||
files_to_copy = serv.get_required_files_local_paths()
|
||||
for filename in files_to_copy:
|
||||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
# -z --inplace
|
||||
rsync_cap = rsync_project(local_dir=filename, remote_dir=remote_sim_rsync_dir,
|
||||
ssh_opts="-o StrictHostKeyChecking=no", extra_opts="-L", capture=True)
|
||||
rootLogger.debug(rsync_cap)
|
||||
|
@ -469,7 +489,7 @@ class InstanceDeployManager:
|
|||
|
||||
if self.instance_assigned_switches():
|
||||
# all nodes could have a switch
|
||||
for slotno in range(self.parentnode.get_num_switch_slots()):
|
||||
for slotno in range(self.parentnode.get_num_switch_slots_consumed()):
|
||||
self.copy_switch_slot_infrastructure(slotno)
|
||||
|
||||
|
||||
|
@ -480,7 +500,7 @@ class InstanceDeployManager:
|
|||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run("sudo rm -rf /dev/shm/*")
|
||||
|
||||
for slotno in range(self.parentnode.get_num_switch_slots()):
|
||||
for slotno in range(self.parentnode.get_num_switch_slots_consumed()):
|
||||
self.start_switch_slot(slotno)
|
||||
|
||||
def start_simulations_instance(self):
|
||||
|
@ -493,7 +513,7 @@ class InstanceDeployManager:
|
|||
def kill_switches_instance(self):
|
||||
""" Kill all the switches on this instance. """
|
||||
if self.instance_assigned_switches():
|
||||
for slotno in range(self.parentnode.get_num_switch_slots()):
|
||||
for slotno in range(self.parentnode.get_num_switch_slots_consumed()):
|
||||
self.kill_switch_slot(slotno)
|
||||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run("sudo rm -rf /dev/shm/*")
|
||||
|
@ -541,7 +561,9 @@ class InstanceDeployManager:
|
|||
if teardown:
|
||||
# handle the case where we're just tearing down nodes that have
|
||||
# ONLY switches
|
||||
for counter, switchsim in enumerate(self.parentnode.switch_slots):
|
||||
numswitchesused = self.parentnode.get_num_switch_slots_consumed()
|
||||
for counter in range(numswitchesused):
|
||||
switchsim = self.parentnode.switch_slots[counter]
|
||||
switchsim.copy_back_switchlog_from_run(job_results_dir, counter)
|
||||
|
||||
if terminateoncompletion:
|
||||
|
@ -555,7 +577,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:
|
||||
for switchsim in self.parentnode.switch_slots[:self.parentnode.get_num_switch_slots_consumed()]:
|
||||
swname = switchsim.switch_builder.switch_binary_name()
|
||||
if swname not in switchescompleteddict.keys():
|
||||
switchescompleteddict[swname] = True
|
||||
|
@ -587,7 +609,7 @@ class InstanceDeployManager:
|
|||
|
||||
if self.instance_assigned_switches():
|
||||
# fill in whether switches have terminated for some reason
|
||||
for switchsim in self.parentnode.switch_slots:
|
||||
for switchsim in self.parentnode.switch_slots[:self.parentnode.get_num_switch_slots_consumed()]:
|
||||
swname = switchsim.switch_builder.switch_binary_name()
|
||||
if swname not in switchescompleteddict.keys():
|
||||
switchescompleteddict[swname] = True
|
||||
|
@ -626,7 +648,7 @@ class InstanceDeployManager:
|
|||
|
||||
self.kill_switches_instance()
|
||||
|
||||
for counter, switchsim in enumerate(self.parentnode.switch_slots):
|
||||
for counter, switchsim in enumerate(self.parentnode.switch_slots[:self.parentnode.get_num_switch_slots_consumed()]):
|
||||
switchsim.copy_back_switchlog_from_run(job_results_dir, counter)
|
||||
|
||||
if now_done and terminateoncompletion:
|
||||
|
|
|
@ -76,7 +76,7 @@ class RuntimeHWConfig:
|
|||
|
||||
def get_boot_simulation_command(self, macaddr, blkdev, slotid,
|
||||
linklatency, netbw, bootbin,
|
||||
trace_enable, trace_start, trace_end):
|
||||
trace_enable, trace_start, trace_end, shmemportname):
|
||||
""" return the command used to boot the simulation. this has to have
|
||||
some external params passed to it, because not everything is contained
|
||||
in a runtimehwconfig. TODO: maybe runtimehwconfig should be renamed to
|
||||
|
@ -89,10 +89,10 @@ class RuntimeHWConfig:
|
|||
# the sed is in there to get rid of newlines in runtime confs
|
||||
driver = self.get_local_driver_binaryname()
|
||||
runtimeconf = self.get_local_runtimeconf_binaryname()
|
||||
basecommand = """screen -S fsim{slotid} -d -m bash -c "script -f -c 'stty intr ^] && sudo ./{driver} +permissive $(sed \':a;N;$!ba;s/\\n/ /g\' {runtimeconf}) +macaddr={macaddr} +blkdev={blkdev} +slotid={slotid} +niclog=niclog {tracefile} +trace-start={trace_start} +trace-end={trace_end} +linklatency={linklatency} +netbw={netbw} +profile-interval=-1 +zero-out-dram +permissive-off {bootbin} && stty intr ^c' uartlog"; sleep 1""".format(
|
||||
basecommand = """screen -S fsim{slotid} -d -m bash -c "script -f -c 'stty intr ^] && sudo ./{driver} +permissive $(sed \':a;N;$!ba;s/\\n/ /g\' {runtimeconf}) +macaddr={macaddr} +blkdev={blkdev} +slotid={slotid} +niclog=niclog {tracefile} +trace-start={trace_start} +trace-end={trace_end} +linklatency={linklatency} +netbw={netbw} +profile-interval=-1 +zero-out-dram +shmemportname={shmemportname} +permissive-off {bootbin} && stty intr ^c' uartlog"; sleep 1""".format(
|
||||
slotid=slotid, driver=driver, runtimeconf=runtimeconf,
|
||||
macaddr=macaddr, blkdev=blkdev, linklatency=linklatency,
|
||||
netbw=netbw, bootbin=bootbin, tracefile=tracefile,
|
||||
netbw=netbw, shmemportname=shmemportname, bootbin=bootbin, tracefile=tracefile,
|
||||
trace_start=trace_start, trace_end=trace_end)
|
||||
|
||||
return basecommand
|
||||
|
|
|
@ -11,8 +11,6 @@ from util.streamlogger import StreamLogger
|
|||
|
||||
rootLogger = logging.getLogger()
|
||||
|
||||
BASEPORT = 10000
|
||||
|
||||
class AbstractSwitchToSwitchConfig:
|
||||
""" This class is responsible for providing functions that take a FireSimSwitchNode
|
||||
and emit the correct config header to produce an actual switch simulator binary
|
||||
|
@ -28,37 +26,35 @@ class AbstractSwitchToSwitchConfig:
|
|||
self.build_disambiguate = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(64))
|
||||
|
||||
def emit_init_for_uplink(self, uplinkno):
|
||||
""" Emit an init for a switch to talk to it's uplink.
|
||||
""" Emit an init for a switch to talk to it's uplink."""
|
||||
|
||||
TODO: currently, we only support one uplink. """
|
||||
assert uplinkno < 1, "Only 1 uplink is currently supported."
|
||||
downlinkno = None
|
||||
iterno = 0
|
||||
for downlink in self.fsimswitchnode.uplinks[uplinkno].downlinks:
|
||||
if self.fsimswitchnode == downlink:
|
||||
downlinkno = iterno
|
||||
break
|
||||
iterno += 1
|
||||
assert self.fsimswitchnode.host_instance.is_bound_to_real_instance(), "Instances must be bound to private IP to emit switches with uplinks. i.e. you must have a running Run Farm."
|
||||
# TODO: remove the requirement from the above assert by passing IPs
|
||||
# as cmd line arguments.
|
||||
uplinkip = self.fsimswitchnode.uplinks[uplinkno].host_instance.get_private_ip()
|
||||
return "new SocketClientPort(" + str(len(self.fsimswitchnode.downlinks)+uplinkno) + \
|
||||
", \"" + uplinkip + "\", " + str(BASEPORT + downlinkno) + ");\n"
|
||||
linkobj = self.fsimswitchnode.uplinks[uplinkno]
|
||||
upperswitch = linkobj.get_uplink_side()
|
||||
|
||||
target_local_portno = len(self.fsimswitchnode.downlinks) + uplinkno
|
||||
if linkobj.link_crosses_hosts():
|
||||
uplinkhostip = linkobj.link_hostserver_ip() #upperswitch.host_instance.get_private_ip()
|
||||
uplinkhostport = linkobj.link_hostserver_port()
|
||||
|
||||
return "new SocketClientPort(" + str(target_local_portno) + \
|
||||
", \"" + uplinkhostip + "\", " + str(uplinkhostport) + ");\n"
|
||||
|
||||
else:
|
||||
linkbasename = linkobj.get_global_link_id()
|
||||
return "new ShmemPort(" + str(target_local_portno) + ', "' + linkbasename + '", true);\n'
|
||||
|
||||
def emit_init_for_downlink(self, downlinkno):
|
||||
""" emit an init for the specified downlink. """
|
||||
downlink = self.fsimswitchnode.downlinks[downlinkno]
|
||||
# this must be here to avoid circular deps
|
||||
# TODO: for real fix, need to refactor the abstract switch / implementation
|
||||
# interface
|
||||
from runtools.firesim_topology_elements import FireSimSwitchNode
|
||||
if isinstance(downlink, FireSimSwitchNode):
|
||||
downlinkobj = self.fsimswitchnode.downlinks[downlinkno]
|
||||
downlink = downlinkobj.get_downlink_side()
|
||||
if downlinkobj.link_crosses_hosts():
|
||||
hostport = downlinkobj.link_hostserver_port()
|
||||
# create a SocketServerPort
|
||||
return "new SocketServerPort(" + str(downlinkno) + ", " + \
|
||||
str(BASEPORT + downlinkno) + ");\n"
|
||||
str(hostport) + ");\n"
|
||||
else:
|
||||
return "new ShmemPort(" + str(downlinkno) + ");\n"
|
||||
linkbasename = downlinkobj.get_global_link_id()
|
||||
return "new ShmemPort(" + str(downlinkno) + ', "' + linkbasename + '", false);\n'
|
||||
|
||||
def emit_switch_configfile(self):
|
||||
""" Produce a config file for the switch generator for this switch """
|
||||
|
@ -99,12 +95,16 @@ class AbstractSwitchToSwitchConfig:
|
|||
|
||||
def get_numclientsconfig(self):
|
||||
""" Emit constants for num ports. """
|
||||
totalports = len(self.fsimswitchnode.downlinks) + len(self.fsimswitchnode.uplinks)
|
||||
numdownlinks = len(self.fsimswitchnode.downlinks)
|
||||
numuplinks = len(self.fsimswitchnode.uplinks)
|
||||
totalports = numdownlinks + numuplinks
|
||||
|
||||
retstr = """
|
||||
#ifdef NUMCLIENTSCONFIG
|
||||
#define NUMPORTS {}
|
||||
#endif""".format(totalports)
|
||||
#define NUMDOWNLINKS {}
|
||||
#define NUMUPLINKS {}
|
||||
#endif""".format(totalports, numdownlinks, numuplinks)
|
||||
return retstr
|
||||
|
||||
def get_portsetup(self):
|
||||
|
@ -166,7 +166,8 @@ class AbstractSwitchToSwitchConfig:
|
|||
""" Return the command to boot the switch."""
|
||||
switchlatency = self.fsimswitchnode.switch_switching_latency
|
||||
linklatency = self.fsimswitchnode.switch_link_latency
|
||||
return """screen -S {} -d -m bash -c "script -f -c './{} {} {}' switchlog"; sleep 1""".format(self.switch_binary_name(), self.switch_binary_name(), linklatency, switchlatency)
|
||||
# insert gdb -ex run --args between sudo and ./ below to start switches in gdb
|
||||
return """screen -S {} -d -m bash -c "script -f -c 'sudo ./{} {} {}' switchlog"; sleep 1""".format(self.switch_binary_name(), self.switch_binary_name(), linklatency, switchlatency)
|
||||
|
||||
def kill_switch_simulation_command(self):
|
||||
""" Return the command to kill the switch. """
|
||||
|
|
|
@ -8,6 +8,174 @@ class UserTopologies(object):
|
|||
""" A class that just separates out user-defined/configurable topologies
|
||||
from the rest of the boilerplate in FireSimTopology() """
|
||||
|
||||
def clos_m_n_r(self, m, n, r):
|
||||
""" DO NOT USE THIS DIRECTLY, USE ONE OF THE INSTANTIATIONS BELOW. """
|
||||
""" Clos topol where:
|
||||
m = number of root switches
|
||||
n = number of links to nodes on leaf switches
|
||||
r = number of leaf switches
|
||||
|
||||
and each leaf switch has a link to each root switch.
|
||||
|
||||
With the default mapping specified below, you will need:
|
||||
m m4.16xlarges.
|
||||
n f1.16xlarges.
|
||||
|
||||
TODO: improve this later to pack leaf switches with <= 4 downlinks onto
|
||||
one 16x.large.
|
||||
"""
|
||||
|
||||
rootswitches = [FireSimSwitchNode() for x in range(m)]
|
||||
self.roots = rootswitches
|
||||
leafswitches = [FireSimSwitchNode() for x in range(r)]
|
||||
servers = [[FireSimServerNode() for x in range(n)] for y in range(r)]
|
||||
for rswitch in rootswitches:
|
||||
rswitch.add_downlinks(leafswitches)
|
||||
|
||||
for leafswitch, servergroup in zip(leafswitches, servers):
|
||||
leafswitch.add_downlinks(servergroup)
|
||||
|
||||
def custom_mapper(fsim_topol_with_passes):
|
||||
for i, rswitch in enumerate(rootswitches):
|
||||
fsim_topol_with_passes.run_farm.m4_16s[i].add_switch(rswitch)
|
||||
|
||||
for j, lswitch in enumerate(leafswitches):
|
||||
fsim_topol_with_passes.run_farm.f1_16s[j].add_switch(lswitch)
|
||||
for sim in servers[j]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[j].add_simulation(sim)
|
||||
|
||||
self.custom_mapper = custom_mapper
|
||||
|
||||
def clos_2_8_2(self):
|
||||
""" clos topol with:
|
||||
2 roots
|
||||
8 nodes/leaf
|
||||
2 leaves. """
|
||||
self.clos_m_n_r(2, 8, 2)
|
||||
|
||||
def clos_8_8_16(self):
|
||||
""" clos topol with:
|
||||
8 roots
|
||||
8 nodes/leaf
|
||||
16 leaves. = 128 nodes."""
|
||||
self.clos_m_n_r(8, 8, 16)
|
||||
|
||||
def fat_tree_4ary(self):
|
||||
# 4-ary fat tree as described in
|
||||
# http://ccr.sigcomm.org/online/files/p63-alfares.pdf
|
||||
coreswitches = [FireSimSwitchNode() for x in range(4)]
|
||||
self.roots = coreswitches
|
||||
aggrswitches = [FireSimSwitchNode() for x in range(8)]
|
||||
edgeswitches = [FireSimSwitchNode() for x in range(8)]
|
||||
servers = [FireSimServerNode() for x in range(16)]
|
||||
for switchno in range(len(coreswitches)):
|
||||
core = coreswitches[switchno]
|
||||
base = 0 if switchno < 2 else 1
|
||||
dls = range(base, 8, 2)
|
||||
dls = map(lambda x: aggrswitches[x], dls)
|
||||
core.add_downlinks(dls)
|
||||
for switchbaseno in range(0, len(aggrswitches), 2):
|
||||
switchno = switchbaseno + 0
|
||||
aggr = aggrswitches[switchno]
|
||||
aggr.add_downlinks([edgeswitches[switchno], edgeswitches[switchno+1]])
|
||||
switchno = switchbaseno + 1
|
||||
aggr = aggrswitches[switchno]
|
||||
aggr.add_downlinks([edgeswitches[switchno-1], edgeswitches[switchno]])
|
||||
for edgeno in range(len(edgeswitches)):
|
||||
edgeswitches[edgeno].add_downlinks([servers[edgeno*2], servers[edgeno*2+1]])
|
||||
|
||||
|
||||
def custom_mapper(fsim_topol_with_passes):
|
||||
""" In a custom mapper, you have access to the firesim topology with passes,
|
||||
where you can access the run_farm nodes:
|
||||
|
||||
fsim_topol_with_passes.run_farm.{f1_16s, f1_2s, m4_16s}
|
||||
|
||||
To map, call add_switch or add_simulation on run farm instance
|
||||
objs in the aforementioned arrays.
|
||||
|
||||
Because of the scope of this fn, you also have access to whatever
|
||||
stuff you created in the topology itself, which we expect will be
|
||||
useful for performing the mapping."""
|
||||
|
||||
# map the fat tree onto one m4.16xlarge (for core switches)
|
||||
# and two f1.16xlarges (two pods of aggr/edge/4sims per f1.16xlarge)
|
||||
for core in coreswitches:
|
||||
fsim_topol_with_passes.run_farm.m4_16s[0].add_switch(core)
|
||||
|
||||
for aggrsw in aggrswitches[:4]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[0].add_switch(aggrsw)
|
||||
for aggrsw in aggrswitches[4:]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[1].add_switch(aggrsw)
|
||||
|
||||
for edgesw in edgeswitches[:4]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[0].add_switch(edgesw)
|
||||
for edgesw in edgeswitches[4:]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[1].add_switch(edgesw)
|
||||
|
||||
for sim in servers[:8]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[0].add_simulation(sim)
|
||||
for sim in servers[8:]:
|
||||
fsim_topol_with_passes.run_farm.f1_16s[1].add_simulation(sim)
|
||||
|
||||
self.custom_mapper = custom_mapper
|
||||
|
||||
|
||||
|
||||
def example_multilink(self):
|
||||
self.roots = [FireSimSwitchNode()]
|
||||
midswitch = FireSimSwitchNode()
|
||||
lowerlayer = [midswitch for x in range(16)]
|
||||
self.roots[0].add_downlinks(lowerlayer)
|
||||
servers = [FireSimServerNode()]
|
||||
midswitch.add_downlinks(servers)
|
||||
|
||||
def example_multilink_32(self):
|
||||
self.roots = [FireSimSwitchNode()]
|
||||
midswitch = FireSimSwitchNode()
|
||||
lowerlayer = [midswitch for x in range(32)]
|
||||
self.roots[0].add_downlinks(lowerlayer)
|
||||
servers = [FireSimServerNode()]
|
||||
midswitch.add_downlinks(servers)
|
||||
|
||||
def example_multilink_64(self):
|
||||
self.roots = [FireSimSwitchNode()]
|
||||
midswitch = FireSimSwitchNode()
|
||||
lowerlayer = [midswitch for x in range(64)]
|
||||
self.roots[0].add_downlinks(lowerlayer)
|
||||
servers = [FireSimServerNode()]
|
||||
midswitch.add_downlinks(servers)
|
||||
|
||||
def example_cross_links(self):
|
||||
self.roots = [FireSimSwitchNode() for x in range(2)]
|
||||
midswitches = [FireSimSwitchNode() for x in range(2)]
|
||||
self.roots[0].add_downlinks(midswitches)
|
||||
self.roots[1].add_downlinks(midswitches)
|
||||
servers = [FireSimServerNode() for x in range(2)]
|
||||
midswitches[0].add_downlinks([servers[0]])
|
||||
midswitches[1].add_downlinks([servers[1]])
|
||||
|
||||
|
||||
def small_hierarchy_8sims(self):
|
||||
self.custom_mapper = 'mapping_use_one_f1_16xlarge'
|
||||
self.roots = [FireSimSwitchNode()]
|
||||
midlevel = [FireSimSwitchNode() for x in range(4)]
|
||||
servers = [[FireSimServerNode() for x in range(2)] for x in range(4)]
|
||||
self.roots[0].add_downlinks(midlevel)
|
||||
for swno in range(len(midlevel)):
|
||||
midlevel[swno].add_downlinks(servers[swno])
|
||||
|
||||
|
||||
def small_hierarchy_2sims(self):
|
||||
self.custom_mapper = 'mapping_use_one_f1_16xlarge'
|
||||
self.roots = [FireSimSwitchNode()]
|
||||
midlevel = [FireSimSwitchNode() for x in range(1)]
|
||||
servers = [[FireSimServerNode() for x in range(2)] for x in range(1)]
|
||||
self.roots[0].add_downlinks(midlevel)
|
||||
for swno in range(len(midlevel)):
|
||||
midlevel[swno].add_downlinks(servers[swno])
|
||||
|
||||
|
||||
def example_1config(self):
|
||||
self.roots = [FireSimSwitchNode()]
|
||||
servers = [FireSimServerNode() for y in range(1)]
|
||||
|
|
|
@ -41,7 +41,7 @@ static void simplify_frac(int n, int d, int *nn, int *dd)
|
|||
simplenic_t::simplenic_t(
|
||||
simif_t *sim, char *slotid,
|
||||
uint64_t mac_little_end, int netbw, int netburst, int linklatency,
|
||||
char *niclogfile, bool loopback): endpoint_t(sim)
|
||||
char *niclogfile, bool loopback, char *shmemportname): endpoint_t(sim)
|
||||
{
|
||||
#ifdef SIMPLENICWIDGET_0
|
||||
// store link latency:
|
||||
|
@ -71,17 +71,31 @@ simplenic_t::simplenic_t(
|
|||
}
|
||||
}
|
||||
|
||||
char name[100];
|
||||
char name[257];
|
||||
int shmemfd;
|
||||
|
||||
if (!loopback) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
sprintf(name, "/port_nts%s_%d", slotid, j);
|
||||
if (shmemportname) {
|
||||
printf("Using non-slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_nts%s_%d", shmemportname, j);
|
||||
} else {
|
||||
printf("Using slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_nts%s_%d", slotid, j);
|
||||
}
|
||||
printf("opening/creating shmem region %s\n", name);
|
||||
shmemfd = shm_open(name, O_RDWR | O_CREAT , S_IRWXU);
|
||||
ftruncate(shmemfd, BUFBYTES+EXTRABYTES);
|
||||
pcis_read_bufs[j] = (char*)mmap(NULL, BUFBYTES+EXTRABYTES, PROT_READ | PROT_WRITE, MAP_SHARED, shmemfd, 0);
|
||||
sprintf(name, "/port_stn%s_%d", slotid, j);
|
||||
|
||||
if (shmemportname) {
|
||||
printf("Using non-slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_stn%s_%d", shmemportname, j);
|
||||
} else {
|
||||
printf("Using slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_stn%s_%d", slotid, j);
|
||||
}
|
||||
|
||||
printf("opening/creating shmem region %s\n", name);
|
||||
shmemfd = shm_open(name, O_RDWR | O_CREAT , S_IRWXU);
|
||||
ftruncate(shmemfd, BUFBYTES+EXTRABYTES);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
class simplenic_t: public endpoint_t
|
||||
{
|
||||
public:
|
||||
simplenic_t(simif_t* sim, char * slotid, uint64_t mac_little_end, int netbw, int netburst, int linklatency, char * niclogfile, bool loopback);
|
||||
simplenic_t(simif_t* sim, char * slotid, uint64_t mac_little_end, int netbw, int netburst, int linklatency, char * niclogfile, bool loopback, char *shmemportname);
|
||||
~simplenic_t();
|
||||
|
||||
virtual void init();
|
||||
|
|
|
@ -19,6 +19,7 @@ firesim_top_t::firesim_top_t(int argc, char** argv)
|
|||
char * niclogfile = NULL;
|
||||
char * slotid = NULL;
|
||||
char * tracefile = NULL;
|
||||
char * shmemportname = NULL;
|
||||
uint64_t mac_little_end = 0; // default to invalid mac addr, force user to specify one
|
||||
uint64_t trace_start = 0, trace_end = ULONG_MAX;
|
||||
int netbw = MAX_BANDWIDTH, netburst = 8;
|
||||
|
@ -42,6 +43,12 @@ firesim_top_t::firesim_top_t(int argc, char** argv)
|
|||
if (arg.find("+slotid=") == 0) {
|
||||
slotid = const_cast<char*>(arg.c_str()) + 8;
|
||||
}
|
||||
|
||||
// TODO: move this and a bunch of other NIC arg parsing into the nic endpoint code itself
|
||||
if (arg.find("+shmemportname=") == 0) {
|
||||
shmemportname = const_cast<char*>(arg.c_str()) + 15;
|
||||
}
|
||||
|
||||
if (arg.find("+zero-out-dram") == 0) {
|
||||
do_zero_out_dram = true;
|
||||
}
|
||||
|
@ -111,7 +118,7 @@ firesim_top_t::firesim_top_t(int argc, char** argv)
|
|||
#endif
|
||||
|
||||
add_endpoint(new blockdev_t(this, args));
|
||||
add_endpoint(new simplenic_t(this, slotid, mac_little_end, netbw, netburst, linklatency, niclogfile, nic_loopback));
|
||||
add_endpoint(new simplenic_t(this, slotid, mac_little_end, netbw, netburst, linklatency, niclogfile, nic_loopback, shmemportname));
|
||||
add_endpoint(new tracerv_t(this, tracefile, trace_start, trace_end));
|
||||
// add more endpoints here
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 6640fc7cc787938c0cb012673c4fcdb1f4c851ff
|
||||
Subproject commit 8e475fa6597ac1383a4241db2badeed4826f234f
|
|
@ -57,12 +57,14 @@ void BasePort::write_flits_to_output() {
|
|||
uint64_t basetime = this_iter_cycles_start;
|
||||
uint64_t maxtime = this_iter_cycles_start + LINKLATENCY;
|
||||
|
||||
bool empty_buf = true;
|
||||
|
||||
while (!(outputqueue.empty())) {
|
||||
// first, check timing boundaries.
|
||||
uint64_t space_available = LINKLATENCY - flitswritten;
|
||||
uint64_t outputtimestamp = outputqueue.front()->timestamp;
|
||||
uint64_t outputtimestampend = outputtimestamp + outputqueue.front()->amtwritten;
|
||||
|
||||
|
||||
// confirm that a) we are allowed to send this out based on timestamp
|
||||
// b) we are allowed to send this out based on available space (TODO fix)
|
||||
if (outputtimestampend < maxtime && (outputqueue.front()->amtwritten <= space_available)) {
|
||||
|
@ -91,6 +93,7 @@ void BasePort::write_flits_to_output() {
|
|||
write_last_flit(current_output_buf, flitswritten, i == (thispacket->amtwritten-1));
|
||||
write_valid_flit(current_output_buf, flitswritten);
|
||||
write_flit(current_output_buf, flitswritten, thispacket->dat[i]);
|
||||
empty_buf = false;
|
||||
flitswritten++;
|
||||
}
|
||||
free(thispacket);
|
||||
|
@ -100,6 +103,9 @@ void BasePort::write_flits_to_output() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (empty_buf) {
|
||||
((uint64_t*)current_output_buf)[0] = 0xDEADBEEFDEADBEEFL;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize output port fullness for this round
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
/* ----------------------------------------------------
|
||||
* buffer flit operations
|
||||
*
|
||||
|
@ -63,6 +65,13 @@ uint16_t get_port_from_flit(uint64_t flit, int current_port) {
|
|||
if (sendport != 0xffff) {
|
||||
sendport = mac2port[sendport];
|
||||
}
|
||||
if (sendport == NUMDOWNLINKS) {
|
||||
// this has been mapped to "any uplink", so pick one
|
||||
int randval = rand() % NUMUPLINKS;
|
||||
sendport = randval + NUMDOWNLINKS;
|
||||
// printf("sending to random uplink.\n");
|
||||
// printf("port: %04x\n", sendport);
|
||||
}
|
||||
//printf("port: %04x\n", sendport);
|
||||
return sendport;
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// THIS FILE IS MACHINE GENERATED. SEE emitconfig.py
|
||||
|
||||
#ifdef NUMCLIENTSCONFIG
|
||||
#define NUMPORTS 8
|
||||
#endif
|
||||
#ifdef PORTSETUPCONFIG
|
||||
ports[0] = new ShmemPort(0);
|
||||
ports[1] = new ShmemPort(1);
|
||||
ports[2] = new ShmemPort(2);
|
||||
ports[3] = new ShmemPort(3);
|
||||
ports[4] = new ShmemPort(4);
|
||||
ports[5] = new ShmemPort(5);
|
||||
ports[6] = new ShmemPort(6);
|
||||
ports[7] = new ShmemPort(7);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MACPORTSCONFIG
|
||||
uint16_t mac2port[10] {8, 8, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
#endif
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
#include <errno.h>
|
||||
|
||||
class ShmemPort : public BasePort {
|
||||
public:
|
||||
ShmemPort(int portNo);
|
||||
ShmemPort(int portNo, char * shmemportname, bool uplink);
|
||||
void tick();
|
||||
void tick_pre();
|
||||
void send();
|
||||
|
@ -13,26 +13,116 @@ class ShmemPort : public BasePort {
|
|||
int currentround = 0;
|
||||
};
|
||||
|
||||
ShmemPort::ShmemPort(int portNo) : BasePort(portNo) {
|
||||
ShmemPort::ShmemPort(int portNo, char * shmemportname, bool uplink) : BasePort(portNo) {
|
||||
#define SHMEM_EXTRABYTES 1
|
||||
|
||||
// create shared memory regions
|
||||
char name[100];
|
||||
int shmemfd;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
sprintf(name, "/port_nts%d_%d", _portNo, j);
|
||||
printf("opening/creating shmem region %s\n", name);
|
||||
shmemfd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
|
||||
ftruncate(shmemfd, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
recvbufs[j] = (uint8_t*)mmap(NULL, BUFSIZE_BYTES+SHMEM_EXTRABYTES, PROT_READ | PROT_WRITE, MAP_SHARED, shmemfd,0);
|
||||
memset(recvbufs[j], 0, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
|
||||
sprintf(name, "/port_stn%d_%d", _portNo, j);
|
||||
printf("opening/creating shmem region %s\n", name);
|
||||
shmemfd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
|
||||
ftruncate(shmemfd, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
char * recvdirection;
|
||||
char * senddirection;
|
||||
|
||||
int ftresult;
|
||||
|
||||
int shm_flags;
|
||||
if (uplink) {
|
||||
// uplink should not truncate on SHM_OPEN
|
||||
shm_flags = O_RDWR /*| O_CREAT*/;
|
||||
} else {
|
||||
shm_flags = O_RDWR | O_CREAT | O_TRUNC;
|
||||
}
|
||||
|
||||
if (uplink) {
|
||||
fprintf(stdout, "Uplink Port\n");
|
||||
recvdirection = "stn";
|
||||
senddirection = "nts";
|
||||
} else {
|
||||
fprintf(stdout, "Downlink Port\n");
|
||||
recvdirection = "nts";
|
||||
senddirection = "stn";
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++) {
|
||||
if (shmemportname) {
|
||||
fprintf(stdout, "Using non-slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_%s%s_%d", recvdirection, shmemportname, j);
|
||||
} else {
|
||||
fprintf(stdout, "Using slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_%s%d_%d", recvdirection, _portNo, j);
|
||||
}
|
||||
fprintf(stdout, "opening/creating shmem region\n%s\n", name);
|
||||
shmemfd = shm_open(name, shm_flags, S_IRWXU);
|
||||
|
||||
while (shmemfd == -1) {
|
||||
perror("shm_open failed");
|
||||
if (uplink) {
|
||||
fprintf(stdout, "retrying in 1s...\n");
|
||||
sleep(1);
|
||||
shmemfd = shm_open(name, shm_flags, S_IRWXU);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (!uplink) {
|
||||
ftresult = ftruncate(shmemfd, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
if (ftresult == -1) {
|
||||
perror("ftruncate failed");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
recvbufs[j] = (uint8_t*)mmap(NULL, BUFSIZE_BYTES+SHMEM_EXTRABYTES, PROT_READ | PROT_WRITE, MAP_SHARED, shmemfd,0);
|
||||
|
||||
if (recvbufs[j] == MAP_FAILED) {
|
||||
perror("mmap failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!uplink) {
|
||||
memset(recvbufs[j], 0, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
}
|
||||
|
||||
if (shmemportname) {
|
||||
fprintf(stdout, "Using non-slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_%s%s_%d", senddirection, shmemportname, j);
|
||||
} else {
|
||||
fprintf(stdout, "Using slot-id associated shmemportname:\n");
|
||||
sprintf(name, "/port_%s%d_%d", senddirection, _portNo, j);
|
||||
}
|
||||
fprintf(stdout, "opening/creating shmem region\n%s\n", name);
|
||||
shmemfd = shm_open(name, shm_flags, S_IRWXU);
|
||||
|
||||
while (shmemfd == -1) {
|
||||
perror("shm_open failed");
|
||||
if (uplink) {
|
||||
fprintf(stdout, "retrying in 1s...\n");
|
||||
sleep(1);
|
||||
shmemfd = shm_open(name, shm_flags, S_IRWXU);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (!uplink) {
|
||||
ftresult = ftruncate(shmemfd, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
if (ftresult == -1) {
|
||||
perror("ftruncate failed");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
sendbufs[j] = (uint8_t*)mmap(NULL, BUFSIZE_BYTES+SHMEM_EXTRABYTES, PROT_READ | PROT_WRITE, MAP_SHARED, shmemfd,0);
|
||||
memset(sendbufs[j], 0, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
|
||||
if (sendbufs[j] == MAP_FAILED) {
|
||||
perror("mmap failed");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!uplink) {
|
||||
memset(sendbufs[j], 0, BUFSIZE_BYTES+SHMEM_EXTRABYTES);
|
||||
}
|
||||
}
|
||||
|
||||
// setup "current" bufs. tick will swap for shmem passing
|
||||
|
@ -41,6 +131,11 @@ ShmemPort::ShmemPort(int portNo) : BasePort(portNo) {
|
|||
}
|
||||
|
||||
void ShmemPort::send() {
|
||||
if (((uint64_t*)current_output_buf)[0] == 0xDEADBEEFDEADBEEFL) {
|
||||
// if compress flag is set, clear it, this port type doesn't care
|
||||
// (and in fact, we're writing too much, so stuff later will get confused)
|
||||
((uint64_t*)current_output_buf)[0] = 0L;
|
||||
}
|
||||
// mark flag to initiate "send"
|
||||
current_output_buf[BUFSIZE_BYTES] = 1;
|
||||
}
|
||||
|
|
|
@ -47,12 +47,29 @@ SocketClientPort::SocketClientPort(int portNo, char * serverip, int hostport) :
|
|||
}
|
||||
|
||||
void SocketClientPort::send() {
|
||||
int amtsent = ::send(clientsocket, current_output_buf, BUFSIZE_BYTES, 0);
|
||||
if (amtsent != BUFSIZE_BYTES) { printf("SOCKETPORT SEND ERROR\n"); exit(1); }
|
||||
if (((uint64_t*)current_output_buf)[0] == 0xDEADBEEFDEADBEEFL) {
|
||||
// printf("sending compressed\n");
|
||||
#define COMPRESS_NUM_BYTES (8)
|
||||
int amtsent = ::send(clientsocket, current_output_buf, COMPRESS_NUM_BYTES, 0);
|
||||
if (amtsent != COMPRESS_NUM_BYTES) { printf("SOCKETPORT SEND ERROR\n"); exit(1); }
|
||||
} else {
|
||||
int amtsent = ::send(clientsocket, current_output_buf, BUFSIZE_BYTES, 0);
|
||||
if (amtsent != BUFSIZE_BYTES) { printf("SOCKETPORT SEND ERROR\n"); exit(1); }
|
||||
}
|
||||
}
|
||||
|
||||
void SocketClientPort::recv() {
|
||||
int amtread = 0;
|
||||
while (amtread < COMPRESS_NUM_BYTES) {
|
||||
amtread += ::recv(clientsocket, current_input_buf + amtread,
|
||||
COMPRESS_NUM_BYTES - amtread, 0);
|
||||
}
|
||||
if (((uint64_t*)current_input_buf)[0] == 0xDEADBEEFDEADBEEFL) {
|
||||
// printf("recv compressed\n");
|
||||
memset(current_input_buf, 0x0, BUFSIZE_BYTES);
|
||||
return;
|
||||
}
|
||||
|
||||
while (amtread < BUFSIZE_BYTES) {
|
||||
amtread += ::recv(clientsocket, current_input_buf + amtread,
|
||||
BUFSIZE_BYTES - amtread, 0);
|
||||
|
@ -125,12 +142,29 @@ SocketServerPort::SocketServerPort(int portNo, int hostport) : BasePort(portNo)
|
|||
}
|
||||
|
||||
void SocketServerPort::send() {
|
||||
int amtsent = ::send(serversocket, current_output_buf, BUFSIZE_BYTES, 0);
|
||||
if (amtsent != BUFSIZE_BYTES) { printf("SOCKETPORT SEND ERROR\n"); exit(1); }
|
||||
if (((uint64_t*)current_output_buf)[0] == 0xDEADBEEFDEADBEEFL) {
|
||||
// printf("sending compressed\n");
|
||||
#define COMPRESS_NUM_BYTES (8)
|
||||
int amtsent = ::send(serversocket, current_output_buf, COMPRESS_NUM_BYTES, 0);
|
||||
if (amtsent != COMPRESS_NUM_BYTES) { printf("SOCKETPORT SEND ERROR\n"); exit(1); }
|
||||
} else {
|
||||
int amtsent = ::send(serversocket, current_output_buf, BUFSIZE_BYTES, 0);
|
||||
if (amtsent != BUFSIZE_BYTES) { printf("SOCKETPORT SEND ERROR\n"); exit(1); }
|
||||
}
|
||||
}
|
||||
|
||||
void SocketServerPort::recv() {
|
||||
int amtread = 0;
|
||||
while (amtread < COMPRESS_NUM_BYTES) {
|
||||
amtread += ::recv(serversocket, current_input_buf + amtread,
|
||||
COMPRESS_NUM_BYTES - amtread, 0);
|
||||
}
|
||||
if (((uint64_t*)current_input_buf)[0] == 0xDEADBEEFDEADBEEFL) {
|
||||
// printf("recv compressed\n");
|
||||
memset(current_input_buf, 0x0, BUFSIZE_BYTES);
|
||||
return;
|
||||
}
|
||||
|
||||
while (amtread < BUFSIZE_BYTES) {
|
||||
amtread += ::recv(serversocket, current_input_buf + amtread,
|
||||
BUFSIZE_BYTES - amtread, 0);
|
||||
|
|
|
@ -87,6 +87,12 @@ void SSHPort::send() {
|
|||
// (data is in current_output_buf)
|
||||
// and push it into queues to send into the TAP
|
||||
|
||||
if (((uint64_t*)current_output_buf)[0] == 0xDEADBEEFDEADBEEFL) {
|
||||
// if compress flag is set, clear it, this port type doesn't care
|
||||
// (and in fact, we're writing too much, so stuff later will get confused)
|
||||
((uint64_t*)current_output_buf)[0] = 0L;
|
||||
}
|
||||
|
||||
// first, push into out_flits queue
|
||||
for (int tokenno = 0; tokenno < NUM_TOKENS; tokenno++) {
|
||||
if (is_valid_flit(current_output_buf, tokenno)) {
|
||||
|
|
|
@ -159,7 +159,11 @@ while (!pqueue.empty()) {
|
|||
printf("packet for port: %x\n", send_to_port);
|
||||
printf("packet timestamp: %ld\n", tsp->timestamp);
|
||||
if (send_to_port == BROADCAST_ADJUSTED) {
|
||||
for (int i = 0; i < NUMPORTS; i++) {
|
||||
#define ADDUPLINK (NUMUPLINKS > 0 ? 1 : 0)
|
||||
// this will only send broadcasts to the first (zeroeth) uplink.
|
||||
// on a switch receiving broadcast packet from an uplink, this should
|
||||
// automatically prevent switch from sending the broadcast to any uplink
|
||||
for (int i = 0; i < NUMDOWNLINKS + ADDUPLINK; i++) {
|
||||
if (i != tsp->sender ) {
|
||||
switchpacket * tsp2 = (switchpacket*)malloc(sizeof(switchpacket));
|
||||
memcpy(tsp2, tsp, sizeof(switchpacket));
|
||||
|
|
Loading…
Reference in New Issue