Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse learn trace #42

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TOOLS = \
fann-random \
fann-train \
generate-ant \
parse-learn-trace \
fann-eval \
fann-eval-fixed
BINS = $(addprefix $(DIR_BIN)/, $(TOOLS))
Expand Down Expand Up @@ -48,11 +49,15 @@ LDIRS = \
$(DIR_BIN)/fann-train.o \
$(DIR_BIN)/fann-random.o \
$(DIR_BIN)/fann-float-to-fixed.o \
$(DIR_BIN)/generate-ant.o
$(DIR_BIN)/generate-ant.o \
$(DIR_BIN)/parse-learn-trace.o

$(DIR_BIN)/generate-ant: $(DIR_BIN)/generate-ant.o $(DIR_TOP)/tests/libs/build/$(TARGET)/libxfiles-ant.a $(libfann_dep)
$(CC) $(CFLAGS) $< $(LDIRS) -lxfiles-ant -o $@

$(DIR_BIN)/parse-learn-trace: $(DIR_BIN)/parse-learn-trace.o $(DIR_TOP)/tests/libs/build/$(TARGET)/libxfiles-ant.a $(libfann_dep)
$(CC) $(CFLAGS) $< $(LDIRS) -lxfiles-ant -o $@

# No pattern rules as I need to be explicit about what is linking
# against FANN since it's LGPLv2

Expand Down
29 changes: 28 additions & 1 deletion tools/scripts/parse_emu_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
import os
import mmap
import ipdb
import struct
from collections import defaultdict

re_in_out_mapping = re.compile(r'RegFile: (?:Saw TTable write|PE write element).+(?P<tidx>0x[0-9a-fA-F]+)\/(?P<addr>0x[0-9a-fA-F]+)\/(?P<data>0x[0-9a-fA-F]+)')
re_sram_blo_inc = re.compile(r'SramBloInc[\D\s]+0x[01]\/0x1.+\n[\D\s]+(?P<addr>0x[a-f0-9]+)\/(?P<dataOld>0x[a-f0-9]+)\/(?P<dataNew>0x[a-f0-9]+)')
re_in_val = re.compile(r'queueIn\[0\]\sdeq\s\[data:(0x[\da-f]+)')
re_out_val = re.compile(r'queueOut\[0\]\sdeq\s\[data:(0x[\da-f]+)')
re_in_out_val = re.compile(r"(?P<inputs>(?:[a-f0-9]+\s)+)->(?P<outputs>(?:\s[a-f0-9]+)+)")
re_store_data = re.compile(r"Received store data 0x([\da-f]+)")
path_fann_eval_fixed = 'tools/bin/fann-eval-fixed'
#path_emulator_bin = 'emulator/emulator-rocketchip-XFilesDanaCppPe1Epb4Config'
path_emulator_bin = 'emulator/emulator-rocketchip-XFilesDanaCppPe4Epb4Config'
Expand Down Expand Up @@ -113,7 +115,8 @@ def parse_fann_eval_fixed_trace(trace_file_path, write_file=False):
return fann_fixed_outputs


@click.command()

@click.group()
@click.option('--net_file_path', '-n', type=click.Path(exists=True), required=False)
@click.option('--train_file_path', '-t', type=click.Path(exists=True), required=False)
@click.option('--fann_trace_file_path', '-ft', type=click.Path(exists=True), required=False)
Expand All @@ -124,6 +127,8 @@ def parse_fann_eval_fixed_trace(trace_file_path, write_file=False):
@click.option('--debug', is_flag=True, required=False)
@click.option('--learn', is_flag=True, required=False)
def cli(net_file_path, train_file_path, fann_trace_file_path, baremetal_bin_file_path, baremetal_trace_file_path, test_list_file_path, trace_list_file_path, debug, learn):
pass

if test_list_file_path:
with open(test_list_file_path, 'r') as test_list_file:
test_list = test_list_file.read()
Expand Down Expand Up @@ -214,6 +219,8 @@ def cli(net_file_path, train_file_path, fann_trace_file_path, baremetal_bin_file
print(item['data'])
ipdb.set_trace()
else:
parse_learn_trace_new(baremetal_trace_file_path)
sys.exit(0)
print("Generating baremetal trace")
baremetal_trace_file_path = baremetal_trace_file_path or generate_baremetal_trace(path_emulator_bin, baremetal_bin_file_path)
print("Parsing baremetal trace")
Expand Down Expand Up @@ -267,5 +274,25 @@ def cli(net_file_path, train_file_path, fann_trace_file_path, baremetal_bin_file
j = int(j.decode("utf-8"), 16)
print("{}, {}, {}".format(j, out_val, abs(j - out_val)))

@cli.command()
@click.option('--baremetal_trace_file_path', '-bt', type=click.Path(exists=True), required=False)
def parse_learn_trace_new(baremetal_trace_file_path):
with open(baremetal_trace_file_path) as learn_trace_file:
with open('a.out', 'wb') as out_file:
for line in learn_trace_file:
res = re_store_data.search(line)
if res:
foo = res.groups()[0]
print(foo)
bar = []
for i in range(0, len(foo), 4):
baz = foo[i+2:i+4] + foo[i:i+2]
bar.append(baz)
bar.reverse()
baz = ''.join(bar)
print(baz)
print()
out_file.write(bytes.fromhex(baz))

if __name__ == '__main__':
cli()
298 changes: 298 additions & 0 deletions tools/scripts/tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
#!/usr/bin/env python3
"""tt - the xfiles-dana test tool

Provides functions for running emulator tests and inspecting memory

Usage: tt --help
"""

import click
from re import compile
from os import path
from subprocess import run, PIPE, DEVNULL, TimeoutExpired
# from ipdb import set_trace
from os import system


@click.group()
@click.option('--debug', is_flag=True)
@click.option('--rocket_chip_project_path')
@click.pass_context
def tt(ctx, debug, rocket_chip_project_path):
ctx.obj['DEBUG'] = debug
rocket_chip_project_path = rocket_chip_project_path or os.environ.get(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was running this on my machine and I needed to import os. Can you verify that this does work?

'ROCKET_CHIP_PROJECT_PATH')
assert rocket_chip_project_path, "Must specify option rocket_chip_project_path or define ROCKET_CHIP_PROJECT_PATH environment variable"
ctx.obj['ROCKET_CHIP_PROJECT_PATH'] = rocket_chip_project_path
if debug:
click.echo("rocket_chip_path: {}".format(rocket_chip_project_path))
xfiles_dana_path = path.join(rocket_chip_project_path, 'xfiles-dana')
if debug:
click.echo("xfiles_dana_path: {}".format(xfiles_dana_path))
ctx.obj['XFILES_DANA_PATH'] = xfiles_dana_path


@tt.command()
@click.argument('test_names', nargs=-1)
@click.pass_context
def emu_test(ctx, test_names, timeout=300):
"""Run a baremetal emulation test."""
debug = ctx.obj['DEBUG']
rocket_chip_path = ctx.obj['ROCKET_CHIP_PATH']
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ROCKET_CHIP_PROJECT_PATH

xfiles_dana_path = ctx.obj['XFILES_DANA_PATH']

# Build and assert paths
emulator_bin_path = path.join(
rocket_chip_path,
'emulator',
'emulator-rocketchip-VelvetConfig')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The emulator name is not a known quantity and will be emulator-[package]-[config]. I think it's safe to just specify the name of the emulator with an additional command line option.

assert path.exists(emulator_bin_path), "emulator_bin_path does not exist!"
ctx.obj['EMULATOR_BIN_PATH'] = emulator_bin_path
parse_learn_bin_path = path.join(
xfiles_dana_path, 'tools', 'bin', 'parse-learn-trace')
assert path.exists(
parse_learn_bin_path), "parse_learn_bin_path does not exist!"
ctx.obj['PARSE_LEARN_BIN_PATH'] = parse_learn_bin_path
baremetal_bin_dir_path = path.join(
xfiles_dana_path, 'tests', 'build', 'nets')
assert path.exists(
baremetal_bin_dir_path), "baremetal_bin_dir_path does not exist!"
ctx.obj['BAREMETAL_BIN_DIR_PATH'] = baremetal_bin_dir_path
build_nets_dir_path = path.join(xfiles_dana_path, 'build', 'nets')
assert path.exists(
build_nets_dir_path), "build_nets_dir_path does not exist!"
ctx.obj['BUILD_NETS_DIR_PATH'] = build_nets_dir_path

# Run tests
for test_name in test_names:
if debug:
click.echo('Running emulation test {}'.format(test_name))
# Build and assert test path
baremetal_bin_file_name = test_name
baremetal_bin_file_path = path.join(
baremetal_bin_dir_path, baremetal_bin_file_name)
baremetal_trace_file_name = baremetal_bin_file_name + '.test.trace'
baremetal_trace_file_path = baremetal_trace_file_name
if debug:
click.echo('baremetal_bin_file_path: {}'.format(
baremetal_bin_file_path))
assert path.exists(baremetal_bin_file_path), "baremetal_bin_file_path {} does not exist!".format(
baremetal_bin_file_path)

# Run test with timeout. If timeout expires, proceed to next test.
# Write test debug output to file
try:
emulator = run([emulator_bin_path,
'+verbose',
baremetal_bin_file_path],
stderr=PIPE,
timeout=timeout)
except TimeoutExpired as e:
click.echo(e)
continue
with open(baremetal_trace_file_path, 'wb') as baremetal_trace_file:
for line in emulator.stderr.splitlines():
if chr(line[0]) == '[':
baremetal_trace_file.write(line)
baremetal_trace_file.write(b'\n')


def _diff_cache_dump(
debug,
cache_dump_ascii_file_path_0,
cache_dump_ascii_file_path_1,
out_file_path=None):
"""Helper function to run diff on two cache dumps processed by parse_learn_trace. Optionally write output to file"""
if out_file_path:
cmd = ' '.join(['diff', '-y', cache_dump_ascii_file_path_0,
cache_dump_ascii_file_path_1, '>', out_file_path])
else:
cmd = ' '.join(['diff',
'-y',
cache_dump_ascii_file_path_0,
cache_dump_ascii_file_path_1])
if debug:
click.echo(cmd)
system(cmd)


def _parse_learn_trace(
ctx,
cache_dump_bin_file_path,
cache_dump_ascii_file_name):
"""Helper function to convert binary cache dump to ascii cache dump"""
debug = ctx.obj['DEBUG']
parse_learn_bin_path = ctx.obj['PARSE_LEARN_BIN_PATH']
cmd = ' '.join([parse_learn_bin_path,
cache_dump_bin_file_path,
'>',
cache_dump_ascii_file_name])
if debug:
click.echo(cmd)
system(cmd)


@tt.command()
@click.argument('emu_cache_dump_ascii_file_paths', nargs=-1)
@click.pass_context
def diff_cache_dumps(ctx, emu_cache_dump_ascii_file_paths):
"""Run diff on a list of ascii-format emulator dumps. Expects xfiles-emu-nets filenames.

Emulator cache dump file names are assumed to be xfiles-emu-nets-p-<net name>.cache.ascii
FANN cache dump file names are assumed to be <net name>-fixed.16bin.cache.ascii

Usage: find . '*.cache.ascii' |xargs tt diff_cache_dumps

Outputs: <net name>.cache.ascii.diff"""

debug = ctx.obj['DEBUG']
xfiles_dana_path = ctx.obj['XFILES_DANA_PATH']
build_nets_dir_path = path.join(xfiles_dana_path, 'build', 'nets')
_build_parse_learn_bin_path(ctx)
for emu_cache_dump_ascii_file_path in emu_cache_dump_ascii_file_paths:
# Get the filename
foo = emu_cache_dump_ascii_file_path.split('/')[-1]
# Remove the filename extension
net_name = foo.split('.')[0][19:-6]
if debug:
click.echo(net_name)
baseline_cache_bin_file_path = path.join(
build_nets_dir_path, net_name + '-fixed.16bin')
if debug:
click.echo(baseline_cache_bin_file_path)
# parse_learn_trace of baseline cache
_parse_learn_trace(
ctx,
baseline_cache_bin_file_path,
net_name +
'-fixed.cache.ascii')
_diff_cache_dump(
ctx,
net_name +
'-fixed.cache.ascii',
emu_cache_dump_ascii_file_path,
net_name +
'.cache.ascii.diff')


def _build_parse_learn_bin_path(ctx):
"""Helper function that adds PARSE_LEARN_BIN_PATH to the context"""
# Get xfiles-dana path from context
xfiles_dana_path = ctx.obj['XFILES_DANA_PATH']
# Build path to parse-learn-trace, assert it exists
parse_learn_bin_path = path.join(
xfiles_dana_path, 'tools', 'bin', 'parse-learn-trace')
assert path.exists(
parse_learn_bin_path), "parse_learn_bin_path does not exist!"
ctx.obj['PARSE_LEARN_BIN_PATH'] = parse_learn_bin_path


@tt.command()
@click.argument('cache_dump_bin_file_paths', nargs=-1)
@click.pass_context
def dump_cache_ascii(ctx, cache_dump_bin_file_paths):
"""Convert a list of binary cache dumps to ascii

Usage: find . '*.cache.bin' |xargs tt dump_cache_ascii

Outputs: <input_file_name>.cache.ascii"""
debug = ctx.obj['DEBUG']
_build_parse_learn_bin_path(ctx)
# Iterate over binary cache dump files
for cache_dump_bin_file_path in cache_dump_bin_file_paths:
# Get the filename
foo = cache_dump_bin_file_path.split('/')[-1]
# Remove the filename extension
cache_dump_bin_file_name = foo.split('.')[0]
if debug:
click.echo(cache_dump_bin_file_name)
# Run parse-learn-trace and dump ascii
_parse_learn_trace(
ctx,
cache_dump_bin_file_path,
cache_dump_bin_file_name +
'.cache.ascii')

# @tt.command()
# @click.argument('cache_dump_names', nargs=-1)
# @click.pass_context
# def compare_cache_dumps(ctx, cache_dump_names):
# xfiles_dana_path = ctx.obj['XFILES_DANA_PATH']
# build_nets_dir_path = path.join(xfiles_dana_path, 'build', 'nets')
# assert path.exists(build_nets_dir_path), "build_nets_dir_path does not exist!"
# parse_learn_bin_path = path.join(xfiles_dana_path, 'tools', 'bin', 'parse-learn-trace')
# assert path.exists(parse_learn_bin_path), "parse_learn_bin_path does not exist!"
# ctx.obj['PARSE_LEARN_BIN_PATH'] = parse_learn_bin_path
# for name in cache_dump_names:
# baseline_cache_file_name = name[19:-19] + '-fixed.16bin'
# baseline_cache_file_path = path.join(build_nets_dir_path, baseline_cache_file_name)
# click.echo(name)
# click.echo(baseline_cache_file_path)
# # Convert binary cache trace to ascii cache trace
# _parse_learn_trace(ctx, baseline_cache_file_path, baseline_cache_file_name + '.cache.ascii')
# click.echo()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove



def _parse_store_data_from_line(debug, res):
"""_cache_dump helper function that fixes endinaness"""
foo = res.groups()[0]
# if debug: click.echo(foo)
bar = []
for i in range(0, len(foo), 4):
baz = foo[i + 2:i + 4] + foo[i:i + 2]
bar.append(baz)
bar.reverse()
baz = ''.join(bar)
# if debug: click.echo(baz)
return baz


def _cache_dump(debug, baremetal_trace_file_path, cache_dump_file_path):
"""Given a baremetal trace file path, find the cache lines and dump them to a binary file

Returns: list of found cache lines"""
re_store_data = compile(r"Received store data 0x([\da-f]+)")
cache_dump_res = []
# Search the trace file line-by-line,
# store found cache lines in list `cache_dump_res`
with open(baremetal_trace_file_path) as trace_file:
for line in trace_file:
res = re_store_data.search(line)
if res:
foo = _parse_store_data_from_line(debug, res)
cache_dump_res.append(foo)
if debug:
click.echo(cache_dump_res)
if cache_dump_res:
with open(cache_dump_file_path, 'wb') as out_file:
for line in cache_dump_res:
out_file.write(bytes.fromhex(line))
return cache_dump_res


@tt.command()
@click.argument('baremetal_trace_file_paths', nargs=-1)
@click.pass_context
def dump_cache_bin(ctx, baremetal_trace_file_paths):
"""Dump binary format cache lines from baremetal learn trace files.

Usage: find . -name '*learn.test.trace' |xargs tt cache_dump_bin

Outputs: <file name>.cache.bin"""
debug = ctx.obj['DEBUG']
for baremetal_trace_file_path in baremetal_trace_file_paths:
# Get the filename
foo = baremetal_trace_file_path.split('/')[-1]
# Remove the filename extension
cache_dump_bin_file_name = foo.split('.')[0]
if debug:
click.echo(cache_dump_bin_file_name)
_cache_dump(
debug,
baremetal_trace_file_path,
cache_dump_bin_file_name +
'.cache.bin')


if __name__ == '__main__':
tt(obj={})
Loading