Skip to content

Instantly share code, notes, and snippets.

@heborras
Created July 20, 2020 12:18
Show Gist options
  • Save heborras/e4196b7584496f17cfcd8e85d694a946 to your computer and use it in GitHub Desktop.
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
Display the source blob
Display the rendered blob
Raw
{
"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