From 1ba2d5398a11745f83e59dd451920467ba82f909 Mon Sep 17 00:00:00 2001 From: AlexandreSinger Date: Tue, 17 Jun 2025 10:37:08 -0400 Subject: [PATCH] [AP] Generalized Argument Parsing and Added Target Density The `appack_max_dist_th` cli option has a useful regex based interface which can be used in other parts of VPR, especially in AP. Generalized the interface so it can be used outside of the context of max distance thresholding. Used this general interface to pass in a target density per physical tile type. This spoofs the capacity into being smaller than it appears which tells the partial legalizer to not fill the tiles beyond the capacity. Setting the target density to interesting values revealed a bug in the partial legalizer regarding numerical precision when computing the prefix sum. Changed the underlying data type within the prefix sum class used into fixed-point which resolved the issue. --- doc/src/vpr/command_line_usage.rst | 34 ++++ .../analytical_placement_flow.cpp | 1 + .../analytical_place/ap_argparse_utils.cpp | 156 ++++++++++++++++++ vpr/src/analytical_place/ap_argparse_utils.h | 44 +++++ .../flat_placement_density_manager.cpp | 74 +++++++++ .../flat_placement_density_manager.h | 13 ++ vpr/src/analytical_place/global_placer.cpp | 4 + vpr/src/analytical_place/global_placer.h | 2 + .../analytical_place/partial_legalizer.cpp | 36 +++- vpr/src/analytical_place/partial_legalizer.h | 15 +- vpr/src/base/SetupVPR.cpp | 1 + vpr/src/base/read_options.cpp | 18 ++ vpr/src/base/read_options.h | 1 + vpr/src/base/vpr_types.h | 5 + vpr/src/pack/appack_max_dist_th_manager.cpp | 148 +++-------------- .../no_fixed_blocks/config/config.txt | 2 +- .../no_fixed_blocks/config/golden_results.txt | 12 +- 17 files changed, 428 insertions(+), 138 deletions(-) create mode 100644 vpr/src/analytical_place/ap_argparse_utils.cpp create mode 100644 vpr/src/analytical_place/ap_argparse_utils.h diff --git a/doc/src/vpr/command_line_usage.rst b/doc/src/vpr/command_line_usage.rst index 26047cf70f1..3f388eebed3 100644 --- a/doc/src/vpr/command_line_usage.rst +++ b/doc/src/vpr/command_line_usage.rst @@ -1281,6 +1281,40 @@ Analytical Placement is generally split into three stages: **Default:** ``0.5`` +.. option:: --ap_partial_legalizer_target_density { auto | :, } + + Sets the target density of different physical tiles on the FPGA device + for the partial legalizer in the AP flow. The partial legalizer will + try to fill tiles up to (but not beyond) this target density. This + is used as a guide, the legalizer may not follow this if it must fill + the tile more. + + The partial legalizer uses an abstraction called "mass" to describe the resources + used by a set of primitives in the netlist and the capacity of resources in a + given tile. For primitives like LUTs, FFs, and DSPs this mass can be thought of + as the number of pins used (but not exactly). For memories, this mass can be + thought of as the number of bits stored. This target density parameter lowers + the mass capacity of tiles. + + When this option is set ot auto, VPR will select good values for the + target density of tiles. + + reasonable values are between 0.0 and 1.0, with negative values not being allowed. + + This option is similar to appack_max_dist_th, where a regex string + is used to set the target density of different physical tiles. + + For example: + + .. code-block:: none + + --ap_partial_legalizer_target_density .*:0.9 "clb|memory:0.8" + + Would set the target density of all physical tiles to be 0.9, except for the clb and + memory tiles, which will be set to a target density of 0.8. + + **Default:** ``auto`` + .. option:: --appack_max_dist_th { auto | :, } Sets the maximum candidate distance thresholds for the logical block types diff --git a/vpr/src/analytical_place/analytical_placement_flow.cpp b/vpr/src/analytical_place/analytical_placement_flow.cpp index 83b9b843a6d..e54d0166878 100644 --- a/vpr/src/analytical_place/analytical_placement_flow.cpp +++ b/vpr/src/analytical_place/analytical_placement_flow.cpp @@ -156,6 +156,7 @@ static PartialPlacement run_global_placer(const t_ap_opts& ap_opts, place_delay_model, ap_opts.ap_timing_tradeoff, ap_opts.generate_mass_report, + ap_opts.ap_partial_legalizer_target_density, ap_opts.num_threads, ap_opts.log_verbosity); return global_placer->place(); diff --git a/vpr/src/analytical_place/ap_argparse_utils.cpp b/vpr/src/analytical_place/ap_argparse_utils.cpp new file mode 100644 index 00000000000..c58863c25db --- /dev/null +++ b/vpr/src/analytical_place/ap_argparse_utils.cpp @@ -0,0 +1,156 @@ +/** + * @file + * @author Alex Singer + * @date June 2025 + * @brief Implementation of utility functions used for parsing AP arguments. + */ +#include "ap_argparse_utils.h" +#include +#include +#include +#include +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vpr_error.h" + +/** + * @brief Helper method to convert a string into a float with error checking. + */ +static float str_to_float_or_error(const std::string& str); + +/** + * @brief Parse the given key, value string argument. The string is expected to + * be of the form: + * ":,," + * + * This method returns a tuple containing the regex string and a vector of the + * values. The vector will be of the length expected_num_vals_per_key. + */ +static std::tuple> +parse_key_val_arg(const std::string& arg, unsigned expected_num_vals_per_key); + +std::unordered_map> +key_to_float_argument_parser(const std::vector& arg_vals, + const std::vector& valid_keys, + unsigned expected_num_vals_per_key) { + + // Create the key to float map which will be returned from this method. + std::unordered_map> key_to_float_map; + + // Go through each of the arguments to parse. + for (const std::string& arg_val : arg_vals) { + // Parse this argument. + // Key is the regex string, vals is the vector of values. + auto [key, vals] = parse_key_val_arg(arg_val, expected_num_vals_per_key); + + // Create a regex object to be used to match for valid keys. + std::regex key_regex(key); + + // Go through each valid key and find which ones match the regex. + bool found_match = false; + for (const std::string& valid_key : valid_keys) { + bool is_match = std::regex_match(valid_key, key_regex); + if (!is_match) + continue; + + // If this key matches the regex, set the map to the given values. + key_to_float_map[valid_key] = vals; + found_match = true; + } + + // If no match is found for this key regex, raise a warning to the user. + // They may have made a mistake and may want to be warned about it. + if (!found_match) { + VTR_LOG_WARN("Unable to find a valid key that matches regex pattern: %s\n", + key.c_str()); + } + } + + // Return the map. + return key_to_float_map; +} + +static std::tuple> +parse_key_val_arg(const std::string& arg, unsigned expected_num_vals_per_key) { + // Verify the format of the string. It must have one and only one colon. + unsigned colon_count = 0; + for (char c : arg) { + if (c == ':') + colon_count++; + } + if (colon_count != 1) { + VTR_LOG_ERROR("Invalid argument string: %s\n", + arg.c_str()); + VPR_FATAL_ERROR(VPR_ERROR_PACK, + "Error when parsing argument string"); + } + + // Split the string along the colon. + auto del_pos = arg.find(':'); + std::string key_regex_str = arg.substr(0, del_pos); + std::string val_list_str = arg.substr(del_pos + 1, std::string::npos); + + // Verify that there are a correct number of commas given the expected number + // of values. + unsigned comma_count = 0; + for (char c : val_list_str) { + if (c == ',') + comma_count++; + } + if (comma_count != expected_num_vals_per_key - 1) { + VTR_LOG_ERROR("Invalid argument string (too many commas): %s\n", + arg.c_str()); + VPR_FATAL_ERROR(VPR_ERROR_PACK, + "Error when parsing argument string"); + } + + // Collect the comma seperated values into a vector. + std::vector vals; + vals.reserve(expected_num_vals_per_key); + + // As we are reading each comma-seperated value, keep track of the current + // part of the string we are reading. We read from left to right. + std::string acc_val_list_str = val_list_str; + + // For each expected value up to the last one, parse the current value before + // the comma. + VTR_ASSERT(expected_num_vals_per_key > 0); + for (unsigned i = 0; i < expected_num_vals_per_key - 1; i++) { + // Split the string before and after the comma. + auto comma_pos = acc_val_list_str.find(","); + VTR_ASSERT(comma_pos != std::string::npos); + std::string current_val_str = val_list_str.substr(0, comma_pos); + // Send the string after the comma to the next iteration. + acc_val_list_str = val_list_str.substr(comma_pos + 1, std::string::npos); + + // Cast the string before the comma into a float and store it. + float current_val = str_to_float_or_error(current_val_str); + vals.push_back(current_val); + } + + // Parse the last value in the list. This one should not have a comma in it. + VTR_ASSERT(acc_val_list_str.find(",") == std::string::npos); + float last_val = str_to_float_or_error(acc_val_list_str); + vals.push_back(last_val); + + // Return the results as a tuple. + return std::make_tuple(key_regex_str, vals); +} + +static float str_to_float_or_error(const std::string& str) { + float val = -1; + try { + val = std::stof(str); + } catch (const std::invalid_argument& e) { + VTR_LOG_ERROR("Error while parsing float arg value: %s\n" + "Failed with invalid argument: %s\n", + str.c_str(), + e.what()); + } catch (const std::out_of_range& e) { + VTR_LOG_ERROR("Error while parsing float arg value: %s\n" + "Failed with out of range: %s\n", + str.c_str(), + e.what()); + } + return val; +} diff --git a/vpr/src/analytical_place/ap_argparse_utils.h b/vpr/src/analytical_place/ap_argparse_utils.h new file mode 100644 index 00000000000..ba482035921 --- /dev/null +++ b/vpr/src/analytical_place/ap_argparse_utils.h @@ -0,0 +1,44 @@ +#pragma once +/** + * @file + * @author Alex Singer + * @date June 2025 + * @brief Delcarations of utility functions used to parse AP options. + */ + +#include +#include +#include + +/** + * @brief Parser method for parsing a list of arguments of the form: + * ":,,,..." + * + * This method will will return a map containing the value for each key matched. + * The map will not contain an entry for a key that was not set by the arguments. + * + * Example usage: + * // Create a list of valid keys. + * std::vector valid_keys = {"foo", "bar"} + * + * // User passed regex args. Sets all values to {0.5, 0.5, 0.5} THEN sets + * // "foo" specifically to {0.1, 0.2, 0.3}. + * // NOTE: Arguments are read left to right (first to last). + * std::vector arg_vals = {".*:0.5,0.5,0.5", "foo:0.1,0.2,0.3"} + * + * auto key_to_val_map = key_to_float_argument_parser(arg_vals, + * valid_keys, + * 3); + * // Map will contain {0.1, 0.2, 0.3} for "foo" and {0.5, 0.5, 0.5} for "bar" + * + * @param arg_vals + * The list of arguments to parse. + * @param valid_keys + * A list of valid keys that the argument regex patterns can match for. + * @param expected_num_vals_per_key + * The expected number of floating point values per key. + */ +std::unordered_map> +key_to_float_argument_parser(const std::vector& arg_vals, + const std::vector& valid_keys, + unsigned expected_num_vals_per_key = 1); diff --git a/vpr/src/analytical_place/flat_placement_density_manager.cpp b/vpr/src/analytical_place/flat_placement_density_manager.cpp index 2899981943e..93f7021c22c 100644 --- a/vpr/src/analytical_place/flat_placement_density_manager.cpp +++ b/vpr/src/analytical_place/flat_placement_density_manager.cpp @@ -7,6 +7,8 @@ #include "flat_placement_density_manager.h" #include +#include +#include "ap_argparse_utils.h" #include "ap_netlist.h" #include "ap_netlist_fwd.h" #include "atom_netlist.h" @@ -18,6 +20,8 @@ #include "prepack.h" #include "primitive_dim_manager.h" #include "primitive_vector.h" +#include "vpr_error.h" +#include "vpr_utils.h" #include "vtr_assert.h" #include "vtr_geometry.h" #include "vtr_vector.h" @@ -45,6 +49,60 @@ static PrimitiveVector calc_bin_underfill(const PrimitiveVector& bin_utilization return underfill; } +/** + * @brief Get the physical type target densities given the user arguments. + * + * This will automatically select good target densisities, but will allow the + * user to override these values from the command line. + * + * @param target_density_arg_strs + * The command-line arguments provided by the user. + * @param physical_tile_types + * A vector of all physical tile types in the architecture. + */ +static std::vector get_physical_type_target_densities(const std::vector& target_density_arg_strs, + const std::vector& physical_tile_types) { + // Get the target densisty of each physical block type. + // TODO: Create auto feature to automatically select target densities based + // on properties of the architecture. Need to sweep to find reasonable + // values. + std::vector phy_ty_target_density(physical_tile_types.size(), 1.0f); + + // Set to auto if no user args are provided. + if (target_density_arg_strs.size() == 0) + return phy_ty_target_density; + if (target_density_arg_strs.size() == 1 && target_density_arg_strs[0] == "auto") + return phy_ty_target_density; + + // Parse the user args. The physical type names are expected to be used as keys. + std::vector phy_ty_names; + phy_ty_names.reserve(physical_tile_types.size()); + std::unordered_map phy_ty_name_to_index; + for (const t_physical_tile_type& phy_ty : physical_tile_types) { + phy_ty_names.push_back(phy_ty.name); + phy_ty_name_to_index[phy_ty.name] = phy_ty.index; + } + auto phy_ty_name_to_tar_density = key_to_float_argument_parser(target_density_arg_strs, + phy_ty_names, + 1); + + // Update the target densities based on the user args. + for (const auto& phy_ty_name_to_density_pair : phy_ty_name_to_tar_density) { + const std::string& phy_ty_name = phy_ty_name_to_density_pair.first; + VTR_ASSERT(phy_ty_name_to_density_pair.second.size() == 1); + float target_density = phy_ty_name_to_density_pair.second[0]; + if (target_density < 0.0f) { + VPR_FATAL_ERROR(VPR_ERROR_AP, + "Cannot have negative target density"); + } + + int phy_ty_index = phy_ty_name_to_index[phy_ty_name]; + phy_ty_target_density[phy_ty_index] = target_density; + } + + return phy_ty_target_density; +} + FlatPlacementDensityManager::FlatPlacementDensityManager(const APNetlist& ap_netlist, const Prepacker& prepacker, const AtomNetlist& atom_netlist, @@ -52,6 +110,7 @@ FlatPlacementDensityManager::FlatPlacementDensityManager(const APNetlist& ap_net const std::vector& logical_block_types, const std::vector& physical_tile_types, const LogicalModels& models, + const std::vector& target_density_arg_strs, int log_verbosity) : ap_netlist_(ap_netlist) , bins_(ap_netlist) @@ -62,6 +121,15 @@ FlatPlacementDensityManager::FlatPlacementDensityManager(const APNetlist& ap_net std::tie(num_layers, width, height) = device_grid.dim_sizes(); bin_spatial_lookup_.resize({num_layers, width, height}); + // Get the target densisty of each physical block type. + std::vector phy_ty_target_densities = get_physical_type_target_densities(target_density_arg_strs, + physical_tile_types); + VTR_LOG("Partial legalizer is using target densities:"); + for (const t_physical_tile_type& phy_ty : physical_tile_types) { + VTR_LOG(" %s:%.1f", phy_ty.name.c_str(), phy_ty_target_densities[phy_ty.index]); + } + VTR_LOG("\n"); + // Create a bin for each tile. This will create one bin for each root tile // location. vtr::vector_map bin_phy_tile_type_idx; @@ -96,6 +164,12 @@ FlatPlacementDensityManager::FlatPlacementDensityManager(const APNetlist& ap_net // Store the index of the physical tile type into a map to be // used to compute the capacity. bin_phy_tile_type_idx.insert(new_bin_id, tile_type->index); + + // Set the target density for this bin based on the physical + // tile type.. + float target_density = phy_ty_target_densities[tile_type->index]; + bin_target_density_.push_back(target_density); + VTR_ASSERT(bin_target_density_[new_bin_id] = target_density); } } } diff --git a/vpr/src/analytical_place/flat_placement_density_manager.h b/vpr/src/analytical_place/flat_placement_density_manager.h index 73f27b4efd3..c030f773f5c 100644 --- a/vpr/src/analytical_place/flat_placement_density_manager.h +++ b/vpr/src/analytical_place/flat_placement_density_manager.h @@ -69,6 +69,7 @@ class FlatPlacementDensityManager { * @param logical_block_types * @param physical_tile_types * @param models + * @param target_density_arg_strs * @param log_verbosity */ FlatPlacementDensityManager(const APNetlist& ap_netlist, @@ -78,6 +79,7 @@ class FlatPlacementDensityManager { const std::vector& logical_block_types, const std::vector& physical_tile_types, const LogicalModels& models, + const std::vector& target_density_arg_strs, int log_verbosity); /** @@ -168,6 +170,14 @@ class FlatPlacementDensityManager { return bin_underfill_[bin_id]; } + /** + * @brief Returns the target density for the given bin. + */ + inline float get_bin_target_density(FlatPlacementBinId bin_id) const { + VTR_ASSERT_SAFE(bin_id.is_valid()); + return bin_target_density_[bin_id]; + } + /** * @brief Returns true of the given bin is overfilled (it contains too much * mass and is over capacity). @@ -292,6 +302,9 @@ class FlatPlacementDensityManager { /// 1 in this vector, and 0 otherwise. PrimitiveVector used_dims_mask_; + /// @brief The target density of each bin. + vtr::vector bin_target_density_; + /// @brief The verbosity of log messages in this class. const int log_verbosity_; }; diff --git a/vpr/src/analytical_place/global_placer.cpp b/vpr/src/analytical_place/global_placer.cpp index 9b9e3ceeb42..b44118ceb5a 100644 --- a/vpr/src/analytical_place/global_placer.cpp +++ b/vpr/src/analytical_place/global_placer.cpp @@ -44,6 +44,7 @@ std::unique_ptr make_global_placer(e_ap_analytical_solver analytic std::shared_ptr place_delay_model, float ap_timing_tradeoff, bool generate_mass_report, + const std::vector& target_density_arg_strs, unsigned num_threads, int log_verbosity) { return std::make_unique(analytical_solver_type, @@ -59,6 +60,7 @@ std::unique_ptr make_global_placer(e_ap_analytical_solver analytic place_delay_model, ap_timing_tradeoff, generate_mass_report, + target_density_arg_strs, num_threads, log_verbosity); } @@ -76,6 +78,7 @@ SimPLGlobalPlacer::SimPLGlobalPlacer(e_ap_analytical_solver analytical_solver_ty std::shared_ptr place_delay_model, float ap_timing_tradeoff, bool generate_mass_report, + const std::vector& target_density_arg_strs, unsigned num_threads, int log_verbosity) : GlobalPlacer(ap_netlist, log_verbosity) @@ -105,6 +108,7 @@ SimPLGlobalPlacer::SimPLGlobalPlacer(e_ap_analytical_solver analytical_solver_ty logical_block_types, physical_tile_types, models, + target_density_arg_strs, log_verbosity_); if (generate_mass_report) density_manager_->generate_mass_report(); diff --git a/vpr/src/analytical_place/global_placer.h b/vpr/src/analytical_place/global_placer.h index 033db223b11..f87dec400b2 100644 --- a/vpr/src/analytical_place/global_placer.h +++ b/vpr/src/analytical_place/global_placer.h @@ -87,6 +87,7 @@ std::unique_ptr make_global_placer(e_ap_analytical_solver analytic std::shared_ptr place_delay_model, float ap_timing_tradeoff, bool generate_mass_report, + const std::vector& target_density_arg_strs, unsigned num_threads, int log_verbosity); @@ -164,6 +165,7 @@ class SimPLGlobalPlacer : public GlobalPlacer { std::shared_ptr place_delay_model, float ap_timing_tradeoff, bool generate_mass_report, + const std::vector& target_density_arg_strs, unsigned num_threads, int log_verbosity); diff --git a/vpr/src/analytical_place/partial_legalizer.cpp b/vpr/src/analytical_place/partial_legalizer.cpp index f80ec368190..317aa2732b4 100644 --- a/vpr/src/analytical_place/partial_legalizer.cpp +++ b/vpr/src/analytical_place/partial_legalizer.cpp @@ -694,11 +694,18 @@ PerPrimitiveDimPrefixSum2D::PerPrimitiveDimPrefixSum2D(const FlatPlacementDensit const PrimitiveDimManager& dim_manager = density_manager.mass_calculator().get_dim_manager(); dim_prefix_sum_.resize(dim_manager.dims().size()); for (PrimitiveVectorDim dim : density_manager.get_used_dims_mask().get_non_zero_dims()) { - dim_prefix_sum_[dim] = vtr::PrefixSum2D( + dim_prefix_sum_[dim] = vtr::PrefixSum2D( width, height, [&](size_t x, size_t y) { - return lookup(dim, x, y); + // Convert the floating point value into fixed point to prevent + // error accumulation in the prefix sum. + // Note: We ceil here since we do not want to lose information + // on numbers that get very close to 0. + float val = lookup(dim, x, y); + VTR_ASSERT_SAFE_MSG(val >= 0.0f, + "PerPrimitiveDimPrefixSum2D expected to only hold positive values"); + return std::ceil(val * fractional_scale_); }); } } @@ -707,10 +714,14 @@ float PerPrimitiveDimPrefixSum2D::get_dim_sum(PrimitiveVectorDim dim, const vtr::Rect& region) const { VTR_ASSERT_SAFE(dim.is_valid()); // Get the sum over the given region. - return dim_prefix_sum_[dim].get_sum(region.xmin(), - region.ymin(), - region.xmax() - 1, - region.ymax() - 1); + uint64_t sum = dim_prefix_sum_[dim].get_sum(region.xmin(), + region.ymin(), + region.xmax() - 1, + region.ymax() - 1); + + // The sum is stored as a fixed point number. Cast into float by casting to + // a float and dividing by the fractional scale. + return static_cast(sum) / fractional_scale_; } PrimitiveVector PerPrimitiveDimPrefixSum2D::get_sum(const std::vector& dims, @@ -846,13 +857,22 @@ BiPartitioningPartialLegalizer::BiPartitioningPartialLegalizer( // Get the capacity of the bin for this dim. float cap = density_manager_->get_bin_capacity(bin_id).get_dim_val(dim); VTR_ASSERT_SAFE(cap >= 0.0f); + + // Update the capacity with the target density. By multiplying by the + // target density, we make the capacity appear smaller than it actually + // is during partial legalization. + float target_density = density_manager_->get_bin_target_density(bin_id); + cap *= target_density; + // Bins may be large, but the prefix sum assumes a 1x1 grid of // values. Normalize by the area of the bin to turn this into // a 1x1 bin equivalent. const vtr::Rect& bin_region = density_manager_->flat_placement_bins().bin_region(bin_id); float bin_area = bin_region.width() * bin_region.height(); - VTR_ASSERT_SAFE(!vtr::isclose(bin_area, 0.f)); - return cap / bin_area; + VTR_ASSERT_SAFE(!vtr::isclose(bin_area, 0.0f)); + cap /= bin_area; + + return cap; }); num_windows_partitioned_ = 0; diff --git a/vpr/src/analytical_place/partial_legalizer.h b/vpr/src/analytical_place/partial_legalizer.h index 30932b30bd5..4349faca5ed 100644 --- a/vpr/src/analytical_place/partial_legalizer.h +++ b/vpr/src/analytical_place/partial_legalizer.h @@ -308,6 +308,16 @@ struct PartitionedWindow { * regions. */ class PerPrimitiveDimPrefixSum2D { + // This class stores the prefix sum as a fixed-point number instead of a + // floating point number. This is to prevent error accumulation which can + // occur due to numerical imprecisions. This variable selects how many bits + // the fractional component of the fixed-point number should have. + static constexpr unsigned num_fractional_bits_ = 10; + + // When converting to/from fixed-point, we need to scale/shrink by 2 to the + // power of the number of fractional bits. + static constexpr float fractional_scale_ = 2 << num_fractional_bits_; + public: PerPrimitiveDimPrefixSum2D() = default; @@ -336,8 +346,9 @@ class PerPrimitiveDimPrefixSum2D { const vtr::Rect& region) const; private: - /// @brief Per-Dim Prefix Sums - vtr::vector> dim_prefix_sum_; + /// @brief Per-Dim Prefix Sums. These are stored as fixed-point numbers to + /// prevent error accumulations due to numerical imprecisions. + vtr::vector> dim_prefix_sum_; }; /// @brief A unique ID of a group of primitive dims created by the PrimitiveDimGrouper class. diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index a6c52327523..2d06d0c25f9 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -559,6 +559,7 @@ void SetupAPOpts(const t_options& options, apOpts.detailed_placer_type = options.ap_detailed_placer.value(); apOpts.ap_timing_tradeoff = options.ap_timing_tradeoff.value(); apOpts.ap_high_fanout_threshold = options.ap_high_fanout_threshold.value(); + apOpts.ap_partial_legalizer_target_density = options.ap_partial_legalizer_target_density.value(); apOpts.appack_max_dist_th = options.appack_max_dist_th.value(); apOpts.num_threads = options.num_workers.value(); apOpts.log_verbosity = options.ap_verbosity.value(); diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index d2f452af6a1..2030ff1e7dd 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -1957,6 +1957,24 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("256") .show_in(argparse::ShowIn::HELP_ONLY); + ap_grp.add_argument(args.ap_partial_legalizer_target_density, "--ap_partial_legalizer_target_density") + .help( + "Sets the target density of different physical tiles on the FPGA device " + "for the partial legalizer in the AP flow. The partial legalizer will " + "try to fill tiles up to (but not beyond) this target density. This " + "is used as a guide, the legalizer may not follow this if it must fill " + "the tile more." + "\n" + "When this option is set ot auto, VPR will select good values for the " + "target density of tiles." + "\n" + "This option is similar to appack_max_dist_th, where a regex string " + "is used to set the target density of different physical tiles. See " + "the documentation for more information.") + .nargs('+') + .default_value({"auto"}) + .show_in(argparse::ShowIn::HELP_ONLY); + ap_grp.add_argument(args.appack_max_dist_th, "--appack_max_dist_th") .help( "Sets the maximum candidate distance thresholds for the logical block types" diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 854f283a26f..7612f29a815 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -103,6 +103,7 @@ struct t_options { argparse::ArgValue ap_partial_legalizer; argparse::ArgValue ap_full_legalizer; argparse::ArgValue ap_detailed_placer; + argparse::ArgValue> ap_partial_legalizer_target_density; argparse::ArgValue> appack_max_dist_th; argparse::ArgValue ap_verbosity; argparse::ArgValue ap_timing_tradeoff; diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 34d47914309..2101faab25e 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1105,6 +1105,9 @@ struct t_placer_opts { * @param ap_high_fanout_threshold; * The threshold to ignore nets with higher fanout than that * value while constructing the solver. + * @param ap_partial_legalizer_target_density + * Vector of strings passed by the user to configure the target + * density of different physical tiles on the device. * @param appack_max_dist_th * Array of string passed by the user to configure the max candidate * distance thresholds. @@ -1131,6 +1134,8 @@ struct t_ap_opts { int ap_high_fanout_threshold; + std::vector ap_partial_legalizer_target_density; + std::vector appack_max_dist_th; unsigned num_threads; diff --git a/vpr/src/pack/appack_max_dist_th_manager.cpp b/vpr/src/pack/appack_max_dist_th_manager.cpp index c5c9b685b73..4d602bed003 100644 --- a/vpr/src/pack/appack_max_dist_th_manager.cpp +++ b/vpr/src/pack/appack_max_dist_th_manager.cpp @@ -6,10 +6,10 @@ */ #include "appack_max_dist_th_manager.h" -#include -#include -#include +#include +#include #include +#include "ap_argparse_utils.h" #include "device_grid.h" #include "physical_types.h" #include "physical_types_util.h" @@ -18,20 +18,6 @@ #include "vtr_assert.h" #include "vtr_log.h" -/** - * @brief Helper method to convert a string into a float with error checking. - */ -static float str_to_float_or_error(const std::string& str); - -/** - * @brief Helper method to parse one term of the user-provided max distance - * threshold string. - * - * This method decomposes the user string of the form ":," - * into its three components. - */ -static std::tuple parse_max_dist_th(const std::string& max_dist_th); - /** * @brief Recursive helper method to deduce if the given pb_type is or contains * pb_types which are of the memory class. @@ -155,117 +141,37 @@ void APPackMaxDistThManager::set_max_distance_thresholds_from_strings( const std::vector& logical_block_types, const DeviceGrid& device_grid) { - // Go through each of the user-provided strings. - for (const std::string& max_dist_th : max_dist_ths) { - // If any of them are the word "auto", this was a user error and should - // be flagged. - // TODO: Maybe move this and other semantic checks up to the checker of - // VPR's command line. - if (max_dist_th == "auto") { - VPR_FATAL_ERROR(VPR_ERROR_PACK, - "APPack: Cannot provide both auto and other max distance threshold strings"); - } + std::vector lb_type_names; + std::unordered_map lb_type_name_to_index; + for (const t_logical_block_type& lb_ty : logical_block_types) { + lb_type_names.push_back(lb_ty.name); + lb_type_name_to_index[lb_ty.name] = lb_ty.index; + } - // Parse the string for the regex, scale, and offset. - std::string logical_block_regex_str; - float logical_block_max_dist_th_scale; - float logical_block_max_dist_th_offset; - std::tie(logical_block_regex_str, - logical_block_max_dist_th_scale, - logical_block_max_dist_th_offset) = parse_max_dist_th(max_dist_th); + auto lb_to_floats_map = key_to_float_argument_parser(max_dist_ths, lb_type_names, 2); - // Setup the regex for the logical blocks the user wants to set the - // thresholds for. - std::regex logical_block_regex(logical_block_regex_str); + for (const auto& lb_name_to_floats_pair : lb_to_floats_map) { + const std::string& lb_name = lb_name_to_floats_pair.first; + const std::vector& lb_floats = lb_name_to_floats_pair.second; + VTR_ASSERT(lb_floats.size() == 2); + float logical_block_max_dist_th_scale = lb_floats[0]; + float logical_block_max_dist_th_offset = lb_floats[1]; + + if (logical_block_max_dist_th_scale < 0.0) { + VPR_FATAL_ERROR(VPR_ERROR_PACK, + "APPack: Cannot have negative max distance threshold scale"); + } + if (logical_block_max_dist_th_offset < 0.0) { + VPR_FATAL_ERROR(VPR_ERROR_PACK, + "APPack: Cannot have negative max distance threshold offset"); + } // Compute the max distance threshold the user selected. float max_device_distance = device_grid.width() + device_grid.height(); float logical_block_max_dist_th = std::max(max_device_distance * logical_block_max_dist_th_scale, logical_block_max_dist_th_offset); - // Search through all logical blocks and set the thresholds of any matches - // to the threshold the user selected. - bool found_match = false; - for (const t_logical_block_type& lb_ty : logical_block_types) { - bool is_match = std::regex_match(lb_ty.name, logical_block_regex); - if (!is_match) - continue; - - logical_block_dist_thresholds_[lb_ty.index] = logical_block_max_dist_th; - found_match = true; - } - // If no match is found, send a warning to the user. - if (!found_match) { - VTR_LOG_WARN("Unable to find logical block type for max distance threshold regex string: %s\n", - logical_block_regex_str.c_str()); - } - } -} - -static std::tuple parse_max_dist_th(const std::string& max_dist_th) { - // Verify the format of the string. It must have one and only one colon. - unsigned colon_count = 0; - for (char c : max_dist_th) { - if (c == ':') - colon_count++; - } - if (colon_count != 1) { - VTR_LOG_ERROR("Invalid max distance threshold string: %s\n", - max_dist_th.c_str()); - VPR_FATAL_ERROR(VPR_ERROR_PACK, - "Error when parsing APPack max distance threshold string"); - } - - // Split the string along the colon. - auto del_pos = max_dist_th.find(':'); - std::string logical_block_regex_str = max_dist_th.substr(0, del_pos); - std::string lb_max_dist_th_str = max_dist_th.substr(del_pos + 1, std::string::npos); - - // Split along the comma for the scale/offset. - // Verify that the comma only appears once in the scale/offset string. - unsigned comma_count = 0; - for (char c : lb_max_dist_th_str) { - if (c == ',') - comma_count++; - } - if (comma_count != 1) { - VTR_LOG_ERROR("Invalid max distance threshold string: %s\n", - max_dist_th.c_str()); - VPR_FATAL_ERROR(VPR_ERROR_PACK, - "Error when parsing APPack max distance threshold string"); - } - - // Split the string along the comma. - auto comma_pos = lb_max_dist_th_str.find(','); - std::string lb_max_dist_th_scale_str = lb_max_dist_th_str.substr(0, comma_pos); - std::string lb_max_dist_th_offset_str = lb_max_dist_th_str.substr(comma_pos + 1, std::string::npos); - - // Convert the scale and offset into floats (error checking to be safe). - float lb_max_dist_th_scale = str_to_float_or_error(lb_max_dist_th_scale_str); - float lb_max_dist_th_offset = str_to_float_or_error(lb_max_dist_th_offset_str); - - // Return the results as a tuple. - return std::make_tuple(logical_block_regex_str, lb_max_dist_th_scale, lb_max_dist_th_offset); -} - -static float str_to_float_or_error(const std::string& str) { - float val = -1; - try { - val = std::stof(str); - } catch (const std::invalid_argument& e) { - VTR_LOG_ERROR("Error while parsing max distance threshold value: %s\n" - "Failed with invalid argument: %s\n", - str.c_str(), - e.what()); - } catch (const std::out_of_range& e) { - VTR_LOG_ERROR("Error while parsing max distance threshold value: %s\n" - "Failed with out of range: %s\n", - str.c_str(), - e.what()); - } - if (val < 0.0f) { - VPR_FATAL_ERROR(VPR_ERROR_PACK, - "Error when parsing APPack max distance threshold string"); + int lb_ty_index = lb_type_name_to_index[lb_name]; + logical_block_dist_thresholds_[lb_ty_index] = logical_block_max_dist_th; } - return val; } diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/config.txt index 7678dea6b00..ed380bf5fa2 100755 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/config.txt @@ -35,7 +35,7 @@ circuit_constraint_list_add=(stereovision3.v, route_chan_width=44) circuit_constraint_list_add=(ch_intrinsics.v, route_chan_width=52) circuit_constraint_list_add=(spree.v, route_chan_width=78) circuit_constraint_list_add=(boundtop.v, route_chan_width=50) -circuit_constraint_list_add=(or1200.v, route_chan_width=118) +circuit_constraint_list_add=(or1200.v, route_chan_width=124) # Parse info and how to parse parse_file=vpr_fixed_chan_width.txt diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/golden_results.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/golden_results.txt index 5bce89c0fd7..a3ab75a5888 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/golden_results.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_ap/no_fixed_blocks/config/golden_results.txt @@ -1,6 +1,6 @@ - arch circuit script_params vtr_flow_elapsed_time vtr_max_mem_stage vtr_max_mem error odin_synth_time max_odin_mem parmys_synth_time max_parmys_mem abc_depth abc_synth_time abc_cec_time abc_sec_time max_abc_mem ace_time max_ace_mem num_clb num_io num_memories num_mult vpr_status vpr_revision vpr_build_info vpr_compiler vpr_compiled hostname rundir max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_mem pack_time initial_placed_wirelength_est placed_wirelength_est total_swap accepted_swap rejected_swap aborted_swap place_mem place_time place_quench_time initial_placed_CPD_est placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est placed_geomean_nonvirtual_intradomain_critical_path_delay_est place_delay_matrix_lookup_time place_quench_timing_analysis_time place_quench_sta_time place_total_timing_analysis_time place_total_sta_time ap_mem ap_time ap_full_legalizer_mem ap_full_legalizer_time routed_wirelength avg_routed_wirelength routed_wiresegment avg_routed_wiresegment total_nets_routed total_connections_routed total_heap_pushes total_heap_pops logic_block_area_total logic_block_area_used routing_area_total routing_area_per_tile crit_path_route_success_iteration num_rr_graph_nodes num_rr_graph_edges collapsed_nodes critical_path_delay geomean_nonvirtual_intradomain_critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS create_rr_graph_time create_intra_cluster_rr_graph_time adding_internal_edges route_mem crit_path_route_time crit_path_total_timing_analysis_time crit_path_total_sta_time router_lookahead_mem tile_lookahead_computation_time router_lookahead_computation_time - k6_frac_N10_frac_chain_mem32K_40nm.xml boundtop.v common 9.58 vpr 82.57 MiB -1 -1 6.82 42428 3 0.61 -1 -1 37568 -1 -1 46 196 1 0 success v8.0.0-13084-g071ad3865 release IPO VTR_ASSERT_LEVEL=2 GNU 13.3.0 on Linux-6.8.0-60-generic x86_64 2025-06-17T09:37:40 betzgrp-wintermute /home/pooladam/vtr-verilog-to-routing 84552 196 193 798 0 1 604 436 20 20 400 -1 vtr_extra_small -1 -1 3760.61 3044 33476 4713 27728 1035 82.6 MiB 1.33 0.01 2.93578 2.81317 -1151 -2.81317 2.81317 0.00 0.00180736 0.00165078 0.0492256 0.0457389 82.6 MiB 1.33 82.6 MiB 0.70 5106 8.58151 1525 2.56303 1759 2700 156727 46750 2.07112e+07 3.02712e+06 1.26946e+06 3173.65 11 38988 203232 -1 3.15897 3.15897 -1301.64 -3.15897 0 0 0.13 -1 -1 82.6 MiB 0.10 0.206096 0.192796 39.7 MiB -1 0.04 - k6_frac_N10_frac_chain_mem32K_40nm.xml ch_intrinsics.v common 1.25 vpr 75.55 MiB -1 -1 0.19 21308 3 0.07 -1 -1 33104 -1 -1 68 99 1 0 success v8.0.0-13084-g071ad3865 release IPO VTR_ASSERT_LEVEL=2 GNU 13.3.0 on Linux-6.8.0-60-generic x86_64 2025-06-17T09:37:40 betzgrp-wintermute /home/pooladam/vtr-verilog-to-routing 77368 99 130 264 0 1 226 298 20 20 400 -1 vtr_extra_small -1 -1 885.731 708 16218 4754 9792 1672 75.6 MiB 0.51 0.00 1.87109 1.87109 -121.775 -1.87109 1.87109 0.00 0.000575195 0.000536795 0.0131266 0.0123694 75.6 MiB 0.51 75.6 MiB 0.26 1253 7.50299 388 2.32335 376 577 30318 8963 2.07112e+07 4.21279e+06 1.31074e+06 3276.84 10 39388 210115 -1 1.99059 1.99059 -137.535 -1.99059 0 0 0.15 -1 -1 75.6 MiB 0.03 0.0573551 0.0537716 38.4 MiB -1 0.05 - k6_frac_N10_frac_chain_mem32K_40nm.xml or1200.v common 19.28 vpr 134.58 MiB -1 -1 2.70 59328 8 2.91 -1 -1 40540 -1 -1 247 385 2 1 success v8.0.0-13084-g071ad3865 release IPO VTR_ASSERT_LEVEL=2 GNU 13.3.0 on Linux-6.8.0-60-generic x86_64 2025-06-17T09:37:40 betzgrp-wintermute /home/pooladam/vtr-verilog-to-routing 137812 385 362 3328 0 1 2408 997 30 30 900 -1 vtr_small -1 -1 37706.7 32316 309633 71864 234222 3547 134.6 MiB 10.53 0.04 10.8573 9.10491 -10763.7 -9.10491 9.10491 0.00 0.0110376 0.0102668 0.852951 0.784901 134.6 MiB 10.53 134.6 MiB 5.41 44145 18.4476 11407 4.76682 10587 34974 1884640 335487 4.8774e+07 1.48038e+07 6.56785e+06 7297.61 18 120772 1084977 -1 9.39133 9.39133 -11054.2 -9.39133 0 0 0.85 -1 -1 134.6 MiB 1.07 1.8929 1.75049 83.0 MiB -1 0.23 - k6_frac_N10_frac_chain_mem32K_40nm.xml spree.v common 5.96 vpr 86.36 MiB -1 -1 1.56 32544 16 0.44 -1 -1 34372 -1 -1 62 45 3 1 success v8.0.0-13084-g071ad3865 release IPO VTR_ASSERT_LEVEL=2 GNU 13.3.0 on Linux-6.8.0-60-generic x86_64 2025-06-17T09:37:40 betzgrp-wintermute /home/pooladam/vtr-verilog-to-routing 88436 45 32 944 0 1 766 143 20 20 400 -1 vtr_extra_small -1 -1 7012.23 6542 6857 949 5832 76 86.4 MiB 2.96 0.00 11.8281 11.6952 -7166.94 -11.6952 11.6952 0.00 0.00194449 0.00171015 0.066214 0.0598273 86.4 MiB 2.96 86.4 MiB 1.92 10810 14.1678 2765 3.62385 3021 8126 667447 163597 2.07112e+07 5.38143e+06 1.91495e+06 4787.38 15 44576 305072 -1 12.2006 12.2006 -7360.63 -12.2006 0 0 0.21 -1 -1 86.4 MiB 0.23 0.319432 0.291044 44.2 MiB -1 0.07 - k6_frac_N10_frac_chain_mem32K_40nm.xml stereovision3.v common 1.44 vpr 74.96 MiB -1 -1 0.31 24764 5 0.12 -1 -1 32640 -1 -1 15 11 0 0 success v8.0.0-13084-g071ad3865 release IPO VTR_ASSERT_LEVEL=2 GNU 13.3.0 on Linux-6.8.0-60-generic x86_64 2025-06-17T09:37:40 betzgrp-wintermute /home/pooladam/vtr-verilog-to-routing 76760 11 2 140 0 2 84 28 20 20 400 -1 vtr_extra_small -1 -1 322.099 315 112 28 73 11 75.0 MiB 0.38 0.00 2.10685 2.10685 -167.1 -2.10685 1.95087 0.00 0.000412674 0.000356264 0.00455256 0.00433906 75.0 MiB 0.38 75.0 MiB 0.24 493 6.32051 127 1.62821 160 274 5744 1513 2.07112e+07 808410 1.12964e+06 2824.09 10 37792 180905 -1 2.11477 2.00072 -170.487 -2.11477 0 0 0.12 -1 -1 75.0 MiB 0.02 0.0422746 0.0387358 37.1 MiB -1 0.04 +arch circuit script_params vtr_flow_elapsed_time vtr_max_mem_stage vtr_max_mem error odin_synth_time max_odin_mem parmys_synth_time max_parmys_mem abc_depth abc_synth_time abc_cec_time abc_sec_time max_abc_mem ace_time max_ace_mem num_clb num_io num_memories num_mult vpr_status vpr_revision vpr_build_info vpr_compiler vpr_compiled hostname rundir max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_mem pack_time initial_placed_wirelength_est placed_wirelength_est total_swap accepted_swap rejected_swap aborted_swap place_mem place_time place_quench_time initial_placed_CPD_est placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est placed_geomean_nonvirtual_intradomain_critical_path_delay_est place_delay_matrix_lookup_time place_quench_timing_analysis_time place_quench_sta_time place_total_timing_analysis_time place_total_sta_time ap_mem ap_time ap_full_legalizer_mem ap_full_legalizer_time routed_wirelength avg_routed_wirelength routed_wiresegment avg_routed_wiresegment total_nets_routed total_connections_routed total_heap_pushes total_heap_pops logic_block_area_total logic_block_area_used routing_area_total routing_area_per_tile crit_path_route_success_iteration num_rr_graph_nodes num_rr_graph_edges collapsed_nodes critical_path_delay geomean_nonvirtual_intradomain_critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS create_rr_graph_time create_intra_cluster_rr_graph_time adding_internal_edges route_mem crit_path_route_time crit_path_total_timing_analysis_time crit_path_total_sta_time router_lookahead_mem tile_lookahead_computation_time router_lookahead_computation_time +k6_frac_N10_frac_chain_mem32K_40nm.xml boundtop.v common 10.42 vpr 84.87 MiB -1 -1 7.24 52056 3 0.63 -1 -1 39008 -1 -1 48 196 1 0 success v8.0.0-13089-g96c4fc94e release VTR_ASSERT_LEVEL=3 GNU 13.3.0 on Linux-6.8.0-58-generic x86_64 2025-06-17T18:59:40 srivatsan-Precision-Tower-5810 /home/alex/vtr-verilog-to-routing 86908 196 193 798 0 1 605 438 20 20 400 -1 vtr_extra_small -1 -1 3997.05 3285 73566 12097 59046 2423 84.9 MiB 1.70 0.01 2.82664 2.65254 -1140.6 -2.65254 2.65254 0.00 0.00198171 0.00172432 0.103308 0.0907731 84.9 MiB 1.70 84.9 MiB 0.88 5408 9.07383 1597 2.67953 1723 2368 159040 47645 2.07112e+07 3.13491e+06 1.26946e+06 3173.65 10 38988 203232 -1 3.17051 3.17051 -1227.06 -3.17051 0 0 0.18 -1 -1 84.9 MiB 0.10 0.270353 0.241577 41.4 MiB -1 0.06 +k6_frac_N10_frac_chain_mem32K_40nm.xml ch_intrinsics.v common 1.84 vpr 78.14 MiB -1 -1 0.36 30392 3 0.11 -1 -1 37180 -1 -1 68 99 1 0 success v8.0.0-13089-g96c4fc94e release VTR_ASSERT_LEVEL=3 GNU 13.3.0 on Linux-6.8.0-58-generic x86_64 2025-06-17T18:59:40 srivatsan-Precision-Tower-5810 /home/alex/vtr-verilog-to-routing 80012 99 130 264 0 1 226 298 20 20 400 -1 vtr_extra_small -1 -1 885.731 708 16218 4754 9792 1672 78.1 MiB 0.85 0.01 1.87109 1.87109 -121.775 -1.87109 1.87109 0.00 0.00106913 0.000942715 0.0226412 0.020327 78.1 MiB 0.85 78.1 MiB 0.42 1253 7.50299 388 2.32335 376 577 30318 8963 2.07112e+07 4.21279e+06 1.31074e+06 3276.84 10 39388 210115 -1 1.99059 1.99059 -137.535 -1.99059 0 0 0.19 -1 -1 78.1 MiB 0.05 0.095672 0.0864075 40.2 MiB -1 0.08 +k6_frac_N10_frac_chain_mem32K_40nm.xml or1200.v common 23.36 vpr 136.85 MiB -1 -1 2.84 66136 8 3.15 -1 -1 45136 -1 -1 250 385 2 1 success v8.0.0-13089-g96c4fc94e release VTR_ASSERT_LEVEL=3 GNU 13.3.0 on Linux-6.8.0-58-generic x86_64 2025-06-17T18:59:40 srivatsan-Precision-Tower-5810 /home/alex/vtr-verilog-to-routing 140132 385 362 3328 0 1 2406 1000 30 30 900 -1 vtr_small -1 -1 37338.5 30254 340864 75209 262031 3624 136.8 MiB 14.12 0.08 10.9083 9.279 -10729.1 -9.279 9.279 0.00 0.00962194 0.00850512 0.739236 0.650392 136.8 MiB 14.12 136.8 MiB 7.41 40781 17.0560 10534 4.40569 9354 30561 1592054 287754 4.8774e+07 1.49655e+07 6.84542e+06 7606.03 16 123468 1137417 -1 9.3335 9.3335 -10939.7 -9.3335 0 0 1.27 -1 -1 136.8 MiB 0.80 1.80362 1.62001 86.4 MiB -1 0.29 +k6_frac_N10_frac_chain_mem32K_40nm.xml spree.v common 6.71 vpr 88.48 MiB -1 -1 1.73 42548 16 0.45 -1 -1 38756 -1 -1 60 45 3 1 success v8.0.0-13089-g96c4fc94e release VTR_ASSERT_LEVEL=3 GNU 13.3.0 on Linux-6.8.0-58-generic x86_64 2025-06-17T18:59:40 srivatsan-Precision-Tower-5810 /home/alex/vtr-verilog-to-routing 90608 45 32 944 0 1 766 141 20 20 400 -1 vtr_extra_small -1 -1 7841.8 6489 7827 1250 6283 294 88.5 MiB 3.50 0.01 12.1051 11.0146 -6876.8 -11.0146 11.0146 0.00 0.00222847 0.00181942 0.0703686 0.0597694 88.5 MiB 3.50 88.5 MiB 2.41 10653 13.9620 2897 3.79685 3514 9994 754010 198329 2.07112e+07 5.27364e+06 1.91495e+06 4787.38 14 44576 305072 -1 11.3646 11.3646 -7213.07 -11.3646 0 0 0.30 -1 -1 88.5 MiB 0.26 0.33906 0.296281 45.7 MiB -1 0.08 +k6_frac_N10_frac_chain_mem32K_40nm.xml stereovision3.v common 2.13 vpr 77.10 MiB -1 -1 0.59 33840 5 0.17 -1 -1 36828 -1 -1 15 11 0 0 success v8.0.0-13089-g96c4fc94e release VTR_ASSERT_LEVEL=3 GNU 13.3.0 on Linux-6.8.0-58-generic x86_64 2025-06-17T18:59:40 srivatsan-Precision-Tower-5810 /home/alex/vtr-verilog-to-routing 78952 11 2 140 0 2 84 28 20 20 400 -1 vtr_extra_small -1 -1 322.099 315 112 28 73 11 77.1 MiB 0.54 0.00 2.10685 2.10685 -167.1 -2.10685 1.95087 0.00 0.00050932 0.000417877 0.00464267 0.00430535 77.1 MiB 0.54 77.1 MiB 0.27 493 6.32051 127 1.62821 160 274 5744 1513 2.07112e+07 808410 1.12964e+06 2824.09 10 37792 180905 -1 2.11477 2.00072 -170.487 -2.11477 0 0 0.28 -1 -1 77.1 MiB 0.02 0.0658957 0.0582486 38.7 MiB -1 0.10