Skip to content

Commit 3ecf1a3

Browse files
authored
Merge pull request #2272 from verilog-to-routing/block_type_based_RLplace_agent
RLPlace 2.0: Proposing block and move types
2 parents 6e98512 + 207e485 commit 3ecf1a3

File tree

81 files changed

+4028
-3477
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+4028
-3477
lines changed

comparison_output.xlsx

-39.3 KB
Binary file not shown.

vpr/src/base/SetupVPR.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ static void SetupPlacerOpts(const t_options& Options, t_placer_opts* PlacerOpts)
658658
PlacerOpts->place_agent_epsilon = Options.place_agent_epsilon;
659659
PlacerOpts->place_agent_gamma = Options.place_agent_gamma;
660660
PlacerOpts->place_dm_rlim = Options.place_dm_rlim;
661+
PlacerOpts->place_agent_space = Options.place_agent_space;
661662
PlacerOpts->place_reward_fun = Options.place_reward_fun;
662663
PlacerOpts->place_crit_limit = Options.place_crit_limit;
663664
PlacerOpts->place_agent_algorithm = Options.place_agent_algorithm;

vpr/src/base/clustered_netlist.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ t_logical_block_type_ptr ClusteredNetlist::block_type(const ClusterBlockId id) c
2828
return block_types_[id];
2929
}
3030

31+
std::vector<ClusterBlockId> ClusteredNetlist::blocks_per_type(const t_logical_block_type blk_type) const {
32+
if (blocks_per_type_.count(blk_type.index) == 0) {
33+
std::vector<ClusterBlockId> empty_vector;
34+
return empty_vector;
35+
}
36+
return blocks_per_type_.at(blk_type.index);
37+
}
38+
3139
ClusterNetId ClusteredNetlist::block_net(const ClusterBlockId blk_id, const int logical_pin_index) const {
3240
auto pin_id = block_pin(blk_id, logical_pin_index);
3341

@@ -108,6 +116,8 @@ ClusterBlockId ClusteredNetlist::create_block(const char* name, t_pb* pb, t_logi
108116
block_pbs_.insert(blk_id, pb);
109117
block_types_.insert(blk_id, type);
110118

119+
blocks_per_type_[type->index].push_back(blk_id);
120+
111121
//Allocate and initialize every potential pin of the block
112122
block_logical_pins_.insert(blk_id, std::vector<ClusterPinId>(get_max_num_pins(type), ClusterPinId::INVALID()));
113123
}
@@ -168,11 +178,14 @@ ClusterNetId ClusteredNetlist::create_net(const std::string name) {
168178
}
169179

170180
void ClusteredNetlist::remove_block_impl(const ClusterBlockId blk_id) {
181+
//find the block type, so we can remove it from blocks_per_type_ data structure
182+
auto blk_type = block_type(blk_id);
171183
//Remove & invalidate pointers
172184
free_pb(block_pbs_[blk_id]);
173185
delete block_pbs_[blk_id];
174186
block_pbs_.insert(blk_id, NULL);
175187
block_types_.insert(blk_id, NULL);
188+
std::remove(blocks_per_type_[blk_type->index].begin(), blocks_per_type_[blk_type->index].end(), blk_id);
176189
block_logical_pins_.insert(blk_id, std::vector<ClusterPinId>());
177190
}
178191

vpr/src/base/clustered_netlist.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ class ClusteredNetlist : public Netlist<ClusterBlockId, ClusterPortId, ClusterPi
134134
///@brief Returns the type of CLB (Logic block, RAM, DSP, etc.)
135135
t_logical_block_type_ptr block_type(const ClusterBlockId id) const;
136136

137+
///@brief Returns the blocks with the specific block types in the netlist
138+
std::vector<ClusterBlockId> blocks_per_type(const t_logical_block_type blk_type) const;
139+
137140
///@brief Returns the net of the block attached to the specific pin index
138141
ClusterNetId block_net(const ClusterBlockId blk_id, const int pin_index) const;
139142

@@ -331,6 +334,7 @@ class ClusteredNetlist : public Netlist<ClusterBlockId, ClusterPortId, ClusterPi
331334
vtr::vector_map<ClusterBlockId, t_pb*> block_pbs_; ///<Physical block representing the clustering & internal hierarchy of each CLB
332335
vtr::vector_map<ClusterBlockId, t_logical_block_type_ptr> block_types_; ///<The type of logical block this user circuit block is mapped to
333336
vtr::vector_map<ClusterBlockId, std::vector<ClusterPinId>> block_logical_pins_; ///<The logical pin associated with each physical tile pin
337+
std::unordered_map<int, std::vector<ClusterBlockId>> blocks_per_type_; ///<Block IDs associated with each physical block type, Used in placement to move specific block type
334338

335339
//Pins
336340
/**

vpr/src/base/netlist.tpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -977,12 +977,12 @@ void Netlist<BlockId, PortId, PinId, NetId>::remove_block(const BlockId blk_id)
977977
StringId name_id = block_names_[blk_id];
978978
block_name_to_block_id_.insert(name_id, BlockId::INVALID());
979979

980-
//Mark as invalid
981-
block_ids_[blk_id] = BlockId::INVALID();
982-
983980
//Call derived class' remove()
984981
remove_block_impl(blk_id);
985982

983+
//Mark as invalid
984+
block_ids_[blk_id] = BlockId::INVALID();
985+
986986
//Mark netlist dirty
987987
dirty_ = true;
988988
}

vpr/src/base/read_options.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,37 @@ struct ParsePlaceAgentAlgorithm {
461461
}
462462
};
463463

464+
struct ParsePlaceAgentSpace {
465+
ConvertedValue<e_agent_space> from_str(std::string str) {
466+
ConvertedValue<e_agent_space> conv_value;
467+
if (str == "move_type")
468+
conv_value.set_value(MOVE_TYPE);
469+
else if (str == "move_block_type")
470+
conv_value.set_value(MOVE_BLOCK_TYPE);
471+
else {
472+
std::stringstream msg;
473+
msg << "Invalid conversion from '" << str << "' to e_agent_space (expected one of: " << argparse::join(default_choices(), ", ") << ")";
474+
conv_value.set_error(msg.str());
475+
}
476+
return conv_value;
477+
}
478+
479+
ConvertedValue<std::string> to_str(e_agent_space val) {
480+
ConvertedValue<std::string> conv_value;
481+
if (val == MOVE_TYPE)
482+
conv_value.set_value("move_type");
483+
else {
484+
VTR_ASSERT(val == MOVE_BLOCK_TYPE);
485+
conv_value.set_value("move_block_type");
486+
}
487+
return conv_value;
488+
}
489+
490+
std::vector<std::string> default_choices() {
491+
return {"move_type", "move_block_type"};
492+
}
493+
};
494+
464495
struct ParseFixPins {
465496
ConvertedValue<e_pad_loc_type> from_str(std::string str) {
466497
ConvertedValue<e_pad_loc_type> conv_value;
@@ -2083,6 +2114,14 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg
20832114
.choices({"e_greedy", "softmax"})
20842115
.show_in(argparse::ShowIn::HELP_ONLY);
20852116

2117+
place_grp.add_argument<e_agent_space, ParsePlaceAgentSpace>(args.place_agent_space, "--place_agent_space")
2118+
.help(
2119+
"Agent exploration space can be either based on only move types or also consider different block types\n"
2120+
"The available values are: move_type, move_block_type")
2121+
.default_value("move_block_type")
2122+
.choices({"move_type", "move_block_type"})
2123+
.show_in(argparse::ShowIn::HELP_ONLY);
2124+
20862125
auto& place_timing_grp = parser.add_argument_group("timing-driven placement options");
20872126

20882127
place_timing_grp.add_argument(args.PlaceTimingTradeoff, "--timing_tradeoff")

vpr/src/base/read_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct t_options {
134134
argparse::ArgValue<float> place_agent_epsilon;
135135
argparse::ArgValue<float> place_agent_gamma;
136136
argparse::ArgValue<float> place_dm_rlim;
137+
argparse::ArgValue<e_agent_space> place_agent_space;
137138
argparse::ArgValue<e_agent_algorithm> place_agent_algorithm;
138139
argparse::ArgValue<std::string> place_reward_fun;
139140
argparse::ArgValue<float> place_crit_limit;

vpr/src/base/vpr_context.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,19 @@ struct PlacementContext : public Context {
387387
* Used for unique identification and consistency checking
388388
*/
389389
std::string placement_id;
390+
391+
/**
392+
* @brief Map physical block type to RL-agent block type
393+
*
394+
* RL-agent block types are the physical block types that are used in the netlist (at least one logical block in the netlist maps to).
395+
* As an example:
396+
* Having physical block types (EMPTY, LAB, DSP, IO),
397+
* agent block types would be (LAB,IO) if netlist doesn't contain DSP blocks.
398+
* Key : physical (agent) block type index
399+
* Value : agent (physical) block type index
400+
*/
401+
std::unordered_map<int, int> phys_blk_type_to_agent_blk_type_map;
402+
std::unordered_map<int, int> agent_blk_type_to_phys_blk_type_map;
390403
};
391404

392405
/**

vpr/src/base/vpr_types.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,18 @@ enum e_agent_algorithm {
983983
SOFTMAX
984984
};
985985

986+
/**
987+
* @brief Used to determines the dimensionality of the RL agent exploration space
988+
*
989+
* Agent exploration space can be either based on only move types or
990+
* can be based on (block_type, move_type) pair.
991+
*
992+
*/
993+
enum e_agent_space {
994+
MOVE_TYPE,
995+
MOVE_BLOCK_TYPE
996+
};
997+
986998
///@brief Used to calculate the inner placer loop's block swapping limit move_lim.
987999
enum e_place_effort_scaling {
9881000
CIRCUIT, ///<Effort scales based on circuit size only
@@ -1065,6 +1077,8 @@ enum class e_place_delta_delay_algorithm {
10651077
* @param place_constraint_subtile
10661078
* True if subtiles should be specified when printing floorplan
10671079
* constraints. False if not.
1080+
*
1081+
*
10681082
*/
10691083
struct t_placer_opts {
10701084
t_place_algorithm place_algorithm;
@@ -1113,6 +1127,7 @@ struct t_placer_opts {
11131127
float place_agent_epsilon;
11141128
float place_agent_gamma;
11151129
float place_dm_rlim;
1130+
e_agent_space place_agent_space;
11161131
//int place_timing_cost_func;
11171132
std::string place_reward_fun;
11181133
float place_crit_limit;

vpr/src/draw/manual_moves.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ e_create_move manual_move_display_and_propose(ManualMoveGenerator& manual_move_g
310310
draw_manual_moves_window("");
311311
update_screen(ScreenUpdatePriority::MAJOR, " ", PLACEMENT, nullptr);
312312
move_type = e_move_type::MANUAL_MOVE;
313-
return manual_move_generator.propose_move(blocks_affected, move_type, rlim, placer_opts, criticalities);
313+
t_logical_block_type blk_type; //no need to specify block type in manual move "propose_move" function
314+
return manual_move_generator.propose_move(blocks_affected, move_type, blk_type, rlim, placer_opts, criticalities);
314315
}
315316

316317
#endif /*NO_GRAPHICS*/

vpr/src/place/RL_agent_util.cpp

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -23,63 +23,68 @@ void create_move_generators(std::unique_ptr<MoveGenerator>& move_generator, std:
2323
move_generator2 = std::make_unique<StaticMoveGenerator>(placer_opts.place_static_notiming_move_prob);
2424
}
2525
} else { //RL based placement
26-
/* For the non timing driven placecment: the agent has a single state *
27-
* - Available actions are (Uniform / Median / Centroid) *
26+
/* For the non timing driven placement: the agent has a single state *
27+
* - Available moves are (Uniform / Median / Centroid) *
2828
* *
2929
* For the timing driven placement: the agent has two states *
30-
* - 1st state: includes 4 actions (Uniform / Median / Centroid / *
30+
* - 1st state: includes 4 moves (Uniform / Median / Centroid / *
3131
* WeightedCentroid) *
32-
* - 2nd state: includes 7 actions (Uniform / Median / Centroid / *
32+
* If agent should propose block type as well as the mentioned *
33+
* move types, 1st state Q-table size is: *
34+
* 4 move types * number of block types in the netlist *
35+
* if not, the Q-table size is : 4 *
36+
* *
37+
* *
38+
* - 2nd state: includes 7 moves (Uniform / Median / Centroid / *
3339
* WeightedCentroid / WeightedMedian / Feasible *
3440
* Region / CriticalUniform) *
35-
* *
36-
* This state is activated late in the anneale and in the Quench */
41+
* 2nd state agent Q-table size is always 7 and always proposes *
42+
* only move type. *
43+
* This state is activated late in the anneal and in the Quench */
44+
45+
//extract available physical block types in the netlist
46+
determine_agent_block_types();
47+
48+
auto& place_ctx = g_vpr_ctx.placement();
49+
int num_1st_state_avail_moves = placer_opts.place_algorithm.is_timing_driven() ? NUM_PL_1ST_STATE_MOVE_TYPES : NUM_PL_NONTIMING_MOVE_TYPES;
50+
int num_2nd_state_avail_moves = placer_opts.place_algorithm.is_timing_driven() ? NUM_PL_MOVE_TYPES : NUM_PL_NONTIMING_MOVE_TYPES;
3751

3852
if (placer_opts.place_agent_algorithm == E_GREEDY) {
39-
VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move types\n");
4053
std::unique_ptr<EpsilonGreedyAgent> karmed_bandit_agent1, karmed_bandit_agent2;
41-
if (placer_opts.place_algorithm.is_timing_driven()) {
42-
//agent's 1st state
43-
karmed_bandit_agent1 = std::make_unique<EpsilonGreedyAgent>(NUM_PL_1ST_STATE_MOVE_TYPES, placer_opts.place_agent_epsilon);
44-
karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim);
45-
move_generator = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent1);
46-
//agent's 2nd state
47-
karmed_bandit_agent2 = std::make_unique<EpsilonGreedyAgent>(NUM_PL_MOVE_TYPES, placer_opts.place_agent_epsilon);
48-
karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim);
49-
move_generator2 = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent2);
54+
//agent's 1st state
55+
if (placer_opts.place_agent_space == e_agent_space::MOVE_BLOCK_TYPE) {
56+
VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move and block types\n");
57+
karmed_bandit_agent1 = std::make_unique<EpsilonGreedyAgent>(num_1st_state_avail_moves,
58+
place_ctx.agent_blk_type_to_phys_blk_type_map.size(),
59+
placer_opts.place_agent_epsilon);
5060
} else {
51-
//agent's 1st state
52-
karmed_bandit_agent1 = std::make_unique<EpsilonGreedyAgent>(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon);
53-
karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim);
54-
move_generator = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent1);
55-
//agent's 2nd state
56-
karmed_bandit_agent2 = std::make_unique<EpsilonGreedyAgent>(NUM_PL_NONTIMING_MOVE_TYPES, placer_opts.place_agent_epsilon);
57-
karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim);
58-
move_generator2 = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent2);
61+
VTR_LOG("Using simple RL 'Epsilon Greedy agent' for choosing move types\n");
62+
karmed_bandit_agent1 = std::make_unique<EpsilonGreedyAgent>(num_1st_state_avail_moves,
63+
placer_opts.place_agent_epsilon);
5964
}
65+
karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim);
66+
move_generator = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent1);
67+
//agent's 2nd state
68+
karmed_bandit_agent2 = std::make_unique<EpsilonGreedyAgent>(num_2nd_state_avail_moves, placer_opts.place_agent_epsilon);
69+
karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim);
70+
move_generator2 = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent2);
6071
} else {
61-
VTR_LOG("Using simple RL 'Softmax agent' for choosing move types\n");
6272
std::unique_ptr<SoftmaxAgent> karmed_bandit_agent1, karmed_bandit_agent2;
63-
64-
if (placer_opts.place_algorithm.is_timing_driven()) {
65-
//agent's 1st state
66-
karmed_bandit_agent1 = std::make_unique<SoftmaxAgent>(NUM_PL_1ST_STATE_MOVE_TYPES);
67-
karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim);
68-
move_generator = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent1);
69-
//agent's 2nd state
70-
karmed_bandit_agent2 = std::make_unique<SoftmaxAgent>(NUM_PL_MOVE_TYPES);
71-
karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim);
72-
move_generator2 = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent2);
73+
//agent's 1st state
74+
if (placer_opts.place_agent_space == e_agent_space::MOVE_BLOCK_TYPE) {
75+
VTR_LOG("Using simple RL 'Softmax agent' for choosing move and block types\n");
76+
karmed_bandit_agent1 = std::make_unique<SoftmaxAgent>(num_1st_state_avail_moves,
77+
place_ctx.agent_blk_type_to_phys_blk_type_map.size());
7378
} else {
74-
//agent's 1st state
75-
karmed_bandit_agent1 = std::make_unique<SoftmaxAgent>(NUM_PL_NONTIMING_MOVE_TYPES);
76-
karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim);
77-
move_generator = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent1);
78-
//agent's 2nd state
79-
karmed_bandit_agent2 = std::make_unique<SoftmaxAgent>(NUM_PL_NONTIMING_MOVE_TYPES);
80-
karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim);
81-
move_generator2 = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent2);
79+
VTR_LOG("Using simple RL 'Softmax agent' for choosing move types\n");
80+
karmed_bandit_agent1 = std::make_unique<SoftmaxAgent>(num_1st_state_avail_moves);
8281
}
82+
karmed_bandit_agent1->set_step(placer_opts.place_agent_gamma, move_lim);
83+
move_generator = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent1);
84+
//agent's 2nd state
85+
karmed_bandit_agent2 = std::make_unique<SoftmaxAgent>(num_2nd_state_avail_moves);
86+
karmed_bandit_agent2->set_step(placer_opts.place_agent_gamma, move_lim);
87+
move_generator2 = std::make_unique<SimpleRLMoveGenerator>(karmed_bandit_agent2);
8388
}
8489
}
8590
}
@@ -111,3 +116,21 @@ void update_move_generator(std::unique_ptr<MoveGenerator>& move_generator, std::
111116
move_generator2 = std::move(current_move_generator);
112117
}
113118
}
119+
120+
void determine_agent_block_types() {
121+
//Loop through all available logical block types and store the ones that exist in the netlist
122+
auto& device_ctx = g_vpr_ctx.device();
123+
auto& cluster_ctx = g_vpr_ctx.clustering();
124+
auto& place_ctx = g_vpr_ctx.mutable_placement();
125+
int agent_type_index = 0;
126+
for (auto itype : device_ctx.logical_block_types) {
127+
if (itype.index == 0) //ignore empty type
128+
continue;
129+
auto blk_per_type = cluster_ctx.clb_nlist.blocks_per_type(itype);
130+
if (blk_per_type.size() != 0) {
131+
place_ctx.phys_blk_type_to_agent_blk_type_map.insert(std::pair<int, int>(agent_type_index, itype.index));
132+
place_ctx.agent_blk_type_to_phys_blk_type_map.insert(std::pair<int, int>(itype.index, agent_type_index));
133+
agent_type_index++;
134+
}
135+
}
136+
}

vpr/src/place/RL_agent_util.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@ void assign_current_move_generator(std::unique_ptr<MoveGenerator>& move_generato
3030
* @ brief move the updated current_move_generator to its original move_Generator structure based on he placer_options and the agent state
3131
*/
3232
void update_move_generator(std::unique_ptr<MoveGenerator>& move_generator, std::unique_ptr<MoveGenerator>& move_generator2, e_agent_state agent_state, const t_placer_opts& placer_opts, bool in_quench, std::unique_ptr<MoveGenerator>& current_move_generator);
33+
34+
/**
35+
* @ brief determine which block types used by the netlist and create a map between physical block types and agent block types (the ones that are used in the netlist)
36+
*/
37+
void determine_agent_block_types();
38+
3339
#endif

0 commit comments

Comments
 (0)