reserve configuration blocks and bits in bitstream manager builder to be memory efficient

This commit is contained in:
tangxifan 2020-07-02 15:28:52 -06:00
parent b85af57971
commit 405824081b
3 changed files with 108 additions and 1 deletions

View File

@ -154,6 +154,13 @@ void BitstreamManager::reserve_blocks(const size_t& num_blocks) {
child_block_ids_.reserve(num_blocks);
}
void BitstreamManager::reserve_bits(const size_t& num_bits) {
bit_ids_.reserve(num_bits);
bit_values_.reserve(num_bits);
shared_config_bit_values_.reserve(num_bits);
bit_parent_block_ids_.reserve(num_bits);
}
ConfigBlockId BitstreamManager::create_block() {
ConfigBlockId block = ConfigBlockId(block_ids_.size());
/* Add a new bit, and allocate associated data structures */

View File

@ -98,6 +98,9 @@ class BitstreamManager {
/* Reserve memory for a number of clocks */
void reserve_blocks(const size_t& num_blocks);
/* Reserve memory for a number of bits */
void reserve_bits(const size_t& num_bits);
/* Create a new block of configuration bits */
ConfigBlockId create_block();

View File

@ -20,6 +20,82 @@
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Estimate the number of blocks to be added to the whole device bitstream
* This function will recursively walk through the module graph
* from the specified top module and count the number of configurable children
* which are the blocks that will be added to the bitstream manager
*******************************************************************/
static
size_t rec_estimate_device_bitstream_num_blocks(const ModuleManager& module_manager,
const ModuleId& top_module) {
size_t num_blocks = 0;
/* Those child modules which have no children are
* actually configurable memory elements
* We skip them in couting
*/
if (0 == module_manager.configurable_children(top_module).size()) {
return 0;
}
size_t num_configurable_children = module_manager.configurable_children(top_module).size();
for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) {
ModuleId child_module = module_manager.configurable_children(top_module)[ichild];
num_blocks += rec_estimate_device_bitstream_num_blocks(module_manager, child_module);
}
/* Add the number of blocks at current level */
num_blocks++;
return num_blocks;
}
/********************************************************************
* Estimate the number of configuration bits to be added to the whole device bitstream
* This function will recursively walk through the module graph
* from the specified top module and count the number of leaf configurable children
* which are the bits that will be added to the bitstream manager
*******************************************************************/
static
size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager,
const ModuleId& top_module,
const e_config_protocol_type& config_protocol_type) {
size_t num_bits = 0;
/* If a child module has no configurable children, this is a leaf node
* We can count it in. Otherwise, we should go recursively.
*/
if (0 == module_manager.configurable_children(top_module).size()) {
return 1;
}
size_t num_configurable_children = module_manager.configurable_children(top_module).size();
/* Frame-based configuration protocol will have 1 decoder
* if there are more than 1 configurable children
*/
if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type)
&& (2 <= num_configurable_children)) {
num_configurable_children--;
}
/* Memory configuration protocol will have 2 decoders
* at the top-level
*/
if (CONFIG_MEM_MEMORY_BANK == config_protocol_type) {
std::string top_block_name = generate_fpga_top_module_name();
if (top_module == module_manager.find_module(top_block_name)) {
num_configurable_children -= 2;
}
}
for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) {
ModuleId child_module = module_manager.configurable_children(top_module)[ichild];
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, child_module, config_protocol_type);
}
return num_bits;
}
/********************************************************************
* A top-level function to build a bistream from the FPGA device
* 1. It will organize the bitstream w.r.t. the hierarchy of module graphs
@ -52,6 +128,21 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
*/
std::string top_block_name = generate_fpga_top_module_name();
ConfigBlockId top_block = bitstream_manager.add_block(top_block_name);
const ModuleId& top_module = openfpga_ctx.module_graph().find_module(top_block_name);
VTR_ASSERT(true == openfpga_ctx.module_graph().valid_module_id(top_module));
/* Estimate the number of blocks to be added to the database */
size_t num_blocks_to_reserve = rec_estimate_device_bitstream_num_blocks(openfpga_ctx.module_graph(),
top_module);
bitstream_manager.reserve_blocks(num_blocks_to_reserve);
VTR_LOGV(verbose, "Reserved %lu configurable blocks\n", num_blocks_to_reserve);
/* Estimate the number of bits to be added to the database */
size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(),
top_module,
openfpga_ctx.arch().config_protocol.type());
bitstream_manager.reserve_bits(num_bits_to_reserve);
VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve);
/* Create bitstream from grids */
VTR_LOGV(verbose, "Building grid bitstream...\n");
@ -80,7 +171,13 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
openfpga_ctx.device_rr_gsb());
VTR_LOGV(verbose, "Done\n");
VTR_LOGV(verbose, "Decoded %lu configuration bits\n", bitstream_manager.bits().size());
VTR_LOGV(verbose,
"Decoded %lu configuration bits into %lu blocks\n",
bitstream_manager.bits().size(),
bitstream_manager.blocks().size());
//VTR_ASSERT(num_blocks_to_reserve == bitstream_manager.blocks().size());
//VTR_ASSERT(num_bits_to_reserve == bitstream_manager.bits().size());
return bitstream_manager;
}