Skip to content
Open
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
27 changes: 27 additions & 0 deletions vpr/src/analytical_place/global_placer.cpp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to keep the drawing code pretty isolated from the AP code as much as possible. In the future, we may decide to make another global placer as well, and I would like to avoid duplicate code.

I suggest that you create a new class in the analytical_place directory for drawing. Something like APDrawManager or something. This class would then have methods for drawing the pre and post legalized placements. This would remove the global accesses from this method. The global placer can then take this as an argument, which it can use to draw whenever it needs.

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include "ap_netlist_fwd.h"
#include "atom_netlist.h"
#include "device_grid.h"
#include "draw.h"
#ifndef NO_GRAPHICS
#include "draw_global.h"
#endif
#include "flat_placement_bins.h"
#include "flat_placement_density_manager.h"
#include "globals.h"
Expand Down Expand Up @@ -352,6 +356,10 @@ PartialPlacement SimPLGlobalPlacer::place() {
PartialPlacement best_p_placement(ap_netlist_);
double best_ub_hpwl = std::numeric_limits<double>::max();

#ifndef NO_GRAPHICS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comments above. I would like to keep these ifdefs and the draw state out of this class.

get_draw_state_vars()->set_ap_partial_placement_ref(p_placement);
update_screen(ScreenUpdatePriority::MAJOR, "AP starts", ANALYTICAL_PLACEMENT, nullptr);
#endif
// Run the global placer.
for (size_t i = 0; i < max_num_iterations_; i++) {
float iter_start_time = runtime_timer.elapsed_sec();
Expand All @@ -361,12 +369,22 @@ PartialPlacement SimPLGlobalPlacer::place() {
solver_->solve(i, p_placement);
float solver_end_time = runtime_timer.elapsed_sec();
double lb_hpwl = p_placement.get_hpwl(ap_netlist_);
#ifndef NO_GRAPHICS
// Per iteration analytical solve display
std::string iter_msg = vtr::string_fmt("AP Iteration %zu after analytical solve", i);
update_screen(ScreenUpdatePriority::MAJOR, iter_msg.c_str(), ANALYTICAL_PLACEMENT, nullptr);
#endif

// Run the legalizer.
float legalizer_start_time = runtime_timer.elapsed_sec();
partial_legalizer_->legalize(p_placement);
float legalizer_end_time = runtime_timer.elapsed_sec();
double ub_hpwl = p_placement.get_hpwl(ap_netlist_);
#ifndef NO_GRAPHICS
// Per iteration legalized display
iter_msg = vtr::string_fmt("AP Iteration %zu after partial legalization", i);
update_screen(ScreenUpdatePriority::MAJOR, iter_msg.c_str(), ANALYTICAL_PLACEMENT, nullptr);
#endif

// Perform a timing update
float timing_update_start_time = runtime_timer.elapsed_sec();
Expand Down Expand Up @@ -422,6 +440,8 @@ PartialPlacement SimPLGlobalPlacer::place() {

if (hpwl_relative_gap < target_hpwl_relative_gap_)
break;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add these extra lines?


}

// Update the setup slacks. This is performed down here (as well as being
Expand Down Expand Up @@ -450,6 +470,13 @@ PartialPlacement SimPLGlobalPlacer::place() {
*density_manager_,
pre_cluster_timing_manager_);


#ifndef NO_GRAPHICS
// Final display of the last iteration's placement
get_draw_state_vars()->set_ap_partial_placement_ref(p_placement);
update_screen(ScreenUpdatePriority::MAJOR, "Global Placement Complete", ANALYTICAL_PLACEMENT, nullptr);
get_draw_state_vars()->clear_ap_partial_placement_ref();
#endif
// Return the placement from the final iteration.
return best_p_placement;
}
1 change: 1 addition & 0 deletions vpr/src/base/vpr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ enum class e_sched_type {
enum pic_type {
NO_PICTURE,
PLACEMENT,
ANALYTICAL_PLACEMENT,
ROUTING
};
/* What's on screen? */
Expand Down
134 changes: 89 additions & 45 deletions vpr/src/draw/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
#include <cstring>
#include <cmath>
#include "draw.h"
#include "draw_types.h"
#include "timing_info.h"
#include "physical_types.h"

#include "move_utils.h"
#include "vpr_types.h"

#ifndef NO_GRAPHICS

Expand Down Expand Up @@ -174,63 +176,65 @@ static void draw_main_canvas(ezgl::renderer* g) {
t_draw_state* draw_state = get_draw_state_vars();

g->set_font_size(14);
if (draw_state->pic_on_screen != ANALYTICAL_PLACEMENT) {
draw_block_pin_util();
drawplace(g);
draw_internal_draw_subblk(g);

draw_block_pin_util();
drawplace(g);
draw_internal_draw_subblk(g);
if (draw_state->pic_on_screen == ROUTING) { // ROUTING on screen

if (draw_state->pic_on_screen == ROUTING) { // ROUTING on screen
draw_rr(g);

draw_rr(g);
if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) {
draw_route(ALL_NETS, g);

if (draw_state->show_nets && draw_state->draw_nets == DRAW_ROUTED_NETS) {
draw_route(ALL_NETS, g);

if (draw_state->highlight_fan_in_fan_out) {
draw_route(HIGHLIGHTED, g);
if (draw_state->highlight_fan_in_fan_out) {
draw_route(HIGHLIGHTED, g);
}
}
}

draw_congestion(g);
draw_congestion(g);

draw_routing_costs(g);
draw_routing_costs(g);

draw_router_expansion_costs(g);
draw_router_expansion_costs(g);

draw_routing_util(g);
draw_routing_util(g);

draw_routing_bb(g);
}
draw_routing_bb(g);
}

draw_placement_macros(g);
draw_placement_macros(g);

#ifndef NO_SERVER
if (g_vpr_ctx.server().gate_io.is_running()) {
const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut
draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g);
} else {
draw_crit_path(g);
}
if (g_vpr_ctx.server().gate_io.is_running()) {
const ServerContext& server_ctx = g_vpr_ctx.server(); // shortcut
draw_crit_path_elements(server_ctx.crit_paths, server_ctx.crit_path_element_indexes, server_ctx.draw_crit_path_contour, g);
} else {
draw_crit_path(g);
}
#else
draw_crit_path(g);
draw_crit_path(g);
#endif /* NO_SERVER */

draw_logical_connections(g);
draw_logical_connections(g);

draw_selected_pb_flylines(g);
draw_selected_pb_flylines(g);

draw_noc(g);
draw_noc(g);

if (draw_state->draw_partitions) {
highlight_all_regions(g);
draw_constrained_atoms(g);
}
if (draw_state->draw_partitions) {
highlight_all_regions(g);
draw_constrained_atoms(g);
}

if (draw_state->color_map) {
draw_color_map_legend(*draw_state->color_map, g);
draw_state->color_map.reset(); //Free color map in preparation for next redraw
if (draw_state->color_map) {
draw_color_map_legend(*draw_state->color_map, g);
draw_state->color_map.reset(); //Free color map in preparation for next redraw
}
} else {
draw_analytical_place(g);
}

if (draw_state->auto_proceed) {
//Automatically exit the event loop, so user's don't need to manually click proceed

Expand Down Expand Up @@ -286,7 +290,7 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type
* value controls whether or not the Proceed button must be clicked to *
* continue. Saves the pic_on_screen_val to allow pan and zoom redraws. */
t_draw_state* draw_state = get_draw_state_vars();

strcpy(draw_state->default_message, msg);

if (!draw_state->show_graphics)
Expand All @@ -302,16 +306,30 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type

state_change = true;

if (draw_state->show_graphics) {
if (pic_on_screen_val == ANALYTICAL_PLACEMENT) {
set_initial_world_ap();
} else {
set_initial_world();
}
}

if (draw_state->pic_on_screen == NO_PICTURE) {
// Only add the canvas the first time we open graphics
application.add_canvas("MainCanvas", draw_main_canvas,
initial_world);
application.add_canvas("MainCanvas", draw_main_canvas, initial_world);
} else {
// TODO: will this ever be null?
auto canvas = application.get_canvas(application.get_main_canvas_id());
if (canvas != nullptr) {
canvas->get_camera().set_world(initial_world);
}
}

draw_state->setup_timing_info = setup_timing_info;
draw_state->pic_on_screen = pic_on_screen_val;
}

// What is this? Always true!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would mark this as a FIXME, or raise an issue so we can resolve. A comment like this will get missed.

bool should_pause = int(priority) >= draw_state->gr_automode;

//If there was a state change, we must call ezgl::application::run() to update the buttons.
Expand Down Expand Up @@ -481,7 +499,18 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) {
//Margin beyond edge of the drawn device to extend the visible world
//Setting this to > 0.0 means 'Zoom Fit' leave some fraction of white
//space around the device edges
#else
(void)clb_width;
(void)blk_loc_registry;
#endif /* NO_GRAPHICS */
}

#ifndef NO_GRAPHICS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be careful with this ifdef. You are not defining these functions when graphics is disabled. However, they are still available in the header file...

I would put the ifdef inside of the method and have the method do nothing when graphics is not enabled.


void set_initial_world() {
constexpr float VISIBLE_MARGIN = 0.01;
t_draw_coords* draw_coords = get_draw_coords_vars();
const DeviceContext& device_ctx = g_vpr_ctx.device();

float draw_width = draw_coords->tile_x[device_ctx.grid.width() - 1]
+ draw_coords->get_tile_width();
Expand All @@ -491,14 +520,24 @@ void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry) {
initial_world = ezgl::rectangle(
{-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height},
{(1. + VISIBLE_MARGIN) * draw_width, (1. + VISIBLE_MARGIN)
* draw_height});
#else
(void)clb_width;
(void)blk_loc_registry;
#endif /* NO_GRAPHICS */
* draw_height});
}

#ifndef NO_GRAPHICS
void set_initial_world_ap() {
constexpr float VISIBLE_MARGIN = 0.01f;
const DeviceContext& device_ctx = g_vpr_ctx.device();

const size_t grid_w = device_ctx.grid.width();
const size_t grid_h = device_ctx.grid.height();


float draw_width = static_cast<float>(grid_w);
float draw_height = static_cast<float>(grid_h);

initial_world = ezgl::rectangle(
{-VISIBLE_MARGIN * draw_width, -VISIBLE_MARGIN * draw_height},
{(1.f + VISIBLE_MARGIN) * draw_width, (1.f + VISIBLE_MARGIN) * draw_height});
}

int get_track_num(int inode, const vtr::OffsetMatrix<int>& chanx_track, const vtr::OffsetMatrix<int>& chany_track) {
/* Returns the track number of this routing resource node. */
Expand Down Expand Up @@ -624,6 +663,11 @@ void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x,
* fanins and fanouts are highlighted when you click on a block *
* attached to them. */

if (get_draw_state_vars()->pic_on_screen == ANALYTICAL_PLACEMENT) {
// No selection in analytical placement mode yet
return;
}

/* Control + mouse click to select multiple nets. */
if (!(event->state & GDK_CONTROL_MASK))
deselect_all();
Expand Down
3 changes: 3 additions & 0 deletions vpr/src/draw/draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ void update_screen(ScreenUpdatePriority priority, const char* msg, enum pic_type
*/
void init_draw_coords(float clb_width, const BlkLocRegistry& blk_loc_registry);

void set_initial_world_ap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new methods need comments. Also see my prior comments on their definitions.

void set_initial_world();

/* Sets the static show_graphics and gr_automode variables to the *
* desired values. They control if graphics are enabled and, if so, *
* how often the user is prompted for input. */
Expand Down
57 changes: 55 additions & 2 deletions vpr/src/draw/draw_basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@

#include "physical_types_util.h"
#include "vtr_assert.h"
#include "vtr_ndoffsetmatrix.h"
#include "vtr_color_map.h"

#include "vpr_utils.h"
#include "vpr_error.h"

#include "globals.h"
#include "draw_color.h"
Expand All @@ -29,6 +27,7 @@
#include "move_utils.h"
#include "route_export.h"
#include "tatum/report/TimingPathCollector.hpp"
#include "partial_placement.h"

//To process key presses we need the X11 keysym definitions,
//which are unavailable when building with MINGW
Expand Down Expand Up @@ -193,6 +192,60 @@ void drawplace(ezgl::renderer* g) {
}
}

void draw_analytical_place(ezgl::renderer* g) {
// Draw a tightly packed view of the device grid using only device context info.
t_draw_state* draw_state = get_draw_state_vars();
const DeviceContext& device_ctx = g_vpr_ctx.device();

g->set_line_dash(ezgl::line_dash::none);
g->set_line_width(0);

int total_layers = device_ctx.grid.get_num_layers();
for (int layer = 0; layer < total_layers; ++layer) {
const auto& layer_disp = draw_state->draw_layer_display[layer];
if (!layer_disp.visible) continue;

for (int x = 0; x < (int)device_ctx.grid.width(); ++x) {
for (int y = 0; y < (int)device_ctx.grid.height(); ++y) {
// Only draw at the root of a non-unit tile
int w_off = device_ctx.grid.get_width_offset({x, y, layer});
int h_off = device_ctx.grid.get_height_offset({x, y, layer});
if (w_off > 0 || h_off > 0) continue;

t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({x, y, layer});
if (type->capacity == 0) continue;

ezgl::point2d bl{static_cast<double>(x), static_cast<double>(y)};
ezgl::point2d tr{static_cast<double>(x + type->width), static_cast<double>(y + type->height)};

ezgl::color fill_color = get_block_type_color(type);
g->set_color(fill_color, layer_disp.alpha);
g->fill_rectangle(bl, tr);

if (draw_state->draw_block_outlines) {
g->set_color(ezgl::BLACK, layer_disp.alpha);
g->draw_rectangle(bl, tr);
}
}
}
}

const double half_size = 0.05;

const PartialPlacement* ap_pp = draw_state->get_ap_partial_placement_ref();
// The reference should be set in the beginning of analytial placement.
VTR_ASSERT(ap_pp != nullptr);
for (const auto& [blk_id, x] : ap_pp->block_x_locs.pairs()) {
double y = ap_pp->block_y_locs[blk_id];

ezgl::point2d bl{x - half_size, y - half_size};
ezgl::point2d tr{x + half_size, y + half_size};

g->set_color(ezgl::BLACK);
g->fill_rectangle(bl, tr);
}
}

/* This routine draws the nets on the placement. The nets have not *
* yet been routed, so we just draw a chain showing a possible path *
* for each net. This gives some idea of future congestion. */
Expand Down
2 changes: 2 additions & 0 deletions vpr/src/draw/draw_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
* Blocks are drawn in layer order (so that semi-transparent blocks/grids render well)*/
void drawplace(ezgl::renderer* g);

void draw_analytical_place(ezgl::renderer* g);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs comment.


/** This routine draws the nets on the placement. The nets have not
* yet been routed, so we just draw a chain showing a possible path
* for each net. This gives some idea of future congestion.
Expand Down
Loading