Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[APPack] Added read_flat_place Option and Verifier #2861

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 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,50 @@ 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. Each line in the flat
placement file should have the following syntax:

.. code-block:: none

<atom_name : str> <x : float> <y : float> <layer : float> <atom_sub_tile : int> <atom_site_idx? : int>

For example:

.. code-block:: none

n523 6 8 0 0 3
n522 6 8 0 0 5
n520 6 8 0 0 2
n518 6 8 0 0 16

The position of the atom on the FPGA is given by 3 floating point values
(``x``, ``y``, ``layer``). We allow for the positions of atom to be not
quite legal (ok to be off-grid) since this flat placement will be fed into
the packer and placer, which will snap the positions to grid locations. By
allowing for off-grid positions, the packer can better trade-off where to
move atom blocks if they cannot be placed at the given position.
For 2D FPGA architectures, the ``layer`` should be 0.

The ``sub_tile`` is a clustered placement construct: which cluster-level
location at a given (x, y, layer) should these atoms go at (relevant when
multiple clusters can be stacked there). A sub-tile of -1 may be used when
the sub-tile of an atom is unkown (allowing the packing algorithm to choose
any sub-tile at the given (x, y, layer) location).

The ``site_idx`` is an optional index into a linearized list of primitive
locations within a cluster-level block 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
84 changes: 84 additions & 0 deletions vpr/src/base/FlatPlacementInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @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;

// The following three floating point numbers describe the flat position of
// an atom block. These are floats instead of integers to allow for flat
// placements which are not quite legal (ok to be off-grid). This allows
// the flat placement to encode information about where atom blocks would
// want to go if they cannot be placed at the grid position they are at.
// (for example, a block placed at (0.9, 0.9) wants to be at tile (0, 0),
// but if thats not possible it would prefer (1, 1) over anything else.

/// @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.
AlexandreSinger marked this conversation as resolved.
Show resolved Hide resolved
vtr::vector<AtomBlockId, float> blk_y_pos;
/// @brief The layer of each atom block. Is UNDEFINED_POS if undefined.
vtr::vector<AtomBlockId, float> blk_layer;

/// @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. This is an optional index
/// into a linearized list of primitive locations within a cluster-
/// level 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_layer(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
90 changes: 88 additions & 2 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 @@ -45,9 +50,10 @@ static void print_flat_cluster(FILE* fp,
t_pb_graph_node* atom_pbgn = atom_ctx.lookup.atom_pb(atom)->pb_graph_node;

// Print the flat placement information for this atom.
fprintf(fp, "%s %d %d %d %d #%zu %s\n",
fprintf(fp, "%s %d %d %d %d %d #%zu %s\n",
atom_ctx.nlist.block_name(atom).c_str(),
blk_loc.x, blk_loc.y, blk_loc.sub_tile,
blk_loc.x, blk_loc.y, blk_loc.layer,
blk_loc.sub_tile,
atom_pbgn->flat_site_index,
static_cast<size_t>(blk_id),
atom_pbgn->pb_type->name);
Expand Down Expand Up @@ -77,6 +83,86 @@ 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
// - Atom layer
// - Atom sub-tile
if (tokens.size() < 5) {
VTR_LOG_WARN("Flat placement file, line %d has too few arguments. "
"Requires at least: <atom_name> <x> <y> <layer> <sub_tile>\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, y, layer) position of the atom. These functions have
// error checking built in. We parse these 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]);
flat_placement_info.blk_layer[atom_blk_id] = vtr::atof(tokens[3]);

// Parse the sub-tile as an integer.
flat_placement_info.blk_sub_tile[atom_blk_id] = vtr::atoi(tokens[4]);

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

// 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
Loading
Loading