Merge remote-tracking branch 'origin/dev' into chisel-3.5-published
This commit is contained in:
commit
5b62907400
|
@ -1 +0,0 @@
|
|||
*.pyc
|
|
@ -1,17 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, manager_hostname
|
||||
from ci_variables import ci_workflow_id
|
||||
|
||||
def build_default_workloads():
|
||||
""" Builds workloads that will be run on F1 instances as part of CI """
|
||||
|
||||
with prefix('cd {} && source ./env.sh'.format(manager_fsim_dir)), \
|
||||
prefix('cd deploy/workloads'):
|
||||
run("marshal -v build br-base.json")
|
||||
run("make linux-poweroff")
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute(build_default_workloads, hosts=[manager_hostname(ci_workflow_id)])
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Changes the state of instances associated with the CI run's unique tag.
|
||||
# Where a run is a workflow in CircleCI. Can be used to start, stop, or
|
||||
# terminate. This may run from either the manager or from the CI instance.
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
import common
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('tag_value',
|
||||
help = "The tag used to identify workflow instances.")
|
||||
parser.add_argument('state_change',
|
||||
choices = ['terminate', 'stop', 'start'],
|
||||
help = "The state transition to initiate on workflow instances.")
|
||||
|
||||
args = parser.parse_args()
|
||||
common.change_workflow_instance_states(args.tag_value, args.state_change)
|
|
@ -1,265 +0,0 @@
|
|||
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference
|
||||
version: 2.1
|
||||
orbs:
|
||||
aws-cli: circleci/aws-cli@1.0.0
|
||||
executors:
|
||||
main-env:
|
||||
docker:
|
||||
- image: firesim/firesim-ci:v1.1
|
||||
user: "centos"
|
||||
environment:
|
||||
JVM_MEMORY: 3500M # Default JVM maximum heap limit
|
||||
LANG: en_US.UTF-8 # required by sbt when it sees boost directories
|
||||
MARSHAL_JLEVEL: 8 # This is unset by default, leading to starvation conditions on the manager
|
||||
aws:
|
||||
docker:
|
||||
- image: cimg/python:2.7-node
|
||||
|
||||
commands:
|
||||
machinelaunchscript:
|
||||
description: "Run firesim's machine launch script"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
cd scripts && /usr/bin/bash ./machine-launch-script.sh
|
||||
|
||||
install-ci-python-reqs:
|
||||
description: "Installs python deps for manager-managing CI container"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
pip install -r .circleci/requirements.txt
|
||||
|
||||
buildsetup:
|
||||
description: "Run firesim's build-setup.sh"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
./build-setup.sh fast
|
||||
|
||||
scala-build:
|
||||
description: "Compile all relevant Scala sources for CI"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
source env.sh
|
||||
make -C sim TARGET_PROJECT=midasexamples sbt SBT_COMMAND=test:compile
|
||||
|
||||
build-scala-doc:
|
||||
description: "Compiles Scala Doc"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
source env.sh
|
||||
make -C sim scaladoc
|
||||
|
||||
push-scaladoc-to-ghpages:
|
||||
description: "Pushes scaladoc to ghphage branch"
|
||||
steps:
|
||||
# The default SSH key does not have write permissions
|
||||
- add_ssh_keys:
|
||||
fingerprint:
|
||||
- 0e:d9:c3:3b:62:03:7a:da:17:1f:a9:5a:4f:34:50:4c
|
||||
- run:
|
||||
command: |
|
||||
git config --global user.email "biancolin@berkeley.edu"
|
||||
git config --global user.name "circleci"
|
||||
- when:
|
||||
condition: << pipeline.git.tag >>
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
source env.sh
|
||||
export SBT_GHPAGES_COMMIT_MESSAGE="[ci skip] Update scaladoc for << pipeline.git.tag >> release"
|
||||
make -C sim TARGET_PROJECT=midasexamples sbt SBT_COMMAND='set apiDirectory := \"<< pipeline.git.tag >>\"; ghpagesPushSite'
|
||||
- unless:
|
||||
condition: << pipeline.git.tag >>
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
source env.sh
|
||||
export SBT_GHPAGES_COMMIT_MESSAGE="[ci skip] Update scaladoc for dev:<< pipeline.git.revision >>"
|
||||
make -C sim TARGET_PROJECT=midasexamples sbt SBT_COMMAND="ghpagesPushSite"
|
||||
|
||||
run-scala-test:
|
||||
description: "Runs the scala test with name <test-package>.<test-name>"
|
||||
parameters:
|
||||
target-project:
|
||||
type: string
|
||||
default: "midasexamples"
|
||||
test-name:
|
||||
type: string
|
||||
test-package:
|
||||
type: string
|
||||
default: "firesim.midasexamples"
|
||||
timeout:
|
||||
type: string
|
||||
default: "120m"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
.circleci/run-scala-test.py << parameters.target-project >> << parameters.test-package >>.<< parameters.test-name >>
|
||||
no_output_timeout: << parameters.timeout >>
|
||||
|
||||
|
||||
initialize-manager:
|
||||
description: "Setups the manager instance and firesim repo"
|
||||
parameters:
|
||||
max-runtime-hours:
|
||||
type: integer
|
||||
timeout:
|
||||
type: string
|
||||
default: "30m"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
.circleci/initialize-manager.py << parameters.max-runtime-hours >>
|
||||
no_output_timeout: << parameters.timeout >>
|
||||
|
||||
# This avoids a race that occurs when multiple cold scala compilations are launched at the same time.
|
||||
initial-scala-compile:
|
||||
description: "Initial Scala Compilation"
|
||||
parameters:
|
||||
timeout:
|
||||
type: string
|
||||
default: "30m"
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
.circleci/run-sbt-command.py firesim test:compile
|
||||
no_output_timeout: << parameters.timeout >>
|
||||
|
||||
repo-setup:
|
||||
description: "Runs all baseline setup tasks up to scala compilation in the CI container."
|
||||
steps:
|
||||
- checkout
|
||||
- machinelaunchscript
|
||||
- buildsetup
|
||||
- scala-build
|
||||
|
||||
repo-setup-aws:
|
||||
description: "Runs all baseline setup to interact with a AWS-hosted manager instance"
|
||||
steps:
|
||||
- checkout
|
||||
- aws-cli/setup
|
||||
- install-ci-python-reqs
|
||||
|
||||
jobs:
|
||||
setup-default-manager:
|
||||
executor: aws
|
||||
environment:
|
||||
TERM: xterm-256color
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run:
|
||||
name: Initialize FireSim manager
|
||||
command: |
|
||||
.circleci/launch-manager-instance.py
|
||||
- initialize-manager:
|
||||
max-runtime-hours: 10
|
||||
- initial-scala-compile
|
||||
|
||||
build-default-workloads:
|
||||
description: "Invokes marshal to build the default rootfs."
|
||||
executor: aws
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run:
|
||||
command: |
|
||||
.circleci/build-default-workloads.py
|
||||
no_output_timeout: 30m
|
||||
|
||||
run-manager-pytests:
|
||||
executor: aws
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run:
|
||||
command: .circleci/run-manager-pytests.py
|
||||
|
||||
run-test-groupA:
|
||||
executor: aws
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run-scala-test:
|
||||
test-name: "CIGroupA"
|
||||
|
||||
run-test-groupB:
|
||||
executor: aws
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run-scala-test:
|
||||
test-name: "CIGroupB"
|
||||
|
||||
run-chipyard-tests:
|
||||
executor: aws
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run-scala-test:
|
||||
target-project: "firesim"
|
||||
test-package: "firesim.firesim"
|
||||
test-name: "CITests"
|
||||
|
||||
publish-scala-doc:
|
||||
executor: main-env
|
||||
steps:
|
||||
- repo-setup
|
||||
- build-scala-doc
|
||||
- push-scaladoc-to-ghpages
|
||||
|
||||
cull-old-ci-instances:
|
||||
executor: aws
|
||||
steps:
|
||||
- repo-setup-aws
|
||||
- run:
|
||||
name: Cull Old CI AWS Instances
|
||||
command: |
|
||||
.circleci/cull-old-ci-instances.py
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
firesimCIall:
|
||||
jobs:
|
||||
- setup-default-manager
|
||||
|
||||
- build-default-workloads:
|
||||
requires:
|
||||
- setup-default-manager
|
||||
|
||||
- run-test-groupA:
|
||||
requires:
|
||||
- setup-default-manager
|
||||
|
||||
- run-test-groupB:
|
||||
requires:
|
||||
- run-test-groupA
|
||||
|
||||
- run-chipyard-tests:
|
||||
requires:
|
||||
- run-test-groupB
|
||||
|
||||
- run-manager-pytests:
|
||||
requires:
|
||||
- setup-default-manager
|
||||
|
||||
# This uses a CI container, not a manager instance
|
||||
- publish-scala-doc:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- dev
|
||||
tags:
|
||||
only:
|
||||
- /[0-9]*\.[0-9]*\.[0-9]*/
|
||||
|
||||
cull-old-ci-instances:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "0 0,12 * * *"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- dev
|
||||
jobs:
|
||||
- cull-old-ci-instances
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
fabric==1.14.0
|
||||
boto3==1.6.2
|
||||
pytz
|
||||
pyyaml
|
|
@ -1,15 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, manager_hostname
|
||||
from ci_variables import ci_workflow_id
|
||||
|
||||
def run_manager_pytests():
|
||||
""" Runs all manager pytests """
|
||||
|
||||
with cd(manager_fsim_dir), prefix('source env.sh'):
|
||||
run("cd deploy && python -m pytest")
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute(run_manager_pytests, hosts=[manager_hostname(ci_workflow_id)])
|
|
@ -1,21 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, manager_hostname
|
||||
from ci_variables import ci_workflow_id
|
||||
|
||||
def run_scala_test(target_project, test_name):
|
||||
""" Runs a scala test under the desired target project
|
||||
|
||||
target_project -- The make variable to select the desired target project makefrag
|
||||
|
||||
test_name -- the full classname of the test
|
||||
"""
|
||||
with cd(manager_fsim_dir), prefix('source env.sh'):
|
||||
run("make -C sim testOnly TARGET_PROJECT={} SCALA_TEST={}".format(target_project, test_name))
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute(run_scala_test, sys.argv[1], sys.argv[2], hosts = [manager_hostname(ci_workflow_id)])
|
|
@ -1,72 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# Runs in the background on a manager instance to determine when it can be torn
|
||||
# down by polling the workflow's state using CircleCI's v2.0 restful api.
|
||||
#
|
||||
# Terminate instances if:
|
||||
# - the workflow is successful (all jobs complete successfully)
|
||||
# - the workflow is cancelled
|
||||
# Stop instances if:
|
||||
# - the workflow has failed (all jobs have completed, but at least one has failed)
|
||||
#
|
||||
# Other states to consider: not_run, on_hold, unauthorized
|
||||
|
||||
import httplib
|
||||
import time
|
||||
import sys
|
||||
import base64
|
||||
import json
|
||||
|
||||
from common import terminate_workflow_instances, stop_workflow_instances
|
||||
|
||||
# Time between HTTPS requests to circleci
|
||||
POLLING_INTERVAL_SECONDS = 60
|
||||
# Number of failed requests before stopping the instances
|
||||
QUERY_FAILURE_THRESHOLD = 10
|
||||
|
||||
# We should never get to 'not_run' or 'unauthorized' but terminate for good measure
|
||||
TERMINATE_STATES = ['success', 'canceled', 'not_run', 'unauthorized']
|
||||
STOP_STATES = ['failed', 'error']
|
||||
NOP_STATES = ['running', 'failing']
|
||||
|
||||
def main(workflow_id, circle_ci_token):
|
||||
|
||||
state = None
|
||||
consecutive_failures = 0
|
||||
auth_token = base64.b64encode(b"{}:", circle_ci_token)
|
||||
headers = {'authorization': "Basic {}".format(auth_token)}
|
||||
|
||||
while True:
|
||||
time.sleep(POLLING_INTERVAL_SECONDS)
|
||||
|
||||
conn = httplib.HTTPSConnection("circleci.com")
|
||||
conn.request("GET", "/api/v2/workflow/{}".format(workflow_id), headers=headers)
|
||||
|
||||
res = conn.getresponse()
|
||||
|
||||
if res.status == httplib.OK:
|
||||
consecutive_failures = 0
|
||||
res_dict = json.load(res)
|
||||
state = res_dict["status"]
|
||||
|
||||
print "Workflow {} status: {}".format(workflow_id, state)
|
||||
if state in TERMINATE_STATES:
|
||||
terminate_workflow_instances(workflow_id)
|
||||
exit(0)
|
||||
elif state in STOP_STATES:
|
||||
stop_workflow_instances(workflow_id)
|
||||
exit(0)
|
||||
elif state not in NOP_STATES:
|
||||
print "Unexpected Workflow State: {}".format(state)
|
||||
raise ValueError
|
||||
|
||||
else:
|
||||
print "HTTP GET error: {} {}. Retrying.".format(res.status, res.reason)
|
||||
consecutive_failures = consecutive_failures + 1
|
||||
if consecutive_failures == QUERY_FAILURE_THRESHOLD:
|
||||
stop_workflow_instances(workflow_id)
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1], sys.argv[2])
|
|
@ -0,0 +1,46 @@
|
|||
FireSim Continuous Integration
|
||||
==============================
|
||||
|
||||
Helpful Links:
|
||||
* Workflow GUI - https://github.com/firesim/firesim/actions
|
||||
* Chipyard Explanation of Github Actions (GH-A) - https://github.com/ucb-bar/chipyard/blob/dev/.github/CI_README.md
|
||||
|
||||
Github Actions (GH-A) Description
|
||||
---------------------------------
|
||||
|
||||
Much of the following CI infrastructure is based on the Chipyard CI.
|
||||
For a basic explanation of how the GH-A CI works, see https://github.com/ucb-bar/chipyard/blob/dev/.github/CI_README.md.
|
||||
However, there are a couple of notable differences/comments as follows:
|
||||
|
||||
* In order to provide a fresh environment to test changes, the CI dynamically spawns a AWS instance and sets up GH-A
|
||||
to use this instance as a GH-A self-hosted runner (see https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
|
||||
* All scripts that run on the manager instance use Fabric with `localhost` and each GH-A step must include `runs-on: ${{ github.run_id }}` KV pair to indicate that you want to run directly on a runner that is on the manager instance.
|
||||
* Currently only 4 runners are spawned per workflow (reused across multiple workflow runs - i.e. clicking rerun). Every commit gets its own manager instance and 4 runners that run on the manager instance.
|
||||
* When the CI terminates/stops an instance, the CI automatically deregisters the runners from GH-A (any runner API calls require a personal token with the `repo` scope).
|
||||
* The CI structure is as follows:
|
||||
1. Launch the manager instance + setup the N self-hosted runners.
|
||||
2. Run the original initialization (add the firesim.pem, run the build setup, etc).
|
||||
3. Continue with the rest of the tests using the GH-A runners.
|
||||
|
||||
|
||||
Running FPGA-related Tasks
|
||||
--------------------------
|
||||
|
||||
CI now includes the capability to run FPGA-simulations on specific PRs.
|
||||
However, by default, this requires approval from the `firesim-fpga-approval` team (called a "deployment").
|
||||
You can gain approval to run FPGA-simulations in two ways.
|
||||
|
||||
1. Each member in the `firesim-fpga-approval` team will receive an email asking for approval on a specific PR. From that email, they can approve the request and run the FPGA-simulation tests.
|
||||
2. From the workflow run GUI (go to https://github.com/firesim/firesim/actions and click a specific workflow run) a `firesim-fpga-approval` team member can approve the deployment (note this button only shows up once the job that needs approval is reached).
|
||||
|
||||
Debugging Failures
|
||||
------------------
|
||||
|
||||
When a failure occurs on the manager instance the CI will stop or terminate the instance (terminate if your instance is using the spot market).
|
||||
Currently, the only way to access any running instance that is created from the CI is to do the following:
|
||||
|
||||
1. Request the CI PEM file needed to SSH into the CI instances (ask the FireSim developers)
|
||||
2. Obtain the public IP address from the "Launch AWS instance used for the FireSim manager (instance info found here)" (which runs the `launch-manager-instance.py` script) step in the `setup-self-hosted-manager` job in the CI.
|
||||
3. SSH into the instance and do any testing required.
|
||||
|
||||
If the instance is stopped, then you must request a AWS IAM user account from the FireSim developers to access the EC2 console and restart the instance.
|
|
@ -0,0 +1,10 @@
|
|||
name: build-scala-doc
|
||||
description: "Compiles Scala Doc"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
source env.sh
|
||||
make -C sim scaladoc
|
||||
shell: bash
|
|
@ -0,0 +1,8 @@
|
|||
name: buildsetup
|
||||
description: "Run firesim's build-setup.sh"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: ./build-setup.sh fast
|
||||
shell: bash
|
|
@ -0,0 +1,8 @@
|
|||
name: initial-scala-compile
|
||||
description: "Initial Scala Compilation"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: .github/scripts/run-sbt-command.py firesim test:compile
|
||||
shell: bash
|
|
@ -0,0 +1,13 @@
|
|||
name: initialize-manager
|
||||
description: "Sets up the manager instance and firesim repo"
|
||||
|
||||
inputs:
|
||||
max-runtime-hours:
|
||||
description: "Max runtime hours"
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: .github/scripts/initialize-manager.py ${{ inputs.max-runtime-hours }}
|
||||
shell: bash
|
|
@ -0,0 +1,10 @@
|
|||
name: install-ci-python-reqs
|
||||
description: "Installs python deps for manager-managing CI container"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
pip3 install --upgrade pip==21.3.1
|
||||
python3 -m pip install -r .github/scripts/requirements.txt
|
||||
shell: bash
|
|
@ -0,0 +1,8 @@
|
|||
name: job-end
|
||||
description: "Save a job status"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: echo "success" > run_result
|
||||
shell: bash
|
|
@ -0,0 +1,19 @@
|
|||
name: job-start
|
||||
description: "Setup a job status"
|
||||
outputs:
|
||||
run_result:
|
||||
value: ${{ steps.run_result.outputs.run_result }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Restore the previous run result
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: run_result
|
||||
key: ${{ github.run_id }}-${{ github.job }}
|
||||
restore-keys: ${{ github.run_id }}-${{ github.job }}
|
||||
- name: Set run_result to default or use cached value
|
||||
id: run_result
|
||||
run: echo "::set-output name=run_result::$(cat run_result 2>/dev/null || echo 'default')"
|
||||
shell: bash
|
|
@ -0,0 +1,10 @@
|
|||
name: machinelaunchscript
|
||||
description: "Run FireSim's machine-launch-script.sh"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
sudo yum -y remove git git224 git224-core ius-release.noarch # remove any older git versions and collateral first
|
||||
cd scripts/ && /usr/bin/bash machine-launch-script.sh
|
||||
shell: bash
|
|
@ -0,0 +1,27 @@
|
|||
name: push-scaladoc-to-ghpages
|
||||
description: "Pushes scaladoc to ghphage branch"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install SSH key for Github.com
|
||||
uses: webfactory/ssh-agent@v0.5.4
|
||||
with:
|
||||
ssh-private-key: ${{ env.FIRESIM-REPO-DEP-KEY }}
|
||||
|
||||
- run: |
|
||||
git config --global user.email "abe.gonzalez@berkeley.edu"
|
||||
git config --global user.name "github-actions"
|
||||
shell: bash
|
||||
|
||||
- run: |
|
||||
if [[ "${{ github.ref_type }}" != 'tag' ]]; then
|
||||
source env.sh
|
||||
export SBT_GHPAGES_COMMIT_MESSAGE="[ci skip] Update scaladoc for ${{ github.ref_type }} release"
|
||||
make -C sim TARGET_PROJECT=midasexamples sbt SBT_COMMAND='set apiDirectory := \"${{ github.ref_type }}\"; ghpagesPushSite'
|
||||
else
|
||||
source env.sh
|
||||
export SBT_GHPAGES_COMMIT_MESSAGE="[ci skip] Update scaladoc for dev:${{ github.sha }}"
|
||||
make -C sim TARGET_PROJECT=midasexamples sbt SBT_COMMAND="ghpagesPushSite"
|
||||
fi
|
||||
shell: bash
|
|
@ -0,0 +1,17 @@
|
|||
name: repo-setup-aws
|
||||
description: "Runs all baseline setup to interact with a AWS-hosted manager instance"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: ${{ env.AWS-ACCESS-KEY-ID }}
|
||||
aws-secret-access-key: ${{ env.AWS-SECRET-ACCESS-KEY }}
|
||||
aws-region: ${{ env.AWS-DEFAULT-REGION }}
|
||||
- name: Install SSH key
|
||||
uses: shimataro/ssh-key-action@v2
|
||||
with:
|
||||
key: ${{ env.FIRESIM_PEM }}
|
||||
known_hosts: unnecessary
|
||||
- uses: ./.github/actions/install-ci-python-reqs
|
|
@ -0,0 +1,9 @@
|
|||
name: repo-setup
|
||||
description: "Runs all baseline setup tasks up to scala compilation in the CI container."
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: ./.github/actions/machinelaunchscript
|
||||
- uses: ./.github/actions/buildsetup
|
||||
- uses: ./.github/actions/scala-build
|
|
@ -0,0 +1,22 @@
|
|||
name: run-scala-test
|
||||
description: "Runs the scala test with name <test-package>.<test-name>"
|
||||
|
||||
inputs:
|
||||
target-project:
|
||||
description: "Target project"
|
||||
required: false
|
||||
default: "midasexamples"
|
||||
test-name:
|
||||
description: "Test name"
|
||||
required: true
|
||||
test-package:
|
||||
description: "Test package"
|
||||
required: false
|
||||
default: "firesim.midasexamples"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
.github/scripts/run-scala-test.py ${{ inputs.target-project }} ${{ inputs.test-package }}.${{ inputs.test-name }}
|
||||
shell: bash
|
|
@ -0,0 +1,10 @@
|
|||
name: scala-build
|
||||
description: "Compile all relevant Scala sources for CI"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
source env.sh
|
||||
make -C sim TARGET_PROJECT=midasexamples sbt SBT_COMMAND=test:compile
|
||||
shell: bash
|
|
@ -6,13 +6,14 @@ RUN yum -y install sudo epel-release
|
|||
RUN yum -y install python-pip
|
||||
# Match the version on the dev ami
|
||||
RUN pip2 install --upgrade pip==18.0
|
||||
# Provide a baseline of version for circle CI to use.
|
||||
# If Circle CI uses its native version to initialize the repo, future submodule
|
||||
# Provide a baseline of version for GH-A CI to use.
|
||||
# If GH-A CI uses its native version to initialize the repo, future submodule
|
||||
# initializations with the machine-launch installed version of git produce very
|
||||
# non-intuitive results
|
||||
# (the chipyard submodule is initialized to an apparently random commit)
|
||||
# If we want to get rid of this we could reclone the repo under the updated git
|
||||
RUN yum -y install git
|
||||
RUN yum -y install https://repo.ius.io/ius-release-el7.rpm
|
||||
RUN yum -y install git224
|
||||
|
||||
RUN adduser centos
|
||||
RUN usermod -aG wheel centos
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, set_fabric_firesim_pem
|
||||
|
||||
def build_default_workloads():
|
||||
""" Builds workloads that will be run on F1 instances as part of CI """
|
||||
|
||||
with prefix('cd {} && source ./env.sh'.format(manager_fsim_dir)), \
|
||||
prefix('cd deploy/workloads'):
|
||||
|
||||
# avoid logging excessive amounts to prevent GH-A masking secrets (which slows down log output)
|
||||
with settings(warn_only=True):
|
||||
rc = run("marshal -v build br-base.json &> br-base.full.log").return_code
|
||||
if rc != 0:
|
||||
run("cat br-base.full.log")
|
||||
raise Exception("Building br-base.json failed to run")
|
||||
|
||||
run("make linux-poweroff")
|
||||
run("make allpaper")
|
||||
|
||||
if __name__ == "__main__":
|
||||
set_fabric_firesim_pem()
|
||||
execute(build_default_workloads, hosts=["localhost"])
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Changes the state of instances associated with the CI workflow run's unique tag.
|
||||
# Can be used to start, stop, or terminate. This may run from either the manager
|
||||
# or from the CI instance.
|
||||
|
||||
import argparse
|
||||
|
||||
from common import change_workflow_instance_states
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('tag_value',
|
||||
help = "The tag used to identify workflow instances.")
|
||||
parser.add_argument('state_change',
|
||||
choices = ['terminate', 'stop', 'start'],
|
||||
help = "The state transition to initiate on workflow instances.")
|
||||
parser.add_argument('github_api_token',
|
||||
help = "API token to modify self-hosted runner state.")
|
||||
|
||||
args = parser.parse_args()
|
||||
change_workflow_instance_states(args.github_api_token, args.tag_value, args.state_change)
|
|
@ -5,9 +5,9 @@ import os
|
|||
|
||||
# CI instance environment variables
|
||||
# This is used as a unique tag for all instances launched in a workflow
|
||||
ci_workflow_id = os.environ['CIRCLE_WORKFLOW_ID']
|
||||
ci_commit_sha1 = os.environ['CIRCLE_SHA1']
|
||||
ci_workflow_run_id = os.environ['GITHUB_RUN_ID']
|
||||
ci_commit_sha1 = os.environ['GITHUB_SHA']
|
||||
# expanduser to replace the ~ present in the default, for portability
|
||||
ci_workdir = os.path.expanduser(os.environ['CIRCLE_WORKING_DIRECTORY'])
|
||||
ci_api_token = os.environ['CIRCLE_CI_API_TOKEN']
|
||||
|
||||
ci_workdir = os.path.expanduser(os.environ['GITHUB_WORKSPACE'])
|
||||
ci_api_token = os.environ['GITHUB_TOKEN']
|
||||
ci_personal_api_token = os.environ['PERSONAL_ACCESS_TOKEN']
|
|
@ -1,21 +1,31 @@
|
|||
import sys
|
||||
import boto3
|
||||
import os
|
||||
from fabric.api import *
|
||||
import requests
|
||||
|
||||
# Reuse manager utilities
|
||||
from ci_variables import ci_workdir
|
||||
sys.path.append(ci_workdir + "/deploy/awstools")
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__)) + "/../.."
|
||||
sys.path.append(script_dir + "/deploy/awstools")
|
||||
from awstools import get_instances_with_filter
|
||||
|
||||
# Remote paths
|
||||
manager_home_dir = "/home/centos"
|
||||
manager_fsim_dir = "/home/centos/firesim"
|
||||
manager_fsim_pem = manager_home_dir + "/firesim.pem"
|
||||
manager_fsim_dir = manager_home_dir + "/firesim"
|
||||
manager_marshal_dir = manager_fsim_dir + "/target-design/chipyard/software/firemarshal"
|
||||
manager_ci_dir = manager_fsim_dir + "/.circleci"
|
||||
manager_ci_dir = manager_fsim_dir + "/.github/scripts"
|
||||
|
||||
# Common fabric settings
|
||||
env.output_prefix = False
|
||||
env.abort_on_prompts = True
|
||||
env.timeout = 100
|
||||
env.connection_attempts = 10
|
||||
env.disable_known_hosts = True
|
||||
env.keepalive = 60 # keep long SSH connections running
|
||||
|
||||
def set_fabric_firesim_pem():
|
||||
env.key_filename = manager_fsim_pem
|
||||
|
||||
# This tag is common to all instances launched as part of a given workflow
|
||||
unique_tag_key = 'ci-workflow-id'
|
||||
|
@ -35,7 +45,7 @@ def get_manager_tag_dict(sha, tag_value):
|
|||
unique_tag_key: tag_value}
|
||||
|
||||
def get_manager_instance(tag_value):
|
||||
""" Looks up the manager instance dict using the CI run's unique tag"""
|
||||
""" Looks up the manager instance dict using the CI workflow run's unique tag"""
|
||||
instances = get_instances_with_filter([get_ci_filter(tag_value), manager_filter])
|
||||
if instances:
|
||||
assert len(instances) == 1
|
||||
|
@ -44,7 +54,7 @@ def get_manager_instance(tag_value):
|
|||
return None
|
||||
|
||||
def get_manager_instance_id(tag_value):
|
||||
""" Looks up the manager instance ID using the CI run's unique tag"""
|
||||
""" Looks up the manager instance ID using the CI workflow run's unique tag"""
|
||||
|
||||
manager = get_manager_instance(tag_value)
|
||||
if manager is None:
|
||||
|
@ -54,7 +64,7 @@ def get_manager_instance_id(tag_value):
|
|||
return manager['InstanceId']
|
||||
|
||||
def get_manager_ip(tag_value):
|
||||
""" Looks up the manager IP using the CI run's unique tag"""
|
||||
""" Looks up the manager IP using the CI workflow run's unique tag"""
|
||||
|
||||
manager = get_manager_instance(tag_value)
|
||||
if manager is None:
|
||||
|
@ -67,7 +77,7 @@ def manager_hostname(tag_value):
|
|||
return "centos@{}".format(get_manager_ip(tag_value))
|
||||
|
||||
def get_all_workflow_instances(tag_value):
|
||||
""" Grabs a list of all instance dicts sharing the CI run's unique tag """
|
||||
""" Grabs a list of all instance dicts sharing the CI workflow run's unique tag """
|
||||
return get_instances_with_filter([get_ci_filter(tag_value)])
|
||||
|
||||
def instance_metadata_str(instance):
|
||||
|
@ -83,9 +93,26 @@ def instance_metadata_str(instance):
|
|||
|
||||
return static_md + dynamic_md
|
||||
|
||||
def deregister_runner_if_exists(gh_token, runner_name):
|
||||
headers = {'Authorization': "token {}".format(gh_token.strip())}
|
||||
|
||||
def change_workflow_instance_states(tag_value, state_change, dryrun=False):
|
||||
""" Change the state of all instances sharing the same CI run's tag. """
|
||||
# Check if exists before deregistering
|
||||
r = requests.get("https://api.github.com/repos/firesim/firesim/actions/runners", headers=headers)
|
||||
if r.status_code != 200:
|
||||
# if couldn't delete then just exit
|
||||
return
|
||||
|
||||
res_dict = r.json()
|
||||
runner_list = res_dict["runners"]
|
||||
for runner in runner_list:
|
||||
if runner_name in runner["name"]:
|
||||
r = requests.delete("https://api.github.com/repos/firesim/firesim/actions/runners/{}".format(runner["id"]), headers=headers)
|
||||
if r.status_code != 204:
|
||||
# if couldn't delete then just exit
|
||||
return
|
||||
|
||||
def change_workflow_instance_states(gh_token, tag_value, state_change, dryrun=False):
|
||||
""" Change the state of all instances sharing the same CI workflow run's tag. """
|
||||
|
||||
all_instances = get_all_workflow_instances(tag_value)
|
||||
manager_instance = get_manager_instance(tag_value)
|
||||
|
@ -100,6 +127,7 @@ def change_workflow_instance_states(tag_value, state_change, dryrun=False):
|
|||
client = boto3.client('ec2')
|
||||
if state_change == 'stop':
|
||||
print("Stopping instances: {}".format(", ".join(instance_ids)))
|
||||
deregister_runner_if_exists(gh_token, tag_value)
|
||||
client.stop_instances(InstanceIds=instance_ids, DryRun=dryrun)
|
||||
elif state_change == 'start':
|
||||
print("Starting instances: {}".format(", ".join(instance_ids)))
|
||||
|
@ -116,15 +144,16 @@ def change_workflow_instance_states(tag_value, state_change, dryrun=False):
|
|||
|
||||
elif state_change == 'terminate':
|
||||
print("Terminating instances: {}".format(", ".join(instance_ids)))
|
||||
deregister_runner_if_exists(gh_token, tag_value)
|
||||
client.terminate_instances(InstanceIds=instance_ids, DryRun=dryrun)
|
||||
else:
|
||||
raise ValueError("Unrecognized transition type: {}".format(state_change))
|
||||
|
||||
def terminate_workflow_instances(tag_value, dryrun=False):
|
||||
change_workflow_instance_states(tag_value, "terminate", dryrun)
|
||||
def terminate_workflow_instances(gh_token, tag_value, dryrun=False):
|
||||
change_workflow_instance_states(gh_token, tag_value, "terminate", dryrun)
|
||||
|
||||
def stop_workflow_instances(tag_value, dryrun=False):
|
||||
change_workflow_instance_states(tag_value, "stop", dryrun)
|
||||
def stop_workflow_instances(gh_token, tag_value, dryrun=False):
|
||||
change_workflow_instance_states(gh_token, tag_value, "stop", dryrun)
|
||||
|
||||
def start_workflow_instances(tag_value, dryrun=False):
|
||||
change_workflow_instance_states(tag_value, "start", dryrun)
|
||||
def start_workflow_instances(gh_token, tag_value, dryrun=False):
|
||||
change_workflow_instance_states(gh_token, tag_value, "start", dryrun)
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Runs periodically in it's own workflow in the CI/CD environment to teardown
|
||||
# instances that have exceeded a lifetime limit
|
||||
|
@ -8,10 +8,10 @@ import pytz
|
|||
import boto3
|
||||
import sys
|
||||
|
||||
from common import unique_tag_key
|
||||
from common import unique_tag_key, deregister_runner_if_exists
|
||||
|
||||
# Reuse manager utilities
|
||||
from ci_variables import ci_workdir
|
||||
from ci_variables import ci_workdir, ci_personal_api_token, ci_workflow_run_id
|
||||
sys.path.append(ci_workdir + "/deploy/awstools")
|
||||
from awstools import get_instances_with_filter
|
||||
|
||||
|
@ -27,12 +27,13 @@ def main():
|
|||
all_ci_instances = get_instances_with_filter([all_ci_instances_filter], allowed_states=['*'])
|
||||
|
||||
client = boto3.client('ec2')
|
||||
print "Terminated Instances:"
|
||||
print("Terminated Instances:")
|
||||
for inst in all_ci_instances:
|
||||
lifetime_secs = (current_time - inst["LaunchTime"]).total_seconds()
|
||||
if lifetime_secs > (INSTANCE_LIFETIME_LIMIT_HOURS * 3600):
|
||||
deregister_runner_if_exists(ci_personal_api_token, ci_workflow_run_id):
|
||||
client.terminate_instances(InstanceIds=[inst["InstanceId"]])
|
||||
print " " + inst["InstanceId"]
|
||||
print(" " + inst["InstanceId"])
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,16 @@
|
|||
#! /usr/bin/env expect
|
||||
|
||||
set timeout -1
|
||||
|
||||
set token [lindex $argv 0]
|
||||
set runner_name [lindex $argv 1]
|
||||
set unique_label [lindex $argv 2]
|
||||
|
||||
spawn ./config.sh --url https://github.com/firesim/firesim --token $token
|
||||
|
||||
send -- "\r"
|
||||
send -- "$runner_name\r"
|
||||
send -- "$unique_label\r"
|
||||
send -- "\r"
|
||||
|
||||
expect eof
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import traceback
|
||||
import time
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
|
@ -12,20 +13,24 @@ def initialize_manager(max_runtime):
|
|||
""" Performs the prerequisite tasks for all CI jobs that will run on the manager instance
|
||||
|
||||
max_runtime (hours): The maximum uptime this manager and its associated
|
||||
instances should have before it is stopped. This serves as a redundant check
|
||||
instances should have before it is stopped. This serves as a redundant check
|
||||
in case the workflow-monitor is brought down for some reason.
|
||||
"""
|
||||
|
||||
# Catch any exception that occurs so that we can gracefully teardown
|
||||
try:
|
||||
put(ci_workdir + "/scripts/machine-launch-script.sh", manager_home_dir)
|
||||
# wait until machine launch is complete
|
||||
with cd(manager_home_dir):
|
||||
run("chmod +x machine-launch-script.sh")
|
||||
run("sudo ./machine-launch-script.sh")
|
||||
run("git clone https://github.com/firesim/firesim.git")
|
||||
# add firesim.pem
|
||||
with open(manager_fsim_pem, "w") as pem_file:
|
||||
pem_file.write(os.environ["FIRESIM_PEM"])
|
||||
local("chmod 600 {}".format(manager_fsim_pem))
|
||||
set_fabric_firesim_pem()
|
||||
|
||||
# copy ci version of the repo into the new globally accessible location
|
||||
run("git clone {} {}".format(ci_workdir, manager_fsim_dir))
|
||||
|
||||
with cd(manager_fsim_dir):
|
||||
run("git checkout " + ci_commit_sha1)
|
||||
run("./build-setup.sh --fast")
|
||||
|
||||
# Initialize marshal submodules early because it appears some form of
|
||||
|
@ -36,27 +41,27 @@ def initialize_manager(max_runtime):
|
|||
run("./init-submodules.sh")
|
||||
|
||||
with cd(manager_fsim_dir), prefix("source ./sourceme-f1-manager.sh"):
|
||||
run(".circleci/firesim-managerinit.expect {} {} {}".format(
|
||||
os.environ["AWS_ACCESS_KEY_ID"],
|
||||
os.environ["AWS_SECRET_ACCESS_KEY"],
|
||||
os.environ["AWS_DEFAULT_REGION"]))
|
||||
run(".github/scripts/firesim-managerinit.expect {} {} {}".format(
|
||||
os.environ["AWS-ACCESS-KEY-ID"],
|
||||
os.environ["AWS-SECRET-ACCESS-KEY"],
|
||||
os.environ["AWS-DEFAULT-REGION"]))
|
||||
|
||||
with cd(manager_ci_dir):
|
||||
# Put a baseline time-to-live bound on the manager.
|
||||
# Instances will be stopped and cleaned up in a nightly job.
|
||||
# Instances will be terminated (since they are spot requests) and cleaned up in a nightly job.
|
||||
|
||||
# Setting pty=False is required to stop the screen from being
|
||||
# culled when the SSH session associated with teh run command ends.
|
||||
run("screen -S ttl -dm bash -c \'sleep {}; ./change-workflow-instance-states.py {} stop\'"
|
||||
.format(int(max_runtime) * 3600, ci_workflow_id), pty=False)
|
||||
# culled when the SSH session associated with the run command ends.
|
||||
run("screen -S ttl -dm bash -c \'sleep {}; ./change-workflow-instance-states.py {} terminate {}\'"
|
||||
.format(int(max_runtime) * 3600, ci_workflow_run_id, ci_personal_api_token), pty=False)
|
||||
run("screen -S workflow-monitor -L -dm ./workflow-monitor.py {} {}"
|
||||
.format(ci_workflow_id, ci_api_token), pty=False)
|
||||
.format(ci_workflow_run_id, ci_personal_api_token), pty=False)
|
||||
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
terminate_workflow_instances(ci_workflow_id)
|
||||
terminate_workflow_instances(ci_personal_api_token, ci_workflow_run_id)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
max_runtime = sys.argv[1]
|
||||
execute(initialize_manager, max_runtime, hosts=[manager_hostname(ci_workflow_id)])
|
||||
execute(initialize_manager, max_runtime, hosts=["localhost"])
|
|
@ -1,11 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Used to launch a fresh manager instance from the CI container.
|
||||
|
||||
import sys
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
# This must run in the CI container
|
||||
from ci_variables import *
|
||||
from common import *
|
||||
|
@ -16,7 +14,7 @@ import awstools
|
|||
|
||||
def main():
|
||||
""" Spins up a new manager instance for our CI run """
|
||||
manager_instance = get_manager_instance(ci_workflow_id)
|
||||
manager_instance = get_manager_instance(ci_workflow_run_id)
|
||||
if manager_instance is not None:
|
||||
print("There is an existing manager instance for this CI workflow:")
|
||||
print(instance_metadata_str(manager_instance))
|
||||
|
@ -27,11 +25,13 @@ def main():
|
|||
'launch',
|
||||
'--inst_type', 'z1d.2xlarge',
|
||||
'--block_devices', str([{'DeviceName':'/dev/sda1','Ebs':{'VolumeSize':300,'VolumeType':'gp2'}}]),
|
||||
'--tags', str(get_manager_tag_dict(ci_commit_sha1, ci_workflow_id))])
|
||||
manager_instance = get_manager_instance(ci_workflow_id)
|
||||
'--tags', str(get_manager_tag_dict(ci_commit_sha1, ci_workflow_run_id)),
|
||||
'--user_data_file', ci_workdir + "/scripts/machine-launch-script.sh"
|
||||
])
|
||||
manager_instance = get_manager_instance(ci_workflow_run_id)
|
||||
|
||||
print("Instance ready.")
|
||||
print(instance_metadata_str(get_manager_instance(ci_workflow_id)))
|
||||
print(instance_metadata_str(get_manager_instance(ci_workflow_run_id)))
|
||||
sys.stdout.flush()
|
||||
|
||||
if __name__ == "__main__":
|
|
@ -0,0 +1,5 @@
|
|||
fab-classic==1.19.1
|
||||
boto3==1.20.21
|
||||
pytz
|
||||
pyyaml
|
||||
requests
|
|
@ -0,0 +1,88 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, manager_ci_dir, manager_fsim_pem, set_fabric_firesim_pem
|
||||
|
||||
import sys
|
||||
|
||||
def run_build_recipes_ini_api_tests():
|
||||
""" Test config_{build, build_recipes}.ini APIs """
|
||||
|
||||
def commands_to_run(commands, opts):
|
||||
""" Run a list of commands with the specified opts """
|
||||
for command in commands:
|
||||
with prefix('cd {} && source sourceme-f1-manager.sh'.format(manager_fsim_dir)):
|
||||
rc = 0
|
||||
with settings(warn_only=True):
|
||||
rc = run("{} {}".format(command, opts)).return_code
|
||||
if rc == 0:
|
||||
print("{} passed unexpectedly.".format(command))
|
||||
|
||||
# exit since passing is not wanted
|
||||
sys.exit(1)
|
||||
|
||||
def run_test(name):
|
||||
# test files should exist on the manager already
|
||||
test_dir = "{}/ini-tests/failing-buildafi-files/{}".format(manager_ci_dir, name)
|
||||
|
||||
commands_to_run(
|
||||
["firesim buildafi"],
|
||||
"-b {}/sample_config_build.ini -r {}/sample_config_build_recipes.ini".format(test_dir, test_dir))
|
||||
|
||||
run_test("invalid-build-section")
|
||||
run_test("invalid-recipe-inst-type")
|
||||
|
||||
# test invalid config_build.ini
|
||||
commands_to_run(["firesim buildafi"], "-b ~/GHOST_FILE")
|
||||
|
||||
# test invalid config_build_recipes.ini
|
||||
commands_to_run(["firesim buildafi"], "-r ~/GHOST_FILE")
|
||||
|
||||
def run_runtime_hwdb_ini_api_tests():
|
||||
""" Test config_{runtime, hwdb}.ini APIs """
|
||||
|
||||
def commands_to_run(commands, opts):
|
||||
""" Run a list of commands with the specified opts """
|
||||
for command in commands:
|
||||
with prefix('cd {} && source sourceme-f1-manager.sh'.format(manager_fsim_dir)):
|
||||
rc = 0
|
||||
with settings(warn_only=True):
|
||||
rc = run("{} {}".format(command, opts)).return_code
|
||||
if rc == 0:
|
||||
print("{} passed unexpectedly.".format(command))
|
||||
|
||||
# test passed so make sure to terminate runfarm
|
||||
run("firesim terminaterunfarm -q {}".format(opts))
|
||||
|
||||
# exit since passing is not wanted
|
||||
sys.exit(1)
|
||||
|
||||
def run_test(name):
|
||||
# test files should exist on the manager already
|
||||
test_dir = "{}/ini-tests/failing-runtime-files/{}".format(manager_ci_dir, name)
|
||||
|
||||
commands_to_run(
|
||||
["firesim launchrunfarm", "firesim infrasetup", "firesim runworkload", "firesim terminaterunfarm -q"],
|
||||
"-c {}/sample_config_runtime.ini -a {}/sample_config_hwdb.ini".format(test_dir, test_dir))
|
||||
|
||||
run_test("hwdb-invalid-afi")
|
||||
run_test("runtime-invalid-hwconfig")
|
||||
run_test("runtime-invalid-topology")
|
||||
run_test("runtime-invalid-workloadname")
|
||||
|
||||
# test invalid config_runtime.ini
|
||||
commands_to_run(["firesim launchrunfarm", "firesim infrasetup", "firesim runworkload", "firesim terminaterunfarm -q"], "-c ~/GHOST_FILE")
|
||||
|
||||
# test invalid config_hwdb.ini
|
||||
commands_to_run(["firesim launchrunfarm", "firesim infrasetup", "firesim runworkload", "firesim terminaterunfarm -q"], "-a ~/GHOST_FILE")
|
||||
|
||||
def run_ini_api_tests():
|
||||
""" Test manager .ini file APIs """
|
||||
|
||||
run_build_recipes_ini_api_tests()
|
||||
run_runtime_hwdb_ini_api_tests()
|
||||
|
||||
if __name__ == "__main__":
|
||||
set_fabric_firesim_pem()
|
||||
execute(run_ini_api_tests, hosts=["localhost"])
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, set_fabric_firesim_pem
|
||||
|
||||
def run_linux_poweroff():
|
||||
""" Runs Linux poweroff workloads """
|
||||
|
||||
with prefix('cd {} && source sourceme-f1-manager.sh'.format(manager_fsim_dir)):
|
||||
run("cd sw/firesim-software && ./marshal -v build br-base.json && ./marshal -v install br-base.json")
|
||||
run("cd deploy/workloads/ && make linux-poweroff")
|
||||
|
||||
def run_w_timeout(workload, timeout):
|
||||
""" Run workload with a specific timeout
|
||||
|
||||
:arg: workload (str) - workload ini (abs path)
|
||||
:arg: timeout (str) - timeout amount for the workload to run
|
||||
"""
|
||||
rc = 0
|
||||
with settings(warn_only=True):
|
||||
# avoid logging excessive amounts to prevent GH-A masking secrets (which slows down log output)
|
||||
# pty=False needed to avoid issues with screen -ls stalling in fabric
|
||||
rc = run("timeout {} ./deploy/workloads/run-workload.sh {} --withlaunch &> {}.log".format(timeout, workload, workload), pty=False).return_code
|
||||
if rc != 0:
|
||||
# need to confirm that instance is off
|
||||
print("Workload {} failed. Printing last lines of log. See {}.log for full info".format(workload, workload))
|
||||
print("Log start:")
|
||||
run("tail -n 100 {}.log".format(workload))
|
||||
print("Log end.")
|
||||
print("Terminating workload")
|
||||
run("firesim terminaterunfarm -q -c {}".format(workload))
|
||||
sys.exit(rc)
|
||||
else:
|
||||
print("Workload {} successful.".format(workload))
|
||||
|
||||
run_w_timeout("{}/deploy/workloads/linux-poweroff-all-no-nic.ini".format(manager_fsim_dir), "30m")
|
||||
run_w_timeout("{}/deploy/workloads/linux-poweroff-nic.ini".format(manager_fsim_dir), "30m")
|
||||
|
||||
if __name__ == "__main__":
|
||||
set_fabric_firesim_pem()
|
||||
execute(run_linux_poweroff, hosts=["localhost"])
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, set_fabric_firesim_pem
|
||||
|
||||
def run_manager_pytests():
|
||||
""" Runs all manager pytests """
|
||||
|
||||
with cd(manager_fsim_dir), prefix('source env.sh'):
|
||||
run("cd deploy && python3 -m pytest")
|
||||
|
||||
if __name__ == "__main__":
|
||||
set_fabric_firesim_pem()
|
||||
execute(run_manager_pytests, hosts=["localhost"])
|
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, manager_hostname
|
||||
from ci_variables import ci_workflow_id
|
||||
from common import manager_fsim_dir, manager_hostname, set_fabric_firesim_pem
|
||||
from ci_variables import ci_workflow_run_id
|
||||
|
||||
def run_sbt_command(target_project, command):
|
||||
""" Runs a command in SBT shell for the default project specified by the target_project makefrag
|
||||
|
@ -19,4 +19,5 @@ def run_sbt_command(target_project, command):
|
|||
run("make -C sim sbt SBT_COMMAND={} TARGET_PROJECT={}".format(command, target_project))
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute(run_sbt_command, sys.argv[1], sys.argv[2], hosts=[manager_hostname(ci_workflow_id)])
|
||||
set_fabric_firesim_pem()
|
||||
execute(run_sbt_command, sys.argv[1], sys.argv[2], hosts=["localhost"])
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import manager_fsim_dir, set_fabric_firesim_pem
|
||||
|
||||
def run_scala_test(target_project, test_name):
|
||||
""" Runs a scala test under the desired target project
|
||||
|
||||
target_project -- The make variable to select the desired target project makefrag
|
||||
|
||||
test_name -- the full classname of the test
|
||||
"""
|
||||
with cd(manager_fsim_dir), prefix('source env.sh'):
|
||||
# avoid logging excessive amounts to prevent GH-A masking secrets (which slows down log output)
|
||||
with settings(warn_only=True):
|
||||
rc = run("make -C sim testOnly TARGET_PROJECT={} SCALA_TEST={} &> scala-test.full.log".format(target_project, test_name)).return_code
|
||||
if rc != 0:
|
||||
run("cat scala-test.full.log")
|
||||
raise Exception("Running scala test failed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
set_fabric_firesim_pem()
|
||||
execute(run_scala_test, sys.argv[1], sys.argv[2], hosts = ["localhost"])
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import traceback
|
||||
import time
|
||||
import requests
|
||||
import sys
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
from common import *
|
||||
# This is expected to be launch from the ci container
|
||||
from ci_variables import *
|
||||
|
||||
def initialize_manager_hosted():
|
||||
""" Performs the prerequisite tasks for all CI jobs that will run on the manager instance
|
||||
|
||||
max_runtime (hours): The maximum uptime this manager and its associated
|
||||
instances should have before it is stopped. This serves as a redundant check
|
||||
in case the workflow-monitor is brought down for some reason.
|
||||
"""
|
||||
|
||||
# Catch any exception that occurs so that we can gracefully teardown
|
||||
try:
|
||||
# wait until machine launch is complete
|
||||
with cd(manager_home_dir):
|
||||
with settings(warn_only=True):
|
||||
rc = run("timeout 10m grep -q '.*machine launch script complete.*' <(tail -f machine-launchstatus)").return_code
|
||||
if rc != 0:
|
||||
run("cat machine-launchstatus.log")
|
||||
raise Exception("machine-launch-script.sh failed to run")
|
||||
|
||||
# get the runner version based off the latest tag on the github runner repo
|
||||
RUNNER_VERSION = local("git ls-remote --refs --tags https://github.com/actions/runner.git | cut --delimiter='/' --fields=3 | tr '-' '~' | sort --version-sort | tail --lines=1", capture=True)
|
||||
RUNNER_VERSION = RUNNER_VERSION.replace("v", "")
|
||||
print("Using Github Actions Runner v{}".format(RUNNER_VERSION))
|
||||
# create NUM_RUNNER self-hosted runners on the manager that run in parallel
|
||||
NUM_RUNNERS = 4
|
||||
for runner_idx in range(NUM_RUNNERS):
|
||||
actions_dir = "{}/actions-runner-{}".format(manager_home_dir, runner_idx)
|
||||
run("mkdir -p {}".format(actions_dir))
|
||||
with cd(actions_dir):
|
||||
run("curl -o actions-runner-linux-x64-{}.tar.gz -L https://github.com/actions/runner/releases/download/v{}/actions-runner-linux-x64-{}.tar.gz".format(RUNNER_VERSION, RUNNER_VERSION, RUNNER_VERSION))
|
||||
run("tar xzf ./actions-runner-linux-x64-{}.tar.gz".format(RUNNER_VERSION))
|
||||
|
||||
# install deps
|
||||
run("sudo ./bin/installdependencies.sh")
|
||||
|
||||
# get registration token from API
|
||||
headers = {'Authorization': "token {}".format(ci_personal_api_token.strip())}
|
||||
r = requests.post("https://api.github.com/repos/firesim/firesim/actions/runners/registration-token", headers=headers)
|
||||
if r.status_code != 201:
|
||||
raise Exception("HTTPS error: {} {}. Retrying.".format(r.status_code, r.json()))
|
||||
|
||||
res_dict = r.json()
|
||||
reg_token = res_dict["token"]
|
||||
|
||||
# config runner
|
||||
put(".github/scripts/gh-a-runner.expect", actions_dir)
|
||||
run("chmod +x gh-a-runner.expect")
|
||||
runner_name = "{}-{}".format(ci_workflow_run_id, runner_idx) # used to teardown runner
|
||||
unique_label = ci_workflow_run_id # used within the yaml to choose a runner
|
||||
run("./gh-a-runner.expect {} {} {}".format(reg_token, runner_name, unique_label))
|
||||
|
||||
# start runner
|
||||
# Setting pty=False is required to stop the screen from being
|
||||
# culled when the SSH session associated with the run command ends.
|
||||
run("screen -S gh-a-runner-{} -L -dm ./run.sh".format(runner_idx), pty=False)
|
||||
|
||||
# double check that screen is setup properly
|
||||
with settings(warn_only=True):
|
||||
rc = run("screen -ls | grep \"gh-a-runner-{}\"".format(runner_idx)).return_code
|
||||
if rc != 0:
|
||||
run("cat screenlog.*")
|
||||
raise Exception("There was an issue with setting up Github Actions runner {}".format(runner_idx))
|
||||
|
||||
except BaseException as e:
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
terminate_workflow_instances(ci_personal_api_token, ci_workflow_run_id)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute(initialize_manager_hosted, hosts=[manager_hostname(ci_workflow_run_id)])
|
|
@ -0,0 +1,71 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Runs in the background on a manager instance to determine when it can be torn
|
||||
# down by polling the workflow's state using GitHub Actions's RESTful api.
|
||||
#
|
||||
# Site: https://docs.github.com/en/rest/reference/actions#get-a-workflow-run
|
||||
#
|
||||
# Terminate instances if:
|
||||
# - the workflow is successful (all jobs complete successfully)
|
||||
# - the workflow is cancelled
|
||||
# Stop instances if:
|
||||
# - the workflow has failed (all jobs have completed, but at least one has failed)
|
||||
#
|
||||
# Other states to consider: not_run, on_hold, unauthorized
|
||||
|
||||
import time
|
||||
import sys
|
||||
import requests
|
||||
|
||||
from common import terminate_workflow_instances, stop_workflow_instances
|
||||
|
||||
# Time between HTTPS requests to github
|
||||
POLLING_INTERVAL_SECONDS = 60
|
||||
# Number of failed requests before stopping the instances
|
||||
QUERY_FAILURE_THRESHOLD = 10
|
||||
|
||||
# We should never get to 'not_run' or 'unauthorized' but terminate for good measure
|
||||
TERMINATE_STATES = ["cancelled", "success", "skipped", "stale"]
|
||||
STOP_STATES = ["failure", "timed_out"]
|
||||
NOP_STATES = ["action_required"] # TODO: unsure when this happens
|
||||
|
||||
def main(workflow_id, gha_ci_personal_token):
|
||||
|
||||
state = None
|
||||
consecutive_failures = 0
|
||||
headers = {'Authorization': "token {}".format(gha_ci_personal_token.strip())}
|
||||
|
||||
while True:
|
||||
time.sleep(POLLING_INTERVAL_SECONDS)
|
||||
|
||||
res = requests.get("https://api.github.com/repos/firesim/firesim/actions/runs/{}".format(workflow_id), headers=headers)
|
||||
if res.status_code == 200:
|
||||
consecutive_failures = 0
|
||||
res_dict = res.json()
|
||||
state_status = res_dict["status"]
|
||||
state_concl = res_dict["conclusion"]
|
||||
|
||||
print("Workflow {} status: {} {}".format(workflow_id, state_status, state_concl))
|
||||
if state_status in ['completed']:
|
||||
if state_concl in TERMINATE_STATES:
|
||||
terminate_workflow_instances(gha_ci_personal_token, workflow_id)
|
||||
exit(0)
|
||||
elif state_concl in STOP_STATES:
|
||||
stop_workflow_instances(gha_ci_personal_token, workflow_id)
|
||||
exit(0)
|
||||
elif state_concl not in NOP_STATES:
|
||||
print("Unexpected Workflow State On Completed: {}".format(state_concl))
|
||||
raise ValueError
|
||||
elif state_status not in ['in_progress', 'queued', 'waiting', 'requested']:
|
||||
print("Unexpected Workflow State: {}".format(state_status))
|
||||
raise ValueError
|
||||
|
||||
else:
|
||||
print("HTTP GET error: {}. Retrying.".format(res.json()))
|
||||
consecutive_failures = consecutive_failures + 1
|
||||
if consecutive_failures == QUERY_FAILURE_THRESHOLD:
|
||||
stop_workflow_instances(gha_ci_personal_token, workflow_id)
|
||||
exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1], sys.argv[2])
|
|
@ -0,0 +1,26 @@
|
|||
name: firesim-cull-instances
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0,12 * * *"
|
||||
|
||||
env:
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_A_PERSONAL_ACCESS_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AWS-ACCESS-KEY-ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS-SECRET-ACCESS-KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS-DEFAULT-REGION: ${{ secrets.AWS_DEFAULT_REGION }}
|
||||
FIRESIM_PEM: ${{ secrets.FIRESIM_PEM }}
|
||||
|
||||
jobs:
|
||||
cull-old-ci-instances:
|
||||
name: cull-old-ci-instances
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: dev
|
||||
- uses: ./.github/actions/repo-setup-aws
|
||||
- run: .github/scripts/cull-old-ci-instances.py
|
|
@ -0,0 +1,34 @@
|
|||
name: firesim-publish-scala-doc
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
tags:
|
||||
- '[0-9]*.[0-9]*.[0-9]*'
|
||||
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AWS-ACCESS-KEY-ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS-SECRET-ACCESS-KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS-DEFAULT-REGION: ${{ secrets.AWS_DEFAULT_REGION }}
|
||||
FIRESIM_PEM: ${{ secrets.FIRESIM_PEM }}
|
||||
FIRESIM-REPO-DEP-KEY: ${{ secrets.FIRESIM_REPO_DEP_KEY }}
|
||||
LANG: "en_US.UTF-8" # required by SBT when it sees boost directories
|
||||
LANGUAGE: "en_US:en"
|
||||
LC_ALL: "en_US.UTF-8"
|
||||
|
||||
jobs:
|
||||
publish-scala-doc:
|
||||
name: publish-scala-doc
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: firesim/firesim-ci:v1.3
|
||||
options: --entrypoint /bin/bash
|
||||
env:
|
||||
JVM_MEMORY: 3500M # Default JVM maximum heap limit
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/repo-setup
|
||||
- uses: ./.github/actions/build-scala-doc
|
||||
- uses: ./.github/actions/push-scaladoc-to-ghpages
|
|
@ -0,0 +1,204 @@
|
|||
name: firesim-ci-process
|
||||
|
||||
on:
|
||||
# run ci when pring to dev/master/main (note: ci runs on the merge commit of the pr!)
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
- master
|
||||
- main
|
||||
|
||||
env:
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_A_PERSONAL_ACCESS_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
AWS-ACCESS-KEY-ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS-SECRET-ACCESS-KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
AWS-DEFAULT-REGION: ${{ secrets.AWS_DEFAULT_REGION }}
|
||||
FIRESIM_PEM: ${{ secrets.FIRESIM_PEM }}
|
||||
LANG: "en_US.UTF-8" # required by SBT when it sees boost directories
|
||||
LANGUAGE: "en_US:en"
|
||||
LC_ALL: "en_US.UTF-8"
|
||||
|
||||
jobs:
|
||||
cancel-prior-workflows:
|
||||
name: cancel-prior-workflows
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- name: Cancel previous workflow runs
|
||||
uses: styfle/cancel-workflow-action@0.9.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
setup-self-hosted-manager:
|
||||
name: setup-self-hosted-manager
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Install Python CI requirements
|
||||
uses: ./.github/actions/repo-setup-aws
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- name: Launch AWS instance used for the FireSim manager (instance info found here)
|
||||
run: ./.github/scripts/launch-manager-instance.py
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- name: Setup N Github Actions Runners on AWS instance
|
||||
run: ./.github/scripts/setup-manager-self-hosted.py
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
setup-manager:
|
||||
name: setup-manager
|
||||
needs: [setup-self-hosted-manager]
|
||||
runs-on: ${{ github.run_id }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Setup FireSim repo (.pem, build-setup.sh, AWS credentials, submodules) and CI daemons
|
||||
uses: ./.github/actions/initialize-manager
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
with:
|
||||
max-runtime-hours: 10
|
||||
- name: Initial Scala compilation
|
||||
uses: ./.github/actions/initial-scala-compile
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
build-default-workloads:
|
||||
name: build-default-workloads
|
||||
needs: [setup-manager]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Build default workloads (FireMarshal and paper workloads)
|
||||
run: .github/scripts/build-default-workloads.py
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
run-manager-pytests:
|
||||
name: run-manager-pytests
|
||||
needs: [setup-manager]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Run pytests
|
||||
run: .github/scripts/run-manager-pytests.py
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
run-test-groupA:
|
||||
name: run-test-groupA
|
||||
needs: [setup-manager]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Run CIGroupA Scala tests
|
||||
uses: ./.github/actions/run-scala-test
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
with:
|
||||
test-name: "CIGroupA"
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
run-test-groupB:
|
||||
name: run-test-groupB
|
||||
needs: [run-test-groupA]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Run CIGroupB Scala tests
|
||||
uses: ./.github/actions/run-scala-test
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
with:
|
||||
test-name: "CIGroupB"
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
run-chipyard-tests:
|
||||
name: run-chipyard-tests
|
||||
needs: [run-test-groupB]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Run other (CITests) Scala tests
|
||||
uses: ./.github/actions/run-scala-test
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
with:
|
||||
target-project: "firesim"
|
||||
test-package: "firesim.firesim"
|
||||
test-name: "CITests"
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
run-basic-linux-poweroff:
|
||||
name: run-basic-linux-poweroff
|
||||
needs: [build-default-workloads]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
environment: use-fpgas
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Run linux-poweroff test
|
||||
run: .github/scripts/run-linux-poweroff.py
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
run-ini-api-tests:
|
||||
name: run-ini-api-tests
|
||||
needs: [setup-manager]
|
||||
runs-on: ${{ github.run_id }}
|
||||
env:
|
||||
TERM: xterm-256-color
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Run .ini API verification tests
|
||||
run: .github/scripts/run-ini-api-tests.py
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
- uses: ./.github/actions/job-end
|
||||
|
||||
documentation-check:
|
||||
name: documentation-check
|
||||
runs-on: ubuntu-18.04
|
||||
container:
|
||||
image: firesim/firesim-ci:v1.3
|
||||
options: --entrypoint /bin/bash
|
||||
env:
|
||||
JVM_MEMORY: 3500M # Default JVM maximum heap limit
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/job-start
|
||||
id: job-start
|
||||
- name: Check that documentation builds with no warnings/errors
|
||||
if: steps.job-start.outputs.run_result != 'success'
|
||||
run: |
|
||||
sudo yum update -y
|
||||
sudo yum install -y python3-pip make
|
||||
sudo pip3 install -r docs/requirements.txt
|
||||
make -C docs html
|
||||
- name: Show error log from sphinx if failed
|
||||
if: ${{ steps.job-start.outputs.run_result != 'success' && failure() }}
|
||||
run: cat /tmp/sphinx-err*.log
|
||||
- uses: ./.github/actions/job-end
|
|
@ -1,7 +1,7 @@
|
|||
# FireSim: Easy-to-use, Scalable, FPGA-accelerated Cycle-accurate Hardware Simulation
|
||||
|
||||
![FireSim Documentation Status](https://readthedocs.org/projects/firesim/badge/)
|
||||
[![firesim](https://circleci.com/gh/firesim/firesim.svg?style=shield)](https://app.circleci.com/pipelines/github/firesim/firesim)
|
||||
![Github Actions Status](https://github.com/firesim/firesim/actions/workflows/firesim-run-tests.yml/badge.svg)
|
||||
|
||||
## Contents
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
|||
## Using FireSim
|
||||
|
||||
To get started with using FireSim, see the tutorials on the FireSim documentation
|
||||
site: https://docs.fires.im/.
|
||||
site: https://docs.fires.im/.
|
||||
|
||||
Another good overview (in video format) is our tutorial from the Chisel Community Conference on [YouTube](https://www.youtube.com/watch?v=S3OriQnJXYQ).
|
||||
|
||||
|
@ -31,6 +31,7 @@ You can learn more about FireSim in the following places:
|
|||
* **FireSim website**: https://fires.im
|
||||
* **FireSim ISCA 2018 Paper**: [Paper PDF](https://sagark.org/assets/pubs/firesim-isca2018.pdf) | [IEEE Xplore](https://ieeexplore.ieee.org/document/8416816) | [ACM DL](https://dl.acm.org/citation.cfm?id=3276543) | [BibTeX](https://sagark.org/assets/pubs/firesim-isca2018.bib.txt) | Selected as one of IEEE Micro’s “Top Picks from Computer Architecture Conferences, 2018”.
|
||||
* **FireSim documentation**: https://docs.fires.im
|
||||
* **Scala API Documentation**: https://fires.im/firesim/latest/api/
|
||||
* **Two-minute lightning talk from ISCA 2018** (FireSim simulating a datacenter): [YouTube](https://www.youtube.com/watch?v=4XwoSe5c8lY)
|
||||
* **Chisel Community Conference Tutorial**: [YouTube](https://www.youtube.com/watch?v=S3OriQnJXYQ)
|
||||
* **Updates/News**: [Changelog](/CHANGELOG.md) | [FireSim Blog](https://fires.im/blog/) | [Twitter](https://twitter.com/firesimproject)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import random
|
||||
|
@ -151,7 +153,7 @@ def construct_instance_market_options(instancemarket, spotinterruptionbehavior,
|
|||
else:
|
||||
assert False, "INVALID INSTANCE MARKET TYPE."
|
||||
|
||||
def launch_instances(instancetype, count, instancemarket, spotinterruptionbehavior, spotmaxprice, blockdevices=None, tags=None, randomsubnet=False):
|
||||
def launch_instances(instancetype, count, instancemarket, spotinterruptionbehavior, spotmaxprice, blockdevices=None, tags=None, randomsubnet=False, user_data_file=None):
|
||||
""" Launch count instances of type instancetype, optionally with additional
|
||||
block devices mappings and instance tags
|
||||
|
||||
|
@ -192,30 +194,37 @@ def launch_instances(instancetype, count, instancemarket, spotinterruptionbehavi
|
|||
|
||||
chosensubnet = subnets[startsubnet].subnet_id
|
||||
try:
|
||||
instance = ec2.create_instances(ImageId=f1_image_id,
|
||||
EbsOptimized=True,
|
||||
BlockDeviceMappings=(blockdevices + [
|
||||
{
|
||||
'DeviceName': '/dev/sdb',
|
||||
'NoDevice': '',
|
||||
},
|
||||
]),
|
||||
InstanceType=instancetype, MinCount=1, MaxCount=1,
|
||||
NetworkInterfaces=[
|
||||
{'SubnetId': chosensubnet,
|
||||
'DeviceIndex':0,
|
||||
'AssociatePublicIpAddress':True,
|
||||
'Groups':[firesimsecuritygroup]}
|
||||
],
|
||||
KeyName=keyname,
|
||||
TagSpecifications=([] if tags is None else [
|
||||
{
|
||||
'ResourceType': 'instance',
|
||||
'Tags': [{ 'Key': k, 'Value': v} for k, v in tags.items()],
|
||||
},
|
||||
]),
|
||||
InstanceMarketOptions=marketconfig
|
||||
)
|
||||
instance_args = {"ImageId":f1_image_id,
|
||||
"EbsOptimized":True,
|
||||
"BlockDeviceMappings":(blockdevices + [
|
||||
{
|
||||
'DeviceName': '/dev/sdb',
|
||||
'NoDevice': '',
|
||||
},
|
||||
]),
|
||||
"InstanceType":instancetype,
|
||||
"MinCount":1,
|
||||
"MaxCount":1,
|
||||
"NetworkInterfaces":[
|
||||
{'SubnetId': chosensubnet,
|
||||
'DeviceIndex':0,
|
||||
'AssociatePublicIpAddress':True,
|
||||
'Groups':[firesimsecuritygroup]}
|
||||
],
|
||||
"KeyName":keyname,
|
||||
"TagSpecifications":([] if tags is None else [
|
||||
{
|
||||
'ResourceType': 'instance',
|
||||
'Tags': [{ 'Key': k, 'Value': v} for k, v in tags.items()],
|
||||
},
|
||||
]),
|
||||
"InstanceMarketOptions":marketconfig,
|
||||
}
|
||||
if user_data_file is not None:
|
||||
with open(user_data_file, "r") as f:
|
||||
instance_args["UserData"] = ''.join(f.readlines())
|
||||
|
||||
instance = ec2.create_instances(**instance_args)
|
||||
instances += instance
|
||||
|
||||
except client.exceptions.ClientError as e:
|
||||
|
@ -472,6 +481,7 @@ def main(args):
|
|||
parser.add_argument("--block_devices", type=yaml.safe_load, default=run_block_device_dict(), help="List of dicts with block device information. Used by \'launch\'.")
|
||||
parser.add_argument("--tags", type=yaml.safe_load, default=run_tag_dict(), help="Dict of tags to add to instances. Used by \'launch\'.")
|
||||
parser.add_argument("--filters", type=yaml.safe_load, default=run_filters_list_dict(), help="List of dicts used to filter instances. Used by \'terminate\'.")
|
||||
parser.add_argument("--user_data_file", default=None, help="File path to use as user data (run on initialization). Used by \'launch\'.")
|
||||
args = parser.parse_args(args)
|
||||
|
||||
if args.command == "launch":
|
||||
|
@ -483,7 +493,8 @@ def main(args):
|
|||
args.spot_max_price,
|
||||
args.block_devices,
|
||||
args.tags,
|
||||
args.random_subnet)
|
||||
args.random_subnet,
|
||||
args.user_data_file)
|
||||
instids = get_instance_ids_for_instances(insts)
|
||||
print("Instance IDs: {}".format(instids))
|
||||
wait_on_instance_launches(insts)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
manager """
|
||||
|
||||
from time import strftime, gmtime
|
||||
import ConfigParser
|
||||
import configparser
|
||||
import pprint
|
||||
|
||||
from runtools.runtime_config import RuntimeHWDB
|
||||
|
@ -89,7 +89,7 @@ class GlobalBuildConfig:
|
|||
|
||||
self.args = args
|
||||
|
||||
global_build_configfile = ConfigParser.ConfigParser(allow_no_value=True)
|
||||
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)
|
||||
|
@ -111,9 +111,9 @@ class GlobalBuildConfig:
|
|||
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'))
|
||||
builds_to_run_list = list(map(lambda x: x[0], global_build_configfile.items('builds')))
|
||||
|
||||
build_recipes_configfile = ConfigParser.ConfigParser(allow_no_value=True)
|
||||
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)
|
||||
|
@ -167,7 +167,7 @@ class GlobalBuildConfig:
|
|||
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)
|
||||
return list(map(lambda x: x.get_build_instance_private_ip(), self.builds_list))
|
||||
|
||||
def get_builds_list(self):
|
||||
return self.builds_list
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
|
||||
# REQUIRES PYTHON2, because fabric requires python2
|
||||
|
||||
from __future__ import with_statement, print_function
|
||||
import sys
|
||||
import os
|
||||
|
@ -83,7 +81,7 @@ def managerinit():
|
|||
rootLogger.debug(m)
|
||||
rootLogger.debug(m.stderr)
|
||||
|
||||
useremail = raw_input("If you are a new user, supply your email address [abc@xyz.abc] for email notifications (leave blank if you do not want email notifications): ")
|
||||
useremail = input("If you are a new user, supply your email address [abc@xyz.abc] for email notifications (leave blank if you do not want email notifications): ")
|
||||
if useremail != "":
|
||||
subscribe_to_firesim_topic(useremail)
|
||||
else:
|
||||
|
@ -118,7 +116,7 @@ def buildafi(globalbuildconf):
|
|||
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.")
|
||||
userconfirm = raw_input("Do you also want to terminate your build instances? Type 'yes' to do so.\n")
|
||||
userconfirm = input("Do you also want to terminate your build instances? Type 'yes' to do so.\n")
|
||||
if userconfirm == "yes":
|
||||
globalbuildconf.terminate_all_build_instances()
|
||||
rootLogger.info("Instances terminated. Please confirm in your AWS Management Console.")
|
||||
|
|
|
@ -6,12 +6,13 @@ import pprint
|
|||
import logging
|
||||
import datetime
|
||||
|
||||
from switch_model_config import *
|
||||
from firesim_topology_core import *
|
||||
from utils import MacAddress
|
||||
from runtools.switch_model_config import *
|
||||
from runtools.firesim_topology_core import *
|
||||
from runtools.utils import MacAddress
|
||||
from fabric.api import *
|
||||
from colorama import Fore, Style
|
||||
import types
|
||||
from functools import reduce
|
||||
|
||||
from util.streamlogger import StreamLogger
|
||||
|
||||
|
@ -191,7 +192,7 @@ class FireSimTopologyWithPasses:
|
|||
# Filter out FireSimDummyServerNodes for actually deploying.
|
||||
# Infrastructure after this point will automatically look at the
|
||||
# FireSimDummyServerNodes if a FireSimSuperNodeServerNode is used
|
||||
downlinknodes = map(lambda x: x.get_downlink_side(), [downlink for downlink in switch.downlinks if not isinstance(downlink.get_downlink_side(), FireSimDummyServerNode)])
|
||||
downlinknodes = list(map(lambda x: x.get_downlink_side(), [downlink for downlink in switch.downlinks if not isinstance(downlink.get_downlink_side(), FireSimDummyServerNode)]))
|
||||
if all([isinstance(x, FireSimSwitchNode) for x in downlinknodes]):
|
||||
# all downlinks are switches
|
||||
self.run_farm.m4_16s[m4_16s_used].add_switch(switch)
|
||||
|
@ -465,7 +466,7 @@ class FireSimTopologyWithPasses:
|
|||
break
|
||||
# If AutoILA is disabled, use the following condition
|
||||
elif "No Sockets found" in screenoutput:
|
||||
break
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
execute(screens, hosts=all_runfarm_ips)
|
||||
|
@ -501,22 +502,22 @@ class FireSimTopologyWithPasses:
|
|||
|
||||
instancestate_map = dict()
|
||||
if terminateoncompletion:
|
||||
for instip, instdata in instancestates.iteritems():
|
||||
for instip, instdata in instancestates.items():
|
||||
# if terminateoncompletion and all sims are terminated, the inst must have been terminated
|
||||
instancestate_map[instip] = all([x[1] for x in instdata['sims'].iteritems()])
|
||||
instancestate_map[instip] = all([x[1] for x in instdata['sims'].items()])
|
||||
else:
|
||||
instancestate_map = {inst: False for inst in instancestates.keys()}
|
||||
|
||||
switchstates = []
|
||||
for instip, instdata in instancestates.iteritems():
|
||||
for switchname, switchcompleted in instdata['switches'].iteritems():
|
||||
for instip, instdata in instancestates.items():
|
||||
for switchname, switchcompleted in instdata['switches'].items():
|
||||
switchstates.append({'hostip': instip,
|
||||
'switchname': switchname,
|
||||
'running': not switchcompleted})
|
||||
|
||||
simstates = []
|
||||
for instip, instdata in instancestates.iteritems():
|
||||
for simname, simcompleted in instdata['sims'].iteritems():
|
||||
for instip, instdata in instancestates.items():
|
||||
for simname, simcompleted in instdata['sims'].items():
|
||||
simstates.append({'hostip': instip,
|
||||
'simname': simname,
|
||||
'running': not simcompleted})
|
||||
|
@ -532,7 +533,7 @@ class FireSimTopologyWithPasses:
|
|||
totalsims = len(simstates)
|
||||
totalinsts = len(instancestate_map.keys())
|
||||
runningsims = len([x for x in simstates if x['running']])
|
||||
runninginsts = len([x for x in instancestate_map.iteritems() if not x[1]])
|
||||
runninginsts = len([x for x in instancestate_map.items() if not x[1]])
|
||||
|
||||
# clear the screen
|
||||
rootLogger.info('\033[2J')
|
||||
|
|
|
@ -337,7 +337,7 @@ class RunFarm:
|
|||
|
||||
if not forceterminate:
|
||||
# --forceterminate was not supplied, so confirm with the user
|
||||
userconfirm = raw_input("Type yes, then press enter, to continue. Otherwise, the operation will be cancelled.\n")
|
||||
userconfirm = input("Type yes, then press enter, to continue. Otherwise, the operation will be cancelled.\n")
|
||||
else:
|
||||
userconfirm = "yes"
|
||||
|
||||
|
@ -384,14 +384,17 @@ class InstanceDeployManager:
|
|||
def get_and_install_aws_fpga_sdk(self):
|
||||
""" Installs the aws-sdk. This gets us access to tools to flash the fpga. """
|
||||
|
||||
# TODO: we checkout a specific version of aws-fpga here, in case upstream
|
||||
# master is bumped. But now we have to remember to change AWS_FPGA_FIRESIM_UPSTREAM_VERSION
|
||||
# when we bump our stuff. Need a better way to do this.
|
||||
AWS_FPGA_FIRESIM_UPSTREAM_VERSION = "6c707ab4a26c2766b916dad9d40727266fa0e4ef"
|
||||
self.instance_logger("""Installing AWS FPGA SDK on remote nodes. Upstream hash: {}""".format(AWS_FPGA_FIRESIM_UPSTREAM_VERSION))
|
||||
with prefix('cd ../'), \
|
||||
StreamLogger('stdout'), \
|
||||
StreamLogger('stderr'):
|
||||
# use local version of aws_fpga on runfarm nodes
|
||||
aws_fpga_upstream_version = local('git -C platforms/f1/aws-fpga describe --tags --always --dirty', capture=True)
|
||||
if "-dirty" in aws_fpga_upstream_version:
|
||||
rootLogger.critical("Unable to use local changes to aws-fpga. Continuing without them.")
|
||||
self.instance_logger("""Installing AWS FPGA SDK on remote nodes. Upstream hash: {}""".format(aws_fpga_upstream_version))
|
||||
with warn_only(), StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run('git clone https://github.com/aws/aws-fpga')
|
||||
run('cd aws-fpga && git checkout ' + AWS_FPGA_FIRESIM_UPSTREAM_VERSION)
|
||||
run('cd aws-fpga && git checkout ' + aws_fpga_upstream_version)
|
||||
with cd('/home/centos/aws-fpga'), StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run('source sdk_setup.sh')
|
||||
|
||||
|
@ -547,7 +550,7 @@ class InstanceDeployManager:
|
|||
self.instance_logger("Starting Vivado virtual JTAG.")
|
||||
with StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
run("""screen -S virtual_jtag -d -m bash -c "script -f -c 'sudo fpga-start-virtual-jtag -P 10201 -S 0'"; sleep 1""")
|
||||
|
||||
|
||||
def kill_ila_server(self):
|
||||
""" Kill the vivado hw_server and virtual jtag """
|
||||
with warn_only(), StreamLogger('stdout'), StreamLogger('stderr'):
|
||||
|
|
|
@ -4,7 +4,7 @@ simulation tasks. """
|
|||
from __future__ import print_function
|
||||
|
||||
from time import strftime, gmtime
|
||||
import ConfigParser
|
||||
import configparser
|
||||
import pprint
|
||||
import logging
|
||||
|
||||
|
@ -223,7 +223,7 @@ class RuntimeHWDB:
|
|||
as endpoints on the simulation. """
|
||||
|
||||
def __init__(self, hardwaredbconfigfile):
|
||||
agfidb_configfile = ConfigParser.ConfigParser(allow_no_value=True)
|
||||
agfidb_configfile = configparser.ConfigParser(allow_no_value=True)
|
||||
agfidb_configfile.read(hardwaredbconfigfile)
|
||||
agfidb_dict = {s:dict(agfidb_configfile.items(s)) for s in agfidb_configfile.sections()}
|
||||
|
||||
|
@ -240,7 +240,7 @@ class InnerRuntimeConfiguration:
|
|||
""" Pythonic version of config_runtime.ini """
|
||||
|
||||
def __init__(self, runtimeconfigfile, configoverridedata):
|
||||
runtime_configfile = ConfigParser.ConfigParser(allow_no_value=True)
|
||||
runtime_configfile = configparser.ConfigParser(allow_no_value=True)
|
||||
runtime_configfile.read(runtimeconfigfile)
|
||||
runtime_dict = {s:dict(runtime_configfile.items(s)) for s in runtime_configfile.sections()}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
[firesim-rocket-quadcore-nic-l2-llc4mb-ddr3]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=WithNIC_DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimHighPerfConfigTweaks_chipyard.QuadRocketConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_F90MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F90MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -23,7 +23,7 @@ deploytriplet=None
|
|||
[firesim-rocket-quadcore-no-nic-l2-llc4mb-ddr3]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimTestChipConfigTweaks_chipyard.QuadRocketConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_F140MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F140MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -32,7 +32,7 @@ deploytriplet=None
|
|||
[firesim-boom-singlecore-nic-l2-llc4mb-ddr3]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=WithNIC_DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimHighPerfConfigTweaks_chipyard.LargeBoomConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_F65MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F65MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -41,7 +41,7 @@ deploytriplet=None
|
|||
[firesim-boom-singlecore-no-nic-l2-llc4mb-ddr3]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimTestChipConfigTweaks_chipyard.LargeBoomConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_F75MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F75MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -50,7 +50,7 @@ deploytriplet=None
|
|||
[firesim-cva6-singlecore-no-nic-l2-llc4mb-ddr3]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimConfigTweaks_chipyard.CVA6Config
|
||||
PLATFORM_CONFIG=WithAutoILA_F90MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F90MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -59,7 +59,7 @@ deploytriplet=None
|
|||
[firesim-rocket-singlecore-gemmini-no-nic-l2-llc4mb-ddr3]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimConfigTweaks_chipyard.GemminiRocketConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_F110MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F30MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -68,7 +68,7 @@ deploytriplet=None
|
|||
[firesim-boom-singlecore-no-nic-l2-llc4mb-ddr3-ramopts]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimTestChipConfigTweaks_chipyard.LargeBoomConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_MCRams_F90MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=MCRams_F90MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
@ -77,7 +77,7 @@ deploytriplet=None
|
|||
[firesim-supernode-rocket-singlecore-nic-l2-lbp]
|
||||
DESIGN=FireSim
|
||||
TARGET_CONFIG=WithNIC_SupernodeFireSimRocketConfig
|
||||
PLATFORM_CONFIG=WithAutoILA_F85MHz_BaseF1Config
|
||||
PLATFORM_CONFIG=F85MHz_BaseF1Config
|
||||
instancetype=z1d.2xlarge
|
||||
deploytriplet=None
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import boto3
|
|||
from botocore.stub import Stubber
|
||||
from moto import mock_sns
|
||||
|
||||
from mock import patch
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
from pytest import raises
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ which has no license associated with it.
|
|||
"""
|
||||
import sys
|
||||
import logging
|
||||
import cStringIO
|
||||
import io
|
||||
|
||||
|
||||
class StreamLogger(object):
|
||||
|
@ -37,7 +37,7 @@ class StreamLogger(object):
|
|||
self.__name = name
|
||||
self.__stream = getattr(sys, name)
|
||||
self.__logger = logger or logging.getLogger()
|
||||
self.__buffer = cStringIO.StringIO()
|
||||
self.__buffer = io.StringIO()
|
||||
self.__unbuffered = unbuffered
|
||||
self.__flush_on_new_line = flush_on_new_line
|
||||
|
||||
|
|
|
@ -21,44 +21,41 @@ gapbs: input = graph500
|
|||
|
||||
$(GAP_DIR)/overlay/$(input):
|
||||
cd $(GAP_DIR) && ./gen_run_scripts.sh --binaries --input $(input)
|
||||
|
||||
|
||||
gapbs: gapbs.json $(GAP_DIR)/overlay/$(input)
|
||||
|
||||
gapbs: gapbs.json $(GAP_DIR)/overlay/$(input)
|
||||
mkdir -p $@
|
||||
cp $(BASE_LINUX) $@/bbl-vmlinux
|
||||
python gen-benchmark-rootfs.py -w $< -r -b $(BASE_IMAGE) \
|
||||
python3 gen-benchmark-rootfs.py -w $< -r -b $(BASE_IMAGE) \
|
||||
-s $(GAP_DIR)/overlay/$(input) \
|
||||
|
||||
memcached-thread-imbalance:
|
||||
mkdir -p $@
|
||||
sudo yum -y install gengetopt
|
||||
sudo pip2 install matplotlib
|
||||
sudo pip2 install pandas
|
||||
cd $@ && git submodule update --init mutilate-loadgen-riscv-release
|
||||
cd $@/mutilate-loadgen-riscv-release && ./build.sh
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/mutilate-loadgen-riscv-release/overlay
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/mutilate-loadgen-riscv-release/overlay
|
||||
|
||||
bw-test-two-instances: bw-test-two-instances.json
|
||||
cd ../../sw/network-benchmarks && python build-bw-test.py -n 8
|
||||
cd ../../sw/network-benchmarks && python3 build-bw-test.py -n 8
|
||||
cp ../../sw/network-benchmarks/testbuild/*.riscv $@
|
||||
|
||||
bw-test-one-instance: bw-test-one-instance.json
|
||||
cd ../../sw/network-benchmarks && python build-bw-test.py -n 4
|
||||
cd ../../sw/network-benchmarks && python3 build-bw-test.py -n 4
|
||||
cp ../../sw/network-benchmarks/testbuild/*.riscv $@
|
||||
|
||||
ping-latency:
|
||||
mkdir -p $@
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
|
||||
simperf-test:
|
||||
mkdir -p $@
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
|
||||
linux-poweroff:
|
||||
mkdir -p $@/overlay
|
||||
cd ../../sw/check-rtc && make print-mcycle-linux
|
||||
cp ../../sw/check-rtc/print-mcycle-linux $@/overlay/
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
|
||||
simperf-test-scale: simperf-test
|
||||
|
||||
|
@ -69,7 +66,7 @@ flash-stress: simperf-test-latency
|
|||
iperf3: iperf3.json
|
||||
mkdir -p $@
|
||||
cd $@ && ln -sf ../$(BASE_LINUX) bbl-vmlinux
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE)
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE)
|
||||
|
||||
check-rtc:
|
||||
cd ../../sw/check-rtc && make check-rtc
|
||||
|
@ -79,14 +76,14 @@ check-rtc-linux:
|
|||
cd ../../sw/check-rtc && make check-rtc-linux
|
||||
cp ../../sw/check-rtc/check-rtc-linux $@/overlay
|
||||
cd $@ && ln -sf ../$(BASE_LINUX) bbl-vmlinux
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/overlay
|
||||
|
||||
checksum-test:
|
||||
cd ../../target-design/chipyard/tests && make checksum.riscv
|
||||
|
||||
ccbench-cache-sweep:
|
||||
cd ccbench-cache-sweep/ccbench/caches && make ARCH=riscv
|
||||
python gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/
|
||||
python3 gen-benchmark-rootfs.py -w $@.json -r -b $(BASE_IMAGE) -s $@/
|
||||
|
||||
fc-test:
|
||||
cd ../../sw/network-benchmarks/fc-test && make
|
||||
|
|
|
@ -14,9 +14,9 @@ q = f.readlines()
|
|||
f.close()
|
||||
|
||||
|
||||
q = filter(lambda x: x.startswith('App:'), q)
|
||||
q = map(lambda x: x.strip().split(","), q)
|
||||
q = map(lambda x: list(map(lambda z: z.split(":"), x)), q)
|
||||
q = list(filter(lambda x: x.startswith('App:'), q))
|
||||
q = list(map(lambda x: x.strip().split(","), q))
|
||||
q = list(map(lambda x: list(map(lambda z: z.split(":"), x)), q))
|
||||
|
||||
|
||||
def arr_to_dict(q):
|
||||
|
@ -29,9 +29,9 @@ def arr_to_dict(q):
|
|||
as_dict.append(d)
|
||||
return as_dict
|
||||
|
||||
cacheline_stride_bmark = filter(lambda x: ['RunType', '[16]'] in x, q)
|
||||
unit_stride_bmark = filter(lambda x: ['RunType', '[1]'] in x, q)
|
||||
random_bmark = filter(lambda x: ['RunType', '[0]'] in x, q)
|
||||
cacheline_stride_bmark = list(filter(lambda x: ['RunType', '[16]'] in x, q))
|
||||
unit_stride_bmark = list(filter(lambda x: ['RunType', '[1]'] in x, q))
|
||||
random_bmark = list(filter(lambda x: ['RunType', '[0]'] in x, q))
|
||||
|
||||
def data_from_full_dict(array_of_dict):
|
||||
times = []
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
@ -49,7 +49,7 @@ def copy_base_rootfs(base_rootfs, dest):
|
|||
os.makedirs(BUILD_DIR)
|
||||
except OSError:
|
||||
pass
|
||||
print "Copying base rootfs {} to {}".format(base_rootfs, dest)
|
||||
print("Copying base rootfs {} to {}".format(base_rootfs, dest))
|
||||
shutil.copy2(base_rootfs, dest)
|
||||
|
||||
def mount_rootfs(rootfs):
|
||||
|
@ -60,7 +60,7 @@ def mount_rootfs(rootfs):
|
|||
rc = subprocess.check_output(["sudo", "mount", "-t", EXT_TYPE, rootfs, MOUNT_POINT])
|
||||
|
||||
def cp_target(src, target_dest):
|
||||
print "Copying src: {} to {} in target filesystem.".format(src, target_dest)
|
||||
print("Copying src: {} to {} in target filesystem.".format(src, target_dest))
|
||||
if not os.path.isdir(target_dest):
|
||||
dirname = os.path.dirname(target_dest)
|
||||
else:
|
||||
|
@ -84,7 +84,7 @@ def generate_init_script(command):
|
|||
init_script_body = init_script_head + " " + command + init_script_tail
|
||||
|
||||
temp_script = BUILD_DIR + "/temp"
|
||||
with open(temp_script, 'wb') as f:
|
||||
with open(temp_script, 'w') as f:
|
||||
f.write(init_script_body)
|
||||
|
||||
cp_target(temp_script, INIT_SCRIPT_NAME)
|
||||
|
@ -106,7 +106,7 @@ class Workload:
|
|||
self.outputs = outputs
|
||||
|
||||
def generate_rootfs(self, base_rootfs, overlay, gen_init, output_dir):
|
||||
print "\nGenerating a Rootfs image for " + self.name
|
||||
print("\nGenerating a Rootfs image for " + self.name)
|
||||
dest_rootfs = output_dir + "/" + self.name + "." + EXT_TYPE
|
||||
|
||||
copy_base_rootfs(base_rootfs, dest_rootfs)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 150a77698e8e786b8a87c14ae383889a1c24df67
|
||||
Subproject commit 873e0e5ca10f8a3f016023562a3d15e91af9229b
|
|
@ -11,7 +11,7 @@ import os
|
|||
|
||||
basedir = sys.argv[1] + "/"
|
||||
|
||||
files = map(lambda x: basedir + x, sorted(os.listdir(basedir), key=int))
|
||||
files = list(map(lambda x: basedir + x, sorted(os.listdir(basedir), key=int)))
|
||||
|
||||
def process_uartlog(uartlogpath):
|
||||
""" process the log and then report the mean RTT for this link latency """
|
||||
|
@ -52,11 +52,11 @@ def get_average_rtt_from_file(basedirname):
|
|||
|
||||
return [link_latency_us, measured_rtt_in_us, ideal_rtt_in_us]
|
||||
|
||||
resultarray = map(get_average_rtt_from_file, files)
|
||||
resultarray = list(map(get_average_rtt_from_file, files))
|
||||
|
||||
link_latency = map(lambda x: x[0], resultarray)
|
||||
measured_rtt = map(lambda x: x[1], resultarray)
|
||||
ideal_rtt = map(lambda x: x[2], resultarray)
|
||||
link_latency = list(map(lambda x: x[0], resultarray))
|
||||
measured_rtt = list(map(lambda x: x[1], resultarray))
|
||||
ideal_rtt = list(map(lambda x: x[2], resultarray))
|
||||
|
||||
print(resultarray)
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ do
|
|||
mv $originalfilename $resultsdir/$i
|
||||
done
|
||||
|
||||
python $ORIGDIR/bw-test-two-instances/bw-test-graph.py $(pwd)/$resultsdir
|
||||
python3 $ORIGDIR/bw-test-two-instances/bw-test-graph.py $(pwd)/$resultsdir
|
||||
|
||||
cd $ORIGDIR
|
||||
cd ../../
|
||||
|
|
|
@ -39,7 +39,7 @@ do
|
|||
mv $originalfilename $resultsdir/$i
|
||||
done
|
||||
|
||||
python $ORIGDIR/ping-latency/ping-latency-graph.py $(pwd)/$resultsdir
|
||||
python3 $ORIGDIR/ping-latency/ping-latency-graph.py $(pwd)/$resultsdir
|
||||
|
||||
firesim terminaterunfarm -c workloads/ping-latency-config.ini --forceterminate
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ do
|
|||
mv $originalfilename $resultsdir/$i
|
||||
done
|
||||
|
||||
python $ORIGDIR/simperf-test-latency/simperf-test-results.py $(pwd)/$resultsdir
|
||||
python3 $ORIGDIR/simperf-test-latency/simperf-test-results.py $(pwd)/$resultsdir
|
||||
firesim terminaterunfarm -c workloads/simperf-test-latency-config.ini --forceterminate
|
||||
|
||||
|
||||
|
|
|
@ -72,4 +72,4 @@ loopfunc 8 0 0
|
|||
|
||||
loopfunc 4 1 0
|
||||
|
||||
python $ORIGDIR/simperf-test-scale/simperf-test-scale-results.py $(pwd)/$resultsdir
|
||||
python3 $ORIGDIR/simperf-test-scale/simperf-test-scale-results.py $(pwd)/$resultsdir
|
||||
|
|
|
@ -72,4 +72,4 @@ loopfunc 2 0 0
|
|||
|
||||
loopfunc 1 1 0
|
||||
|
||||
python $ORIGDIR/simperf-test-scale/simperf-test-scale-results.py $(pwd)/$resultsdir
|
||||
python3 $ORIGDIR/simperf-test-scale/simperf-test-scale-results.py $(pwd)/$resultsdir
|
||||
|
|
|
@ -11,7 +11,7 @@ import os
|
|||
|
||||
basedir = sys.argv[1] + "/"
|
||||
|
||||
files = map(lambda x: basedir + x, os.listdir(basedir))
|
||||
files = list(map(lambda x: basedir + x, os.listdir(basedir)))
|
||||
|
||||
def process_uartlog(uartlogpath):
|
||||
""" process the log and then report the mean RTT for this link latency """
|
||||
|
@ -62,10 +62,10 @@ def get_simperf_from_file(basedirname):
|
|||
|
||||
return [link_latency_us, simperf_mhz]
|
||||
|
||||
resultarray = map(get_simperf_from_file, files)
|
||||
resultarray = list(map(get_simperf_from_file, files))
|
||||
|
||||
link_latency = map(lambda x: x[0], resultarray)
|
||||
simperf_mhz = map(lambda x: x[1][1], resultarray)
|
||||
link_latency = list(map(lambda x: x[0], resultarray))
|
||||
simperf_mhz = list(map(lambda x: x[1][1], resultarray))
|
||||
|
||||
resultarray = zip(link_latency, simperf_mhz)
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import os
|
|||
|
||||
basedir = sys.argv[1] + "/"
|
||||
|
||||
files = map(lambda x: basedir + x, os.listdir(basedir))
|
||||
files = list(map(lambda x: basedir + x, os.listdir(basedir)))
|
||||
|
||||
def extract_stats_from_uartlog(uartlogpath):
|
||||
""" read a uartlog and get sim perf results """
|
||||
|
@ -44,10 +44,10 @@ def get_simperf_from_file(basedirname):
|
|||
|
||||
return [numnodes, simperf_mhz]
|
||||
|
||||
resultarray = map(get_simperf_from_file, files)
|
||||
resultarray = list(map(get_simperf_from_file, files))
|
||||
|
||||
numnodes = map(lambda x: x[0], resultarray)
|
||||
simperf_mhz = map(lambda x: x[1][1], resultarray)
|
||||
numnodes = list(map(lambda x: x[0], resultarray))
|
||||
simperf_mhz = list(map(lambda x: x[1][1], resultarray))
|
||||
|
||||
resultarray = zip(numnodes, simperf_mhz)
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
_build
|
||||
warnings.txt
|
||||
|
|
|
@ -9,7 +9,7 @@ obvious if it's a bug in the target, or somewhere in the host. To make it easier
|
|||
identify the problem, the simulation driver includes a polling watchdog that
|
||||
tracks for simulation progress, and periodically updates an output file,
|
||||
``heartbeat.csv``, with a target cycle count and a timestamp. When debugging
|
||||
these issues, we always encourage the use of MIDAS-level simulation to try
|
||||
these issues, we always encourage the use of meta-simulation to try
|
||||
reproducing the failure if possible. We outline three common cases in the
|
||||
section below.
|
||||
|
||||
|
|
|
@ -13,11 +13,17 @@ and provided and interface for setting trigger and viewing samples waveforms
|
|||
from the FPGA. For more information about ILAs, please refer to the Xilinx
|
||||
guide on the topic.
|
||||
|
||||
MIDAS, in its ``targetutils`` package, provides annotations for labeling
|
||||
The ``midas.targetutils`` package provides annotations for labeling
|
||||
signals directly in the Chisel source. These will be consumed by a downstream
|
||||
FIRRTL pass which wires out the annotated signals, and binds them to an
|
||||
appropriately sized ILA instance.
|
||||
|
||||
Enabling AutoILA
|
||||
----------------
|
||||
|
||||
To enable AutoILA, mixin `WithAutoILA` must be prepended to the
|
||||
`PLATFORM_CONFIG`. Prior to version 1.13, this was done by default.
|
||||
|
||||
Annotating Signals
|
||||
------------------------
|
||||
|
||||
|
@ -35,7 +41,7 @@ vararg of chisel3.Data. Invoke it as follows:
|
|||
FpgaDebug(out1, in1)
|
||||
}
|
||||
|
||||
You can annotate signals throughout FireSim, including in MIDAS and
|
||||
You can annotate signals throughout FireSim, including in Golden Gate
|
||||
Rocket-Chip Chisel sources, with the only exception being the Chisel3 sources
|
||||
themselves (eg. in Chisel3.util.Queue).
|
||||
|
||||
|
|
|
@ -84,11 +84,11 @@ The commit log trace will by default print to the ``uartlog``.
|
|||
However, you can avoid printing it out by changing ``verbose == false`` in the ``dromajo_cosim.cpp`` file
|
||||
located in ``$CHIPYARD/tools/dromajo/dromajo-src/src/`` folder.
|
||||
|
||||
Troubleshooting Dromajo Simulations with MIDAS Simulations
|
||||
Troubleshooting Dromajo Simulations with Meta-Simulations
|
||||
----------------------------------------------------------
|
||||
|
||||
If FPGA simulation fails with Dromajo, you can use MIDAS-level simulation to determine if your Dromajo setup is correct.
|
||||
First refer to :ref:`Debugging & Testing with RTL Simulation` for more information on MIDAS-level simulation.
|
||||
If FPGA simulation fails with Dromajo, you can use meta-simulation to determine if your Dromajo setup is correct.
|
||||
First refer to :ref:`meta-simulation` for more information on meta-simulation.
|
||||
The main difference between those instructions and simulations with Dromajo is that you need to manually point to the ``dtb``, ``rom``, and binary files when invoking the simulator.
|
||||
Here is an example of a ``make`` command that can be run to check for a correct setup.
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.. _meta-simulation:
|
||||
|
||||
Debugging & Testing with Meta-Simulation
|
||||
=========================================
|
||||
.. _meta-simulation:
|
||||
|
||||
When we speak of RTL simulation in FireSim, we are generally referring to
|
||||
`meta-simulation`: simulating the FireSim simulator's RTL, typically using VCS or
|
||||
|
@ -23,10 +24,10 @@ ones. This illustrated in the chart below.
|
|||
====== ===== ======= ========= ============= =============
|
||||
Type Waves VCS Verilator Verilator -O1 Verilator -O2
|
||||
====== ===== ======= ========= ============= =============
|
||||
Target Off 4.8 kHz 3.9 kHz 6.6 kHz N/A
|
||||
Target On 0.8 kHz 3.0 kHz 5.1 kHz N/A
|
||||
Meta Off 3.8 kHz 2.4 kHz 4.5 kHz 5.3 KHz
|
||||
Meta On 2.9 kHz 1.5 kHz 2.7 kHz 3.4 KHz
|
||||
Target Off 4.8 kHz 3.9 kHz 6.6 kHz N/A
|
||||
Target On 0.8 kHz 3.0 kHz 5.1 kHz N/A
|
||||
Meta Off 3.8 kHz 2.4 kHz 4.5 kHz 5.3 KHz
|
||||
Meta On 2.9 kHz 1.5 kHz 2.7 kHz 3.4 KHz
|
||||
====== ===== ======= ========= ============= =============
|
||||
|
||||
Note that using more aggressive optimization levels when compiling the
|
||||
|
@ -137,7 +138,7 @@ Module Hierarchy
|
|||
To build out a simulator, Golden Gate adds multiple layers of module hierarchy to the target
|
||||
design and performs additional hierarchy mutations to implement bridges and
|
||||
resource optimizations. Meta-simulation uses the ``FPGATop`` module as the
|
||||
top-level module, which excludes the platform shim layer (``F1Shim``, for EC2 F1).
|
||||
top-level module, which excludes the platform shim layer (``F1Shim``, for EC2 F1).
|
||||
The original top-level of the input design is nested three levels below FPGATop:
|
||||
|
||||
.. figure:: /img/metasim-module-hierarchy.png
|
||||
|
|
|
@ -14,7 +14,7 @@ Restrictions on Target RTL
|
|||
Current limitations in Golden Gate place the following restrictions on the (FIR)RTL that can be
|
||||
transformed and thus used in FireSim:
|
||||
|
||||
#. The top-level module must have no inputs or outputs. Input stimulus and output capture must be
|
||||
#. The top-level module must have no inputs or outputs. Input stimulus and output capture must be
|
||||
implemented using target RTL or target-to-host Bridges.
|
||||
#. All target clocks must be generated by a single ``RationalClockBridge``.
|
||||
#. Black boxes must be "clock-gateable" by replacing its input clock with a gated equivalent which will be used
|
||||
|
@ -23,7 +23,7 @@ transformed and thus used in FireSim:
|
|||
a. As a consequence, target clock-gating cannot be implemented using black-box primitives, and must instead be modeled by
|
||||
adding clock-enables to all state elements of the gated clock domain (i.e., by adding an enable or feedback mux on registers to
|
||||
conditionally block updates, and by gating write-enables on memories).
|
||||
#. Asynchronous reset must only be implemented using Rocket Chip's black-box async reset.
|
||||
#. Asynchronous reset must only be implemented using Rocket Chip's black-box async reset.
|
||||
These are replaced with synchronously reset registers using a FIRRTL transformation.
|
||||
|
||||
.. _verilog-ip:
|
||||
|
@ -39,7 +39,7 @@ Verilog Blocks
|
|||
<https://chipyard.readthedocs.io/en/latest/Customization/Incorporating-Verilog-Blocks.html>`_
|
||||
section of the Chipyard documentation.
|
||||
|
||||
#. For the transform to work, the Chisel Blackbox that wraps the Verilog IP must have input clocks
|
||||
#. For the transform to work, the Chisel Blackbox that wraps the Verilog IP must have input clocks
|
||||
that can safely be clock-gated.
|
||||
#. The compiler that produces the decoupled simulator ("FAME Transform") automatically recognizes
|
||||
such blackboxes inside the target design.
|
||||
|
@ -132,7 +132,7 @@ Projects have the following directory structure:
|
|||
├-Makefile # Top-level makefile for projects where FireSim is the top-level repo
|
||||
├-Makefrag # Target-agnostic makefrag, with recipes to generate drivers and RTL simulators
|
||||
├-src/main/scala/{target-project}/
|
||||
│ └─Makefrag # Defines target-specific make variables and recipes.
|
||||
│ └─Makefrag # Defines target-specific make variables and recipes.
|
||||
├-src/main/cc/{target-project}/
|
||||
│ ├─{driver-csrcs}.cc # The target's simulation driver, and sofware-model sources
|
||||
│ └─{driver-headers}.h
|
||||
|
@ -147,8 +147,8 @@ Specifying A Target Instance
|
|||
To generate a specific instance of a target, the build system leverages four Make variables:
|
||||
|
||||
1. ``TARGET_PROJECT``: this points the Makefile (`sim/Makefile`) at the right
|
||||
target-specific Makefrag, which defines the generation and MIDAS-level
|
||||
software-simulation recipes. The makefrag for the default target project is
|
||||
target-specific Makefrag, which defines the generation and meta-simulation
|
||||
software recipes. The makefrag for the default target project is
|
||||
defined at ``sim/src/main/makefrag/firesim``.
|
||||
|
||||
2. ``DESIGN``: the name of the top-level Chisel module to generate (a Scala class name). These are defined
|
||||
|
@ -164,7 +164,7 @@ To generate a specific instance of a target, the build system leverages four Mak
|
|||
Common platform configs are described in ``firesim-lib/sim/src/main/scala/configs/CompilerConfigs.scala``).
|
||||
|
||||
``TARGET_CONFIG`` and ``PLATFORM_CONFIG`` are strings that are used to construct a
|
||||
``Config`` instance (derives from RocketChip's parameterization system, ``Config``, see
|
||||
``Config`` instance (derives from RocketChip's parameterization system, ``Config``, see
|
||||
`freechips.rocketchip.config
|
||||
<https://github.com/freechipsproject/rocket-chip/blob/master/src/main/scala/config/Config.scala>`_). These strings are of the form
|
||||
"{..._}{<Class Name>\_}<Class Name>". Only the final, base class name is
|
||||
|
@ -185,7 +185,7 @@ compound Config instance.
|
|||
With this scheme, you don't need to define a Config class for every instance you
|
||||
wish to generate. We use this scheme to specify FPGA frequencies (eg.
|
||||
"BaseF1Config_F90MHz") in manager build recipes, but it's also very useful for doing
|
||||
sweeping over a parameterization space.
|
||||
sweeping over a parameterization space.
|
||||
|
||||
**Note that the precedence of Configs decreases from left to right in a string**. Appending a config to an existing one will only have an effect if it
|
||||
sets a field not already set in higher precendence Configs. For example, "BaseF1Config_F90MHz" is equivalent to
|
||||
|
@ -225,7 +225,7 @@ expect is to open the scala REPL, instantiate an instance of the desired
|
|||
Rocket Chip Generator-based SoCs (firesim project)
|
||||
--------------------------------------------------
|
||||
|
||||
Using the Make variables listed above, we give examples of generating different targets using
|
||||
Using the Make variables listed above, we give examples of generating different targets using
|
||||
the default Rocket Chip-based target project.
|
||||
|
||||
-----------------
|
||||
|
|
|
@ -6,7 +6,7 @@ Manager Environment Variables
|
|||
This page contains a centralized reference for the environment variables used
|
||||
by the manager.
|
||||
|
||||
.. _config-runtime:
|
||||
.. _runfarm-prefix:
|
||||
|
||||
``FIRESIM_RUNFARM_PREFIX``
|
||||
--------------------------
|
||||
|
|
|
@ -80,16 +80,16 @@ This directory will contain:
|
|||
----------------------
|
||||
|
||||
This command can be used to run only steps 9 & 10 from an aborted ``firesim buildafi`` that has been
|
||||
manually corrected. ``firesim tar2afi`` assumes that you have a
|
||||
manually corrected. ``firesim tar2afi`` assumes that you have a
|
||||
``firesim/deploy/results-build/LAUNCHTIME-CONFIG_TRIPLET-BUILD_NAME/cl_firesim``
|
||||
directory tree that can be submitted to the AWS backend for conversion to an AFI.
|
||||
|
||||
When using this command, you need to also provide the ``--launchtime LAUNCHTIME`` cmdline argument,
|
||||
specifying an already existing LAUNCHTIME.
|
||||
specifying an already existing LAUNCHTIME.
|
||||
|
||||
This command will run for the configurations specified in :ref:`config-build` and
|
||||
This command will run for the configurations specified in :ref:`config-build` and
|
||||
:ref:`config-build-recipes` as with :ref:`firesim-buildafi`. It is likely that you may want
|
||||
to comment out ``BUILD_NAME`` that successfully completed :ref:`firesim-builafi` before
|
||||
to comment out ``BUILD_NAME`` that successfully completed :ref:`firesim-buildafi` before
|
||||
running this command.
|
||||
|
||||
|
||||
|
@ -282,7 +282,7 @@ workload configuration (see the :ref:`defining-custom-workloads` section).
|
|||
|
||||
For
|
||||
non-networked simulations, it will wait for ALL simulations to complete (copying
|
||||
back results as each workload completes), then exit.
|
||||
back results as each workload completes), then exit.
|
||||
|
||||
For
|
||||
globally-cycle-accurate networked simulations, the global simulation will stop
|
||||
|
|
|
@ -135,3 +135,9 @@ Then, you can move the cursor over something you want to jump to and hit
|
|||
``ctrl-]`` to jump to the definition and ``ctrl-t`` to jump back out. E.g. in
|
||||
top-level configurations in FireSim, you can jump all the way down through the
|
||||
Rocket Chip codebase and even down to Chisel.
|
||||
|
||||
Using FireSim CI
|
||||
----------------
|
||||
|
||||
For more information on how to deal with the FireSim CI and how to run FPGA simulations in the CI,
|
||||
refer to the the ``CI_README.md`` under the ``.github/`` directory.
|
||||
|
|
|
@ -79,7 +79,7 @@ directory name the same. In this case, we have set all of them to
|
|||
|
||||
Next, the ``common_bootbinary`` field represents the binary that the simulations
|
||||
in this workload are expected to boot from. The manager will copy this binary
|
||||
for each of the nodes in the simulation (each gets its own copy). The ``common_bootbinary`` path is
|
||||
for each of the nodes in the simulation (each gets its own copy). The ``common_bootbinary`` path is
|
||||
relative to the workload's directory, in this case
|
||||
``firesim/deploy/workloads/linux-uniform``. You'll notice in the above output
|
||||
from ``ls -la`` that this is actually just a symlink to ``br-base-bin`` that
|
||||
|
@ -123,7 +123,7 @@ be fixed in a future release.
|
|||
Non-uniform Workload JSON (explicit job per simulated node)
|
||||
---------------------------------------------------------------
|
||||
|
||||
Now, we'll look at the ``ping-latency`` workload, which explicitly defines a
|
||||
Now, we'll look at the ``ping-latency`` workload, which explicitly defines a
|
||||
job per simulated node.
|
||||
|
||||
.. include:: /../deploy/workloads/ping-latency.json
|
||||
|
@ -193,10 +193,10 @@ see in the ``ping-latency`` directory.
|
|||
::
|
||||
|
||||
[ from the workloads/ directory ]
|
||||
python gen-benchmark-rootfs.py -w ping-latency.json -r -b ../../sw/firesim-software/images/br-base.img -s ping-latency/overlay
|
||||
./gen-benchmark-rootfs.py -w ping-latency.json -r -b ../../sw/firesim-software/images/br-base.img -s ping-latency/overlay
|
||||
|
||||
Notice that we tell this script where the json file lives, where the base rootfs image is, and where we expect to find files
|
||||
that we want to include in the generated disk images. This script will take care of the rest and we'll end up with
|
||||
that we want to include in the generated disk images. This script will take care of the rest and we'll end up with
|
||||
``idler-[1-6].ext2``, ``pingee.ext2``, and ``pinger.ext2``!
|
||||
|
||||
You'll notice a Makefile in the ``workloads/`` directory -- it contains many
|
||||
|
|
|
@ -127,7 +127,7 @@ from the BridgeModule may deadlock the simulator.
|
|||
Registering the Driver
|
||||
++++++++++++++++++++++
|
||||
|
||||
With the Bridge Driver implemented, we now have to register it in the main simulator
|
||||
With the Bridge Driver implemented, we now have to register it in the main simulator
|
||||
simulator class defined in ``sim/src/main/cc/firesim/firesim_top.cc``. Here, we
|
||||
rely on the C preprocessor macros to instantiate the bridge driver only when
|
||||
the corresponding BridgeModule is present:
|
||||
|
@ -157,4 +157,4 @@ Here the main order of business is to add header and source files to
|
|||
:end-before: DOC include end: Bridge Build System Changes
|
||||
|
||||
That's it! At this point you should be able to both test your bridge in software
|
||||
simulation using MIDAS-level simulation, or deploy it to an FPGA.
|
||||
simulation using meta-simulation, or deploy it to an FPGA.
|
||||
|
|
|
@ -108,17 +108,18 @@ See
|
|||
https://docs.aws.amazon.com/cli/latest/userguide/tutorial-ec2-ubuntu.html#configure-cli-launch-ec2
|
||||
for more about aws configure. Within the prompt, you should specify the same region that you chose
|
||||
above (one of ``us-east-1``, ``us-west-2``, ``eu-west-1``) and set the default
|
||||
output format to ``json``. You will need to generate an AWS access key in the "Security Credentials" menu of your AWS settings (as instructed in https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys ).
|
||||
output format to ``json``. You will need to generate an AWS access key in the "Security Credentials" menu of your AWS settings (as instructed in https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys ).
|
||||
|
||||
Again on the ``t2.nano`` instance, do the following:
|
||||
|
||||
::
|
||||
|
||||
sudo yum -y install python-pip
|
||||
sudo pip install boto3
|
||||
sudo pip install --upgrade awscli
|
||||
sudo yum install -y python36-pip
|
||||
sudo pip3 install --upgrade pip
|
||||
sudo python3 -m pip install boto3
|
||||
sudo python3 -m pip install --upgrade awscli
|
||||
wget https://raw.githubusercontent.com/firesim/firesim/master/scripts/aws-setup.py
|
||||
python aws-setup.py
|
||||
./aws-setup.py
|
||||
|
||||
This will create a VPC named ``firesim`` and a security group named
|
||||
``firesim`` in your account.
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXOPTS = -w warnings.txt -n -W
|
||||
SPHINXBUILD = python3 -msphinx
|
||||
SPHINXPROJ = FireSim
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
Building Docs
|
||||
--------------
|
||||
|
||||
sudo pip install -r requirements.txt
|
||||
sudo python3 -m pip install -r requirements.txt
|
||||
make html
|
||||
|
||||
Look in the `_build/html` directory for output. You can also run
|
||||
Look in the `_build/html` directory for output. You can also run
|
||||
|
||||
python -m SimpleHTTPServer
|
||||
python3 -m SimpleHTTPServer
|
||||
|
||||
To get a proper locally-hosted version.
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ html_static_path = ['_static']
|
|||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
html_logo = '_static/images/firesim_logo_small.png'
|
||||
html_logo = '_static/firesim_logo_small.png'
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
ip_address
|
||||
machine-launch-script.sh
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Assumes the following:
|
||||
- Are running on an AWS instance (needed to access private IPs + username centos)
|
||||
- Have a working AWS setup (ran aws configure)
|
||||
- Have a specific hash to test (hash must be accessible from the mainline firesim repo)
|
||||
|
||||
1. Launch manager using script (should log the IP address in a file to use)
|
||||
2. Run a specific regression (up to the user to ensure that it ends properly)
|
||||
3. Terminate manager instance
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
source $SCRIPT_DIR/defaults.sh
|
||||
|
||||
run "cd firesim/ && source sourceme-f1-manager.sh && firesim buildafi"
|
||||
|
||||
echo "Success"
|
|
@ -0,0 +1,32 @@
|
|||
IP_ADDR_FILE=$SCRIPT_DIR/ip_address
|
||||
|
||||
parse_ip_address () {
|
||||
IP_ADDR=$(grep -E -o "192\.168\.[0-9]{1,3}\.[0-9]{1,3}" $IP_ADDR_FILE | head -n 1)
|
||||
IP_ADDR="centos@$IP_ADDR"
|
||||
}
|
||||
|
||||
FIRESIM_PEM_FILE=~/firesim.pem
|
||||
|
||||
copy () {
|
||||
rsync -avzp -e "ssh -o StrictHostKeyChecking=no -i $FIRESIM_PEM_FILE" --exclude '.git' $1 $2
|
||||
}
|
||||
|
||||
copy_no_sym () {
|
||||
rsync -avzpL -e "ssh -o StrictHostKeyChecking=no -i $FIRESIM_PEM_FILE" --exclude '.git' $1 $2
|
||||
}
|
||||
|
||||
run () {
|
||||
if [ -z $IP_ADDR ]; then
|
||||
parse_ip_address
|
||||
fi
|
||||
ssh -i $FIRESIM_PEM_FILE -o "StrictHostKeyChecking no" -t $IP_ADDR "bash -l -c '$@'"
|
||||
}
|
||||
|
||||
run_script () {
|
||||
if [ -z $IP_ADDR ]; then
|
||||
parse_ip_address
|
||||
fi
|
||||
ssh -i $FIRESIM_PEM_FILE -o "StrictHostKeyChecking no" -t $IP_ADDR 'bash -l -s' < $1 "$2"
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#! /usr/bin/env expect
|
||||
set timeout -1
|
||||
spawn firesim managerinit
|
||||
send -- "\r"
|
||||
expect eof
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "$0 <FULL HASH TO TEST>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
source $SCRIPT_DIR/defaults.sh
|
||||
|
||||
FULL_HASH=$1
|
||||
|
||||
# get the userdata file to launch manager with
|
||||
rm -rf machine-launch-script.sh
|
||||
wget https://raw.githubusercontent.com/firesim/firesim/$FULL_HASH/scripts/machine-launch-script.sh
|
||||
|
||||
# launch manager
|
||||
$SCRIPT_DIR/../../deploy/awstools/awstools.py \
|
||||
launch \
|
||||
--inst_type c5.4xlarge \
|
||||
--user_data_file $PWD/machine-launch-script.sh \
|
||||
2>&1 | tee $IP_ADDR_FILE
|
||||
|
||||
rm -rf machine-launch-script.sh
|
||||
|
||||
# make sure managerinit finishes properly
|
||||
run "timeout 10m grep -q \".*machine launch script complete.*\" <(tail -f machine-launchstatus)"
|
||||
|
||||
# setup the repo (similar to ci)
|
||||
|
||||
run "git clone https://github.com/firesim/firesim.git"
|
||||
run "cd firesim/ && git checkout $FULL_HASH"
|
||||
run "cd firesim/ && ./build-setup.sh --fast"
|
||||
run "cd firesim/sw/firesim-software && ./init-submodules.sh"
|
||||
# use local aws permissions (for now bypass the manager)
|
||||
copy ~/.aws/ $IP_ADDR:~/.aws
|
||||
copy ~/firesim.pem $IP_ADDR:~/firesim.pem
|
||||
copy firesim-managerinit.expect $IP_ADDR:~/firesim-managerinit.expect
|
||||
run "cd firesim && source sourceme-f1-manager.sh && cd ../ && ./firesim-managerinit.expect"
|
||||
|
||||
echo "Success"
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||
source $SCRIPT_DIR/defaults.sh
|
||||
|
||||
cd .. # firesim
|
||||
|
||||
run "cd firesim/ && source sourceme-f1-manager.sh && sw/firesim-software && ./marshal -v build br-base.json && ./marshal -v install br-base.json"
|
||||
run "cd firesim/ && source sourceme-f1-manager.sh && cd deploy/workloads/ && make allpaper"
|
||||
run "cd firesim/ && source sourceme-f1-manager.sh && cd deploy/workloads/ && ./run-all.sh"
|
||||
|
||||
echo "Success"
|
|
@ -1,3 +1,5 @@
|
|||
#/usr/bin/env python3
|
||||
|
||||
""" This script configures your AWS account to run FireSim. """
|
||||
|
||||
import boto3
|
||||
|
|
|
@ -4,6 +4,8 @@ set -ex
|
|||
set -o pipefail
|
||||
|
||||
echo "machine launch script started" > /home/centos/machine-launchstatus
|
||||
sudo chgrp centos /home/centos/machine-launchstatus
|
||||
sudo chown centos /home/centos/machine-launchstatus
|
||||
|
||||
{
|
||||
sudo yum install -y ca-certificates
|
||||
|
@ -48,36 +50,28 @@ sudo yum -y install graphviz python-devel
|
|||
# used for CI
|
||||
sudo yum -y install expect
|
||||
|
||||
# pip2 no longer installed on FPGA developer AMIs
|
||||
sudo yum -y install python-pip
|
||||
# In the event it is (as on an older AMI), upgrade it just in case
|
||||
sudo pip2 install --upgrade pip==20.3.4
|
||||
# these need to match what's in deploy/requirements.txt
|
||||
sudo pip2 install fabric==1.14.0
|
||||
sudo pip2 install boto3==1.6.2
|
||||
sudo pip2 install colorama==0.3.7
|
||||
sudo pip2 install argcomplete==1.9.3
|
||||
sudo pip2 install graphviz==0.8.3
|
||||
# upgrade pip
|
||||
sudo pip3 install --upgrade pip==21.3.1
|
||||
# install requirements
|
||||
sudo python3 -m pip install fab-classic==1.19.1
|
||||
sudo python3 -m pip install boto3==1.20.21
|
||||
sudo python3 -m pip install colorama==0.4.3
|
||||
sudo python3 -m pip install argcomplete==1.12.3
|
||||
sudo python3 -m pip install graphviz==0.19
|
||||
# for some of our workload plotting scripts
|
||||
sudo pip2 install --upgrade --ignore-installed pyparsing
|
||||
sudo pip2 install numpy==1.16.6
|
||||
sudo pip2 install kiwisolver==1.1.0
|
||||
sudo pip2 install matplotlib==2.2.2
|
||||
sudo pip2 install pandas==0.22.0
|
||||
# new awscli on 1.6.0 AMI is broken with our versions of boto3
|
||||
sudo pip2 install awscli==1.15.76
|
||||
# pip2 should install pytest 4.6.X as it's the last py2 release. see:
|
||||
# https://pytest.org/en/latest/py27-py34-deprecation.html#what-this-means-for-general-users
|
||||
sudo pip2 install pytest
|
||||
# moto 1.3.1 is newest version that will work with boto3 1.6.2
|
||||
sudo pip2 install moto==1.3.1
|
||||
sudo python3 -m pip install pyparsing==3.0.6
|
||||
sudo python3 -m pip install numpy==1.19.5
|
||||
sudo python3 -m pip install kiwisolver==1.3.1
|
||||
sudo python3 -m pip install matplotlib==3.3.4
|
||||
sudo python3 -m pip install pandas==1.1.5
|
||||
sudo python3 -m pip install awscli==1.22.21
|
||||
sudo python3 -m pip install pytest==6.2.5
|
||||
sudo python3 -m pip install moto==2.2.17
|
||||
# needed for the awstools cmdline parsing
|
||||
sudo pip2 install pyyaml
|
||||
sudo python3 -m pip install pyyaml==5.4.1
|
||||
|
||||
sudo activate-global-python-argcomplete
|
||||
|
||||
# Upgrading pip2 clobbers the pip3 installation paths.
|
||||
sudo yum reinstall -y python36-pip
|
||||
# setup argcomplete
|
||||
activate-global-python-argcomplete
|
||||
|
||||
} 2>&1 | tee /home/centos/machine-launchstatus.log
|
||||
|
||||
|
|
|
@ -2,10 +2,21 @@
|
|||
package firesim
|
||||
|
||||
import java.io.File
|
||||
import scala.io.Source
|
||||
import scala.sys.process.{stringSeqToProcess, ProcessLogger}
|
||||
|
||||
/**
|
||||
* NB: not thread-safe
|
||||
* An base class for implementing FireSim integration tests that call out to the Make
|
||||
* buildsystem. These tests typically have three steps whose results are tracked by scalatest:
|
||||
* 1) Elaborate the target and compile it through golden gate (ElaborateAndCompile)
|
||||
* 2) Compile a metasimulator for the generated RTL (compileMlSimulator)
|
||||
* 3) Run the metasimulator. Running a metasimualtion is somewaht
|
||||
* target-specific and is handled differently by different subclasses.
|
||||
*
|
||||
* Some tests inspect the simulation outputs, or run other simulators. See the
|
||||
* [[TutorialSuite]] for examples of that.
|
||||
*
|
||||
* NB: Not thread-safe.
|
||||
*/
|
||||
abstract class TestSuiteCommon extends org.scalatest.flatspec.AnyFlatSpec {
|
||||
|
||||
|
@ -98,9 +109,48 @@ abstract class TestSuiteCommon extends org.scalatest.flatspec.AnyFlatSpec {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts all lines in a file that begin with a specific prefix, removing
|
||||
* extra whitespace between the prefix and the remainder of the line
|
||||
*
|
||||
* @param filename Input file
|
||||
* @param prefix The per-line prefix to filter with
|
||||
* @param linesToDrop Some number of matched lines to be removed
|
||||
* @param headerLines An initial number of lines to drop before filtering.
|
||||
* Assertions, Printf output have a single line header.
|
||||
* MLsim stdout has some unused output, so set this to 1 by default
|
||||
*
|
||||
*/
|
||||
def extractLines(filename: File, prefix: String, linesToDrop: Int = 0, headerLines: Int = 1): Seq[String] = {
|
||||
val lines = Source.fromFile(filename).getLines.toList.drop(headerLines)
|
||||
lines.filter(_.startsWith(prefix))
|
||||
.dropRight(linesToDrop)
|
||||
.map(_.stripPrefix(prefix).replaceAll(" +", " "))
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Diffs two sets of lines. Wrap calls to this function in a scalatest
|
||||
* behavior spec. @param aName and @param bName can be used to provide more
|
||||
* insightful assertion messages in scalatest reporting.
|
||||
*/
|
||||
def diffLines(
|
||||
aLines: Seq[String],
|
||||
bLines: Seq[String],
|
||||
aName: String = "Actual output",
|
||||
bName: String = "Expected output"): Unit = {
|
||||
assert(aLines.size == bLines.size && aLines.nonEmpty,
|
||||
s"\n${aName} length (${aLines.size}) and ${bName} length (${bLines.size}) differ.")
|
||||
for ((a, b) <- bLines.zip(aLines)) {
|
||||
assert(a == b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: Hijacks TestSuiteCommon to run the MIDAS unit tests
|
||||
/**
|
||||
* Hijacks TestSuiteCommon (mostly for make related features) to run the synthesizable unit tests.
|
||||
*/
|
||||
abstract class MidasUnitTestSuite(unitTestConfig: String, shouldFail: Boolean = false) extends TestSuiteCommon {
|
||||
val targetTuple = unitTestConfig
|
||||
// GENERATED_DIR & OUTPUT_DIR are only used to properly invoke `make clean`
|
||||
|
|
|
@ -62,8 +62,17 @@ FASEDMemoryTimingModel::FASEDMemoryTimingModel(
|
|||
size_t delimit_idx = sub_arg.find("=");
|
||||
size_t suffix_idx = sub_arg.find(suffix);
|
||||
std::string key = sub_arg.substr(0, suffix_idx).c_str();
|
||||
int value = std::stoi(sub_arg.substr(delimit_idx+1).c_str());
|
||||
model_configuration[key] = value;
|
||||
|
||||
// This is the only nullary plusarg supported by fased
|
||||
// All other plusargs are key-value pairs that will be written to the bridge module
|
||||
if (key == std::string("useHardwareDefaultRuntimeSettings")) {
|
||||
require_all_runtime_settings = false;
|
||||
} else if (suffix_idx == std::string::npos) {
|
||||
throw std::runtime_error("[FASED] unknown nullary plusarg: " + key);
|
||||
} else {
|
||||
int value = std::stoi(sub_arg.substr(delimit_idx+1).c_str());
|
||||
model_configuration[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,11 +134,16 @@ void FASEDMemoryTimingModel::init() {
|
|||
}
|
||||
|
||||
if (!exclude) {
|
||||
char buf[100];
|
||||
sprintf(buf, "No value provided for configuration register: %s", pair.first.c_str());
|
||||
throw std::runtime_error(buf);
|
||||
if (require_all_runtime_settings) {
|
||||
char buf[100];
|
||||
sprintf(buf, "[FASED] No value provided for configuration register: %s", pair.first.c_str());
|
||||
throw std::runtime_error(buf);
|
||||
} else {
|
||||
auto init_val = read(pair.first);
|
||||
fprintf(stderr, "[FASED] Using hardware default of %u for configuration register %s\n", init_val, pair.first.c_str());
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Ignoring writeable register: %s\n", pair.first.c_str());
|
||||
fprintf(stderr, "[FASED] Ignoring writeable register: %s\n", pair.first.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,13 @@ private:
|
|||
|
||||
bool has_latency_histograms() { return histograms.size() > 0; };
|
||||
size_t mem_size;
|
||||
// By default, FASED requires that plus args for all timing model parameters
|
||||
// are passed in to prevent accidental misconfigurations (ex. when
|
||||
// DRAM timing parameters are passed to an LBP). When this is set, using the plus arg
|
||||
// +mm_useHardwareDefaultRuntimeSettings_<idx>,
|
||||
// the driver will instead use the hardware reset values (which map to the values emitted in the
|
||||
// runtime.conf) and print those values to the log instead.
|
||||
bool require_all_runtime_settings = true;
|
||||
};
|
||||
|
||||
#endif // __FASED_MEMORY_TIMING_MODEL_H
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import optparse
|
||||
import subprocess
|
||||
import json
|
||||
|
|
|
@ -168,12 +168,12 @@ class LLCModel(cfg: BaseConfig)(implicit p: Parameters) extends NastiModule()(p)
|
|||
val mshr_available = mshrs.exists({m: MSHR => m.available() })
|
||||
val mshr_next_idx = mshrs.indexWhere({ m: MSHR => m.available() })
|
||||
|
||||
// TODO: Put this on a switch
|
||||
val mshrs_allocated = mshrs.count({m: MSHR => m.valid})
|
||||
assert((mshrs_allocated < io.settings.activeMSHRs) || !mshr_available,
|
||||
assert((mshrs_allocated < RegNext(io.settings.activeMSHRs)) || !mshr_available,
|
||||
"Too many runtime MSHRs exposed given runtime programmable limit")
|
||||
assert((mshrs_allocated === io.settings.activeMSHRs) || mshr_available,
|
||||
"Too few runtime MSHRs exposed given runtime programmable limit")
|
||||
|
||||
assert((mshrs_allocated === RegNext(io.settings.activeMSHRs)) || mshr_available,
|
||||
"Too few runtime MSHRs exposed given runtime programmable limit.")
|
||||
|
||||
val s2_ar_mem = Module(new Queue(new NastiReadAddressChannel, 2))
|
||||
val s2_aw_mem = Module(new Queue(new NastiWriteAddressChannel, 2))
|
||||
|
|
|
@ -67,6 +67,7 @@ class LatencyPipe(cfg: LatencyPipeConfig)(implicit p: Parameters) extends SplitT
|
|||
wResp.bits := writePipe.io.deq.bits.xaction
|
||||
writePipe.io.deq.ready := wResp.ready && writeDone
|
||||
|
||||
assert(writePipe.io.enq.ready || !newWReq, "LBP write latency pipe would overflow.")
|
||||
|
||||
// ***** Read Latency Pipe *****
|
||||
val readPipe = Module(new Queue(new ReadPipeEntry, cfg.maxReads, flow = true))
|
||||
|
@ -79,5 +80,7 @@ class LatencyPipe(cfg: LatencyPipeConfig)(implicit p: Parameters) extends SplitT
|
|||
rResp.valid := readPipe.io.deq.valid && readDone
|
||||
rResp.bits := readPipe.io.deq.bits.xaction
|
||||
readPipe.io.deq.ready := rResp.ready && readDone
|
||||
|
||||
assert(readPipe.io.enq.ready || !nastiReq.ar.fire, "LBP read latency pipe would overflow.")
|
||||
}
|
||||
|
||||
|
|
|
@ -241,4 +241,6 @@ abstract class SplitTransactionModel(cfg: BaseConfig)(implicit p: Parameters)
|
|||
awQueue.io.enq.bits := nastiReq.aw.bits
|
||||
awQueue.io.enq.valid := nastiReq.aw.fire
|
||||
awQueue.io.deq.ready := newWReq
|
||||
assert(awQueue.io.enq.ready || !nastiReq.aw.fire,
|
||||
"AW queue in SplitTransaction timing model would overflow.")
|
||||
}
|
||||
|
|
|
@ -80,22 +80,35 @@ abstract class WidgetImp(wrapper: Widget) extends LazyModuleImp(wrapper) {
|
|||
// For inputs, generates a registers and binds that to the map
|
||||
// For outputs, direct binds the wire to the map
|
||||
def attachIO(io: Record, prefix: String = ""): Unit = {
|
||||
def innerAttachIO(node: Data, name: String): Unit = node match {
|
||||
|
||||
/**
|
||||
* For FASED memory timing models, initalize programmable registers to defaults if provided.
|
||||
* See [[midas.models.HasProgrammableRegisters]] for more detail.
|
||||
*/
|
||||
def getInitValue(field: Bits, parent: Data): Option[UInt] = parent match {
|
||||
case p: midas.models.HasProgrammableRegisters if p.regMap.isDefinedAt(field) =>
|
||||
Some(p.regMap(field).default.U)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
def innerAttachIO(node: Data, parent: Data, name: String): Unit = node match {
|
||||
case (b: Bits) => (DataMirror.directionOf(b): @unchecked) match {
|
||||
case ActualDirection.Output => attach(b, s"${name}", ReadOnly)
|
||||
case ActualDirection.Input => genWOReg(b, name)
|
||||
case ActualDirection.Input =>
|
||||
genAndAttachReg(b, name, getInitValue(b, parent))
|
||||
}
|
||||
case (v: Vec[_]) => {
|
||||
(v.zipWithIndex).foreach({ case (elm, idx) => innerAttachIO(elm, s"${name}_$idx")})
|
||||
(v.zipWithIndex).foreach({ case (elm, idx) => innerAttachIO(elm, node, s"${name}_$idx")})
|
||||
}
|
||||
case (r: Record) => {
|
||||
r.elements.foreach({ case (subName, elm) => innerAttachIO(elm, s"${name}_${subName}")})
|
||||
r.elements.foreach({ case (subName, elm) => innerAttachIO(elm, node, s"${name}_${subName}")})
|
||||
}
|
||||
case _ => new RuntimeException("Cannot bind to this sort of node...")
|
||||
}
|
||||
io.elements.foreach({ case (name, elm) => innerAttachIO(elm, s"${prefix}${name}")})
|
||||
io.elements.foreach({ case (name, elm) => innerAttachIO(elm, io, s"${prefix}${name}")})
|
||||
}
|
||||
|
||||
|
||||
def attachDecoupledSink(channel: DecoupledIO[UInt], name: String): Int = {
|
||||
crRegistry.allocate(DecoupledSinkEntry(channel, name))
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os.path
|
||||
import argparse
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os.path
|
||||
import argparse
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue