Copy changes from PR #848

This commit is contained in:
Abraham Gonzalez 2021-10-13 00:05:25 +00:00
parent 716ef87143
commit 8d8c3856b8
11 changed files with 523 additions and 270 deletions

View File

@ -0,0 +1,46 @@
from __future__ import with_statement
import json
import time
import random
import string
import logging
import os
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.contrib.project import rsync_project
from awstools.afitools import *
from awstools.awstools import send_firesim_notification
from util.streamlogger import StreamLogger, InfoStreamLogger
rootLogger = logging.getLogger()
def get_deploy_dir():
""" Must use local here. determine where the firesim/deploy dir is """
with StreamLogger('stdout'), StreamLogger('stderr'):
deploydir = local("pwd", capture=True)
return deploydir
def replace_rtl(build_config):
""" Generate Verilog """
rootLogger.info("Building Verilog for {}".format(str(build_config.get_chisel_triplet())))
with InfoStreamLogger('stdout'), InfoStreamLogger('stderr'):
run("{}/general-scripts/replace-rtl.sh {} {} {} {} \"{}\"".format(
get_deploy_dir() + "/buildtools",
os.getenv('RISCV', ""),
os.getenv('PATH', ""),
os.getenv('LD_LIBRARY_PATH', ""),
get_deploy_dir() + "/..",
build_config.make_recipe("PLATFORM=f1 replace-rtl")))
def build_driver(build_config):
""" Build FPGA driver """
rootLogger.info("Building FPGA driver for {}".format(str(build_config.get_chisel_triplet())))
with InfoStreamLogger('stdout'), InfoStreamLogger('stderr'):
run("{}/general-scripts/build-driver.sh {} {} {} {} \"{}\"".format(
get_deploy_dir() + "/buildtools",
os.getenv('RISCV', ""),
os.getenv('PATH', ""),
os.getenv('LD_LIBRARY_PATH', ""),
get_deploy_dir() + "/..",
build_config.make_recipe("PLATFORM=f1 driver")))

View File

@ -21,116 +21,144 @@ def get_deploy_dir():
deploydir = local("pwd", capture=True)
return deploydir
def replace_rtl(conf, buildconfig):
""" Run chisel/firrtl/fame-1, produce verilog for fpga build.
def replace_rtl(build_config):
""" Generate Verilog """
rootLogger.info("Building Verilog for {}".format(str(build_config.get_chisel_triplet())))
with InfoStreamLogger('stdout'), InfoStreamLogger('stderr'):
run("{}/general-scripts/replace-rtl.sh {} {} {} {} \"{}\"".format(
get_deploy_dir() + "/buildtools",
os.getenv('RISCV', ""),
os.getenv('PATH', ""),
os.getenv('LD_LIBRARY_PATH', ""),
get_deploy_dir() + "/..",
build_config.make_recipe("PLATFORM=f1 replace-rtl")))
THIS ALWAYS RUNS LOCALLY"""
builddir = buildconfig.get_build_dir_name()
fpgabuilddir = "hdk/cl/developer_designs/cl_" + buildconfig.get_chisel_triplet()
ddir = get_deploy_dir()
def build_driver(build_config):
""" Build FPGA driver """
rootLogger.info("Building FPGA driver for {}".format(str(build_config.get_chisel_triplet())))
with InfoStreamLogger('stdout'), InfoStreamLogger('stderr'):
run("{}/general-scripts/build-driver.sh {} {} {} {} \"{}\"".format(
get_deploy_dir() + "/buildtools",
os.getenv('RISCV', ""),
os.getenv('PATH', ""),
os.getenv('LD_LIBRARY_PATH', ""),
get_deploy_dir() + "/..",
build_config.make_recipe("PLATFORM=f1 driver")))
rootLogger.info("Running replace-rtl to generate verilog for " + str(buildconfig.get_chisel_triplet()))
def pre_remote_build(build_config):
# First, Produce dcp/tar for design. Runs on remote machines, out of
# $HOME/firesim-build/ """
with prefix('cd ' + ddir + '/../'), \
prefix('export RISCV={}'.format(os.getenv('RISCV', ""))), \
prefix('export PATH={}'.format(os.getenv('PATH', ""))), \
prefix('export LD_LIBRARY_PATH={}'.format(os.getenv('LD_LIBRARY_PATH', ""))), \
prefix('source sourceme-f1-manager.sh'), \
prefix('export CL_DIR={}/../platforms/f1/aws-fpga/{}'.format(ddir, fpgabuilddir)), \
prefix('cd sim/'), \
InfoStreamLogger('stdout'), \
InfoStreamLogger('stderr'):
run(buildconfig.make_recipe("replace-rtl"))
run("""mkdir -p {}/results-build/{}/""".format(ddir, builddir))
run("""cp $CL_DIR/design/FireSim-generated.sv {}/results-build/{}/FireSim-generated.sv""".format(ddir, builddir))
fpga_build_dir = "hdk/cl/developer_designs/cl_{}".format(build_config.get_chisel_triplet())
local_deploy_dir = get_deploy_dir()
# build the fpga driver that corresponds with this version of the RTL
with prefix('cd ' + ddir + '/../'), \
prefix('export RISCV={}'.format(os.getenv('RISCV', ""))), \
prefix('export PATH={}'.format(os.getenv('PATH', ""))), \
prefix('export LD_LIBRARY_PATH={}'.format(os.getenv('LD_LIBRARY_PATH', ""))), \
prefix('source sourceme-f1-manager.sh'), \
prefix('cd sim/'), \
StreamLogger('stdout'), \
StreamLogger('stderr'):
run(buildconfig.make_recipe("f1"))
# local paths
local_fsim_dir = "{}/..".format(local_deploy_dir)
local_awsfpga_dir = "{}/platforms/f1/aws-fpga".format(local_fsim_dir)
# remote paths
remote_home_dir = ""
with StreamLogger('stdout'), StreamLogger('stderr'):
remote_home_dir = run('echo $HOME')
# override if provision farm asked for it
if build_config.provision_build_farm_dispatcher.override_remote_build_dir:
remote_home_dir = build_config.provision_build_farm_dispatcher.override_remote_build_dir
remote_build_dir = "{}/firesim-build".format(remote_home_dir)
f1_platform_dir = "{}/platforms/f1/".format(remote_build_dir)
awsfpga_dir = "{}/aws-fpga".format(f1_platform_dir)
# copy aws-fpga to the build instance.
# do the rsync, but ignore any checkpoints that might exist on this machine
# (in case builds were run locally)
# extra_opts -l preserves symlinks
with StreamLogger('stdout'), StreamLogger('stderr'):
run('mkdir -p {}'.format(f1_platform_dir))
rsync_cap = rsync_project(
local_dir=local_awsfpga_dir,
remote_dir=f1_platform_dir,
ssh_opts="-o StrictHostKeyChecking=no",
exclude="hdk/cl/developer_designs/cl_*",
extra_opts="-l", capture=True)
rootLogger.debug(rsync_cap)
rootLogger.debug(rsync_cap.stderr)
rsync_cap = rsync_project(
local_dir="{}/{}/*".format(local_awsfpga_dir, fpga_build_dir),
remote_dir='{}/{}'.format(awsfpga_dir, fpga_build_dir),
exclude='build/checkpoints',
ssh_opts="-o StrictHostKeyChecking=no",
extra_opts="-l", capture=True)
rootLogger.debug(rsync_cap)
rootLogger.debug(rsync_cap.stderr)
return "{}/{}".format(awsfpga_dir, fpga_build_dir)
@parallel
def aws_build(global_build_config, bypass=False):
""" Run Vivado, convert tar -> AGFI/AFI. Then terminate the instance at the end.
conf = buildconfig dicitonary
conf = build_config dicitonary
bypass: since this function takes a long time, bypass just returns for
testing purposes when set to True. """
build_config = global_build_config.get_build_by_ip(env.host_string)
if bypass:
### This is duplicated from the end of the function.
buildconfig = global_build_config.get_build_by_ip(env.host_string)
buildconfig.terminate_build_instance(buildconfig)
build_config.provision_build_farm_dispatcher.terminate_build_instance()
return
# The default error-handling procedure. Send an email and teardown instance
def on_build_failure():
message_title = "FireSim FPGA Build Failed"
message_body = "Your FPGA build failed for triplet: " + buildconfig.get_chisel_triplet()
message_body = "Your FPGA build failed for triplet: " + build_config.get_chisel_triplet()
message_body += ".\nInspect the log output from IP address " + env.host_string + " for more information."
send_firesim_notification(message_title, message_body)
rootLogger.info(message_title)
rootLogger.info(message_body)
rootLogger.info("Terminating the build instance now.")
buildconfig.terminate_build_instance()
build_config.provision_build_farm_dispatcher.terminate_build_instance()
rootLogger.info("Running process to build AGFI from verilog.")
rootLogger.info("Building AWS F1 AGFI from Verilog")
# First, Produce dcp/tar for design. Runs on remote machines, out of
# /home/centos/firesim-build/ """
ddir = get_deploy_dir()
buildconfig = global_build_config.get_build_by_ip(env.host_string)
builddir = buildconfig.get_build_dir_name()
# local AWS build directory; might have config-specific changes to fpga flow
fpgabuilddir = "hdk/cl/developer_designs/cl_" + buildconfig.get_chisel_triplet()
remotefpgabuilddir = "hdk/cl/developer_designs/cl_firesim"
fpga_build_dir = "hdk/cl/developer_designs/cl_{}".format(build_config.get_chisel_triplet())
results_dir = build_config.get_build_dir_name()
# first, copy aws-fpga to the build instance. it will live in
# firesim-build/platforms/f1/
with StreamLogger('stdout'), StreamLogger('stderr'):
run('mkdir -p /home/centos/firesim-build/platforms/f1/')
# do the rsync, but ignore any checkpoints that might exist on this machine
# (in case builds were run locally)
# extra_opts -l preserves symlinks
with StreamLogger('stdout'), StreamLogger('stderr'):
rsync_cap = rsync_project(local_dir=ddir + "/../platforms/f1/aws-fpga",
remote_dir='/home/centos/firesim-build/platforms/f1/',
ssh_opts="-o StrictHostKeyChecking=no",
exclude="hdk/cl/developer_designs/cl_*",
extra_opts="-l", capture=True)
rootLogger.debug(rsync_cap)
rootLogger.debug(rsync_cap.stderr)
rsync_cap = rsync_project(local_dir=ddir + "/../platforms/f1/aws-fpga/{}/*".format(fpgabuilddir),
remote_dir='/home/centos/firesim-build/platforms/f1/aws-fpga/' + remotefpgabuilddir,
exclude='build/checkpoints',
ssh_opts="-o StrictHostKeyChecking=no",
extra_opts="-l", capture=True)
rootLogger.debug(rsync_cap)
rootLogger.debug(rsync_cap.stderr)
# cl_dir is the cl_dir that is either local or remote
# if locally no need to copy things around (the makefile should have already created a CL_DIR w. the tuple
# if remote (aka not locally) then you need to copy things
local_deploy_dir = get_deploy_dir()
cl_dir = ""
if not build_config.local:
cl_dir = pre_remote_build()
else:
cl_dir = "{}/../platforms/f1/aws-fpga/{}".format(local_deploy_dir, fpga_build_dir)
# run the Vivado build
vivado_result = 0
with prefix('cd /home/centos/firesim-build/platforms/f1/aws-fpga'), \
prefix('source hdk_setup.sh'), \
prefix('export CL_DIR=/home/centos/firesim-build/platforms/f1/aws-fpga/' + remotefpgabuilddir), \
prefix('cd $CL_DIR/build/scripts/'), InfoStreamLogger('stdout'), InfoStreamLogger('stderr'), \
settings(warn_only=True):
vivado_result = run('./aws_build_dcp_from_cl.sh -foreground').return_code
with InfoStreamLogger('stdout'), InfoStreamLogger('stderr'):
# copy script to fpgabuidldir and execute
rsync_cap = rsync_project(
local_dir="{}/buildtools/platform-specific-scripts/f1/build-bitstream.sh".format(local_deploy_dir),
remote_dir="{}/".format(cl_dir),
ssh_opts="-o StrictHostKeyChecking=no",
extra_opts="-l", capture=True)
rootLogger.debug(rsync_cap)
rootLogger.debug(rsync_cap.stderr)
# rsync in the reverse direction to get build results
vivado_result = run("{}/build-bitstream.sh {}".format(
cl_dir,
cl_dir))
# put build results in the result-build area
with StreamLogger('stdout'), StreamLogger('stderr'):
rsync_cap = rsync_project(local_dir="""{}/results-build/{}/""".format(ddir, builddir),
remote_dir='/home/centos/firesim-build/platforms/f1/aws-fpga/' + remotefpgabuilddir,
ssh_opts="-o StrictHostKeyChecking=no", upload=False, extra_opts="-l",
capture=True)
rsync_cap = rsync_project(
local_dir="""{}/results-build/{}/""".format(local_deploy_dir, results_dir),
remote_dir="{}/".format(cl_dir),
ssh_opts="-o StrictHostKeyChecking=no", upload=False, extra_opts="-l",
capture=True)
rootLogger.debug(rsync_cap)
rootLogger.debug(rsync_cap.stderr)
@ -138,16 +166,13 @@ def aws_build(global_build_config, bypass=False):
on_build_failure()
return
if not aws_create_afi(global_build_config, buildconfig):
if not aws_create_afi(build_config):
on_build_failure()
return
build_config.provision_build_farm_dispatcher.terminate_build_instance()
rootLogger.info("Terminating the build instance now.")
buildconfig.terminate_build_instance()
def aws_create_afi(global_build_config, buildconfig):
def aws_create_afi(build_config):
"""
Convert the tarball created by Vivado build into an Amazon Global FPGA Image (AGFI)
@ -156,19 +181,19 @@ def aws_create_afi(global_build_config, buildconfig):
## next, do tar -> AGFI
## This is done on the local copy
ddir = get_deploy_dir()
builddir = buildconfig.get_build_dir_name()
local_deploy_dir = get_deploy_dir()
results_dir = build_config.get_build_dir_name()
afi = None
agfi = None
s3bucket = global_build_config.s3_bucketname
afiname = buildconfig.name
s3bucket = build_config.global_build_config.s3_bucketname
afiname = build_config.name
# construct the "tags" we store in the AGFI description
tag_buildtriplet = buildconfig.get_chisel_triplet()
tag_buildtriplet = build_config.get_chisel_triplet()
tag_deploytriplet = tag_buildtriplet
if buildconfig.deploytriplet != "None":
tag_deploytriplet = buildconfig.deploytriplet
if build_config.deploytriplet != "None":
tag_deploytriplet = build_config.deploytriplet
# the asserts are left over from when we tried to do this with tags
# - technically I don't know how long these descriptions are allowed to be,
@ -191,7 +216,7 @@ def aws_create_afi(global_build_config, buildconfig):
# append the build node IP + a random string to diff them in s3
global_append = "-" + str(env.host_string) + "-" + ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(10)) + ".tar"
with lcd("""{}/results-build/{}/cl_firesim/build/checkpoints/to_aws/""".format(ddir, builddir)), StreamLogger('stdout'), StreamLogger('stderr'):
with lcd("""{}/results-build/{}/cl_firesim/build/checkpoints/to_aws/""".format(local_deploy_dir, results_dir)), StreamLogger('stdout'), StreamLogger('stderr'):
files = local('ls *.tar', capture=True)
rootLogger.debug(files)
rootLogger.debug(files.stderr)
@ -211,7 +236,7 @@ def aws_create_afi(global_build_config, buildconfig):
rootLogger.info("Resulting AFI: " + str(afi))
rootLogger.info("Waiting for create-fpga-image completion.")
results_build_dir = """{}/results-build/{}/""".format(ddir, builddir)
results_build_dir = """{}/results-build/{}/""".format(local_deploy_dir, results_dir)
checkstate = "pending"
with lcd(results_build_dir), StreamLogger('stdout'), StreamLogger('stderr'):
while checkstate == "pending":
@ -227,7 +252,11 @@ def aws_create_afi(global_build_config, buildconfig):
copy_afi_to_all_regions(afi)
message_title = "FireSim FPGA Build Completed"
agfi_entry = "[" + afiname + "]\nagfi=" + agfi + "\ndeploytripletoverride=None\ncustomruntimeconfig=None\n\n"
agfi_entry = "[" + afiname + "]\n"
agfi_entry += "deploytripletoverride=None\n"
agfi_entry += "customruntimeconfig=None\n"
agfi_entry += "platform=f1\n"
agfi_entry += agfi + "\n\n"
message_body = "Your AGFI has been created!\nAdd\n" + agfi_entry + "\nto your config_hwdb.ini to use this hardware configuration."
send_firesim_notification(message_title, message_body)
@ -238,14 +267,14 @@ def aws_create_afi(global_build_config, buildconfig):
# for convenience when generating a bunch of images. you can just
# cat all the files in this directory after your builds finish to get
# all the entries to copy into config_hwdb.ini
hwdb_entry_file_location = """{}/built-hwdb-entries/""".format(ddir)
hwdb_entry_file_location = """{}/built-hwdb-entries/""".format(local_deploy_dir)
local("mkdir -p " + hwdb_entry_file_location)
with open(hwdb_entry_file_location + "/" + afiname, "w") as outputfile:
outputfile.write(agfi_entry)
if global_build_config.post_build_hook:
if build_config.global_build_config.post_build_hook:
with StreamLogger('stdout'), StreamLogger('stderr'):
localcap = local("""{} {}""".format(global_build_config.post_build_hook,
localcap = local("""{} {}""".format(build_config.global_build_config.post_build_hook,
results_build_dir,
capture=True))
rootLogger.debug("[localhost] " + str(localcap))

View File

@ -4,66 +4,58 @@ manager """
from time import strftime, gmtime
import ConfigParser
import pprint
import sys
from importlib import import_module
from runtools.runtime_config import RuntimeHWDB
from awstools.awstools import *
from buildtools.provisionbuildfarm import *
from buildtools.build import *
class BuildConfig:
""" This represents a SINGLE build configuration. """
def __init__(self, name, buildconfigdict, launch_time):
def __init__(self, name, buildconfigdict, global_build_config, launch_time):
self.name = name
self.global_build_config = global_build_config
# parsed options
self.TARGET_PROJECT = buildconfigdict.get('TARGET_PROJECT')
self.DESIGN = buildconfigdict['DESIGN']
self.TARGET_CONFIG = buildconfigdict['TARGET_CONFIG']
self.PLATFORM_CONFIG = buildconfigdict['PLATFORM_CONFIG']
self.instancetype = buildconfigdict['instancetype']
self.deploytriplet = buildconfigdict['deploytriplet']
self.launch_time = launch_time
self.launched_instance_object = None
# AJG: assigned by the build recipe
self.fpga_bit_builder_dispatcher = getattr(import_module("buildtools.bitbuilder"), buildconfigdict['fpgaplatform'])(self)
# AJG: assigned by the BuildConfigFile
self.build_host = None
self.local = False
self.provision_build_farm_dispatcher = None
def add_build_host_info(self, build_host, provision_build_farm_class_name, provision_build_farm_args):
self.build_host = build_host
# TODO: if given a local ip addr (not localhost) double check that its localhost
if build_host == "localhost":
self.local = True
if provision_build_farm_class_name:
self.provision_build_farm_dispatcher = getattr(import_module("buildtools.provisionbuildfarm"), provision_build_farm_class_name)(self, provision_build_farm_args)
else:
self.provision_build_farm_dispatcher = ProvisionDefaultBuildFarm(self, provision_build_farm_args)
def __repr__(self):
return "BuildConfig obj:\n" + pprint.pformat(vars(self), indent=10)
return "BuildConfig Object:\n" + pprint.pformat(vars(self), indent=10)
def get_chisel_triplet(self):
return """{}-{}-{}""".format(self.DESIGN, self.TARGET_CONFIG, self.PLATFORM_CONFIG)
def launch_build_instance(self, build_instance_market,
spot_interruption_behavior, spot_max_price,
buildfarmprefix):
""" Launch an instance to run this build.
buildfarmprefix can be None.
"""
buildfarmprefix = '' if buildfarmprefix is None else buildfarmprefix
num_instances = 1
self.launched_instance_object = launch_instances(self.instancetype,
num_instances, build_instance_market,
spot_interruption_behavior,
spot_max_price,
blockdevices=[
{
'DeviceName': '/dev/sda1',
'Ebs': {
'VolumeSize': 200,
'VolumeType': 'gp2',
},
},
],
tags={ 'fsimbuildcluster': buildfarmprefix },
randomsubnet=True)[0]
def get_launched_instance_object(self):
""" Get the instance object returned by boto3 for this build. """
""" Get the instance object for this build. """
return self.launched_instance_object
def get_build_instance_private_ip(self):
""" Get the private IP of the instance running this build. """
return self.launched_instance_object.private_ip_address
def terminate_build_instance(self):
""" Terminate the instance running this build. """
instance_ids = get_instance_ids_for_instances([self.launched_instance_object])
terminate_instances(instance_ids, dryrun=False)
def get_build_dir_name(self):
"""" Get the name of the local build directory. """
return """{}-{}""".format(self.launch_time, self.name)
@ -76,103 +68,3 @@ class BuildConfig:
self.TARGET_CONFIG,
self.PLATFORM_CONFIG,
recipe)
class GlobalBuildConfig:
""" Configuration class for builds. This is the "global" configfile, i.e.
sample_config_build.ini """
def __init__(self, args):
if args.launchtime:
launch_time = args.launchtime
else:
launch_time = strftime("%Y-%m-%d--%H-%M-%S", gmtime())
self.args = args
global_build_configfile = ConfigParser.ConfigParser(allow_no_value=True)
# make option names case sensitive
global_build_configfile.optionxform = str
global_build_configfile.read(args.buildconfigfile)
self.s3_bucketname = \
global_build_configfile.get('afibuild', 's3bucketname')
if valid_aws_configure_creds():
aws_resource_names_dict = aws_resource_names()
if aws_resource_names_dict['s3bucketname'] is not None:
# in tutorial mode, special s3 bucket name
self.s3_bucketname = aws_resource_names_dict['s3bucketname']
self.build_instance_market = \
global_build_configfile.get('afibuild', 'buildinstancemarket')
self.spot_interruption_behavior = \
global_build_configfile.get('afibuild', 'spotinterruptionbehavior')
self.spot_max_price = \
global_build_configfile.get('afibuild', 'spotmaxprice')
self.post_build_hook = global_build_configfile.get('afibuild', 'postbuildhook')
# this is a list of actual builds to run
builds_to_run_list = map(lambda x: x[0], global_build_configfile.items('builds'))
build_recipes_configfile = ConfigParser.ConfigParser(allow_no_value=True)
# make option names case sensitive
build_recipes_configfile.optionxform = str
build_recipes_configfile.read(args.buildrecipesconfigfile)
build_recipes = dict()
for section in build_recipes_configfile.sections():
build_recipes[section] = BuildConfig(section,
dict(build_recipes_configfile.items(section)),
launch_time)
self.agfistoshare = [x[0] for x in global_build_configfile.items('agfistoshare')]
self.acctids_to_sharewith = [x[1] for x in global_build_configfile.items('sharewithaccounts')]
self.hwdb = RuntimeHWDB(args.hwdbconfigfile)
self.builds_list = list(map(lambda x: build_recipes[x], builds_to_run_list))
def launch_build_instances(self):
""" Launch an instance for the builds we want to do """
# get access to the runfarmprefix, which we will apply to build
# instances too now.
aws_resource_names_dict = aws_resource_names()
# just duplicate the runfarmprefix for now. This can be None,
# in which case we give an empty build farm prefix
build_farm_prefix = aws_resource_names_dict['runfarmprefix']
for build in self.builds_list:
build.launch_build_instance(self.build_instance_market,
self.spot_interruption_behavior,
self.spot_max_price,
build_farm_prefix)
def wait_build_instances(self):
""" block until all build instances are launched """
instances = [build.get_launched_instance_object() for build in self.builds_list]
wait_on_instance_launches(instances)
def terminate_all_build_instances(self):
for build in self.builds_list:
build.terminate_build_instance()
def get_build_by_ip(self, nodeip):
""" For a particular private IP (aka instance), return the BuildConfig
that it's supposed to be running. """
for build in self.builds_list:
if build.get_build_instance_private_ip() == nodeip:
return build
return None
def get_build_instance_ips(self):
""" Return a list of all the build instance IPs, i.e. hosts to pass to
fabric. """
return map(lambda x: x.get_build_instance_private_ip(), self.builds_list)
def get_builds_list(self):
return self.builds_list
def __str__(self):
return pprint.pformat(vars(self))

View File

@ -0,0 +1,131 @@
""" This converts the build configuration files into something usable by the
manager """
from time import strftime, gmtime
import ConfigParser
import pprint
import sys
import logging
from runtools.runtime_config import RuntimeHWDB
from awstools.awstools import *
from buildtools.buildconfig import BuildConfig
rootLogger = logging.getLogger()
class BuildConfigFile:
""" Configuration class for builds. This is the "global" configfile, i.e.
sample_config_build.ini """
def __init__(self, args):
if args.launchtime:
launch_time = args.launchtime
else:
launch_time = strftime("%Y-%m-%d--%H-%M-%S", gmtime())
self.args = args
global_build_configfile = ConfigParser.ConfigParser(allow_no_value=True)
# make option names case sensitive
global_build_configfile.optionxform = str
global_build_configfile.read(args.buildconfigfile)
# aws specific options
self.s3_bucketname = global_build_configfile.get('afibuild', 's3bucketname')
if valid_aws_configure_creds():
aws_resource_names_dict = aws_resource_names()
if aws_resource_names_dict['s3bucketname'] is not None:
# in tutorial mode, special s3 bucket name
self.s3_bucketname = aws_resource_names_dict['s3bucketname']
self.build_instance_market = global_build_configfile.get('afibuild', 'buildinstancemarket')
self.spot_interruption_behavior = global_build_configfile.get('afibuild', 'spotinterruptionbehavior')
self.spot_max_price = global_build_configfile.get('afibuild', 'spotmaxprice')
self.post_build_hook = global_build_configfile.get('afibuild', 'postbuildhook')
self.agfistoshare = [x[0] for x in global_build_configfile.items('agfistoshare')]
self.acctids_to_sharewith = [x[1] for x in global_build_configfile.items('sharewithaccounts')]
# this is a list of actual builds to run
builds_to_run_list = map(lambda x: x[0], global_build_configfile.items('builds'))
# get host providers
self.host_providers = dict(global_build_configfile.items("hostproviders"))
self.build_hosts = dict(global_build_configfile.items("buildhosts"))
if len(self.build_hosts) != len(builds_to_run_list):
print("ERROR: needs builds.len != buildhosts.len")
sys.exit(1)
# map build to build recipies
build_recipes_configfile = ConfigParser.ConfigParser(allow_no_value=True)
# make option names case sensitive
build_recipes_configfile.optionxform = str
build_recipes_configfile.read(args.buildrecipesconfigfile)
build_recipes = dict()
for section in build_recipes_configfile.sections():
build_recipes[section] = BuildConfig(section,
dict(build_recipes_configfile.items(section)),
self,
launch_time)
self.hwdb = RuntimeHWDB(args.hwdbconfigfile)
self.builds_list = list(map(lambda x: build_recipes[x], builds_to_run_list))
for idx, build in enumerate(self.builds_list):
# get corresponding host and use it
host_w_args = self.build_hosts[str(idx)]
host_w_args = [s for s in host_w_args.split(",")]
host = host_w_args[0]
host_args = host_w_args[1:]
if host in self.host_providers.keys():
build.add_build_host_info(host, self.host_providers[host], host_args)
else:
build.add_build_host_info(host, None, host_args)
def setup(self):
""" Setup based on the types of buildhosts """
if "f1" in list(map(lambda x: x.build_host, self.builds_list)):
auto_create_bucket(self.s3_bucketname)
#check to see email notifications can be subscribed
get_snsname_arn()
def launch_build_instances(self):
""" Launch an instance for the builds we want to do """
# TODO: optimization: batch together items from the same provisionbuildfarm
for build in self.builds_list:
build.provision_build_farm_dispatcher.launch_build_instance()
def wait_build_instances(self):
""" block until all build instances are launched """
for build in self.builds_list:
build.provision_build_farm_dispatcher.wait_on_instance_launch()
def terminate_all_build_instances(self):
for build in self.builds_list:
build.provision_build_farm_dispatcher.terminate_build_instance()
def get_build_by_ip(self, nodeip):
""" For a particular private IP (aka instance), return the BuildConfig
that it's supposed to be running. """
for build in self.builds_list:
if build.provision_build_farm_dispatcher.get_build_instance_private_ip() == nodeip:
return build
return None
def get_build_instance_ips(self):
""" Return a list of all the build instance IPs, i.e. hosts to pass to
fabric. """
ip_list = []
for build in self.builds_list:
ip_list.append(build.provision_build_farm_dispatcher.get_build_instance_private_ip())
return ip_list
def get_builds_list(self):
return self.builds_list
def __str__(self):
return pprint.pformat(vars(self))

View File

@ -0,0 +1,22 @@
#!/bin/bash
set -e
RISCV=$1
PATH=$2
LD_LIBRARY_PATH=$3
FIRESIM_DIR=$4
MAKE_COMMAND=$5
cd $FIRESIM_DIR
export RISCV=$RISCV
export PATH=$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
source sourceme-f1-manager.sh
# Enter simulation dir
cd sim
$MAKE_COMMAND

View File

@ -0,0 +1,22 @@
#!/bin/bash
set -e
RISCV=$1
PATH=$2
LD_LIBRARY_PATH=$3
FIRESIM_DIR=$4
MAKE_COMMAND=$5
cd $FIRESIM_DIR
export RISCV=$RISCV
export PATH=$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
source sourceme-f1-manager.sh
# Enter simulation dir
cd sim
$MAKE_COMMAND

View File

@ -0,0 +1,111 @@
import logging
from awstools.awstools import *
import sys
rootLogger = logging.getLogger()
class ProvisionBuildFarm:
def __init__(self, build_config, args):
self.build_config = build_config
self.args = args
self.override_remote_build_dir = None
for arg in args:
split_k_v = [s for s in arg.split("=")]
key = split_k_v[0]
value = split_k_v[1]
if key == "rembuilddir":
self.override_remote_build_dir = value
def launch_build_instance(self):
return
def wait_on_instance_launch(self):
return
def get_build_instance_private_ip(self):
return
def terminate_build_instance(self):
return
class ProvisionDefaultBuildFarm(ProvisionBuildFarm):
def launch_build_instance(self):
rootLogger.info("No launch needed for {} host (using {})".format(self.build_config.get_chisel_triplet(), self.build_config.build_host))
return None
def wait_on_instance_launch(self):
rootLogger.info("No waiting needed for {} host (using {})".format(self.build_config.get_chisel_triplet(), self.build_config.build_host))
return
def get_build_instance_private_ip(self):
return self.build_config.build_host
def terminate_build_instance(self):
rootLogger.info("No termination needed for {} host (using {})".format(self.build_config.get_chisel_triplet(), self.build_config.build_host))
return
class ProvisionEC2BuildFarm(ProvisionBuildFarm):
def __init__(self, build_config, args):
ProvisionBuildFarm.__init__(self, build_config, args)
# default values
self.instance_type = "z1d.2xlarge"
for arg in args:
split_k_v = [s for s in arg.split("=")]
key = split_k_v[0]
value = split_k_v[1]
if key == "insttype":
self.instance_type = value
def launch_build_instance(self):
globalbuildconf = self.build_config.global_build_config
buildconf = self.build_config
# get access to the runfarmprefix, which we will apply to build
# instances too now.
aws_resource_names_dict = aws_resource_names()
# just duplicate the runfarmprefix for now. This can be None,
# in which case we give an empty build farm prefix
build_farm_prefix = aws_resource_names_dict['runfarmprefix']
build_instance_market = globalbuildconf.build_instance_market
spot_interruption_behavior = globalbuildconf.spot_interruption_behavior
spot_max_price = globalbuildconf.spot_max_price
buildfarmprefix = '' if build_farm_prefix is None else build_farm_prefix
num_instances = 1
buildconf.launched_instance_object = launch_instances(
self.instance_type,
num_instances,
build_instance_market,
spot_interruption_behavior,
spot_max_price,
blockdevices=[
{
'DeviceName': '/dev/sda1',
'Ebs': {
'VolumeSize': 200,
'VolumeType': 'gp2',
},
},
],
tags={ 'fsimbuildcluster': buildfarmprefix },
randomsubnet=True)[0]
def wait_on_instance_launch(self):
wait_on_instance_launches([self.build_config.launched_instance_object])
def get_build_instance_private_ip(self):
""" Get the private IP of the instance running this build. """
return self.build_config.launched_instance_object.private_ip_address
def terminate_build_instance(self):
""" Terminate the instance running this build. """
instance_ids = get_instance_ids_for_instances([self.build_config.launched_instance_object])
rootLogger.info("Terminating build instances {}".format(instance_ids))
terminate_instances(instance_ids, dryrun=False)

View File

@ -22,7 +22,9 @@ from awstools.afitools import *
# firesim buildtools
from buildtools.buildafi import *
from buildtools.buildconfig import GlobalBuildConfig
from buildtools.build import *
from buildtools.buildconfigfile import BuildConfigFile
from buildtools.buildconfig import BuildConfig
from util.streamlogger import StreamLogger
@ -97,6 +99,10 @@ def buildafi(globalbuildconf):
""" Starting from local Chisel, build an AFI for all of the specified
hardware configs. """
for buildconf in globalbuildconf.get_builds_list():
execute(replace_rtl, buildconf, hosts=['localhost'])
execute(build_driver, buildconf, hosts=['localhost'])
@parallel
def instance_liveness():
""" confirm that all instances are running first. """
@ -104,11 +110,6 @@ def buildafi(globalbuildconf):
with StreamLogger('stdout'), StreamLogger('stderr'):
run("uname -a")
auto_create_bucket(globalbuildconf.s3_bucketname)
#check to see email notifications can be subscribed
get_snsname_arn()
def terminate_instances_handler(sig, frame):
""" Handler that prompts to terminate build instances if you press ctrl-c. """
rootLogger.info("You pressed ctrl-c, so builds have been killed.")
@ -122,8 +123,9 @@ def buildafi(globalbuildconf):
signal.signal(signal.SIGINT, terminate_instances_handler)
for buildconf in globalbuildconf.get_builds_list():
execute(replace_rtl, globalbuildconf, buildconf, hosts=['localhost'])
# pre-setup stuff (things that need to be done before instances are spawned/killed)
# specific to the buildhost
globalbuildconf.setup()
# local items (replace_rtl) need to be called in a loop, for each config
# remote items will map themselves

View File

@ -1,14 +1,6 @@
# BUILDTIME/AGFI management configuration for the FireSim Simulation Manager
# See docs/Advanced-Usage/Manager/Manager-Configuration-Files.rst for documentation of all of these params.
[afibuild]
s3bucketname=firesim-AWSUSERNAME
buildinstancemarket=ondemand
spotinterruptionbehavior=terminate
spotmaxprice=ondemand
postbuildhook=
[builds]
# this section references builds defined in config_build_recipes.ini
# if you add a build here, it will be built when you run buildafi
@ -19,7 +11,7 @@ postbuildhook=
# Uncore: 800 MHz
# <Async Crossing>
# DRAM : 1000 MHz
firesim-rocket-quadcore-no-nic-l2-llc4mb-ddr3
firesim-rocket-quadcore-no-nic-l2-llc4mb-ddr3=localbuildhost
firesim-boom-singlecore-no-nic-l2-llc4mb-ddr3
# All NIC-based designs use the legacy FireSim frequency selection, with the
@ -32,6 +24,27 @@ firesim-boom-singlecore-nic-l2-llc4mb-ddr3
# firesim-singlecore-sha3-no-nic-l2-llc4mb-ddr3
# firesim-singlecore-sha3-print-no-nic-l2-llc4mb-ddr3
### Build Hosts ###
# Note: For large designs (ones that would fill a EC2.2xlarge/Xilinx VU9P)
# Vivado uses in excess of 32 GiB. Keep this in mind when selecting a
# non-default instancetype.
[defaultbuildhost]
providerclass=ProvisionEC2BuildFarm
instancetype=z1d.2xlarge
s3bucketname=firesim-AWSUSERNAME
buildinstancemarket=ondemand
spotinterruptionbehavior=terminate
spotmaxprice=ondemand
postbuildhook=
remotebuilddir=
[localbuildhost]
providerclass=ProvisionDefaultBuildFarm
ipaddr=localhost
### AWS F1 Specific options ###
[agfistoshare]
firesim-rocket-quadcore-nic-l2-llc4mb-ddr3
firesim-rocket-quadcore-no-nic-l2-llc4mb-ddr3

View File

@ -5,17 +5,12 @@
# edit config_build.ini to actually "turn on" a config to be built when you run
# buildafi
# Note: For large designs (ones that would fill a EC2.2xlarge/Xilinx VU9P)
# Vivado uses in excess of 32 GiB. Keep this in mind when selecting a
# non-default instancetype.
# Quad-core, Rocket-based recipes
[firesim-rocket-quadcore-nic-l2-llc4mb-ddr3]
DESIGN=FireSim
TARGET_CONFIG=WithNIC_DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimHighPerfConfigTweaks_chipyard.QuadRocketConfig
PLATFORM_CONFIG=WithAutoILA_F90MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# NB: This has a faster host-clock frequency than the NIC-based design, because
@ -24,16 +19,13 @@ deploytriplet=None
DESIGN=FireSim
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimTestChipConfigTweaks_chipyard.QuadRocketConfig
PLATFORM_CONFIG=WithAutoILA_F140MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# Single-core, BOOM-based recipes
[firesim-boom-singlecore-nic-l2-llc4mb-ddr3]
DESIGN=FireSim
TARGET_CONFIG=WithNIC_DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimHighPerfConfigTweaks_chipyard.LargeBoomConfig
PLATFORM_CONFIG=WithAutoILA_F65MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# NB: This has a faster host-clock frequency than the NIC-based design, because
@ -42,43 +34,34 @@ deploytriplet=None
DESIGN=FireSim
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimTestChipConfigTweaks_chipyard.LargeBoomConfig
PLATFORM_CONFIG=WithAutoILA_F75MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# Single-core, CVA6-based recipes
[firesim-cva6-singlecore-no-nic-l2-llc4mb-ddr3]
DESIGN=FireSim
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimConfigTweaks_chipyard.CVA6Config
PLATFORM_CONFIG=WithAutoILA_F90MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# Single-core, Rocket-based recipes with Gemmini
[firesim-rocket-singlecore-gemmini-no-nic-l2-llc4mb-ddr3]
DESIGN=FireSim
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimConfigTweaks_chipyard.GemminiRocketConfig
PLATFORM_CONFIG=WithAutoILA_F110MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# RAM Optimizations enabled by adding _MCRams PLATFORM_CONFIG string
[firesim-boom-singlecore-no-nic-l2-llc4mb-ddr3-ramopts]
DESIGN=FireSim
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimTestChipConfigTweaks_chipyard.LargeBoomConfig
PLATFORM_CONFIG=WithAutoILA_MCRams_F90MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# Supernode configurations -- multiple instances of an SoC in a single simulator
[firesim-supernode-rocket-singlecore-nic-l2-lbp]
DESIGN=FireSim
TARGET_CONFIG=WithNIC_SupernodeFireSimRocketConfig
PLATFORM_CONFIG=WithAutoILA_F85MHz_BaseF1Config
instancetype=z1d.2xlarge
deploytriplet=None
# MIDAS Examples -- BUILD SUPPORT ONLY; Can't launch driver correctly on runfarm
@ -87,5 +70,4 @@ TARGET_PROJECT=midasexamples
DESIGN=GCD
TARGET_CONFIG=NoConfig
PLATFORM_CONFIG=DefaultF1Config
instancetype=z1d.2xlarge
deploytriplet=None

View File

@ -163,6 +163,9 @@ DRIVER_CXXOPTS ?= -O2
$(PLATFORM) = $(OUTPUT_DIR)/$(DESIGN)-$(PLATFORM)
$(PLATFORM): $($(PLATFORM))
.PHONY: driver
driver: $($(PLATFORM))
fpga_dir = $(firesim_base_dir)/../platforms/$(PLATFORM)/aws-fpga
$(f1): export CXXFLAGS := $(CXXFLAGS) $(common_cxx_flags) $(DRIVER_CXXOPTS) -I$(fpga_dir)/sdk/userspace/include
@ -175,7 +178,7 @@ $(f1): $(header) $(DRIVER_CC) $(DRIVER_H) $(midas_cc) $(midas_h)
cp $(header) $(OUTPUT_DIR)/build/
# The manager expects to find the default conf in output/ by this name
cp -f $(GENERATED_DIR)/$(CONF_NAME) $(OUTPUT_DIR)/runtime.conf
$(MAKE) -C $(simif_dir) f1 PLATFORM=f1 DRIVER_NAME=$(DESIGN) GEN_FILE_BASENAME=$(BASE_FILE_NAME) \
$(MAKE) -C $(simif_dir) $(PLATFORM) PLATFORM=$(PLATFORM) DRIVER_NAME=$(DESIGN) GEN_FILE_BASENAME=$(BASE_FILE_NAME) \
GEN_DIR=$(OUTPUT_DIR)/build OUT_DIR=$(OUTPUT_DIR) DRIVER="$(DRIVER_CC)" \
TOP_DIR=$(chipyard_dir)