Skip to content

Commit

Permalink
[APPack] Added read_flat_place Option and Verifier
Browse files Browse the repository at this point in the history
Added the read_flat_place option to VPR's CLI. This allows the user to
pass a flat placement file into the packer.

Added code to parse this file into a FlatPlacementInfo object which only
verifies that the atom given in the file exists in the atom netlist.

Added code in the packer to read in the flat placement and verify that
the flat placement is valid for use in the packer.
  • Loading branch information
AlexandreSinger committed Jan 20, 2025
1 parent c90ac0d commit 18097d4
Show file tree
Hide file tree
Showing 13 changed files with 373 additions and 5 deletions.
25 changes: 25 additions & 0 deletions doc/src/vpr/command_line_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,31 @@ Use the options below to override this default naming behaviour.

Prefix for output files

.. option:: --read_flat_place <file>

Reads a file containing the locations of each atom on the FPGA.

This is used by the packer to better cluster atoms together.

The flat placement file (which often ends in ``.fplace``) is a text file
where each line describes the location of an atom. It has the following
expected syntax:

.. code-block:: none
<atom_name : str> <atom_x_pos : float> <atom_y_pos : float> <atom_sub_tile? : int> <atom_site_idx? : int>
n523 6 8 0 3
n522 6 8 0 5
n520 6 8 0 2
n518 6 8 0 16
The ``sub_tile`` and ``site_idx`` are optional parameters which may be used
as a hint to reconstruct clusters.

.. warning::

This interface is currently experimental and under active development.

.. option:: --write_flat_place <file>

Writes the post-placement locations of each atom into a flat placement file.
Expand Down
71 changes: 71 additions & 0 deletions vpr/src/base/FlatPlacementInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* @file
* @author Alex Singer
* @date January 2025
* @brief Declaration of the FlatPlacementInfo object, which is used to store
* flat placement information used by the packer.
*/

#pragma once

#include "atom_netlist.h"
#include "vtr_vector.h"

/**
* @brief Flat placement storage class.
*
* This stores placement information for each atom in the netlist. It contains
* any information that may be used by the packer to better create clusters.
*/
class FlatPlacementInfo {
public:
/// @brief Identifier for an undefined position.
static constexpr float UNDEFINED_POS = -1.f;
/// @brief Identifier for an undefined sub tile.
static constexpr int UNDEFINED_SUB_TILE = -1;
/// @brief Identifier for an undefined site idx.
static constexpr int UNDEFINED_SITE_IDX = -1;

/// @brief The x-positions of each atom block. Is UNDEFINED_POS if undefined.
vtr::vector<AtomBlockId, float> blk_x_pos;
/// @brief The y-positions of each atom block. Is UNDEFINED_POS if undefined.
vtr::vector<AtomBlockId, float> blk_y_pos;
/// @brief The sub tile location of each atom block. Is UNDEFINED_SUB_TILE
/// if undefined.
vtr::vector<AtomBlockId, int> blk_sub_tile;
/// @brief The flat site idx of each atom block. Is UNDEFINED_SITE_IDX if
/// undefined.
vtr::vector<AtomBlockId, int> blk_site_idx;

/// @brief A flag to signify if this object has been constructed with data
/// or not. This makes it easier to detect if a flat placement exists
/// or not. Is true when a placement has been loaded into this
/// object, false otherwise.
bool valid;

/**
* @brief Default constructor of this class.
*
* Initializes the data structure to invalid so it can be easily checked to
* be uninitialized.
*/
FlatPlacementInfo() : valid(false) {}

/**
* @brief Constructs the flat placement with undefined positions for each
* atom block in the atom netlist.
*
* The valid flag is set to true here, since this structure is now
* initialized with data and can be used.
*
* @param atom_netlist
* The netlist of atom blocks in the circuit.
*/
FlatPlacementInfo(const AtomNetlist& atom_netlist)
: blk_x_pos(atom_netlist.blocks().size(), UNDEFINED_POS),
blk_y_pos(atom_netlist.blocks().size(), UNDEFINED_POS),
blk_sub_tile(atom_netlist.blocks().size(), UNDEFINED_SUB_TILE),
blk_site_idx(atom_netlist.blocks().size(), UNDEFINED_SITE_IDX),
valid(true) {}
};

1 change: 1 addition & 0 deletions vpr/src/base/SetupVPR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ void SetupVPR(const t_options* options,
fileNameOpts->read_vpr_constraints_file = options->read_vpr_constraints_file;
fileNameOpts->write_vpr_constraints_file = options->write_vpr_constraints_file;
fileNameOpts->write_constraints_file = options->write_constraints_file;
fileNameOpts->read_flat_place_file = options->read_flat_place_file;
fileNameOpts->write_flat_place_file = options->write_flat_place_file;
fileNameOpts->write_block_usage = options->write_block_usage;

Expand Down
83 changes: 83 additions & 0 deletions vpr/src/base/load_flat_place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@

#include "load_flat_place.h"

#include <fstream>
#include <unordered_set>
#include "atom_netlist.h"
#include "clustered_netlist.h"
#include "FlatPlacementInfo.h"
#include "globals.h"
#include "vpr_context.h"
#include "vpr_error.h"
#include "vpr_types.h"
#include "vtr_log.h"

/**
* @brief Prints flat placement file entries for the atoms in one placed
Expand Down Expand Up @@ -77,6 +82,84 @@ void write_flat_placement(const char* flat_place_file_path,
fclose(fp);
}

FlatPlacementInfo read_flat_placement(const std::string& read_flat_place_file_path,
const AtomNetlist& atom_netlist) {
// Try to open the file, crash if we cannot open the file.
std::ifstream flat_place_file(read_flat_place_file_path);
if (!flat_place_file.is_open()) {
VPR_ERROR(VPR_ERROR_OTHER, "Unable to open flat placement file: %s\n",
read_flat_place_file_path.c_str());
}

// Create a FlatPlacementInfo object to hold the flat placement.
FlatPlacementInfo flat_placement_info(atom_netlist);

// Read each line of the flat placement file.
unsigned line_num = 0;
std::string line;
while (std::getline(flat_place_file, line)) {
// Split the line into tokens (using spaces, tabs, etc. as delimiters).
std::vector<std::string> tokens = vtr::split(line);
// Skip empty lines
if (tokens.empty())
continue;
// Skip lines that are only comments.
if (tokens[0][0] == '#')
continue;
// Skip lines with too few arguments.
// Required arguments:
// - Atom name
// - Atom x-pos
// - Atom y-pos
if (tokens.size() < 3) {
VTR_LOG_WARN("Flat placement file, line %d has too few arguments. "
"Requires at least: <atom_name> <atom_x_pos> <atom_y_pos>\n",
line_num);
continue;
}

// Get the atom name, which should be the first argument.
AtomBlockId atom_blk_id = atom_netlist.find_block(tokens[0]);
if (!atom_blk_id.is_valid()) {
VTR_LOG_WARN("Flat placement file, line %d atom name does not match "
"any atoms in the atom netlist.\n",
line_num);
continue;
}

// Check if this atom already has a flat placement
// Using the x_pos and y_pos as identifiers.
if (flat_placement_info.blk_x_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS ||
flat_placement_info.blk_y_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS) {
VTR_LOG_WARN("Flat placement file, line %d, atom %s has multiple "
"placement definitions in the flat placement file.\n",
line_num, atom_netlist.block_name(atom_blk_id).c_str());
continue;
}

// Get the x and y position of the atom. These functions have error
// checking built in. We parse x and y as floats to allow for reading
// in more global atom positions.
flat_placement_info.blk_x_pos[atom_blk_id] = vtr::atof(tokens[1]);
flat_placement_info.blk_y_pos[atom_blk_id] = vtr::atof(tokens[2]);

// If a sub-tile is given, parse the sub-tile as an integer.
if (tokens.size() >= 4 && tokens[3][0] != '#')
flat_placement_info.blk_sub_tile[atom_blk_id] = vtr::atoi(tokens[3]);

// If a site index is given, parse the site index as an integer.
if (tokens.size() >= 5 && tokens[4][0] != '#')
flat_placement_info.blk_site_idx[atom_blk_id] = vtr::atoi(tokens[4]);

// Ignore any further tokens.

line_num++;
}

// Return the flat placement info loaded from the file.
return flat_placement_info;
}

/* ingests and legalizes a flat placement file */
bool load_flat_placement(t_vpr_setup& vpr_setup, const t_arch& arch) {
VTR_LOG("load_flat_placement(); when implemented, this function:");
Expand Down
16 changes: 16 additions & 0 deletions vpr/src/base/load_flat_place.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@

#pragma once

#include <string>
#include <unordered_set>
#include "vtr_vector_map.h"
#include "vtr_vector.h"

// Forward declarations
class AtomBlockId;
class AtomNetlist;
class ClusterBlockId;
class ClusteredNetlist;
class FlatPlacementInfo;
class Prepacker;
struct t_arch;
struct t_block_loc;
struct t_vpr_setup;
Expand All @@ -40,6 +44,18 @@ void write_flat_placement(const char* flat_place_file_path,
const vtr::vector_map<ClusterBlockId, t_block_loc> &block_locs,
const vtr::vector<ClusterBlockId, std::unordered_set<AtomBlockId>>& atoms_lookup);

/**
* @brief Reads a flat placement file generated from a previous run of VTR or
* externally generated.
*
* @param read_flat_place_file_path
* Path to the file to read the flat placement from.
* @param atom_netlist
* The netlist of atom blocks in the circuit.
*/
FlatPlacementInfo read_flat_placement(const std::string& read_flat_place_file_path,
const AtomNetlist& atom_netlist);

/**
* @brief A function that loads and legalizes a flat placement file
*/
Expand Down
5 changes: 5 additions & 0 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,11 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.default_value("fix_clusters.out")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.read_flat_place_file, "--read_flat_place")
.help(
"Reads VPR's (or reconstructed external) placement solution in flat placement file format; this file lists cluster and intra-cluster placement coordinates for each atom and can be used to reconstruct a clustering and placement solution.")
.show_in(argparse::ShowIn::HELP_ONLY);

file_grp.add_argument(args.write_flat_place_file, "--write_flat_place")
.help(
"VPR's (or reconstructed external) placement solution in flat placement file format; this file lists cluster and intra-cluster placement coordinates for each atom and can be used to reconstruct a clustering and placement solution.")
Expand Down
1 change: 1 addition & 0 deletions vpr/src/base/read_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct t_options {
argparse::ArgValue<std::string> read_vpr_constraints_file;
argparse::ArgValue<std::string> write_vpr_constraints_file;
argparse::ArgValue<std::string> write_constraints_file;
argparse::ArgValue<std::string> read_flat_place_file;
argparse::ArgValue<std::string> write_flat_place_file;

argparse::ArgValue<std::string> write_placement_delay_lookup;
Expand Down
11 changes: 10 additions & 1 deletion vpr/src/base/vpr_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <cstring>
#include <cmath>

#include "FlatPlacementInfo.h"
#include "cluster_util.h"
#include "verify_placement.h"
#include "vpr_context.h"
Expand Down Expand Up @@ -687,10 +688,18 @@ bool vpr_pack(t_vpr_setup& vpr_setup, const t_arch& arch) {
+ wtoi_switch_del); /* multiply by 4 to get a more conservative estimate */
}

// Read in the flat placement if a flat placement file is provided.
FlatPlacementInfo flat_placement_info;
if (!vpr_setup.FileNameOpts.read_flat_place_file.empty()) {
flat_placement_info = read_flat_placement(
vpr_setup.FileNameOpts.read_flat_place_file,
g_vpr_ctx.atom().nlist);
}

return try_pack(&vpr_setup.PackerOpts, &vpr_setup.AnalysisOpts,
&arch, vpr_setup.user_models,
vpr_setup.library_models, inter_cluster_delay,
vpr_setup.PackerRRGraph);
vpr_setup.PackerRRGraph, flat_placement_info);
}

void vpr_load_packing(t_vpr_setup& vpr_setup, const t_arch& arch) {
Expand Down
1 change: 1 addition & 0 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ struct t_file_name_opts {
std::string read_vpr_constraints_file;
std::string write_vpr_constraints_file;
std::string write_constraints_file;
std::string read_flat_place_file;
std::string write_flat_place_file;
std::string write_block_usage;
bool verify_file_digests;
Expand Down
28 changes: 25 additions & 3 deletions vpr/src/pack/pack.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#include <unordered_set>

#include "pack.h"

#include <unordered_set>
#include "FlatPlacementInfo.h"
#include "SetupGrid.h"
#include "attraction_groups.h"
#include "cluster_legalizer.h"
#include "cluster_util.h"
#include "constraints_report.h"
#include "globals.h"
#include "greedy_clusterer.h"
#include "pack.h"
#include "prepack.h"
#include "verify_flat_placement.h"
#include "vpr_context.h"
#include "vpr_error.h"
#include "vpr_types.h"
Expand All @@ -26,7 +29,8 @@ bool try_pack(t_packer_opts* packer_opts,
const t_model* user_models,
const t_model* library_models,
float interc_delay,
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs) {
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
const FlatPlacementInfo& flat_placement_info) {
const AtomContext& atom_ctx = g_vpr_ctx.atom();
const DeviceContext& device_ctx = g_vpr_ctx.device();
// The clusterer modifies the device context by increasing the size of the
Expand Down Expand Up @@ -69,6 +73,24 @@ bool try_pack(t_packer_opts* packer_opts,
VTR_LOG("%d attraction groups were created during prepacking.\n", attraction_groups.num_attraction_groups());
VTR_LOG("Finish prepacking.\n");

// Verify that the Flat Placement is valid for packing.
if (flat_placement_info.valid) {
unsigned num_errors = verify_flat_placement_for_packing(flat_placement_info,
atom_ctx.nlist,
prepacker);
if (num_errors == 0) {
VTR_LOG("Completed flat placement consistency check successfully.\n");
} else {
// TODO: In the future, we can just erase the flat placement and
// continue. It depends on what we want to happen if the
// flat placement is not valid.
VPR_ERROR(VPR_ERROR_PACK,
"%u errors found while performing flat placement "
"consistency check. Aborting program.\n",
num_errors);
}
}

if (packer_opts->auto_compute_inter_cluster_net_delay) {
packer_opts->inter_cluster_net_delay = interc_delay;
VTR_LOG("Using inter-cluster delay: %g\n", packer_opts->inter_cluster_net_delay);
Expand Down
4 changes: 3 additions & 1 deletion vpr/src/pack/pack.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>

class AtomNetId;
class FlatPlacementInfo;
struct t_analysis_opts;
struct t_arch;
struct t_lb_type_rr_node;
Expand All @@ -17,7 +18,8 @@ bool try_pack(t_packer_opts* packer_opts,
const t_model* user_models,
const t_model* library_models,
float interc_delay,
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs);
std::vector<t_lb_type_rr_node>* lb_type_rr_graphs,
const FlatPlacementInfo& flat_placement_info);

float get_arch_switch_info(short switch_index, int switch_fanin, float& Tdel_switch, float& R_switch, float& Cout_switch);

Expand Down
Loading

0 comments on commit 18097d4

Please sign in to comment.