Created
July 20, 2020 12:18
-
-
Save heborras/e4196b7584496f17cfcd8e85d694a946 to your computer and use it in GitHub Desktop.
Functions for extracting utilization data from synthesis and post-place-and-route reports from FINN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import json\n", | |
"import xml.etree.ElementTree as ET\n", | |
"import pandas as pd" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Specific to each project\n", | |
"vivado_proj = \"/tmp/finn_dev_hendrik/vivado_pynq_proj_t8ogzm7n\"\n", | |
"\n", | |
"# Constant parameters\n", | |
"build_dir = \"/workspace/finn\"\n", | |
"report_path = \"/resizer.runs/impl_1/resizer_wrapper_utilization_placed.rpt\"" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"{'1. Slice Logic': [['Slice LUTs', 28961.0, 0.0, 53200.0, 54.44],\n", | |
" ['LUT as Logic', 25160.0, 0.0, 53200.0, 47.29],\n", | |
" ['LUT as Memory', 3801.0, 0.0, 17400.0, 21.84],\n", | |
" ['Slice Registers', 39807.0, 0.0, 106400.0, 37.41],\n", | |
" ['Register as Flip Flop', 39807.0, 0.0, 106400.0, 37.41],\n", | |
" ['Register as Latch', 0.0, 0.0, 106400.0, 0.0],\n", | |
" ['F7 Muxes', 1263.0, 0.0, 26600.0, 4.75],\n", | |
" ['F8 Muxes', 367.0, 0.0, 13300.0, 2.76]],\n", | |
" '2. Slice Logic Distribution': [['Slice', 12832.0, 0.0, 13300.0, 96.48],\n", | |
" ['LUT as Logic', 25160.0, 0.0, 53200.0, 47.29],\n", | |
" ['LUT as Memory', 3801.0, 0.0, 17400.0, 21.84],\n", | |
" ['Slice Registers', 39807.0, 0.0, 106400.0, 37.41],\n", | |
" []],\n", | |
" '3. Memory': [['Block RAM Tile', 138.0, 0.0, 140.0, 98.57],\n", | |
" ['RAMB36/FIFO*', 101.0, 0.0, 140.0, 72.14],\n", | |
" ['RAMB18', 74.0, 0.0, 280.0, 26.43]],\n", | |
" '4. DSP': [['DSPs', 0.0, 0.0, 220.0, 0.0]],\n", | |
" '6. Clocking': [['BUFGCTRL', 1.0, 0.0, 32.0, 3.13],\n", | |
" ['BUFIO', 0.0, 0.0, 16.0, 0.0],\n", | |
" ['MMCME2_ADV', 0.0, 0.0, 4.0, 0.0],\n", | |
" ['PLLE2_ADV', 0.0, 0.0, 4.0, 0.0],\n", | |
" ['BUFMRCE', 0.0, 0.0, 8.0, 0.0],\n", | |
" ['BUFHCE', 0.0, 0.0, 72.0, 0.0],\n", | |
" ['BUFR', 0.0, 0.0, 16.0, 0.0]]}" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# Read post place utilization report and save results\n", | |
"\n", | |
"with open(vivado_proj + report_path) as f:\n", | |
" content = f.readlines()\n", | |
"\n", | |
"\n", | |
"top_levels_to_parse = [\"1. Slice Logic\", \"2. Slice Logic Distribution\", \"3. Memory\", \"4. DSP\", \"6. Clocking\"]\n", | |
"\n", | |
"utilization_data = {}\n", | |
"top_level_key = \"\"\n", | |
"parse_enable = False\n", | |
"waiting_for_table_start = False\n", | |
"\n", | |
"for line in content:\n", | |
" # check if we stumbled upon one of the top level indicators\n", | |
" if any(top in line for top in top_levels_to_parse):\n", | |
" waiting_for_table_start = True\n", | |
" # Find out which of them it was\n", | |
" for i in range(len(top_levels_to_parse)):\n", | |
" if top_levels_to_parse[i] in line:\n", | |
" top_level_key = top_levels_to_parse[i]\n", | |
" break\n", | |
" utilization_data[top_level_key] = []\n", | |
" \n", | |
" # Check for table start indicator\n", | |
" if waiting_for_table_start:\n", | |
" if \"Available\" in line:\n", | |
" parse_enable = True\n", | |
" waiting_for_table_start = False\n", | |
" continue\n", | |
" \n", | |
" # parse a line\n", | |
" if parse_enable:\n", | |
" # reached a table border\n", | |
" if \"+--\" in line:\n", | |
" continue\n", | |
" # reached end of table\n", | |
" if \"\\n\" == line or \"* Note: Each Block RAM Tile only h\" in line:\n", | |
" parse_enable = False\n", | |
" continue\n", | |
" # parse table row\n", | |
" line = line.strip()\n", | |
" split_line = line.split(\"|\")[1:-1]\n", | |
" row_data = []\n", | |
" for data_snipplet in split_line:\n", | |
" d = data_snipplet.strip()\n", | |
" try:\n", | |
" d = float(d)\n", | |
" except ValueError:\n", | |
" pass\n", | |
" row_data.append(d)\n", | |
" # skip rows with emtpy elements\n", | |
" if '' in row_data:\n", | |
" continue\n", | |
" utilization_data[top_level_key].append(row_data)\n", | |
"\n", | |
"# Save as JSON\n", | |
"# Save results to disk\n", | |
"with open(build_dir+'/pynq_place_report.json', 'w') as f:\n", | |
" json.dump(utilization_data, f)\n", | |
"\n", | |
"utilization_data" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>Instance</th>\n", | |
" <th>Module</th>\n", | |
" <th>Total LUTs</th>\n", | |
" <th>Logic LUTs</th>\n", | |
" <th>LUTRAMs</th>\n", | |
" <th>SRLs</th>\n", | |
" <th>FFs</th>\n", | |
" <th>RAMB36</th>\n", | |
" <th>RAMB18</th>\n", | |
" <th>DSP48 Blocks</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>resizer_wrapper</td>\n", | |
" <td>(top)</td>\n", | |
" <td>29506</td>\n", | |
" <td>25609</td>\n", | |
" <td>726</td>\n", | |
" <td>3171</td>\n", | |
" <td>40116</td>\n", | |
" <td>101</td>\n", | |
" <td>74</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>resizer_i</td>\n", | |
" <td>resizer</td>\n", | |
" <td>29506</td>\n", | |
" <td>25609</td>\n", | |
" <td>726</td>\n", | |
" <td>3171</td>\n", | |
" <td>40116</td>\n", | |
" <td>101</td>\n", | |
" <td>74</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>(resizer_i)</td>\n", | |
" <td>resizer</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>axi_dma_0</td>\n", | |
" <td>resizer_axi_dma_0_0</td>\n", | |
" <td>1959</td>\n", | |
" <td>1749</td>\n", | |
" <td>12</td>\n", | |
" <td>198</td>\n", | |
" <td>2626</td>\n", | |
" <td>8</td>\n", | |
" <td>2</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>(axi_dma_0)</td>\n", | |
" <td>resizer_axi_dma_0_0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>...</th>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" <td>...</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>78</th>\n", | |
" <td>rst_ps7_0_100M</td>\n", | |
" <td>resizer_rst_ps7_0_100M_0</td>\n", | |
" <td>19</td>\n", | |
" <td>18</td>\n", | |
" <td>0</td>\n", | |
" <td>1</td>\n", | |
" <td>40</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>79</th>\n", | |
" <td>U0</td>\n", | |
" <td>resizer_rst_ps7_0_100M_0_proc_sys_reset</td>\n", | |
" <td>19</td>\n", | |
" <td>18</td>\n", | |
" <td>0</td>\n", | |
" <td>1</td>\n", | |
" <td>40</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>80</th>\n", | |
" <td>(U0)</td>\n", | |
" <td>resizer_rst_ps7_0_100M_0_proc_sys_reset</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>5</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>81</th>\n", | |
" <td>EXT_LPF</td>\n", | |
" <td>resizer_rst_ps7_0_100M_0_lpf</td>\n", | |
" <td>6</td>\n", | |
" <td>5</td>\n", | |
" <td>0</td>\n", | |
" <td>1</td>\n", | |
" <td>17</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>82</th>\n", | |
" <td>SEQ</td>\n", | |
" <td>resizer_rst_ps7_0_100M_0_sequence_psr</td>\n", | |
" <td>13</td>\n", | |
" <td>13</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>18</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" <td>0</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"<p>83 rows × 10 columns</p>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" Instance Module Total LUTs \\\n", | |
"0 resizer_wrapper (top) 29506 \n", | |
"1 resizer_i resizer 29506 \n", | |
"2 (resizer_i) resizer 0 \n", | |
"3 axi_dma_0 resizer_axi_dma_0_0 1959 \n", | |
"4 (axi_dma_0) resizer_axi_dma_0_0 0 \n", | |
".. ... ... ... \n", | |
"78 rst_ps7_0_100M resizer_rst_ps7_0_100M_0 19 \n", | |
"79 U0 resizer_rst_ps7_0_100M_0_proc_sys_reset 19 \n", | |
"80 (U0) resizer_rst_ps7_0_100M_0_proc_sys_reset 0 \n", | |
"81 EXT_LPF resizer_rst_ps7_0_100M_0_lpf 6 \n", | |
"82 SEQ resizer_rst_ps7_0_100M_0_sequence_psr 13 \n", | |
"\n", | |
" Logic LUTs LUTRAMs SRLs FFs RAMB36 RAMB18 DSP48 Blocks \n", | |
"0 25609 726 3171 40116 101 74 0 \n", | |
"1 25609 726 3171 40116 101 74 0 \n", | |
"2 0 0 0 0 0 0 0 \n", | |
"3 1749 12 198 2626 8 2 0 \n", | |
"4 0 0 0 0 0 0 0 \n", | |
".. ... ... ... ... ... ... ... \n", | |
"78 18 0 1 40 0 0 0 \n", | |
"79 18 0 1 40 0 0 0 \n", | |
"80 0 0 0 5 0 0 0 \n", | |
"81 5 0 1 17 0 0 0 \n", | |
"82 13 0 0 18 0 0 0 \n", | |
"\n", | |
"[83 rows x 10 columns]" | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# Read the synthesis report and save the results for later processing\n", | |
"\n", | |
"root = ET.parse(vivado_proj+\"/synth_report.xml\").getroot()\n", | |
"\n", | |
"# Read the table header of the synthesis report\n", | |
"table_header = []\n", | |
"for child in root[0][0][0]:\n", | |
" attribs = child.attrib\n", | |
" table_header.append(attribs['contents'])\n", | |
" \n", | |
"# Read the rest of the table\n", | |
"table_cols = []\n", | |
"for child1 in root[0][0][1:]:\n", | |
" one_col = []\n", | |
" for child2 in child1:\n", | |
" content = child2.attrib['contents'].strip()\n", | |
" # Everything that looks like an int should become an int\n", | |
" try:\n", | |
" content = int(content)\n", | |
" except ValueError:\n", | |
" pass\n", | |
" one_col.append(content)\n", | |
" table_cols.append(one_col)\n", | |
"\n", | |
"\n", | |
"# Store data in a nicer format\n", | |
"report_data = pd.DataFrame(table_cols, columns=table_header)\n", | |
"\n", | |
"# Save data to disk\n", | |
"report_data.to_csv(build_dir+\"/pynq_synthesis_report.csv\")\n", | |
"\n", | |
"report_data" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.8" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment