diff --git a/hls4ml/backends/oneapi/oneapi_backend.py b/hls4ml/backends/oneapi/oneapi_backend.py index f527746454..a4000529c3 100644 --- a/hls4ml/backends/oneapi/oneapi_backend.py +++ b/hls4ml/backends/oneapi/oneapi_backend.py @@ -10,6 +10,7 @@ from hls4ml.model.layers import GRU, LSTM, Activation, Conv1D, Conv2D, Dense, Embedding, Layer, SimpleRNN, Softmax from hls4ml.model.optimizer import get_backend_passes, layer_optimizer from hls4ml.model.types import FixedPrecisionType, IntegerPrecisionType, NamedType +from hls4ml.report import parse_oneapi_report from hls4ml.utils import attribute_descriptions as descriptions # from hls4ml.report import parse_oneapi_report @@ -207,6 +208,8 @@ def build(self, model, build_type='fpga_emu', run=False): executable = builddir / f'{model.config.get_project_name()}.{build_type}' subprocess.run(f'{str(executable)}', shell=True, cwd=builddir, check=True) + return parse_oneapi_report(model.config.get_output_dir()) + @layer_optimizer(Layer) def init_base_layer(self, layer): reuse_factor = layer.model.config.get_reuse_factor(layer) diff --git a/hls4ml/report/__init__.py b/hls4ml/report/__init__.py index 3c9b7707b7..1afe1598fa 100644 --- a/hls4ml/report/__init__.py +++ b/hls4ml/report/__init__.py @@ -1,6 +1,8 @@ from hls4ml.report.catapult_report import parse_catapult_report # noqa: F401 from hls4ml.report.catapult_report import qofr # noqa: F401 from hls4ml.report.catapult_report import read_catapult_report # noqa: F401 +from hls4ml.report.oneapi_report import parse_oneapi_report # noqa: F401 +from hls4ml.report.oneapi_report import print_oneapi_report # noqa: F401 from hls4ml.report.quartus_report import parse_quartus_report # noqa: F401 from hls4ml.report.quartus_report import read_quartus_report # noqa: F401 from hls4ml.report.vivado_report import parse_vivado_report # noqa: F401 diff --git a/hls4ml/report/oneapi_report.py b/hls4ml/report/oneapi_report.py new file mode 100644 index 0000000000..55ad2532c0 --- /dev/null +++ b/hls4ml/report/oneapi_report.py @@ -0,0 +1,378 @@ +import glob +import json +import os +import re + + +def _convert_to_oneapi_naming(s): + s2 = s.lower() + + # Capitalize the first letter + s2 = s.capitalize() + + # Capitalize letters after numbers and underscores, and remove underscores + s2 = re.sub(r'(_|\d)([a-z])', lambda m: m.group(1) + m.group(2).upper(), s2) + + # Remove underscores + s2 = s2.replace('_', '') + + return s2 + + +def _find_projects(hls_dir): + prjList = glob.glob(os.path.join(hls_dir, '**/*.prj')) + + if not prjList: + print('No project folders found in target directory!') + return + + if len(prjList) > 1: + firstName = os.path.basename(prjList[0]).rsplit('.', 2)[0] + for prj in prjList[1:]: + newName = os.path.basename(prj).rsplit('.', 2)[0] + if newName != firstName: + print( + 'Multiple project folders found in target directory! ' + + 'Make sure that only one is present (multiple targets are allowed)' + ) + return + + return prjList + + +def _parse_single_report(prjDir): + + if not os.path.exists(prjDir): + print(f'Path {prjDir} does not exist. Exiting.') + return + + report = {} + + PathJson = prjDir + '/reports/resources/json/' + PathQuartusJson = PathJson + 'quartus.ndjson' + PathHLSJson = PathJson + 'summary.ndjson' + PathLoopJson = PathJson + 'loop_attr.ndjson' + # PathInfoJson = PathJson + 'info.ndjson' + # PathSimDataJson = PathJson + 'simulation_raw.ndjson' + + targetName, makeType, _ = os.path.basename(prjDir).rsplit('.', 2) + simTask = _convert_to_oneapi_naming(targetName) + # if targetName not in report: + # report[targetName] = {} + + # you will probably need to modify this section if you compile a design with + # multiple HLS components. + if not os.path.exists(PathQuartusJson) or not os.path.exists(PathHLSJson) or not os.path.exists(PathLoopJson): + print('Unable to read project data. Exiting.') + return + + with open(PathQuartusJson) as fileQuartusData: + JsonDataQuartus = json.load(fileQuartusData) + with open(PathHLSJson) as fileHLSData: + JsonDataHLS = [] + for line in fileHLSData: + JsonDataHLS.append(json.loads(line)) + with open(PathLoopJson) as fileLoopData: + JsonDataLoop = [] + for line in fileLoopData: + JsonDataLoop.append(json.loads(line)) + # with open(PathInfoJson, 'r') as fileInfo: + # JsonInfo = json.load(fileInfo) + # simTask = str(JsonInfo['compileInfo']['nodes'][0]['name']) + + # read synthesis info in quartus.ndjson + if makeType == 'fpga': + quartusReport = {} + + componentNode = -1 + for nodeIdx in range(len(JsonDataQuartus['quartusFitResourceUsageSummary']['nodes'])): + if JsonDataQuartus['quartusFitResourceUsageSummary']['nodes'][nodeIdx]['name'] == simTask: + componentNode = nodeIdx + if componentNode == -1: + componentNode = 0 + print( + 'Could not find component named %s in quartus data. use component %s instead.' + % (simTask, JsonDataQuartus['quartusFitResourceUsageSummary']['nodes'][componentNode]['name']) + ) + + quartusReport['fmax'] = JsonDataQuartus['quartusFitClockSummary']['nodes'][0]['clock fmax'] + resourcesList = ['alm', 'alut', 'reg', 'dsp', 'ram', 'mlab'] + for resource in resourcesList: + quartusReport[resource] = JsonDataQuartus['quartusFitResourceUsageSummary']['nodes'][componentNode][resource] + + report['Quartus'] = quartusReport + + # read HLS info in summary.ndjson + hlsReport = {} + hlsReport['total'] = {} + hlsReport['available'] = {} + resourcesList = ['alut', 'reg', 'ram', 'dsp', 'mlab'] + for line in JsonDataHLS: + if line['name'] == 'Available' or line['name'] == 'Total': + resourceType = line['name'].lower() + for i_resource, resource in enumerate(resourcesList): + hlsReport[resourceType][resource] = line['data'][i_resource] + + report['HLS'] = hlsReport + + # read latency and II in loop_attr.ndjson + loopReport = {} + worstFrequency = 1e9 + worstII = 0 + worstLatency = 0 + for loopInfo in JsonDataLoop: + if 'af' not in loopInfo or 'ii' not in loopInfo or 'lt' not in loopInfo: + continue + if float(loopInfo['af']) < worstFrequency: + worstFrequency = float(loopInfo['af']) + if int(loopInfo['ii']) > worstII: + worstII = int(loopInfo['ii']) + if float(loopInfo['lt']) > worstLatency: + worstLatency = float(loopInfo['lt']) + loopReport = {'worstFrequency': str(worstFrequency), 'worstII': str(worstII), 'worstLatency': str(worstLatency)} + + report['Loop'] = loopReport + + return report + + +def parse_oneapi_report(hls_dir): + ''' + Parse a report from a given oneAPI project as a dictionary. + + Args: + hls_dir (string): The directory where the project is found + Returns: + results (dict): The report dictionary, containing latency, resource usage etc. + + ''' + prjList = _find_projects(hls_dir) + if not prjList: + return + + report = {} + for prj in prjList: + targetType = os.path.basename(prjList[0]).rsplit('.', 2)[1] + report[targetType] = _parse_single_report(prj) + + return report + + +def print_oneapi_report(report_dict): + ''' + Prints the oneAPI report dictionary as a table. + + Args: + report_dict (dictionary): The report dictionary, containing latency, resource usage etc. + + Returns: + None + + ''' + for prjTarget, prjReport in report_dict.items(): + if len(report_dict) > 1: + print('*' * 54 + '\n') + print(f'Report for {prjTarget}:') + if _is_running_in_notebook(): + _print_ipython_report(prjReport) + else: + _print_str_report(prjReport) + + +def _print_ipython_report(report_dict): + from IPython.display import HTML, display + + html = '\n' + _table_css + '
' + body = _make_report_body(report_dict, _make_html_table_template, _make_html_header) + html += body + '\n
\n' + display(HTML(html)) + + +def _print_str_report(report_dict): + body = _make_report_body(report_dict, _make_str_table_template, _make_str_header) + print(body) + + +def _is_running_in_notebook(): + try: + from IPython import get_ipython + + shell = get_ipython().__class__.__name__ + if shell == 'ZMQInteractiveShell': + return True # Jupyter notebook or qtconsole + elif shell == 'TerminalInteractiveShell': + return False # Terminal running IPython + else: + return False # Other type (?) + except NameError: + return False # Probably standard Python interpreter + + +_table_css = ''' + +''' + +_table_base_template = ''' + + + + + + + +{table_rows} + +
{table_header}
+''' + + +def _make_html_table_template(table_header, row_templates): + + num_columns = len(next(iter(row_templates.values()))) + + _row_html_template = ' {{}}' + ''.join('{{{}}}' for _ in range(num_columns)) + '' + + table_rows = '\n'.join( + [_row_html_template.format(row_title, *row_keys) for row_title, row_keys in row_templates.items()] + ) + return _table_base_template.format(colspan=num_columns + 1, table_header=table_header, table_rows=table_rows) + + +def _make_str_table_template(table_header, row_templates): + + len_title = 0 + for row_title in row_templates.keys(): + if len(row_title) > len_title: + len_title = len(row_title) + + head = f'\n - {table_header}:\n' + table_rows = '\n'.join( + [ + ' ' + f'{row_title}:'.ljust(len_title + 2) + ''.join(f' {{{entry}:<17}}' for entry in row_keys) + for row_title, row_keys in row_templates.items() + ] + ) + + return head + table_rows + '\n' + + +def _make_html_header(report_header): + return f'

{report_header}:

' + + +def _make_str_header(report_header): + sep = '=' * 50 + '\n' + return '\n' + sep + '== ' + report_header + '\n' + sep + + +def _get_percentage(part, total): + percentage = round(part / total * 100, 1) + if percentage >= 0.1: + return ' (' + str(percentage) + '%)' + else: + return ' (< 0.1%)' + + +def _make_report_body(report_dict, make_table_template, make_header_template): + body = '' + + perf_rows = { + 'Minimum Frequency (HLS)': ['worst_freq'], + # 'Best-case latency': 'best_latency', + 'Worst-case latency (HLS)': ['worst_latency'], + # 'Interval Min': 'interval_min', + 'Max II (HLS)': ['worst_II'], + # 'Estimated Clock Period': 'estimated_clock', + } + area_rows = { + '': ['hls', 'avail'], + 'ALUTs': ['alut_hls', 'alut_avail'], + 'FFs': ['reg_hls', 'reg_avail'], + 'DSPs': ['dsp_hls', 'dsp_avail'], + 'RAMs': ['ram_hls', 'ram_avail'], + 'MLABs': ['mlab_hls', 'mlab_avail'], + } + + if 'Quartus' not in report_dict: + body += make_header_template('FPGA HLS') + else: + body += make_header_template('FPGA Hardware Synthesis') + + perf_rows['Maximum Frequency'] = ['fmax'] + + area_rows['ALMs'] = ['alm_quartus', 'alm_hls', 'alm_avail'] + area_rows[''].insert(0, 'quartus') + area_rows['ALUTs'].insert(0, 'alut_quartus') + area_rows['FFs'].insert(0, 'reg_quartus') + area_rows['DSPs'].insert(0, 'dsp_quartus') + area_rows['RAMs'].insert(0, 'ram_quartus') + area_rows['MLABs'].insert(0, 'mlab_quartus') + + body += make_table_template('Performance estimates', perf_rows) + body += make_table_template('Resource estimates', area_rows) + + params = {} + params['worst_freq'] = report_dict['Loop']['worstFrequency'] + params['worst_II'] = report_dict['Loop']['worstII'] + params['worst_latency'] = report_dict['Loop']['worstLatency'] + params['hls'] = 'HLS Estimation' + params['avail'] = 'Available' + resourcesList = ['alut', 'reg', 'ram', 'dsp', 'mlab'] + for resource in resourcesList: + resource_hls = int(report_dict['HLS']['total'][resource]) + resource_avail = int(report_dict['HLS']['available'][resource]) + params[resource + '_hls'] = str(resource_hls) + _get_percentage(resource_hls, resource_avail) + params[resource + '_avail'] = str(resource_avail) + if 'Quartus' in report_dict: + resource_quartus = int(report_dict['Quartus'][resource]) + params[resource + '_quartus'] = str(resource_quartus) + _get_percentage(resource_quartus, resource_avail) + + if 'Quartus' in report_dict: + params['quartus'] = 'Quartus Synthesis' + params['fmax'] = report_dict['Quartus']['fmax'] + params['alm_quartus'] = report_dict['Quartus']['alm'] + params['alm_hls'] = 'N/A' + params['alm_avail'] = 'N/A' + + body = body.format(**params) + + return body diff --git a/test/pytest/test_report.py b/test/pytest/test_report.py index 5181dbe4ab..2410c3a88b 100644 --- a/test/pytest/test_report.py +++ b/test/pytest/test_report.py @@ -11,66 +11,140 @@ test_root_path = Path(__file__).parent -@pytest.mark.parametrize('backend', ['Vivado']) -def test_report(backend, capsys): +def copy_vivado_report(output_dir, test_report_dir): + # copy pregenerated Vivado reports + os.makedirs(f'{output_dir}/myproject_prj/solution1/syn/report', exist_ok=True) + shutil.copy(test_report_dir / 'vivado_hls.app', f'{output_dir}/myproject_prj/vivado_hls.app') + shutil.copy( + test_report_dir / 'myproject_csynth.rpt', f'{output_dir}/myproject_prj/solution1/syn/report/myproject_csynth.rpt' + ) + shutil.copy( + test_report_dir / 'myproject_csynth.xml', f'{output_dir}/myproject_prj/solution1/syn/report/myproject_csynth.xml' + ) + shutil.copy(test_report_dir / 'vivado_synth.rpt', f'{output_dir}/vivado_synth.rpt') + + return + + +def copy_oneapi_report(output_dir, test_report_dir): + # copy pregenerated oneAPI reports + json_dir = f'{output_dir}/build/myproject.fpga.prj/reports/resources/json' + os.makedirs(json_dir, exist_ok=True) + shutil.copy(test_report_dir / 'quartus.ndjson', f'{json_dir}/quartus.ndjson') + shutil.copy(test_report_dir / 'summary.ndjson', f'{json_dir}/summary.ndjson') + shutil.copy(test_report_dir / 'loop_attr.ndjson', f'{json_dir}/loop_attr.ndjson') + + return + + +@pytest.fixture +def backend_configs(): + """Returns configuration settings for different backends.""" + config_dict = { + 'Vivado': { + 'backend': 'Vivado', + 'part': 'xc7z020clg400-1', + 'build': {'synth': True, 'vsynth': True}, + 'copy_func': copy_vivado_report, + 'parse_func': hls4ml.report.parse_vivado_report, + 'print_func': hls4ml.report.print_vivado_report, + 'expected_outcome': '\n' + + '======================================================\n' + + '== C Synthesis report\n' + + '======================================================\n\n' + + ' - Performance estimates:\n' + + ' Best-case latency: 10 (50.0 ns)\n' + + ' Worst-case latency: 10 (50.0 ns)\n' + + ' Interval Min: 8\n' + + ' Interval Max: 8\n' + + ' Estimated Clock Period: 4.049\n\n' + + ' - Resource estimates:\n' + + ' BRAM_18K: 0 / 280 (0.0%)\n' + + ' DSP: 73 / 220 (33.2%)\n' + + ' FF: 7969 / 106400 (7.5%)\n' + + ' LUT: 2532 / 53200 (4.8%)\n' + + ' URAM: N/A\n\n' + + '======================================================\n' + + '== Vivado Synthesis report\n' + + '======================================================\n\n' + + ' - Resource utilization:\n' + + ' BRAM_18K: 0\n' + + ' DSP48E: 66\n' + + ' FF: 2428\n' + + ' LUT: 1526\n' + + ' URAM: N/A\n\n', + }, + 'oneAPI': { + 'backend': 'oneAPI', + 'part': 'Agilex7', + 'build': {'build_type': 'fpga'}, + 'copy_func': copy_oneapi_report, + 'parse_func': hls4ml.report.parse_oneapi_report, + 'print_func': hls4ml.report.print_oneapi_report, + 'expected_outcome': '\n' + + '==================================================\n' + + '== FPGA Hardware Synthesis\n' + + '==================================================\n\n' + + ' - Performance estimates:\n' + + ' Minimum Frequency (HLS): 480.0 \n' + + ' Worst-case latency (HLS): 200.0 \n' + + ' Max II (HLS): 1 \n' + + ' Maximum Frequency: 597.73 \n\n' + + ' - Resource estimates:\n' + + ' : Quartus Synthesis HLS Estimation Available \n' + + ' ALUTs: 4181 (0.4%) 2462 (0.3%) 974400 \n' + + ' FFs: 16419 (0.8%) 7938 (0.4%) 1948800 \n' + + ' DSPs: 40 (0.9%) 0 (< 0.1%) 4510 \n' + + ' RAMs: 36 (0.5%) 77 (1.1%) 7110 \n' + + ' MLABs: 52 (0.2%) 92 (0.4%) 24360 \n' + + ' ALMs: 4520.0 N/A N/A \n\n', + }, + } + + return config_dict + + +@pytest.fixture +def hls_model_setup(request, backend_configs, tmp_path): + """Fixture to create, write, and copy the report files of the HLS model + for a given backend.""" + backend_config = backend_configs[request.param] + model = Sequential() model.add(Dense(5, input_shape=(16,), name='fc1', activation='relu')) config = hls4ml.utils.config_from_keras_model(model, granularity='model') - output_dir = str(test_root_path / f'hls4mlprj_report_{backend}') - test_report_dir = test_root_path / 'test_report' + output_dir = str(tmp_path / f'hls4mlprj_report_{backend_config["backend"]}') + test_report_dir = test_root_path / f'test_report/{backend_config["backend"]}' hls_model = hls4ml.converters.convert_from_keras_model( - model, io_type='io_stream', hls_config=config, output_dir=output_dir, part='xc7z020clg400-1', backend=backend + model, + io_type='io_stream', + hls_config=config, + output_dir=output_dir, + part=backend_config['part'], + backend=backend_config['backend'], ) hls_model.write() - # to actually generate the reports (using Vivado 2020.1) - # hls_model.build(synth=True, vsynth=True) + # to actually generate the reports (using Vivado 2020.1 or oneAPI 2025.0) + # hls_model.build(**(backend_config['build'])) - # copy pregenerated reports - os.makedirs(f'{output_dir}/myproject_prj/solution1/syn/report', exist_ok=True) - shutil.copy(test_report_dir / 'vivado_hls.app', f'{output_dir}/myproject_prj/vivado_hls.app') - shutil.copy( - test_report_dir / 'myproject_csynth.rpt', f'{output_dir}/myproject_prj/solution1/syn/report/myproject_csynth.rpt' - ) - shutil.copy( - test_report_dir / 'myproject_csynth.xml', f'{output_dir}/myproject_prj/solution1/syn/report/myproject_csynth.xml' - ) - shutil.copy(test_report_dir / 'vivado_synth.rpt', f'{output_dir}/vivado_synth.rpt') + backend_config["copy_func"](output_dir, test_report_dir) - report = hls4ml.report.parse_vivado_report(output_dir) # or report = hls_model.build(...) + yield output_dir, backend_config + + +@pytest.mark.parametrize("hls_model_setup", ['Vivado', 'oneAPI'], indirect=True) +def test_report(hls_model_setup, capsys): + """Tests that the report parsing and printing functions work for different backends.""" + output_dir, backend_config = hls_model_setup + + report = backend_config['parse_func'](output_dir) capsys.readouterr() # capture to clear - hls4ml.report.print_vivado_report(report) + backend_config['print_func'](report) captured = capsys.readouterr() # capture again to test - assert ( - captured.out - == '\n' - + '======================================================\n' - + '== C Synthesis report\n' - + '======================================================\n\n' - + ' - Performance estimates:\n' - + ' Best-case latency: 10 (50.0 ns)\n' - + ' Worst-case latency: 10 (50.0 ns)\n' - + ' Interval Min: 8\n' - + ' Interval Max: 8\n' - + ' Estimated Clock Period: 4.049\n\n' - + ' - Resource estimates:\n' - + ' BRAM_18K: 0 / 280 (0.0%)\n' - + ' DSP: 73 / 220 (33.2%)\n' - + ' FF: 7969 / 106400 (7.5%)\n' - + ' LUT: 2532 / 53200 (4.8%)\n' - + ' URAM: N/A\n\n' - + '======================================================\n' - + '== Vivado Synthesis report\n' - + '======================================================\n\n' - + ' - Resource utilization:\n' - + ' BRAM_18K: 0\n' - + ' DSP48E: 66\n' - + ' FF: 2428\n' - + ' LUT: 1526\n' - + ' URAM: N/A\n\n' - ) + assert captured.out == backend_config['expected_outcome'] diff --git a/test/pytest/test_report/myproject_csynth.rpt b/test/pytest/test_report/Vivado/myproject_csynth.rpt similarity index 100% rename from test/pytest/test_report/myproject_csynth.rpt rename to test/pytest/test_report/Vivado/myproject_csynth.rpt diff --git a/test/pytest/test_report/myproject_csynth.xml b/test/pytest/test_report/Vivado/myproject_csynth.xml similarity index 100% rename from test/pytest/test_report/myproject_csynth.xml rename to test/pytest/test_report/Vivado/myproject_csynth.xml diff --git a/test/pytest/test_report/vivado_hls.app b/test/pytest/test_report/Vivado/vivado_hls.app similarity index 100% rename from test/pytest/test_report/vivado_hls.app rename to test/pytest/test_report/Vivado/vivado_hls.app diff --git a/test/pytest/test_report/vivado_synth.rpt b/test/pytest/test_report/Vivado/vivado_synth.rpt similarity index 100% rename from test/pytest/test_report/vivado_synth.rpt rename to test/pytest/test_report/Vivado/vivado_synth.rpt diff --git a/test/pytest/test_report/oneAPI/loop_attr.ndjson b/test/pytest/test_report/oneAPI/loop_attr.ndjson new file mode 100644 index 0000000000..c76e2d80cb --- /dev/null +++ b/test/pytest/test_report/oneAPI/loop_attr.ndjson @@ -0,0 +1,10 @@ +{"name":"loop_attributes", "id":312, "nodes":[1, 3, 2]} +{"name":"Myproject", "id":1, "clk":"No", "fmax":"480.00", "type":"kernel", "children":[4, 5]} +{"name":"Myproject.B0", "id":4, "af":"480.00", "br":"0", "ci":"0", "fo":"Disabled", "ii":"1", "ll":"1", "lllt":"17.000000", "lt":"17.000000", "mi":"n/a", "pl":"Yes", "tc":"0", "tn":"1", "type":"bb"} +{"name":"Myproject.B1", "id":5, "af":"480.00", "br":"0", "ci":"0", "fo":"Enabled", "ii":"1", "ll":"1", "lllt":"176.000000", "lt":"176.000000", "mi":"1", "pl":"Yes", "tc":"0", "tn":"1", "details":[{"type":"text", "text":"Hyper-Optimized loop structure: enabled."}], "type":"loop"} +{"name":"relu_config3>()", "id":3, "clk":"No", "fmax":"480.00", "debug":[[{"filename":"/home/enlupi/Work/code/hls4mlprj_report_oneAPI/src/firmware/nnet_utils/nnet_activation_stream.h", "line":32}]], "type":"kernel", "children":[8, 9]} +{"name":"relu_config3>().B0", "id":8, "af":"480.00", "br":"0", "ci":"0", "fo":"Disabled", "ii":"1", "ll":"1", "lllt":"17.000000", "lt":"17.000000", "mi":"n/a", "pl":"Yes", "tc":"0", "tn":"1", "type":"bb"} +{"name":"relu_config3>().B1", "id":9, "af":"480.00", "br":"0", "ci":"0", "fo":"Enabled", "ii":"1", "ll":"1", "lllt":"159.000000", "lt":"159.000000", "mi":"1", "pl":"Yes", "tc":"0", "tn":"1", "details":[{"type":"text", "text":"Hyper-Optimized loop structure: enabled."}], "type":"loop"} +{"name":"bias_t)", "id":2, "clk":"No", "fmax":"480.00", "debug":[[{"filename":"/home/enlupi/Work/code/hls4mlprj_report_oneAPI/src/firmware/nnet_utils/nnet_dense_stream.h", "line":12}]], "type":"kernel", "children":[6, 7]} +{"name":"bias_t).B0", "id":6, "af":"480.00", "br":"0", "ci":"0", "fo":"Disabled", "ii":"1", "ll":"1", "lllt":"17.000000", "lt":"17.000000", "mi":"n/a", "pl":"Yes", "tc":"0", "tn":"1", "type":"bb"} +{"name":"bias_t).B1", "id":7, "af":"480.00", "br":"0", "ci":"0", "fo":"Enabled", "ii":"1", "ll":"1", "lllt":"200.000000", "lt":"200.000000", "mi":"1", "pl":"Yes", "tc":"0", "tn":"1", "details":[{"type":"text", "text":"Hyper-Optimized loop structure: enabled."}], "type":"loop"} diff --git a/test/pytest/test_report/oneAPI/quartus.ndjson b/test/pytest/test_report/oneAPI/quartus.ndjson new file mode 100644 index 0000000000..42fc428e9c --- /dev/null +++ b/test/pytest/test_report/oneAPI/quartus.ndjson @@ -0,0 +1 @@ +{"quartusFitClockSummary":{"nodes":[{"name":"Quartus Fitter: Clock Frequency (MHz)","type":"system","id":1000,"clock1x":"597.73","clock fmax":"597.73","clock":"597.73","details":[{"text":"The actual frequency of the clock is 597.73 MHz after platform PLL adjustment. The maximum frequency for the clock is 597.73 MHz. "}]}]},"quartusFitResourceUsageSummary":{"nodes":[{"type":"system","id":1000,"name":"Quartus Fitter: Device Image","alm":"4520.5","alut":"4182","reg":"16419","dsp":"40","ram":"36","mlab":"52"},{"type":"kernel","id":1010,"name":"Myproject","alm":"4520.0","alut":"4181","reg":"16419","dsp":"40","ram":"36","mlab":"52"}]}} \ No newline at end of file diff --git a/test/pytest/test_report/oneAPI/summary.ndjson b/test/pytest/test_report/oneAPI/summary.ndjson new file mode 100644 index 0000000000..d6c9235149 --- /dev/null +++ b/test/pytest/test_report/oneAPI/summary.ndjson @@ -0,0 +1,13 @@ +{"name":"Kernel Summary", "summary_type":"performanceSummary", "columns":["Kernel Name", "Kernel Type", "Autorun", "Workgroup Size", "# Compute Units", "Hyper-Optimized Handshaking"]} +{"name":"relu_config3>()", "compiler_name":"_ZN4nnet11relu_streamIN4sycl3_V13ext5intel12experimental4pipeI15Layer2OutPipeIDSt5arrayI8ac_fixedILi16ELi6ELb1EL9ac_q_mode0EL9ac_o_mode0EELm5EELi1ENS3_6oneapi12experimental10propertiesISt5tupleIJEEEEvEENS6_I15Layer3OutPipeIDSD_Li0ENSG_ISH_IJNSF_14property_valueINS5_17ready_latency_keyEJSt17integral_constantIiLi0EEEEEEEEEvEE12relu_config3EEvv", "parent":"performanceSummary", "data":["Single work-item", "No", [1, 1, 1], 1, "On"], "details":[{"type":"text", "text":"Kernel type: Single work-item"}, {"type":"text", "text":"Required workgroup size: (1, 1, 1)"}, {"type":"text", "text":"Maximum workgroup size: 1"}], "debug":[[{"filename":"", "line":0}]]} +{"name":"bias_t)", "compiler_name":"_ZN4nnet21dense_resource_streamIN4sycl3_V13ext5intel12experimental4pipeI14Fc1InputPipeIDSt5arrayI8ac_fixedILi16ELi6ELb1EL9ac_q_mode0EL9ac_o_mode0EELm16EELi0ENS3_6oneapi12experimental10propertiesISt5tupleIJNSF_14property_valueINS5_17ready_latency_keyEJSt17integral_constantIiLi0EEEEEEEEEvEENS6_I15Layer2OutPipeIDS8_ISC_Lm5EELi1ENSG_ISH_IJEEEEvEE7config2EEvNT1_8weight_tENSW_6bias_tE", "parent":"performanceSummary", "data":["Single work-item", "No", [1, 1, 1], 1, "On"], "details":[{"type":"text", "text":"Kernel type: Single work-item"}, {"type":"text", "text":"Required workgroup size: (1, 1, 1)"}, {"type":"text", "text":"Maximum workgroup size: 1"}], "debug":[[{"filename":"", "line":0}]]} +{"name":"Myproject", "compiler_name":"_ZTS9Myproject", "parent":"performanceSummary", "data":["Single work-item", "No", [1, 1, 1], 1, "On"], "details":[{"type":"text", "text":"Kernel type: Single work-item"}, {"type":"text", "text":"Required workgroup size: (1, 1, 1)"}, {"type":"text", "text":"Maximum workgroup size: 1"}], "debug":[[{"filename":"/home/enlupi/Work/code/hls4mlprj_report_oneAPI/src/firmware/myproject.h", "line":22}]]} +{"name":"Estimated Resource Usage", "summary_type":"estimatedResources", "dsp_packing_factor":2, "columns":["Kernel Name", "ALUTs ", "FFs ", "RAMs ", "DSPs ", "MLABs", "Frac. DSPs"]} +{"name":"relu_config3>()", "parent":"estimatedResources", "data":[168, 162, 4, 0, 4, 0], "debug":[[{"filename":"", "line":0}]]} +{"name":"bias_t)", "parent":"estimatedResources", "data":[2134, 4436, 71, 0, 87, 80], "debug":[[{"filename":"", "line":0}]]} +{"name":"Myproject", "parent":"estimatedResources", "data":[95, 82, 2, 0, 1, 0], "debug":[[{"filename":"/home/enlupi/Work/code/hls4mlprj_report_oneAPI/src/firmware/myproject.h", "line":22}]]} +{"name":"Kernel Subtotal", "parent":"estimatedResources", "classes":["summary-highlight", "nohover"], "data":[2397, 4680, 77, 0, 92, 80]} +{"name":"Pipe resources", "parent":"estimatedResources", "classes":["summary-highlight", "nohover"], "data":[65, 3258, 0, 0, 0, 0]} +{"name":"Total", "parent":"estimatedResources", "classes":["summary-highlight", "nohover"], "data":[2462, 7938, 77, 0, 92, 80], "data_percent":[0.252668321, 0.407327592, 1.08298171, 0]} +{"name":"Available", "parent":"estimatedResources", "classes":["summary-highlight", "nohover"], "data":["974400", "1948800", "7110", "4510", "24360", "0"]} +{"name":"Compile Warnings", "summary_type":"compileWarnings"}