-
Notifications
You must be signed in to change notification settings - Fork 446
Expand file tree
/
Copy pathload_flat_place.cpp
More file actions
343 lines (305 loc) · 15.1 KB
/
Copy pathload_flat_place.cpp
File metadata and controls
343 lines (305 loc) · 15.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/**
* @file
* @author Alex Singer
* @date January 2025
* @brief Implementation of utility functions for reading and writing flat
* (primitive-level) placements.
*/
#include "load_flat_place.h"
#include <algorithm>
#include <fstream>
#include <unordered_set>
#include "atom_lookup.h"
#include "atom_netlist.h"
#include "clustered_netlist.h"
#include "flat_placement_utils.h"
#include "flat_placement_types.h"
#include "globals.h"
#include "vpr_context.h"
#include "vpr_error.h"
#include "vpr_types.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_vector_map.h"
#include "vtr_version.h"
/**
* @brief Prints the header for the flat placement file. This includes helpful
* information on how to read the file and when it was generated.
*
* @param fp
* File pointer to the file the cluster is printed to.
* @param flat_place_verbosity
* How much annotation the file carries; decides which columns the
* header announces. See write_flat_placement().
*/
static void print_flat_placement_file_header(FILE* fp, int flat_place_verbosity) {
fprintf(fp, "# Flat Placement File\n");
fprintf(fp, "# Auto-generated by VPR %s\n",
vtr::VERSION);
fprintf(fp, "# Created: %s\n",
vtr::BUILD_TIMESTAMP);
fprintf(fp, "#\n");
fprintf(fp, "# This file prints the following information for each atom in the netlist:\n");
if (flat_place_verbosity >= 2) {
fprintf(fp, "# <atom_name> <x> <y> <layer> <atom_sub_tile> #<clb_blk_id> <atom_pb_type> <site_path>\n");
} else {
fprintf(fp, "# <atom_name> <x> <y> <layer> <atom_sub_tile> #<clb_blk_id> <atom_pb_type>\n");
}
fprintf(fp, "\n");
}
/**
* @brief Prints flat placement file entries for the atoms in one placed
* cluster.
*
* @param fp
* File pointer to the file the cluster is printed to.
* @param blk_id
* The ID of the cluster block to print.
* @param block_locs
* The locations of all cluster blocks.
* @param atoms_lookup
* A lookup between all clusters and the atom blocks that they
* contain.
* @param flat_place_verbosity
* How much annotation to append to each atom's line. See
* write_flat_placement().
*/
static void print_flat_cluster(FILE* fp,
ClusterBlockId blk_id,
const vtr::vector_map<ClusterBlockId, t_block_loc>& block_locs,
const vtr::vector<ClusterBlockId, std::unordered_set<AtomBlockId>>& atoms_lookup,
int flat_place_verbosity) {
const AtomContext& atom_ctx = g_vpr_ctx.atom();
// Get the location of this cluster.
const t_pl_loc& blk_loc = block_locs[blk_id].loc;
// Print a line for each atom.
for (AtomBlockId atom : atoms_lookup[blk_id]) {
// Print the placement of this atom. These are the only columns the
// flat placement reader parses; everything below is annotation.
fprintf(fp, "%s %d %d %d %d",
atom_ctx.netlist().block_name(atom).c_str(),
blk_loc.x, blk_loc.y, blk_loc.layer,
blk_loc.sub_tile);
if (flat_place_verbosity >= 1) {
// Get the atom pb graph node, which holds the primitive the atom
// was placed on.
t_pb_graph_node* atom_pbgn = atom_ctx.lookup().atom_pb_bimap().atom_pb(atom)->pb_graph_node;
fprintf(fp, " #%zu %s",
static_cast<size_t>(blk_id),
atom_pbgn->pb_type->name);
if (flat_place_verbosity >= 2) {
// The hierarchical path of the primitive this atom was placed
// on, e.g. "clb[0][default]/lab[0][default]/fle[3][n1_lut6]".
fprintf(fp, " %s", atom_pbgn->hierarchical_type_name().c_str());
}
}
fprintf(fp, "\n");
}
}
void write_flat_placement(const char* flat_place_file_path,
const ClusteredNetlist& cluster_netlist,
const vtr::vector_map<ClusterBlockId, t_block_loc>& block_locs,
const vtr::vector<ClusterBlockId, std::unordered_set<AtomBlockId>>& atoms_lookup,
int flat_place_verbosity) {
// Writes the flat placement to the given flat_place_file_path.
// Only print a flat placement if the clusters have been placed.
if (block_locs.empty())
return;
// Create a file in write mode for the flat placement.
FILE* fp = fopen(flat_place_file_path, "w");
// Add a header to the flat placement file. The header is itself a comment,
// so it is omitted when no annotation was asked for.
if (flat_place_verbosity >= 1) {
print_flat_placement_file_header(fp, flat_place_verbosity);
}
// For each cluster, write out the atoms in the cluster at this cluster's
// location.
for (ClusterBlockId iblk : cluster_netlist.blocks()) {
print_flat_cluster(fp, iblk, block_locs, atoms_lookup, flat_place_verbosity);
}
// Close the file.
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::StringToken(line).split(" \t\n");
// 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]);
// 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(const t_vpr_setup& vpr_setup, const t_arch& arch) {
VTR_LOG("load_flat_placement(); when implemented, this function:");
VTR_LOG("\n\tLoads flat placement file: %s, ", vpr_setup.FileNameOpts.FlatPlaceFile.c_str());
VTR_LOG("\n\tArch id: %s, ", arch.architecture_id.c_str());
VTR_LOG("\n\tPrints clustered netlist file: %s, ", vpr_setup.FileNameOpts.NetFile.c_str());
VTR_LOG("\n\tPrints fix clusters file: %s\n", vpr_setup.FileNameOpts.write_constraints_file.c_str());
return false;
}
void log_flat_placement_reconstruction_info(
const FlatPlacementInfo& flat_placement_info,
const vtr::vector_map<ClusterBlockId, t_block_loc>& block_locs,
const vtr::vector<ClusterBlockId, std::unordered_set<AtomBlockId>>& atoms_lookup,
const AtomLookup& cluster_of_atom_lookup,
const AtomNetlist& atom_netlist,
const ClusteredNetlist& clustered_netlist) {
// Go through each cluster and see how many clusters have atoms that
// do not belong (cluster is imperfect).
unsigned num_imperfect_clusters = 0;
for (ClusterBlockId clb_blk_id : clustered_netlist.blocks()) {
// Get the centroid of the cluster
const auto& clb_atoms = atoms_lookup[clb_blk_id];
float centroid_x = 0.f;
float centroid_y = 0.f;
float centroid_layer = 0.f;
float centroid_sub_tile = 0.f;
for (AtomBlockId atom_blk_id : clb_atoms) {
// TODO: Currently only handle the case when all of the position
// data is provided. This can be extended,
VTR_ASSERT(flat_placement_info.blk_x_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS);
VTR_ASSERT(flat_placement_info.blk_y_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS);
VTR_ASSERT(flat_placement_info.blk_layer[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS);
VTR_ASSERT(flat_placement_info.blk_sub_tile[atom_blk_id] != FlatPlacementInfo::UNDEFINED_SUB_TILE);
centroid_x += flat_placement_info.blk_x_pos[atom_blk_id];
centroid_y += flat_placement_info.blk_y_pos[atom_blk_id];
centroid_layer += flat_placement_info.blk_layer[atom_blk_id];
centroid_sub_tile += flat_placement_info.blk_sub_tile[atom_blk_id];
}
centroid_x /= static_cast<float>(clb_atoms.size());
centroid_y /= static_cast<float>(clb_atoms.size());
centroid_layer /= static_cast<float>(clb_atoms.size());
centroid_sub_tile /= static_cast<float>(clb_atoms.size());
// Check if every atom in the cluster is within 0.5 units of the
// centroid.
for (AtomBlockId atom_blk_id : clb_atoms) {
// If the atom's flat placement more than half a block in any
// direction from the flat placement centroid, then it does not
// want to be in this cluster.
// FIXME: This should take into account large blocks somehow, just
// being 0.5 tiles away may not be sufficient.
if (std::abs(centroid_x - flat_placement_info.blk_x_pos[atom_blk_id]) > 0.5f || std::abs(centroid_y - flat_placement_info.blk_y_pos[atom_blk_id]) > 0.5f || std::abs(centroid_layer - flat_placement_info.blk_layer[atom_blk_id]) > 0.5f || std::abs(centroid_sub_tile - flat_placement_info.blk_sub_tile[atom_blk_id]) > 0.5f) {
num_imperfect_clusters++;
break;
}
}
}
// Go through each atom and compute how much it has displaced and count
// how many have been displaced beyond some threshold.
constexpr float disp_threashold = 0.5f;
float total_disp = 0.f;
float max_disp = 0.f;
unsigned num_atoms_missplaced = 0;
for (AtomBlockId atom_blk_id : atom_netlist.blocks()) {
// TODO: Currently only handle the case when all of the position
// data is provided. This can be extended,
VTR_ASSERT(flat_placement_info.blk_x_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS);
VTR_ASSERT(flat_placement_info.blk_y_pos[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS);
VTR_ASSERT(flat_placement_info.blk_layer[atom_blk_id] != FlatPlacementInfo::UNDEFINED_POS);
VTR_ASSERT(flat_placement_info.blk_sub_tile[atom_blk_id] != FlatPlacementInfo::UNDEFINED_SUB_TILE);
// Get the (x, y, layer) position of the block.
float blk_x = flat_placement_info.blk_x_pos[atom_blk_id];
float blk_y = flat_placement_info.blk_y_pos[atom_blk_id];
float blk_layer = flat_placement_info.blk_layer[atom_blk_id];
t_flat_pl_loc blk_flat_loc({blk_x, blk_y, blk_layer});
// Get the (x, y, layer) position of the cluster that contains this block.
ClusterBlockId atom_clb_id = cluster_of_atom_lookup.atom_clb(atom_blk_id);
const t_block_loc& clb_loc = block_locs[atom_clb_id];
t_physical_tile_loc tile_loc = {clb_loc.loc.x, clb_loc.loc.y, clb_loc.loc.layer};
// Get the L1 distance from the block location to the tile location.
// This will be the minimum distance this block needs to move.
float dist = get_manhattan_distance_to_tile(blk_flat_loc,
tile_loc,
g_vpr_ctx.device().grid);
// Collect the max displacement.
max_disp = std::max(max_disp, dist);
// Accumulate into the total displacement.
total_disp += dist;
// Check if this block has been displaced beyond the threshold.
if (dist >= disp_threashold) {
num_atoms_missplaced++;
}
// TODO: Make this debug option of higher verbosity. Helpful for
// debugging flat placement reconstruction.
/*
* VTR_LOG("%s %d %d %d %d\n",
* g_vpr_ctx.atom().netlist().block_name(atom_blk_id).c_str(),
* clb_loc.loc.x,
* clb_loc.loc.y,
* clb_loc.loc.layer,
* clb_loc.loc.sub_tile);
*/
}
// Log the flat placement reconstruction info.
size_t num_atoms = atom_netlist.blocks().size();
size_t num_clusters = clustered_netlist.blocks().size();
VTR_LOG("Flat Placement Reconstruction Info:\n");
VTR_LOG("\tPercent of clusters with reconstruction errors: %f\n",
100.0f * static_cast<float>(num_imperfect_clusters) / static_cast<float>(num_clusters));
VTR_LOG("\tTotal displacement of initial placement from flat placement: %f\n",
total_disp);
VTR_LOG("\tAverage atom displacement of initial placement from flat placement: %f\n",
total_disp / static_cast<float>(num_atoms));
VTR_LOG("\tMax atom displacement of initial placement from flat placement: %f\n",
max_disp);
VTR_LOG("\tPercent of atoms misplaced from the flat placement: %f\n",
100.0f * static_cast<float>(num_atoms_missplaced) / static_cast<float>(num_atoms));
}