Skip to content
Permalink
933cc88e4a
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
464 lines (389 sloc) 18.9 KB
# Copyright (c) 2016-2018 by the author(s)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author(s):
# Philipp Wagner <philipp.wagner@tum.de>
import os
import subprocess
import pytest
import logging
import time
import re
import util
logging.basicConfig(level=logging.DEBUG)
class TestTutorial:
"""
Test all simulated examples in the User Guide Tutorial
The goal of this test case is to ensure that the tutorials as described in
the user guide continue to work after changes to OpTiMSoC. It therefore
tests only the examples as given in the tutorial, and does not aim for
full coverage of the used parts of OpTiMSoC.
"""
@pytest.fixture
def sim_system_2x2_cccc_sim_dualcore_debug(self, tmpdir):
cmd_sim = '{}/examples/sim/system_2x2_cccc/system_2x2_cccc_sim_dualcore_debug'.format(os.environ['OPTIMSOC'])
p_sim = util.Process(cmd_sim, logdir=str(tmpdir), cwd=str(tmpdir),
startup_done_expect='Glip TCP DPI listening',
startup_timeout=10)
p_sim.run()
yield p_sim
p_sim.terminate()
def test_baremetal_hello(self, baremetal_apps_hello):
"""
Ensure that all files which are mentioned to result from compiling the
hello world example are actually being generated.
"""
assert baremetal_apps_hello.join('hello.elf').isfile()
assert baremetal_apps_hello.join('hello.dis').isfile()
assert baremetal_apps_hello.join('hello.bin').isfile()
assert baremetal_apps_hello.join('hello.vmem').isfile()
def test_tutorial1(self, baremetal_apps_hello, tmpdir):
"""
Tutorial 1: Run hello world on compute_tile_dm with a single core
"""
# run simulation
cmd = ['{}/examples/sim/compute_tile/compute_tile_sim_singlecore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello.join('hello.vmem')))]
subprocess.check_output(cmd, cwd=str(tmpdir))
# check if output files exist
assert tmpdir.join('stdout.000').isfile()
# compare output to golden reference
assert util.matches_golden_reference(str(tmpdir), 'stdout.000',
filter_func=util.filter_timestamps)
def test_tutorial2(self, baremetal_apps_hello, tmpdir):
"""
Tutorial 2: generate a VCD file
"""
cmd = ['{}/examples/sim/compute_tile/compute_tile_sim_singlecore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello.join('hello.vmem'))),
'--vcd']
subprocess.check_output(cmd, cwd=str(tmpdir))
# XXX: We currently only check if the VCD file is written, not if it
# contains meaningful content.
assert tmpdir.join('sim.vcd').isfile()
def test_tutorial3_dualcore(self, baremetal_apps_hello, tmpdir):
"""
Tutorial 3: like tutorial 1, just using two cores
"""
# run simulation
cmd = ['{}/examples/sim/compute_tile/compute_tile_sim_dualcore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello.join('hello.vmem')))]
subprocess.check_output(cmd, cwd=str(tmpdir))
# check all output files
for f in ['stdout.000', 'stdout.001']:
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_timestamps)
def test_tutorial3_quadcore(self, baremetal_apps_hello, tmpdir):
"""
Tutorial 3: like tutorial 1, just using four cores
"""
# run simulation
cmd = ['{}/examples/sim/compute_tile/compute_tile_sim_quadcore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello.join('hello.vmem')))]
subprocess.check_output(cmd, cwd=str(tmpdir))
# check all output files
for f in ['stdout.000', 'stdout.001', 'stdout.002', 'stdout.003']:
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_timestamps)
def test_tutorial4_hello(self, baremetal_apps_hello, tmpdir):
"""
Tutorial 4: Run hello world application on 2x2 CCCC in Verilator
Memory loading is done through Verilator meminit.
"""
# run simulation
cmd = ['{}/examples/sim/system_2x2_cccc/system_2x2_cccc_sim_dualcore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello.join('hello.vmem')))]
subprocess.check_output(cmd, cwd=str(tmpdir))
# check all output files
for i in range(0, 7):
f = "stdout.{:03d}".format(i)
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_timestamps)
def test_tutorial4_hello_mpsimple(self, baremetal_apps_hello_mpsimple, tmpdir):
"""
Tutorial 4: Run hello_mpsimple world application on 2x2 CCCC in Verilator
Memory loading is done through Verilator meminit.
"""
# run simulation
cmd = ['{}/examples/sim/system_2x2_cccc/system_2x2_cccc_sim_dualcore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello_mpsimple.join('hello_mpsimple.vmem')))]
subprocess.check_output(cmd, cwd=str(tmpdir))
# check all output files
for i in range(0, 7):
f = "stdout.{:03d}".format(i)
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_timestamps)
def test_tutorial5_hello_notrace(self, tmpdir, baremetal_apps_hello,
sim_system_2x2_cccc_sim_dualcore_debug):
"""
Tutorial 5: use osd-target-run and system with debug system to run
software (no trace enabled)
"""
hello_elf = str(baremetal_apps_hello.join('hello.elf'))
cmd_targetrun = ['osd-target-run',
'-e', hello_elf,
'-vvv']
p_targetrun = util.Process(cmd_targetrun, logdir=str(tmpdir),
cwd=str(tmpdir))
p_targetrun.run()
logging.getLogger(__name__).info("Program should terminate itself; give it up to 5 minutes")
p_targetrun.proc.wait(timeout=300)
assert p_targetrun.proc.returncode == 0
logging.getLogger(__name__).info("Now wait 60 seconds until the program has finished execution")
time.sleep(60)
try:
p_targetrun.terminate()
except ProcessLookupError:
# process is already dead
pass
# check the simulation-generated stdout files
for i in range(0, 7):
f = "stdout.{:03d}".format(i)
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_timestamps)
def test_tutorial5_hello_systrace(self, tmpdir, baremetal_apps_hello,
sim_system_2x2_cccc_sim_dualcore_debug):
"""
Tutorial 5: use osd-target-run and system with debug system to run
software (with system trace)
"""
startup_done_string = '[INFO] osd-target-run: System is now running. Press CTRL-C to end tracing.'
hello_elf = str(baremetal_apps_hello.join('hello.elf'))
cmd_targetrun = ['osd-target-run',
'-e', hello_elf,
'--systrace',
'-vvv']
p_targetrun = util.Process(cmd_targetrun, logdir=str(tmpdir),
cwd=str(tmpdir),
startup_done_expect=startup_done_string,
startup_timeout=300)
p_targetrun.run()
logging.getLogger(__name__).info("Record traces for 1 minute")
time.sleep(60)
p_targetrun.send_ctrl_c()
# Give the process some time to clean up
p_targetrun.proc.wait(timeout=30)
assert p_targetrun.proc.returncode == 0
try:
p_targetrun.terminate()
except ProcessLookupError:
# process is already dead
pass
# Ensure that the STM logs are written
stmlogs = [ 'systrace.0002.log', 'systrace.0004.log',
'systrace.0007.log', 'systrace.0009.log',
'systrace.0012.log', 'systrace.0014.log',
'systrace.0017.log', 'systrace.0019.log']
for f in stmlogs:
# STM log file exists
assert tmpdir.join(f).isfile()
# STM log >= 0 bytes
# Currently some of the STM logs don't contain a full trace due to
# overload in the debug system causing dropped packets. Checking for
# such partial logs cannot be done reliably.
f_stat = os.stat(str(tmpdir.join(f)))
assert f_stat.st_size > 0
def test_tutorial5_hello_coretrace(self, tmpdir, baremetal_apps_hello,
sim_system_2x2_cccc_sim_dualcore_debug):
"""
Tutorial 5: use osd-target-run and system with debug system to run
software (with core trace)
"""
startup_done_string = '[INFO] osd-target-run: System is now running. Press CTRL-C to end tracing.'
hello_elf = str(baremetal_apps_hello.join('hello.elf'))
cmd_targetrun = ['osd-target-run',
'-e', hello_elf,
'--coretrace',
'-vvv']
p_targetrun = util.Process(cmd_targetrun, logdir=str(tmpdir),
cwd=str(tmpdir),
startup_done_expect=startup_done_string,
startup_timeout=300)
p_targetrun.run()
logging.getLogger(__name__).info("Record traces for 1 minute")
time.sleep(60)
p_targetrun.send_ctrl_c()
# Give the process some time to clean up
p_targetrun.proc.wait(timeout=30)
assert p_targetrun.proc.returncode == 0
try:
p_targetrun.terminate()
except ProcessLookupError:
# process is already dead
pass
# Ensure that the CTM logs are written
ctmlogs = [ 'coretrace.0003.log', 'coretrace.0005.log',
'coretrace.0008.log', 'coretrace.0010.log',
'coretrace.0013.log', 'coretrace.0015.log',
'coretrace.0018.log', 'coretrace.0020.log']
for f in ctmlogs:
# CTM log file exists
assert tmpdir.join(f).isfile()
# CTM log >= 0 bytes
# Currently some of the CTM logs don't contain a full trace due to
# overload in the debug system causing dropped packets. Checking for
# such partial logs cannot be done reliably.
f_stat = os.stat(str(tmpdir.join(f)))
assert f_stat.st_size > 0
def test_tutorial6_hello_mp(self, baremetal_apps_hello_mp, tmpdir):
"""
Tutorial 8: Run hello_mp world application on 2x2 CCCC in Verilator
Memory loading is done through Verilator meminit.
"""
# run simulation
cmd = ['{}/examples/sim/system_2x2_cccc/system_2x2_cccc_sim_dualcore'.format(os.environ['OPTIMSOC']),
'--meminit={}'.format(str(baremetal_apps_hello_mp.join('hello_mp.vmem')))]
subprocess.check_output(cmd, cwd=str(tmpdir))
# check all output files
for i in range(0, 7):
f = "stdout.{:03d}".format(i)
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_timestamps)
class TestTutorialFpga:
"""
Test all FPGA-based tutorial steps in the User Guide
The tests in this class require the same hardware as used in the User Guide
to be connected to the node that executes this test. Currently, this is the
Nexus 4 DDR board.
"""
def test_tutorial7(self, tmpdir, localconf, baremetal_apps_hello):
"""
Tutorial 7: Program a compute_tile system to a Nexys4 DDR board and run
hello world on it.
"""
# program FPGA with bitstream
bitstream = "{}/examples/fpga/nexys4ddr/compute_tile/compute_tile_nexys4ddr_singlecore.bit".format(os.environ['OPTIMSOC'])
cmd_pgm = ['optimsoc-pgm-fpga', bitstream, 'xc7a100t_0']
p_pgm = util.Process(cmd_pgm, logdir=str(tmpdir), cwd=str(tmpdir))
p_pgm.run()
p_pgm.proc.wait(timeout=300)
assert p_pgm.proc.returncode == 0
time.sleep(2)
# run hello.elf on target board
nexys4ddr_device = localconf['boards']['nexys4ddr']['device']
logging.getLogger(__name__).info("Using Nexys 4 DDR board connected to " + nexys4ddr_device)
glip_backend = 'uart'
glip_backend_options = 'device=%s,speed=12000000' % nexys4ddr_device
hello_elf = str(baremetal_apps_hello.join('hello.elf'))
cmd_targetrun = ['osd-target-run',
'-e', hello_elf,
'-b', glip_backend,
'-o', glip_backend_options,
'--coretrace',
'--systrace',
'--verify',
'-vvv']
startup_done_string = '[INFO] osd-target-run: System is now running. Press CTRL-C to end tracing.'
p_targetrun = util.Process(cmd_targetrun, logdir=str(tmpdir),
cwd=str(tmpdir),
startup_done_expect=startup_done_string,
startup_timeout=300)
p_targetrun.run()
logging.getLogger(__name__).info("Record traces for 30 seconds")
time.sleep(30)
p_targetrun.send_ctrl_c()
# Give the process some time to clean up
p_targetrun.proc.wait(timeout=30)
assert p_targetrun.proc.returncode == 0
try:
p_targetrun.terminate()
except ProcessLookupError:
# process is already dead
pass
# Ensure that the STM logs are written
stmlogs = [ 'systrace.0002.log' ]
for f in stmlogs:
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_osd_trace_timestamps)
# Ensure that the CTM logs are written
ctmlogs = [ 'coretrace.0003.log' ]
for f in ctmlogs:
assert tmpdir.join(f).isfile()
assert util.matches_golden_reference(str(tmpdir), f,
filter_func=util.filter_osd_trace_timestamps)
def test_tutorial_linux(self, tmpdir, localconf, linux_compute_tile_singlecore):
"""
Tutorial 8: Execute the Linux example in the tutorial
"""
# program FPGA with bitstream
bitstream = "{}/examples/fpga/nexys4ddr/compute_tile/compute_tile_nexys4ddr_singlecore.bit".format(os.environ['OPTIMSOC'])
cmd_pgm = ['optimsoc-pgm-fpga', bitstream, 'xc7a100t_0']
p_pgm = util.Process(cmd_pgm, logdir=str(tmpdir), cwd=str(tmpdir))
p_pgm.run()
p_pgm.proc.wait(timeout=300)
assert p_pgm.proc.returncode == 0
time.sleep(2)
# run hello.elf on target board
nexys4ddr_device = localconf['boards']['nexys4ddr']['device']
logging.getLogger(__name__).info("Using Nexys 4 DDR board connected to " + nexys4ddr_device)
glip_backend = 'uart'
glip_backend_options = 'device=%s,speed=12000000' % nexys4ddr_device
vmlinux = str(linux_compute_tile_singlecore)
cmd_targetrun = ['osd-target-run',
'-e', vmlinux,
'-b', glip_backend,
'-o', glip_backend_options,
'--systrace',
'--verify',
'--terminal',
'-vvv']
startup_done_string = '[INFO] osd-target-run: System is now running. Press CTRL-C to end tracing.'
p_targetrun = util.Process(cmd_targetrun, logdir=str(tmpdir),
cwd=str(tmpdir),
startup_done_expect=startup_done_string,
startup_timeout=300)
p_targetrun.run()
# Find allocated pseudo-terminal (expected to appear within 10 seconds)
tty_dev = None
search = re.compile(r'^.+DEM-UART pseudo-terminal available at (/dev/pts/\d+)')
match = p_targetrun._find_in_output(search, timeout = 5)
tty_dev = match.group(1)
assert tty_dev
logging.getLogger(__name__).info("Linux console available at " + tty_dev)
# Wait for Linux to boot
logging.getLogger(__name__).info("Run Linux until we get a login prompt")
cmd_tty_cat = ['cat', tty_dev]
p_tty_cat = util.Process(cmd_tty_cat, logdir=str(tmpdir),
cwd=str(tmpdir),
startup_done_expect="Welcome to OpTiMSoC",
startup_timeout=60)
p_tty_cat.run()
p_tty_cat.send_ctrl_c()
p_tty_cat.proc.wait(timeout=5)
try:
p_tty_cat.terminate()
except ProcessLookupError:
# process is already dead
pass
p_targetrun.send_ctrl_c()
# Give the process some time to clean up
p_targetrun.proc.wait(timeout=30)
try:
p_targetrun.terminate()
except ProcessLookupError:
# process is already dead
pass