From 23d9ddc7a54630cebb8d16425bc80c87c1a9f1ae Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 6 Mar 2024 17:32:15 -0500 Subject: [PATCH 01/38] add or-tools as a submodule --- .gitmodules | 3 +++ CMakeLists.txt | 4 ++-- libs/EXTERNAL/CMakeLists.txt | 6 ++++++ libs/EXTERNAL/or-tools | 1 + vpr/CMakeLists.txt | 12 +++++++----- 5 files changed, 19 insertions(+), 7 deletions(-) create mode 160000 libs/EXTERNAL/or-tools diff --git a/.gitmodules b/.gitmodules index 08b907e160b..49f8df696f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "libs/EXTERNAL/libcatch2"] path = libs/EXTERNAL/libcatch2 url = https://github.com/catchorg/Catch2.git +[submodule "libs/EXTERNAL/or-tools"] + path = libs/EXTERNAL/or-tools + url = https://github.com/google/or-tools.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ec1813e020..a7328a74985 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ set(VTR_IPO_BUILD "auto" CACHE STRING "Should VTR be compiled with interprocedur set_property(CACHE VTR_IPO_BUILD PROPERTY STRINGS auto on off) #Allow the user to configure how much assertion checking should occur -set(VTR_ASSERT_LEVEL "2" CACHE STRING "VTR assertion checking level. 0: no assertions, 1: fast assertions, 2: regular assertions, 3: additional assertions with noticable run-time overhead, 4: all assertions (including those with significant run-time cost)") +set(VTR_ASSERT_LEVEL "2" CACHE STRING "VTR assertion checking level. 0: no assertions, 1: fast assertions, 2: regular assertions, 3: additional assertions with noticeable run-time overhead, 4: all assertions (including those with significant run-time cost)") set_property(CACHE VTR_ASSERT_LEVEL PROPERTY STRINGS 0 1 2 3 4) option(VTR_ENABLE_STRICT_COMPILE "Specifies whether compiler warnings should be treated as errors (e.g. -Werror)" OFF) @@ -91,7 +91,7 @@ include(CheckCXXCompilerFlag) # # We require c++17 support # -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) #No compiler specific extensions diff --git a/libs/EXTERNAL/CMakeLists.txt b/libs/EXTERNAL/CMakeLists.txt index 0cb127387ab..0a721ec6049 100644 --- a/libs/EXTERNAL/CMakeLists.txt +++ b/libs/EXTERNAL/CMakeLists.txt @@ -9,6 +9,12 @@ add_subdirectory(libsdcparse) add_subdirectory(libblifparse) add_subdirectory(libtatum) add_subdirectory(libcatch2) + +#SET(BUILD_DEPS ON CACHE BOOL "Build libfoo shared library") +set(BUILD_DEPS ON) +set(BUILD_SAMPLES OFF) +set(BUILD_EXAMPLES OFF) +add_subdirectory(or-tools) #add_subdirectory(parmys) #VPR_USE_EZGL is initialized in the root CMakeLists. diff --git a/libs/EXTERNAL/or-tools b/libs/EXTERNAL/or-tools new file mode 160000 index 00000000000..d37317b17ca --- /dev/null +++ b/libs/EXTERNAL/or-tools @@ -0,0 +1 @@ +Subproject commit d37317b17ca16658451cafe05085fc22c39dd6c8 diff --git a/vpr/CMakeLists.txt b/vpr/CMakeLists.txt index 371d11f39bc..ad0f64e3589 100644 --- a/vpr/CMakeLists.txt +++ b/vpr/CMakeLists.txt @@ -61,7 +61,7 @@ add_library(libvpr STATIC target_include_directories(libvpr PUBLIC ${LIB_INCLUDE_DIRS}) -#VPR_ANALYTIC_PLACE is inisitalized in the root CMakeLists +#VPR_ANALYTIC_PLACE is initialized in the root CMakeLists #Check Eigen dependency if(${VPR_ANALYTIC_PLACE}) message(STATUS "VPR Analytic Placement: Requested") @@ -79,7 +79,7 @@ endif() set_target_properties(libvpr PROPERTIES PREFIX "") #Avoid extra 'lib' prefix -#Specify link-time dependancies +#Specify link-time dependencies target_link_libraries(libvpr libvtrutil libarchfpga @@ -91,6 +91,8 @@ target_link_libraries(libvpr librrgraph ) +target_link_libraries(libvpr ortools::ortools) + #link graphics library only when graphics set to on if (VPR_USE_EZGL STREQUAL "on") target_link_libraries(libvpr @@ -138,7 +140,7 @@ add_executable(vpr ${EXEC_SOURCES}) target_link_libraries(vpr libvpr) -#Supress IPO link warnings if IPO is enabled +#Suppress IPO link warnings if IPO is enabled get_target_property(VPR_USES_IPO vpr INTERPROCEDURAL_OPTIMIZATION) if (VPR_USES_IPO) set_property(TARGET vpr APPEND PROPERTY LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS}) @@ -249,7 +251,7 @@ endif() # Signal handler configuration # if (VPR_USE_SIGNAL_HANDLER) - #Check wheter VPR can use sigaction to handle signals (only supported by POSIX) + #Check whether VPR can use sigaction to handle signals (only supported by POSIX) CHECK_CXX_SYMBOL_EXISTS(sigaction csignal HAVE_SIGACTION) if(HAVE_SIGACTION) target_compile_definitions(libvpr PRIVATE VPR_USE_SIGACTION) @@ -269,7 +271,7 @@ target_link_libraries(test_vpr Catch2::Catch2WithMain libvpr) -#Supress IPO link warnings if IPO is enabled +#Suppress IPO link warnings if IPO is enabled get_target_property(TEST_VPR_USES_IPO vpr INTERPROCEDURAL_OPTIMIZATION) if (TEST_VPR_USES_IPO) set_property(TARGET test_vpr APPEND PROPERTY LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS}) From 52f9d23aecd17bdb5ad655ecfdea5776499f5cc7 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 7 Mar 2024 13:27:54 -0500 Subject: [PATCH 02/38] add is_turn_legal() and get_all_illegal_turns() --- vpr/src/noc/negative_first_routing.cpp | 31 +++++++++++- vpr/src/noc/negative_first_routing.h | 2 + vpr/src/noc/north_last_routing.cpp | 27 +++++++++- vpr/src/noc/north_last_routing.h | 2 + vpr/src/noc/odd_even_routing.cpp | 69 ++++++++++++++++++++++++-- vpr/src/noc/odd_even_routing.h | 2 + vpr/src/noc/turn_model_routing.cpp | 30 +++++++++++ vpr/src/noc/turn_model_routing.h | 5 ++ vpr/src/noc/west_first_routing.cpp | 27 +++++++++- vpr/src/noc/west_first_routing.h | 2 + vpr/src/noc/xy_routing.cpp | 26 ++++++++++ vpr/src/noc/xy_routing.h | 1 + 12 files changed, 218 insertions(+), 6 deletions(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index 23cff958638..00ea2ac7ea5 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -107,4 +107,33 @@ TurnModelRouting::Direction NegativeFirstRouting::select_next_direction(const st } return selected_direction; -} \ No newline at end of file +} + +bool NegativeFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { + const int x1 = noc_routers[0].get().get_router_grid_position_x(); + const int y1 = noc_routers[0].get().get_router_grid_position_y(); + + const int x2 = noc_routers[1].get().get_router_grid_position_x(); + const int y2 = noc_routers[1].get().get_router_grid_position_y(); + + const int x3 = noc_routers[2].get().get_router_grid_position_x(); + const int y3 = noc_routers[2].get().get_router_grid_position_y(); + + VTR_ASSERT(x2 == x1 || y2 == y1); + VTR_ASSERT(x3 == x2 || y3 == y2); + + // going back to the first router is not allowed + if (x1 == x3 && y1 == y3) { + return false; + } + + if (x2 > x1 && y3 < y2) { + return false; + } + + if (y2 > y1 && x3 < x2) { + return false; + } + + return true; +} diff --git a/vpr/src/noc/negative_first_routing.h b/vpr/src/noc/negative_first_routing.h index f4a7cb6e9a7..3a465e3cc28 100644 --- a/vpr/src/noc/negative_first_routing.h +++ b/vpr/src/noc/negative_first_routing.h @@ -65,6 +65,8 @@ class NegativeFirstRouting : public TurnModelRouting { NocRouterId curr_router_id, NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model) override; + + bool is_turn_legal(const std::array, 3>& noc_routers) const override; }; #endif //VTR_NEGATIVE_FIRST_ROUTING_H diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index ebf4e655896..bf9655962e1 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -96,4 +96,29 @@ TurnModelRouting::Direction NorthLastRouting::select_next_direction(const std::v } return selected_direction; -} \ No newline at end of file +} + +bool NorthLastRouting::is_turn_legal(const std::array, 3>& noc_routers) const { + const int x1 = noc_routers[0].get().get_router_grid_position_x(); + const int y1 = noc_routers[0].get().get_router_grid_position_y(); + + const int x2 = noc_routers[1].get().get_router_grid_position_x(); + const int y2 = noc_routers[1].get().get_router_grid_position_y(); + + const int x3 = noc_routers[2].get().get_router_grid_position_x(); + const int y3 = noc_routers[2].get().get_router_grid_position_y(); + + VTR_ASSERT(x2 == x1 || y2 == y1); + VTR_ASSERT(x3 == x2 || y3 == y2); + + // going back to the first router is not allowed + if (x1 == x3 && y1 == y3) { + return false; + } + + if (y2 > y1 && x2 != x3) { + return false; + } + + return true; +} diff --git a/vpr/src/noc/north_last_routing.h b/vpr/src/noc/north_last_routing.h index e9e877e68b4..61aaf8caa4b 100644 --- a/vpr/src/noc/north_last_routing.h +++ b/vpr/src/noc/north_last_routing.h @@ -66,6 +66,8 @@ class NorthLastRouting : public TurnModelRouting { NocRouterId curr_router_id, NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model) override; + + bool is_turn_legal(const std::array, 3>& noc_routers) const override; }; #endif //VTR_NORTH_LAST_ROUTING_H diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 82a9b4950d6..4902c794262 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -35,9 +35,9 @@ const std::vector& OddEvenRouting::get_legal_direct const auto dst_router_pos = dst_router.get_router_physical_location(); // get the compressed location for source, current, and destination NoC routers - auto compressed_src_loc = get_compressed_loc_approx(compressed_noc_grid,t_pl_loc{src_router_pos, 0}, num_layers)[src_router_pos.layer_num]; - auto compressed_curr_loc = get_compressed_loc_approx(compressed_noc_grid,t_pl_loc{curr_router_pos, 0}, num_layers)[curr_router_pos.layer_num]; - auto compressed_dst_loc = get_compressed_loc_approx(compressed_noc_grid,t_pl_loc{dst_router_pos, 0}, num_layers)[dst_router_pos.layer_num]; + auto compressed_src_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{src_router_pos, 0}, num_layers)[src_router_pos.layer_num]; + auto compressed_curr_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{curr_router_pos, 0}, num_layers)[curr_router_pos.layer_num]; + auto compressed_dst_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{dst_router_pos, 0}, num_layers)[dst_router_pos.layer_num]; // clear returned legal directions from the previous call returned_legal_direction.clear(); @@ -145,3 +145,66 @@ bool OddEvenRouting::is_odd(int number) { bool OddEvenRouting::is_even(int number) { return (number % 2) == 0; } + +bool OddEvenRouting::is_turn_legal(const std::array, 3>& noc_routers) const { + // used to access NoC compressed grid + const auto& place_ctx = g_vpr_ctx.placement(); + // used to get NoC logical block type + const auto& cluster_ctx = g_vpr_ctx.clustering(); + // used to get the clustered block ID of a NoC router + auto& noc_ctx = g_vpr_ctx.noc(); + // get number of layers + const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); + + const int x1 = noc_routers[0].get().get_router_grid_position_x(); + const int y1 = noc_routers[0].get().get_router_grid_position_y(); + + const int x2 = noc_routers[1].get().get_router_grid_position_x(); + const int y2 = noc_routers[1].get().get_router_grid_position_y(); + + const int x3 = noc_routers[2].get().get_router_grid_position_x(); + const int y3 = noc_routers[2].get().get_router_grid_position_y(); + + VTR_ASSERT(x2 == x1 || y2 == y1); + VTR_ASSERT(x3 == x2 || y3 == y2); + + // get the position of the second NoC routers + const auto router2_pos = noc_routers[1].get().get_router_physical_location(); + + + // Get the logical block type for router + const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); + + // Get the compressed grid for NoC + const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; + + // get the compressed location of the second NoC router + auto compressed_2_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{router2_pos, 0}, num_layers)[router2_pos.layer_num]; + + // going back to the first router is not allowed + if (x1 == x3 && y1 == y3) { + return false; + } + + if (is_odd(compressed_2_loc.x)) { + if (y2 != y1 && x3 < x2) { + return false; + } + } else { // even column + if (x2 > x1 && y2 != y3) { + return false; + } + } + + return true; +} + + + + + + + + + + diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index 102940446ef..0471ff5dec3 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -20,6 +20,8 @@ class OddEvenRouting : public TurnModelRouting{ NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model) override; + bool is_turn_legal(const std::array, 3>& noc_routers) const override; + static inline bool is_odd(int number); static inline bool is_even(int number); }; diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index 35c9789a135..e88d6d11978 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -233,3 +233,33 @@ TurnModelRouting::Direction TurnModelRouting::select_direction_other_than(const // if there was not any direction different from "other_than", return INVALID return TurnModelRouting::Direction::INVALID; } + +std::vector> TurnModelRouting::get_all_illegal_turns(const NocStorage& noc_model) const { + std::vector> illegal_turns; + + for (const auto& noc_router : noc_model.get_noc_routers()) { + const int noc_router_user_id = noc_router.get_router_user_id(); + const NocRouterId noc_router_id = noc_model.convert_router_id(noc_router_user_id); + VTR_ASSERT(noc_router_id != NocRouterId::INVALID()); + const auto& first_noc_link_ids = noc_model.get_noc_router_outgoing_links(noc_router_id); + + for (auto first_noc_link_id : first_noc_link_ids) { + const NocLink& first_noc_link = noc_model.get_single_noc_link(first_noc_link_id); + const NocRouterId second_noc_router_id = first_noc_link.get_sink_router(); + const NocRouter& second_noc_router = noc_model.get_single_noc_router(second_noc_router_id); + const auto& second_noc_link_ids = noc_model.get_noc_router_outgoing_links(second_noc_router_id); + + for (auto second_noc_link_id : second_noc_link_ids) { + const NocLink& second_noc_link = noc_model.get_single_noc_link(second_noc_link_id); + const NocRouterId third_noc_router_id = second_noc_link.get_sink_router(); + const NocRouter& third_noc_router = noc_model.get_single_noc_router(third_noc_router_id); + if (!is_turn_legal({noc_router, second_noc_router, third_noc_router})) { + illegal_turns.emplace_back(first_noc_link_id, second_noc_link_id); + } + } + } + } + + return illegal_turns; +} + diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 2e8819a8c8f..cc832e33ad6 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -35,6 +35,7 @@ */ #include "noc_routing.h" +#include class TurnModelRouting : public NocRouting { public: @@ -73,6 +74,8 @@ class TurnModelRouting : public NocRouting { std::vector& flow_route, const NocStorage& noc_model) override; + std::vector> get_all_illegal_turns(const NocStorage& noc_model) const; + protected: /** * @brief This enum describes the all the possible @@ -213,6 +216,8 @@ class TurnModelRouting : public NocRouting { const NocStorage& noc_model) = 0; + virtual bool is_turn_legal(const std::array, 3>& noc_routers) const = 0; + protected: // get_legal_directions() return a reference to this vector to avoid allocating a new vector // each time it is called diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index e3308b5b176..4fb9ec19e82 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -93,4 +93,29 @@ TurnModelRouting::Direction WestFirstRouting::select_next_direction(const std::v } return selected_direction; -} \ No newline at end of file +} + +bool WestFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { + const int x1 = noc_routers[0].get().get_router_grid_position_x(); + const int y1 = noc_routers[0].get().get_router_grid_position_y(); + + const int x2 = noc_routers[1].get().get_router_grid_position_x(); + const int y2 = noc_routers[1].get().get_router_grid_position_y(); + + const int x3 = noc_routers[2].get().get_router_grid_position_x(); + const int y3 = noc_routers[2].get().get_router_grid_position_y(); + + VTR_ASSERT(x2 == x1 || y2 == y1); + VTR_ASSERT(x3 == x2 || y3 == y2); + + // going back to the first router is not allowed + if (x1 == x3 && y1 == y3) { + return false; + } + + if (y2 != y1 && x3 < x2) { + return false; + } + + return true; +} diff --git a/vpr/src/noc/west_first_routing.h b/vpr/src/noc/west_first_routing.h index a88e90ea7ac..17b3fa9cc74 100644 --- a/vpr/src/noc/west_first_routing.h +++ b/vpr/src/noc/west_first_routing.h @@ -65,6 +65,8 @@ class WestFirstRouting : public TurnModelRouting { NocRouterId curr_router_id, NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model) override; + + bool is_turn_legal(const std::array, 3>& noc_routers) const override; }; #endif //VTR_WEST_FIRST_ROUTING_H diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index 31edef2b5b4..e6f3dfe47de 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -80,4 +80,30 @@ TurnModelRouting::Direction XYRouting::select_next_direction(const std::vector, 3>& noc_routers) const { + const int x1 = noc_routers[0].get().get_router_grid_position_x(); + const int y1 = noc_routers[0].get().get_router_grid_position_y(); + + const int x2 = noc_routers[1].get().get_router_grid_position_x(); + const int y2 = noc_routers[1].get().get_router_grid_position_y(); + + const int x3 = noc_routers[2].get().get_router_grid_position_x(); + const int y3 = noc_routers[2].get().get_router_grid_position_y(); + + VTR_ASSERT(x2 == x1 || y2 == y1); + VTR_ASSERT(x3 == x2 || y3 == y2); + + // going back to the first router is not allowed + if (x1 == x3 && y1 == y3) { + return false; + } + + // if the first move is vertical, the second one can't be horizontal + if (y1 != y2 && x2 != x3) { + return false; + } + + return true; } \ No newline at end of file diff --git a/vpr/src/noc/xy_routing.h b/vpr/src/noc/xy_routing.h index 43da6be4881..199855710fe 100644 --- a/vpr/src/noc/xy_routing.h +++ b/vpr/src/noc/xy_routing.h @@ -105,6 +105,7 @@ class XYRouting : public TurnModelRouting { NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model) override; + bool is_turn_legal(const std::array, 3>& noc_routers) const override; private: const std::vector x_axis_directions {TurnModelRouting::Direction::LEFT, TurnModelRouting::Direction::RIGHT}; From f35f13708974c6850502e6f9a8c21173cc05bc6a Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 7 Mar 2024 18:53:55 -0500 Subject: [PATCH 03/38] add get_noc_router_incoming_links() method to NocStorage --- vpr/src/noc/bfs_routing.cpp | 2 +- vpr/src/noc/noc_storage.cpp | 81 ++++++++++++++++++------------ vpr/src/noc/noc_storage.h | 12 +++-- vpr/src/noc/odd_even_routing.cpp | 2 +- vpr/src/noc/turn_model_routing.cpp | 2 +- vpr/test/test_noc_storage.cpp | 4 +- vpr/test/test_setup_noc.cpp | 2 +- 7 files changed, 63 insertions(+), 42 deletions(-) diff --git a/vpr/src/noc/bfs_routing.cpp b/vpr/src/noc/bfs_routing.cpp index f25f755c1f5..2fdc2650a7d 100644 --- a/vpr/src/noc/bfs_routing.cpp +++ b/vpr/src/noc/bfs_routing.cpp @@ -58,7 +58,7 @@ void BFSRouting::route_flow(NocRouterId src_router_id, routers_to_process.pop(); // get the links leaving the router currently being processed(these represent possible paths to explore in the NoC) - const std::vector& outgoing_links = noc_model.get_noc_router_connections(processing_router); + const std::vector& outgoing_links = noc_model.get_noc_router_outgoing_links(processing_router); // go through the outgoing links of the current router and process the sink routers connected to these links for (auto link : outgoing_links) { diff --git a/vpr/src/noc/noc_storage.cpp b/vpr/src/noc/noc_storage.cpp index 8438838c1f9..41e296f4e5d 100644 --- a/vpr/src/noc/noc_storage.cpp +++ b/vpr/src/noc/noc_storage.cpp @@ -1,14 +1,19 @@ #include "noc_storage.h" +#include + NocStorage::NocStorage() { clear_noc(); } // getters for the NoC +const std::vector& NocStorage::get_noc_router_outgoing_links(NocRouterId id) const { + return router_outgoing_links_list[id]; +} -const std::vector& NocStorage::get_noc_router_connections(NocRouterId id) const { - return router_link_list[id]; +const std::vector& NocStorage::get_noc_router_incoming_links(NocRouterId id) const { + return router_incoming_links_list[id]; } const vtr::vector& NocStorage::get_noc_routers(void) const { @@ -121,9 +126,8 @@ void NocStorage::add_link(NocRouterId source, NocRouterId sink) { double link_bandwidth = get_noc_link_bandwidth(); link_storage.emplace_back(added_link_id, source, sink, link_bandwidth); - router_link_list[source].push_back(added_link_id); - - return; + router_outgoing_links_list[source].push_back(added_link_id); + router_incoming_links_list[sink].push_back(added_link_id); } void NocStorage::set_noc_link_bandwidth(double link_bandwidth) { @@ -164,39 +168,50 @@ bool NocStorage::remove_link(NocRouterId src_router_id, NocRouterId sink_router_ // check if the src router for the link to remove exists (within the id ranges). Otherwise, there is no point looking for the link if ((size_t)src_router_id < router_storage.size()) { - // get all the outgoing links of the provided sourcer router - std::vector* source_router_outgoing_links = &router_link_list[src_router_id]; + // get all the outgoing links of the provided source router + std::vector& source_router_outgoing_links = router_outgoing_links_list[src_router_id]; + std::vector& sink_router_incoming_links = router_incoming_links_list[sink_router_id]; + + const NocLinkId link_to_be_removed_id = get_single_noc_link_id(src_router_id, sink_router_id); + link_removed_status = (link_to_be_removed_id != NocLinkId::INVALID()); + + auto it = std::remove(source_router_outgoing_links.begin(), + source_router_outgoing_links.end(), + link_to_be_removed_id); + + if (it == source_router_outgoing_links.end()) { + VTR_LOG_WARN("No link could be found among outgoing links of source router with id(%d) " + "that that connects to the sink router with id (%d).\n", + (size_t)src_router_id, + (size_t)sink_router_id); + } - // keeps track of the position of each outgoing link for the provided src router. When the id of the link to remove is found, this index can be used to remove it from the outgoing link vector. - int outgoing_link_index = 0; + source_router_outgoing_links.erase(it, source_router_outgoing_links.end()); - // go through each outgoing link of the source router and see if there is a link that also has the corresponding sink router. - // Save this link index and remove it - for (auto outgoing_link_id = source_router_outgoing_links->begin(); outgoing_link_id != source_router_outgoing_links->end(); outgoing_link_id++) { - // check to see if the current link id matches the id of the link to remove - if (link_storage[*outgoing_link_id].get_sink_router() == sink_router_id) { - // found the link we need to remove, so we delete it here - //change the link to be invalid - link_storage[*outgoing_link_id].set_source_router(NocRouterId::INVALID()); - link_storage[*outgoing_link_id].set_sink_router(NocRouterId::INVALID()); - link_storage[*outgoing_link_id].set_bandwidth_usage(-1); + it = std::remove(sink_router_incoming_links.begin(), + sink_router_incoming_links.end(), + link_to_be_removed_id); - // removing this link as an outgoing link from the source router - source_router_outgoing_links->erase(source_router_outgoing_links->begin() + outgoing_link_index); + if (it == sink_router_incoming_links.end()) { + VTR_LOG_WARN("No link could be found among incoming links of sink router with id(%d) " + "that that connects to the source router with id (%d).\n", + (size_t)sink_router_id, + (size_t)src_router_id); + } - // indicate that the link to remove has been found and deleted - link_removed_status = true; + sink_router_incoming_links.erase(it, sink_router_incoming_links.end()); - break; - } + link_storage[link_to_be_removed_id].set_source_router(NocRouterId::INVALID()); + link_storage[link_to_be_removed_id].set_sink_router(NocRouterId::INVALID()); + link_storage[link_to_be_removed_id].set_bandwidth_usage(-1); - outgoing_link_index++; - } } // if a link was not removed then throw warning message if (!link_removed_status) { - VTR_LOG_WARN("No link could be found that has a source router with id: '%d' and sink router with id:'%d'.\n", (size_t)src_router_id, (size_t)sink_router_id); + VTR_LOG_WARN("No link could be found that has a source router with id: '%d' and sink router with id:'%d'.\n", + (size_t)src_router_id, + (size_t)sink_router_id); } return link_removed_status; @@ -212,7 +227,8 @@ void NocStorage::finished_building_noc(void) { void NocStorage::clear_noc(void) { router_storage.clear(); link_storage.clear(); - router_link_list.clear(); + router_outgoing_links_list.clear(); + router_incoming_links_list.clear(); grid_location_to_router_id.clear(); built_noc = false; @@ -232,7 +248,8 @@ NocRouterId NocStorage::convert_router_id(int id) const { void NocStorage::make_room_for_noc_router_link_list(void) { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); - router_link_list.resize(router_storage.size()); + router_outgoing_links_list.resize(router_storage.size()); + router_incoming_links_list.resize(router_storage.size()); } NocLinkId NocStorage::get_parallel_link(NocLinkId current_link) const { @@ -241,7 +258,7 @@ NocLinkId NocStorage::get_parallel_link(NocLinkId current_link) const { NocRouterId curr_sink_router = link_storage[current_link].get_sink_router(); // get the link list of the sink router - const std::vector* sink_router_links = &(router_link_list[curr_sink_router]); + const std::vector* sink_router_links = &(router_outgoing_links_list[curr_sink_router]); NocLinkId parallel_link = INVALID_LINK_ID; @@ -293,7 +310,7 @@ void NocStorage::echo_noc(char* file_name) const { fprintf(fp, "Equivalent Physical Tile Grid Position -> (%d,%d)\n", router.get_router_grid_position_x(), router.get_router_grid_position_y()); fprintf(fp, "Router Connections ->"); - auto& router_connections = this->get_noc_router_connections(this->convert_router_id(router.get_router_user_id())); + auto& router_connections = this->get_noc_router_outgoing_links(this->convert_router_id(router.get_router_user_id())); // go through the outgoing links of the current router and print the connecting router for (auto router_connection : router_connections) { diff --git a/vpr/src/noc/noc_storage.h b/vpr/src/noc/noc_storage.h index 637d9f52126..0080c596836 100644 --- a/vpr/src/noc/noc_storage.h +++ b/vpr/src/noc/noc_storage.h @@ -63,7 +63,9 @@ class NocStorage { * in the NoC. * */ - vtr::vector> router_link_list; + vtr::vector> router_outgoing_links_list; + + vtr::vector> router_incoming_links_list; /** Contains all the links in the NoC*/ vtr::vector link_storage; @@ -167,7 +169,9 @@ class NocStorage { * @return A vector of links. The links are represented by a unique * identifier. */ - const std::vector& get_noc_router_connections(NocRouterId id) const; + const std::vector& get_noc_router_outgoing_links(NocRouterId id) const; + + const std::vector& get_noc_router_incoming_links(NocRouterId id) const; /** * @brief Get all the routers in the NoC. The routers themselves cannot @@ -282,7 +286,7 @@ class NocStorage { * to the destination router. NocLinkId::INVALID() is such a link is not * found. */ - NocLinkId get_single_noc_link_id(NocRouterId src_router, NocRouterId dst_router) const; + NocLinkId get_single_noc_link_id(NocRouterId src_router, NocRouterId dst_router) const; /** * @brief Given a unique link identifier, get the corresponding link @@ -372,7 +376,7 @@ class NocStorage { void set_device_grid_spec(int grid_width, int grid_height); - // general utiliy functions + // general utility functions /** * @brief The link is removed from the outgoing vector of links for * the source router. The link is not removed from the vector of all diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 4902c794262..7e4e2a2355b 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -179,7 +179,7 @@ bool OddEvenRouting::is_turn_legal(const std::arrayindex]; // get the compressed location of the second NoC router - auto compressed_2_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{router2_pos, 0}, num_layers)[router2_pos.layer_num]; + auto compressed_2_loc = get_compressed_loc(compressed_noc_grid, t_pl_loc{router2_pos, 0}, num_layers)[router2_pos.layer_num]; // going back to the first router is not allowed if (x1 == x3 && y1 == y3) { diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index e88d6d11978..49bfbd93896 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -98,7 +98,7 @@ NocLinkId TurnModelRouting::move_to_next_router(NocRouterId& curr_router_id, bool visited_next_router = false; // get all the outgoing links for the current router - const auto& router_connections = noc_model.get_noc_router_connections(curr_router_id); + const auto& router_connections = noc_model.get_noc_router_outgoing_links(curr_router_id); // go through each outgoing link and determine whether the link leads towards the intended route direction for (auto connecting_link : router_connections) { diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp index 834d81b88a6..2dea1dac843 100644 --- a/vpr/test/test_noc_storage.cpp +++ b/vpr/test/test_noc_storage.cpp @@ -266,7 +266,7 @@ TEST_CASE("test_router_link_list", "[vpr_noc]") { source = (NocRouterId)id; // get the router connections from the - const std::vector& router_links = test_noc.get_noc_router_connections(source); + const std::vector& router_links = test_noc.get_noc_router_outgoing_links(source); // get the size of the current router connection list connection_size = golden_set[source].size(); @@ -351,7 +351,7 @@ TEST_CASE("test_remove_link", "[vpr_noc]") { // variable to keep track of whether the link was deleted from the vector outgoing links of its source router bool link_removed_from_outgoing_vector = true; - auto& outgoing_links = test_noc.get_noc_router_connections(link_to_remove_src_router); + auto& outgoing_links = test_noc.get_noc_router_outgoing_links(link_to_remove_src_router); // go through all the outgoing links of the source router in the link we removed and check that the link does not exist there as well. for (auto outgoing_link : outgoing_links) { // get the current outgoing link diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index b88949b11f3..575e058a849 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -689,7 +689,7 @@ TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { router_connection = noc_info.router_list[router_id - 1].connection_list.begin(); - for (auto noc_link = noc_model.get_noc_router_connections(current_source_router_id).begin(); noc_link != noc_model.get_noc_router_connections(current_source_router_id).end(); noc_link++) { + for (auto noc_link = noc_model.get_noc_router_outgoing_links(current_source_router_id).begin(); noc_link != noc_model.get_noc_router_connections(current_source_router_id).end(); noc_link++) { // get the connecting link const NocLink& connecting_link = noc_model.get_single_noc_link(*noc_link); From 168642e1beae43f983ec88c0f6b6338a4f2308ec Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 8 Mar 2024 19:14:09 -0500 Subject: [PATCH 04/38] congestion-free NoC routes pass SAT constraints This means that constraints are probably set correctly. --- CMakeLists.txt | 2 +- vpr/src/noc/sat_routing.cpp | 353 ++++++++++++++++++++++++ vpr/src/noc/sat_routing.h | 24 ++ vpr/src/place/initial_noc_placement.cpp | 5 + 4 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 vpr/src/noc/sat_routing.cpp create mode 100644 vpr/src/noc/sat_routing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a7328a74985..c818811d8ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ include(CheckCXXCompilerFlag) # # We require c++17 support # -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) #No compiler specific extensions diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp new file mode 100644 index 00000000000..6848185cc0c --- /dev/null +++ b/vpr/src/noc/sat_routing.cpp @@ -0,0 +1,353 @@ + +#include "sat_routing.h" +#include "turn_model_routing.h" +#include "move_utils.h" + +#include "globals.h" + +#include + + +#include "ortools/base/logging.h" +#include "ortools/sat/cp_model.h" +#include "ortools/sat/cp_model.pb.h" +#include "ortools/sat/cp_model_solver.h" + +std::vector get_flow_link_vars(const std::unordered_map, operations_research::sat::BoolVar>& map, + const std::vector& traffic_flow_ids, + const std::vector& noc_link_ids) { + std::vector results; + for (auto traffic_flow_id : traffic_flow_ids) { + for (auto noc_link_id : noc_link_ids) { + auto it = map.find({traffic_flow_id, noc_link_id}); + if (it != map.end()) { + results.push_back(it->second); + } + } + } + return results; +} + +static void forbid_illegal_turns(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, + operations_research::sat::CpModelBuilder& cp_model) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + auto noc_routing_alg = dynamic_cast (noc_ctx.noc_flows_router.get()); + VTR_ASSERT(noc_routing_alg != nullptr); + + // forbid illegal turns based on the routing algorithm + // this includes 180 degree turns + for (const auto& [link1, link2] : noc_routing_alg->get_all_illegal_turns(noc_ctx.noc_model)) { + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + auto& first_var = flow_link_vars[{traffic_flow_id, link1}]; + auto& second_var = flow_link_vars[{traffic_flow_id, link2}]; + cp_model.AddBoolOr({first_var.Not(), second_var.Not()}); + } + } +} + +static void add_congestion_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, + operations_research::sat::CpModelBuilder& cp_model) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + const double link_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth(); + constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 1024; + + vtr::vector rescaled_traffic_flow_bandwidths; + rescaled_traffic_flow_bandwidths.resize(traffic_flow_storage.get_number_of_traffic_flows()); + + // rescale traffic flow bandwidths + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + double bandwidth = traffic_flow.traffic_flow_bandwidth; + int rescaled_bandwidth = (int)std::floor((bandwidth / link_bandwidth) * NOC_LINK_BANDWIDTH_RESOLUTION); + rescaled_traffic_flow_bandwidths[traffic_flow_id] = rescaled_bandwidth; + std::cout << "Rescaled " << rescaled_bandwidth << std::endl; + } + + // add NoC link congestion constraints + for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { + const NocLinkId noc_link_id = noc_link.get_link_id(); + operations_research::sat::LinearExpr lhs; + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + operations_research::sat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; + lhs += operations_research::sat::LinearExpr(binary_var * rescaled_traffic_flow_bandwidths[traffic_flow_id]); + } + + cp_model.AddLessOrEqual(lhs, NOC_LINK_BANDWIDTH_RESOLUTION); + } +} + +static void add_continuity_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, + operations_research::sat::CpModelBuilder& cp_model) +{ + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + const auto& place_ctx = g_vpr_ctx.placement(); + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + // get the source and destination logical router blocks in the current traffic flow + ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; + ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; + + // get the ids of the hard router blocks where the logical router cluster blocks have been placed + NocRouterId source_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_source_router_block_id].loc); + NocRouterId sink_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_sink_router_block_id].loc); + + std::vector vars; + + // exactly one outgoing link of the source must be selected + const auto& src_outgoing_link_ids = noc_ctx.noc_model.get_noc_router_outgoing_links(source_router_id); + vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, src_outgoing_link_ids); + cp_model.AddExactlyOne(vars); + + // exactly one incoming link of the sink must be selected + const auto& dst_incoming_link_ids = noc_ctx.noc_model.get_noc_router_incoming_links(sink_router_id); + vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, dst_incoming_link_ids); + cp_model.AddExactlyOne(vars); + + // each NoC router has at most one incoming and one outgoing link activated + for (const auto& noc_router : noc_ctx.noc_model.get_noc_routers()) { + const int noc_router_user_id = noc_router.get_router_user_id(); + const NocRouterId noc_router_id = noc_ctx.noc_model.convert_router_id(noc_router_user_id); + + if (noc_router_id == source_router_id || noc_router_id == sink_router_id) { + continue; + } + + const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); + vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); + cp_model.AddAtMostOne(vars); + + operations_research::sat::LinearExpr lhs; + lhs = operations_research::sat::LinearExpr::Sum(vars); + + const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); + vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); + cp_model.AddAtMostOne(vars); + + operations_research::sat::LinearExpr rhs; + rhs = operations_research::sat::LinearExpr::Sum(vars); + + cp_model.AddEquality(lhs, rhs); + } + } +} + +static void add_distance_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, + operations_research::sat::CpModelBuilder& cp_model, + const std::vector& up, + const std::vector& down, + const std::vector& right, + const std::vector& left) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + const auto& place_ctx = g_vpr_ctx.placement(); + const auto& cluster_ctx = g_vpr_ctx.clustering(); + + const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); + + // Get the logical block type for router + const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); + + // Get the compressed grid for NoC + const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + // get the source and destination logical router blocks in the current traffic flow + ClusterBlockId logical_src_router_block_id = traffic_flow.source_router_cluster_id; + ClusterBlockId logical_dst_router_block_id = traffic_flow.sink_router_cluster_id; + + // get the ids of the hard router blocks where the logical router cluster blocks have been placed + NocRouterId src_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_src_router_block_id].loc); + NocRouterId dst_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_dst_router_block_id].loc); + + // get source, current, and destination NoC routers + const auto& src_router = noc_ctx.noc_model.get_single_noc_router(src_router_id); + const auto& dst_router = noc_ctx.noc_model.get_single_noc_router(dst_router_id); + + // get the position of source, current, and destination NoC routers + const auto src_router_pos = src_router.get_router_physical_location(); + const auto dst_router_pos = dst_router.get_router_physical_location(); + + // get the compressed location for source, current, and destination NoC routers + auto compressed_src_loc = get_compressed_loc(compressed_noc_grid, t_pl_loc{src_router_pos, 0}, num_layers)[src_router_pos.layer_num]; + auto compressed_dst_loc = get_compressed_loc(compressed_noc_grid, t_pl_loc{dst_router_pos, 0}, num_layers)[dst_router_pos.layer_num]; + + // calculate the distance between the current router and the destination + const int delta_x = compressed_dst_loc.x - compressed_src_loc.x; + const int delta_y = compressed_dst_loc.y - compressed_src_loc.y; + + auto right_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, right); + auto left_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, left); + auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); + auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); + + operations_research::sat::LinearExpr horizontal_expr; + horizontal_expr += operations_research::sat::LinearExpr::Sum(right_vars) - operations_research::sat::LinearExpr::Sum(left_vars); + cp_model.AddEquality(horizontal_expr, delta_x); + + operations_research::sat::LinearExpr vertical_expr; + vertical_expr += operations_research::sat::LinearExpr::Sum(up_vars) - operations_research::sat::LinearExpr::Sum(down_vars); + cp_model.AddEquality(vertical_expr, delta_y); + } +} + +static void group_noc_links_based_on_direction(std::vector& up, + std::vector& down, + std::vector& right, + std::vector& left) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; + + for (const auto& noc_link : noc_model.get_noc_links()) { + const NocLinkId noc_link_id = noc_link.get_link_id(); + const NocRouterId src_noc_router_id = noc_link.get_source_router(); + const NocRouterId dst_noc_router_id = noc_link.get_sink_router(); + const NocRouter& src_noc_router = noc_model.get_single_noc_router(src_noc_router_id); + const NocRouter& dst_noc_router = noc_model.get_single_noc_router(dst_noc_router_id); + auto src_loc = src_noc_router.get_router_physical_location(); + auto dst_loc = dst_noc_router.get_router_physical_location(); + + VTR_ASSERT(src_loc.x == dst_loc.x || src_loc.y == dst_loc.y); + + if (src_loc.x == dst_loc.x) { // vertical link + if (dst_loc.y > src_loc.y) { + up.push_back(noc_link_id); + } else { + down.push_back(noc_link_id); + } + } else { // horizontal link + if (dst_loc.x > src_loc.x) { + right.push_back(noc_link_id); + } else { + left.push_back(noc_link_id); + } + } + } +} + +static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + const double noc_link_latency = noc_model.get_noc_link_latency(); + const double noc_router_latency = noc_model.get_noc_router_latency(); + const double traffic_flow_latency_constraint = traffic_flow.max_traffic_flow_latency; + + VTR_ASSERT(traffic_flow_latency_constraint < 0.1); + + int n_max_links = std::floor((traffic_flow_latency_constraint - noc_router_latency) / (noc_link_latency + noc_router_latency)); + + return n_max_links; + +} + +vtr::vector> noc_sat_route() { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + operations_research::sat::CpModelBuilder cp_model; + + std::unordered_map, operations_research::sat::BoolVar> flow_link_vars; + std::map latency_overrun_vars; + operations_research::Domain latency_overrun_domain(0, 20); + + // create boolean variables for each traffic flow and link pair + // create integer variables for traffic flows with constrained latency + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + if (traffic_flow.max_traffic_flow_latency < 0.1) { + latency_overrun_vars[traffic_flow_id] = cp_model.NewIntVar(latency_overrun_domain); + } + + for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { + const NocLinkId noc_link_id = noc_link.get_link_id(); + flow_link_vars[{traffic_flow_id, noc_link_id}] = cp_model.NewBoolVar(); + } + } + + for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { + int n_max_links = comp_max_number_of_traversed_links(traffic_flow_id); + auto link_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, + {noc_ctx.noc_model.get_noc_links().keys().begin(), noc_ctx.noc_model.get_noc_links().keys().end()}); + + operations_research::sat::LinearExpr latency_overrun_expr; + latency_overrun_expr += operations_research::sat::LinearExpr::Sum(link_vars); + latency_overrun_expr -= n_max_links; + + cp_model.AddMaxEquality(latency_overrun_var, {latency_overrun_expr, 0}); + } + + forbid_illegal_turns(flow_link_vars, cp_model); + + add_congestion_constraints(flow_link_vars, cp_model); + + add_continuity_constraints(flow_link_vars, cp_model); + + std::vector up, down, right, left; + group_noc_links_based_on_direction(up, down, right, left); + + add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& route = traffic_flow_storage.get_traffic_flow_route(traffic_flow_id); + + for (auto noc_link_id : route) { + cp_model.AddEquality(flow_link_vars[{traffic_flow_id, noc_link_id}], 1); + } + } + + + operations_research::sat::LinearExpr latency_overrun_sum; + for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { + latency_overrun_sum += latency_overrun_var; + } + + cp_model.Minimize(latency_overrun_sum); + + const operations_research::sat::CpSolverResponse response = operations_research::sat::Solve(cp_model.Build()); + + LOG(INFO) << CpSolverResponseStats(response); + if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || + response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { + + for (auto& [key, var] : flow_link_vars) { + NocTrafficFlowId flow_id = key.first; + NocLinkId link_id = key.second; + + auto& noc_link = noc_ctx.noc_model.get_single_noc_link(link_id); + const NocRouterId src_noc_router_id = noc_link.get_source_router(); + const NocRouterId dst_noc_router_id = noc_link.get_sink_router(); + const NocRouter& src_noc_router = noc_ctx.noc_model.get_single_noc_router(src_noc_router_id); + const NocRouter& dst_noc_router = noc_ctx.noc_model.get_single_noc_router(dst_noc_router_id); + auto src_loc = src_noc_router.get_router_physical_location(); + auto dst_loc = dst_noc_router.get_router_physical_location(); + + bool value = operations_research::sat::SolutionBooleanValue(response, var); + + if (value) + std::cout << "tf: " << (size_t)flow_id << " (" << src_loc.x << ", " << src_loc.y << ") --> (" << dst_loc.x << ", " << dst_loc.y << ")" << std::endl; + + } + + } else { + for (const int index : response.sufficient_assumptions_for_infeasibility()) { + LOG(INFO) << index; + } + std::cout << "CP-SAT solver failed to find a solution" << std::endl; + } + + return {}; +} \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h new file mode 100644 index 00000000000..238bb396412 --- /dev/null +++ b/vpr/src/noc/sat_routing.h @@ -0,0 +1,24 @@ +#ifndef VTR_SATROUTING_H +#define VTR_SATROUTING_H + +#include + +#include "noc_data_types.h" +#include "vtr_hash.h" +#include "vtr_vector.h" + +vtr::vector> noc_sat_route(); + +namespace std { +template<> +struct hash> { + std::size_t operator()(const std::pair& flow_link) const noexcept { + std::size_t seed = std::hash{}(flow_link.first); + vtr::hash_combine(seed, flow_link.second); + return seed; + } +}; +} // namespace std + + +#endif \ No newline at end of file diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index e13d278af68..e8343bb8376 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -1,9 +1,11 @@ #include "initial_noc_placment.h" #include "initial_placement.h" +#include "sat_routing.h" #include "noc_place_utils.h" #include "noc_place_checkpoint.h" #include "place_constraints.h" + #include "vtr_math.h" /** @@ -284,4 +286,7 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { "At least one cycle was found in NoC channel dependency graph. This may cause a deadlock " "when packets wait on each other in a cycle.\n"); } + + noc_sat_route(); + } \ No newline at end of file From aabcee823fd776ddc91d7c51cc48cc966cee590e Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Sun, 10 Mar 2024 13:02:55 -0400 Subject: [PATCH 05/38] add sort_noc_links_in_chain_order() --- vpr/src/noc/sat_routing.cpp | 104 ++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 27 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 6848185cc0c..d38fb408790 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -253,14 +253,74 @@ static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) } + +std::vector sort_noc_links_in_chain_order(const std::vector& links) { + std::vector route; + if (links.empty()) { + return route; + } + + const auto& noc_model = g_vpr_ctx.noc().noc_model; + + // Create a map to find pairs by their first element + std::unordered_map src_map; + std::unordered_map is_dst; + for (const auto& l : links) { + NocRouterId src_router_id = noc_model.get_single_noc_link(l).get_source_router(); + NocRouterId dst_router_id = noc_model.get_single_noc_link(l).get_sink_router(); + src_map[src_router_id] = l; + is_dst[dst_router_id] = true; + } + + // Find the starting pair (whose first element is not a second element of any pair) + auto it = links.begin(); + for (; it != links.end(); ++it) { + NocRouterId src_router_id = noc_model.get_single_noc_link(*it).get_source_router(); + if (is_dst.find(src_router_id) == is_dst.end()) { + break; + } + } + + // Reconstruct the chain starting from the found starting pair + auto current = *it; + while (true) { + route.push_back(current); + NocRouterId dst_router_id = noc_model.get_single_noc_link(current).get_source_router(); + auto nextIt = src_map.find(dst_router_id); + if (nextIt == src_map.end()) { + break; // End of chain + } + current = nextIt->second; + } + + VTR_ASSERT(route.size() == links.size()); + + return route; +} + vtr::vector> noc_sat_route() { const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + // Used to add variables and constraints to a CP-SAT model operations_research::sat::CpModelBuilder cp_model; + /* + * For each traffic flow and NoC link pair, we create a boolean variable. + * When a variable associated with traffic flow t and NoC link l is set, + * it means that t is routed through l. + */ std::unordered_map, operations_research::sat::BoolVar> flow_link_vars; + + /* + * Each traffic flow latency constraint is translated to how many NoC links + * the traffic flow can traverse without violating the constraint. + * These integer variables specify the number of additional links traversed + * beyond the maximum allowed number of links. + */ std::map latency_overrun_vars; + // TODO: specify the domain based on NoC topology operations_research::Domain latency_overrun_domain(0, 20); // create boolean variables for each traffic flow and link pair @@ -268,10 +328,12 @@ vtr::vector> noc_sat_route() { for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + // create an integer variable for each latency-constrained traffic flow if (traffic_flow.max_traffic_flow_latency < 0.1) { latency_overrun_vars[traffic_flow_id] = cp_model.NewIntVar(latency_overrun_domain); } + // create (traffic flow, NoC link) pair boolean variables for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { const NocLinkId noc_link_id = noc_link.get_link_id(); flow_link_vars[{traffic_flow_id, noc_link_id}] = cp_model.NewBoolVar(); @@ -301,15 +363,6 @@ vtr::vector> noc_sat_route() { add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - const auto& route = traffic_flow_storage.get_traffic_flow_route(traffic_flow_id); - - for (auto noc_link_id : route) { - cp_model.AddEquality(flow_link_vars[{traffic_flow_id, noc_link_id}], 1); - } - } - - operations_research::sat::LinearExpr latency_overrun_sum; for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { latency_overrun_sum += latency_overrun_var; @@ -319,35 +372,32 @@ vtr::vector> noc_sat_route() { const operations_research::sat::CpSolverResponse response = operations_research::sat::Solve(cp_model.Build()); + vtr::vector> routes; + LOG(INFO) << CpSolverResponseStats(response); if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { - for (auto& [key, var] : flow_link_vars) { - NocTrafficFlowId flow_id = key.first; - NocLinkId link_id = key.second; - - auto& noc_link = noc_ctx.noc_model.get_single_noc_link(link_id); - const NocRouterId src_noc_router_id = noc_link.get_source_router(); - const NocRouterId dst_noc_router_id = noc_link.get_sink_router(); - const NocRouter& src_noc_router = noc_ctx.noc_model.get_single_noc_router(src_noc_router_id); - const NocRouter& dst_noc_router = noc_ctx.noc_model.get_single_noc_router(dst_noc_router_id); - auto src_loc = src_noc_router.get_router_physical_location(); - auto dst_loc = dst_noc_router.get_router_physical_location(); + routes.resize(traffic_flow_storage.get_number_of_traffic_flows()); + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; bool value = operations_research::sat::SolutionBooleanValue(response, var); + if (value) { + routes[traffic_flow_id].push_back(noc_link_id); + } + } - if (value) - std::cout << "tf: " << (size_t)flow_id << " (" << src_loc.x << ", " << src_loc.y << ") --> (" << dst_loc.x << ", " << dst_loc.y << ")" << std::endl; - + for (auto& route : routes) { + route = sort_noc_links_in_chain_order(route); } } else { - for (const int index : response.sufficient_assumptions_for_infeasibility()) { - LOG(INFO) << index; - } +// for (const int index : response.sufficient_assumptions_for_infeasibility()) { +// LOG(INFO) << index; +// } std::cout << "CP-SAT solver failed to find a solution" << std::endl; } - return {}; + return routes; } \ No newline at end of file From 9193b2596c49ce1f466590bf846b4e364e41754c Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Sun, 10 Mar 2024 15:53:09 -0400 Subject: [PATCH 06/38] sanity checks for CP-SAT routes --- vpr/src/noc/channel_dependency_graph.cpp | 34 ++++++++++++++++++++++-- vpr/src/noc/channel_dependency_graph.h | 8 ++++-- vpr/src/place/initial_noc_placement.cpp | 10 ++++++- vpr/src/place/noc_place_utils.cpp | 16 ++++++++--- vpr/src/place/noc_place_utils.h | 2 ++ 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/vpr/src/noc/channel_dependency_graph.cpp b/vpr/src/noc/channel_dependency_graph.cpp index abc38cffe6c..31bd4052485 100644 --- a/vpr/src/noc/channel_dependency_graph.cpp +++ b/vpr/src/noc/channel_dependency_graph.cpp @@ -4,8 +4,38 @@ #include -ChannelDependencyGraph::ChannelDependencyGraph(size_t n_links, - const vtr::vector>& traffic_flow_routes) { +ChannelDependencyGraph::ChannelDependencyGraph(const NocStorage& noc_model, + const NocTrafficFlows& traffic_flow_storage, + const vtr::vector>& traffic_flow_routes, + const vtr::vector_map& block_locs) { + VTR_ASSERT((size_t)traffic_flow_storage.get_number_of_traffic_flows() == traffic_flow_routes.size()); + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + const auto& traffic_flow_route = traffic_flow_routes[traffic_flow_id]; + + // get the source and destination logical router blocks in the current traffic flow + ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; + ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; + + // get the ids of the hard router blocks where the logical router cluster blocks have been placed + NocRouterId src_router_id = noc_model.get_router_at_grid_location(block_locs[logical_source_router_block_id].loc); + NocRouterId dst_router_id = noc_model.get_router_at_grid_location(block_locs[logical_sink_router_block_id].loc); + + const NocLink& first_link = noc_model.get_single_noc_link(traffic_flow_route.front()); + VTR_ASSERT(first_link.get_source_router() == src_router_id); + const NocLink& last_link = noc_model.get_single_noc_link(traffic_flow_route.back()); + VTR_ASSERT(last_link.get_sink_router() == dst_router_id); + + for (size_t i = 0; i < traffic_flow_route.size() - 1; i++) { + const NocLink& noc_link1 = noc_model.get_single_noc_link(traffic_flow_route[i]); + const NocLink& noc_link2 = noc_model.get_single_noc_link(traffic_flow_route[i + 1]); + VTR_ASSERT(noc_link1.get_sink_router() == noc_link2.get_source_router()); + } + } + + const size_t n_links = noc_model.get_noc_links().size(); + adjacency_list_.clear(); // In channel dependency graph, vertices represent NoC links. // reserve enough space so that all vertices can store their outgoing neighbors diff --git a/vpr/src/noc/channel_dependency_graph.h b/vpr/src/noc/channel_dependency_graph.h index 455c6324e67..d52ac94c299 100644 --- a/vpr/src/noc/channel_dependency_graph.h +++ b/vpr/src/noc/channel_dependency_graph.h @@ -24,6 +24,8 @@ #include "vtr_vector.h" #include "noc_data_types.h" +#include "noc_storage.h" +#include "noc_traffic_flows.h" class ChannelDependencyGraph { public: @@ -36,8 +38,10 @@ class ChannelDependencyGraph { * @param traffic_flow_routes Generated traffic flow routes by the routing * algorithm. */ - ChannelDependencyGraph(size_t n_links, - const vtr::vector>& traffic_flow_routes); + ChannelDependencyGraph(const NocStorage& noc_model, + const NocTrafficFlows& traffic_flow_storage, + const vtr::vector>& traffic_flow_routes, + const vtr::vector_map& block_locs); /** * @brief Checks whether CDG has any cycles. diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index e8343bb8376..4c7f6618d04 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -287,6 +287,14 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { "when packets wait on each other in a cycle.\n"); } - noc_sat_route(); + + auto traffic_flow_routes = noc_sat_route(); + if (!traffic_flow_routes.empty()) { + has_cycle = noc_routing_has_cycle(traffic_flow_routes); + if (has_cycle) { + std::cout << "SAT NoC routing has cycles" << std::endl; + } + } + } \ No newline at end of file diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index ac9fde26038..fe048918a75 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -871,10 +871,20 @@ bool noc_routing_has_cycle() { // get all traffic flow routes const auto& traffic_flow_routes = noc_ctx.noc_traffic_flows_storage.get_all_traffic_flow_routes(); - // get the total number of NoC links - const size_t num_noc_links = noc_ctx.noc_model.get_number_of_noc_links(); + bool has_cycle = noc_routing_has_cycle(traffic_flow_routes); + + return has_cycle; +} + +bool noc_routing_has_cycle(const vtr::vector>& routes) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& place_ctx = g_vpr_ctx.placement(); + + ChannelDependencyGraph channel_dependency_graph(noc_ctx.noc_model, + noc_ctx.noc_traffic_flows_storage, + routes, + place_ctx.block_locs); - ChannelDependencyGraph channel_dependency_graph(num_noc_links, traffic_flow_routes); bool has_cycles = channel_dependency_graph.has_cycles(); return has_cycles; diff --git a/vpr/src/place/noc_place_utils.h b/vpr/src/place/noc_place_utils.h index 079cc5f001b..8f99d6c7ee5 100644 --- a/vpr/src/place/noc_place_utils.h +++ b/vpr/src/place/noc_place_utils.h @@ -548,4 +548,6 @@ void write_noc_placement_file(const std::string& file_name); */ bool noc_routing_has_cycle(); +bool noc_routing_has_cycle(const vtr::vector>& routes); + #endif \ No newline at end of file From 832712197488b05f990fbaf399eb632d1542c9f3 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Sun, 10 Mar 2024 16:02:00 -0400 Subject: [PATCH 07/38] fix infinite loop in sort_noc_links_in_chain_order --- vpr/src/noc/sat_routing.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index d38fb408790..5ebd6fe6b3b 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -64,7 +64,6 @@ static void add_congestion_constraints(std::unordered_map sort_noc_links_in_chain_order(const std::vector sort_noc_links_in_chain_order(const std::vector> noc_sat_route() { +vtr::vector> noc_sat_route(bool mini) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -334,7 +333,7 @@ vtr::vector> noc_sat_route() { } // create (traffic flow, NoC link) pair boolean variables - for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { + for (const auto& noc_link : noc_model.get_noc_links()) { const NocLinkId noc_link_id = noc_link.get_link_id(); flow_link_vars[{traffic_flow_id, noc_link_id}] = cp_model.NewBoolVar(); } @@ -343,7 +342,7 @@ vtr::vector> noc_sat_route() { for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { int n_max_links = comp_max_number_of_traversed_links(traffic_flow_id); auto link_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, - {noc_ctx.noc_model.get_noc_links().keys().begin(), noc_ctx.noc_model.get_noc_links().keys().end()}); + {noc_model.get_noc_links().keys().begin(), noc_model.get_noc_links().keys().end()}); operations_research::sat::LinearExpr latency_overrun_expr; latency_overrun_expr += operations_research::sat::LinearExpr::Sum(link_vars); From 952745c05c55f4f58e97bf257c21e7f7f33f8ed0 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Sun, 10 Mar 2024 17:55:09 -0400 Subject: [PATCH 08/38] optimize aggregate bandwidth using or-tools --- vpr/src/noc/sat_routing.cpp | 87 ++++++++++++++++++------- vpr/src/noc/sat_routing.h | 2 +- vpr/src/place/initial_noc_placement.cpp | 25 ++++++- vpr/src/place/noc_place_checkpoint.cpp | 2 +- vpr/src/place/noc_place_utils.cpp | 15 +++-- vpr/src/place/noc_place_utils.h | 5 +- vpr/src/place/place_checkpoint.cpp | 2 +- 7 files changed, 101 insertions(+), 37 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 5ebd6fe6b3b..237eed183c8 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -13,6 +13,8 @@ #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_solver.h" +static constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 1024; + std::vector get_flow_link_vars(const std::unordered_map, operations_research::sat::BoolVar>& map, const std::vector& traffic_flow_ids, const std::vector& noc_link_ids) { @@ -47,13 +49,11 @@ static void forbid_illegal_turns(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model) { +static vtr::vector rescale_traffic_flow_bandwidths() { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const double link_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth(); - constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 1024; vtr::vector rescaled_traffic_flow_bandwidths; rescaled_traffic_flow_bandwidths.resize(traffic_flow_storage.get_number_of_traffic_flows()); @@ -66,6 +66,16 @@ static void add_congestion_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, + operations_research::sat::CpModelBuilder& cp_model) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + // add NoC link congestion constraints for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { const NocLinkId noc_link_id = noc_link.get_link_id(); @@ -297,7 +307,33 @@ std::vector sort_noc_links_in_chain_order(const std::vector> noc_sat_route(bool mini) { +static vtr::vector> convert_vars_to_routes(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, + const operations_research::sat::CpSolverResponse& response) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + VTR_ASSERT(response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || + response.status() == operations_research::sat::CpSolverStatus::OPTIMAL); + + vtr::vector> routes; + routes.resize(traffic_flow_storage.get_number_of_traffic_flows()); + + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; + bool value = operations_research::sat::SolutionBooleanValue(response, var); + if (value) { + routes[traffic_flow_id].push_back(noc_link_id); + } + } + + for (auto& route : routes) { + route = sort_noc_links_in_chain_order(route); + } + + return routes; +} + +vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -369,34 +405,35 @@ vtr::vector> noc_sat_route(bool mini) { cp_model.Minimize(latency_overrun_sum); - const operations_research::sat::CpSolverResponse response = operations_research::sat::Solve(cp_model.Build()); + operations_research::sat::CpSolverResponse response = operations_research::sat::Solve(cp_model.Build()); - vtr::vector> routes; - - LOG(INFO) << CpSolverResponseStats(response); if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { - routes.resize(traffic_flow_storage.get_number_of_traffic_flows()); - - for (auto& [key, var] : flow_link_vars) { - auto [traffic_flow_id, noc_link_id] = key; - bool value = operations_research::sat::SolutionBooleanValue(response, var); - if (value) { - routes[traffic_flow_id].push_back(noc_link_id); + if (!minimize_aggregate_bandwidth) { + auto routes = convert_vars_to_routes(flow_link_vars, response); + return routes; + } else { + int latency_overrun_value = operations_research::sat::SolutionIntegerValue(response, latency_overrun_sum); + cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); + + auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + operations_research::sat::LinearExpr agg_bw_expr; + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; + agg_bw_expr += operations_research::sat::LinearExpr(var * rescaled_traffic_flow_bandwidths[traffic_flow_id]); } - } - for (auto& route : routes) { - route = sort_noc_links_in_chain_order(route); - } + cp_model.Minimize(agg_bw_expr); + response = operations_research::sat::Solve(cp_model.Build()); - } else { -// for (const int index : response.sufficient_assumptions_for_infeasibility()) { -// LOG(INFO) << index; -// } - std::cout << "CP-SAT solver failed to find a solution" << std::endl; + if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || + response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { + auto routes = convert_vars_to_routes(flow_link_vars, response); + return routes; + } + } } - return routes; + return {}; } \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 238bb396412..5128727f6e3 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -7,7 +7,7 @@ #include "vtr_hash.h" #include "vtr_vector.h" -vtr::vector> noc_sat_route(); +vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth); namespace std { template<> diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index 4c7f6618d04..2bb68ffb453 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -245,6 +245,13 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) { if (checkpoint.get_cost() < costs.cost) { checkpoint.restore_checkpoint(costs); } + + std::cout << "Initial NoC placement costs: " + << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth + << " Latency: " << costs.noc_cost_terms.latency + << " Latency Over: " << costs.noc_cost_terms.latency_overrun + << " Congestion: " << costs.noc_cost_terms.congestion << std::endl; + } void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { @@ -274,7 +281,7 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { place_noc_routers_randomly(unfixed_routers, seed); // populate internal data structures to maintain route, bandwidth usage, and latencies - initial_noc_routing(); + initial_noc_routing({}); // Run the simulated annealing optimizer for NoC routers noc_routers_anneal(noc_opts); @@ -288,13 +295,25 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { } - auto traffic_flow_routes = noc_sat_route(); + auto traffic_flow_routes = noc_sat_route(true); if (!traffic_flow_routes.empty()) { has_cycle = noc_routing_has_cycle(traffic_flow_routes); if (has_cycle) { std::cout << "SAT NoC routing has cycles" << std::endl; } - } + t_placer_costs costs; + reinitialize_noc_routing(costs, traffic_flow_routes); + + std::cout << "Initial NoC placement costs: " + << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth + << " Latency: " << costs.noc_cost_terms.latency + << " Latency Over: " << costs.noc_cost_terms.latency_overrun + << " Congestion: " << costs.noc_cost_terms.congestion << std::endl; + } else { + std::cout << "SAT routing failed" << std::endl; + } + + exit(0); } \ No newline at end of file diff --git a/vpr/src/place/noc_place_checkpoint.cpp b/vpr/src/place/noc_place_checkpoint.cpp index e0f41dc94f0..3e11d9c8eb6 100644 --- a/vpr/src/place/noc_place_checkpoint.cpp +++ b/vpr/src/place/noc_place_checkpoint.cpp @@ -68,7 +68,7 @@ void NoCPlacementCheckpoint::restore_checkpoint(t_placer_costs& costs) { } // Re-initialize routes and static variables that keep track of NoC-related costs - reinitialize_noc_routing(costs); + reinitialize_noc_routing(costs, {}); } bool NoCPlacementCheckpoint::is_valid() const { diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index fe048918a75..c46bbeec67b 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -54,13 +54,16 @@ static bool select_random_router_cluster(ClusterBlockId& b_from, static std::vector find_affected_links_by_flow_reroute(std::vector& prev_links, std::vector& curr_links); -void initial_noc_routing() { +void initial_noc_routing(const vtr::vector>& new_traffic_flow_routes) { // need to update the link usages within after routing all the traffic flows // also need to route all the traffic flows and store them auto& noc_ctx = g_vpr_ctx.mutable_noc(); NocTrafficFlows& noc_traffic_flows_storage = noc_ctx.noc_traffic_flows_storage; + VTR_ASSERT(new_traffic_flow_routes.size() == (size_t)noc_traffic_flows_storage.get_number_of_traffic_flows() || + new_traffic_flow_routes.empty()); + /* We need all the traffic flow ids to be able to access them. The range * of traffic flow ids go from 0 to the total number of traffic flows within * the NoC. @@ -70,24 +73,28 @@ void initial_noc_routing() { const t_noc_traffic_flow& curr_traffic_flow = noc_traffic_flows_storage.get_single_noc_traffic_flow(traffic_flow_id); // update the traffic flow route based on where the router cluster blocks are placed - std::vector& curr_traffic_flow_route = route_traffic_flow(traffic_flow_id, noc_ctx.noc_model,noc_traffic_flows_storage, *noc_ctx.noc_flows_router); + const std::vector& curr_traffic_flow_route = new_traffic_flow_routes.empty() ? route_traffic_flow(traffic_flow_id, noc_ctx.noc_model,noc_traffic_flows_storage, *noc_ctx.noc_flows_router) : new_traffic_flow_routes[traffic_flow_id]; // update the links used in the found traffic flow route, links' bandwidth should be incremented since the traffic flow is routed update_traffic_flow_link_usage(curr_traffic_flow_route, noc_ctx.noc_model, 1, curr_traffic_flow.traffic_flow_bandwidth); } } -void reinitialize_noc_routing(t_placer_costs& costs) { +void reinitialize_noc_routing(t_placer_costs& costs, + const vtr::vector>& new_traffic_flow_routes) { // used to access NoC links and modify them auto& noc_ctx = g_vpr_ctx.mutable_noc(); + VTR_ASSERT((size_t)noc_ctx.noc_traffic_flows_storage.get_number_of_traffic_flows() == new_traffic_flow_routes.size() || + new_traffic_flow_routes.empty()); + // Zero out bandwidth usage for all links for (auto& noc_link : noc_ctx.noc_model.get_mutable_noc_links()) { noc_link.set_bandwidth_usage(0.0); } // Route traffic flows and update link bandwidth usage - initial_noc_routing(); + initial_noc_routing(new_traffic_flow_routes); // Initialize traffic_flow_costs costs.noc_cost_terms.aggregate_bandwidth = comp_noc_aggregate_bandwidth_cost(); diff --git a/vpr/src/place/noc_place_utils.h b/vpr/src/place/noc_place_utils.h index 8f99d6c7ee5..daf07836143 100644 --- a/vpr/src/place/noc_place_utils.h +++ b/vpr/src/place/noc_place_utils.h @@ -50,7 +50,7 @@ struct TrafficFlowPlaceCost { * routed. This is why this function should only be used once. * */ -void initial_noc_routing(); +void initial_noc_routing(const vtr::vector>& new_traffic_flow_routes); /** * @brief Zeros out all link bandwidth usage an re-routes traffic flows. @@ -65,7 +65,8 @@ void initial_noc_routing(); * * @param costs Used to get aggregate bandwidth and latency costs. */ -void reinitialize_noc_routing(t_placer_costs& costs); +void reinitialize_noc_routing(t_placer_costs& costs, + const vtr::vector>& new_traffic_flow_routes); /** * @brief Goes through all the cluster blocks that were moved diff --git a/vpr/src/place/place_checkpoint.cpp b/vpr/src/place/place_checkpoint.cpp index 73d49e6e80c..86af65142c3 100644 --- a/vpr/src/place/place_checkpoint.cpp +++ b/vpr/src/place/place_checkpoint.cpp @@ -63,7 +63,7 @@ void restore_best_placement(t_placement_checkpoint& placement_checkpoint, * and need to be re-computed from scratch. */ if (noc_opts.noc) { - reinitialize_noc_routing(costs); + reinitialize_noc_routing(costs, {}); } VTR_LOG("\nCheckpoint restored\n"); From fdf6a9875ade9ca14121388dc8077376d1912480 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 12 Mar 2024 16:58:40 -0400 Subject: [PATCH 09/38] remove submodule or-tools --- .gitmodules | 3 --- libs/EXTERNAL/CMakeLists.txt | 4 ---- libs/EXTERNAL/or-tools | 1 - vpr/CMakeLists.txt | 1 + 4 files changed, 1 insertion(+), 8 deletions(-) delete mode 160000 libs/EXTERNAL/or-tools diff --git a/.gitmodules b/.gitmodules index 49f8df696f8..08b907e160b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "libs/EXTERNAL/libcatch2"] path = libs/EXTERNAL/libcatch2 url = https://github.com/catchorg/Catch2.git -[submodule "libs/EXTERNAL/or-tools"] - path = libs/EXTERNAL/or-tools - url = https://github.com/google/or-tools.git diff --git a/libs/EXTERNAL/CMakeLists.txt b/libs/EXTERNAL/CMakeLists.txt index 0a721ec6049..e7988a30907 100644 --- a/libs/EXTERNAL/CMakeLists.txt +++ b/libs/EXTERNAL/CMakeLists.txt @@ -11,10 +11,6 @@ add_subdirectory(libtatum) add_subdirectory(libcatch2) #SET(BUILD_DEPS ON CACHE BOOL "Build libfoo shared library") -set(BUILD_DEPS ON) -set(BUILD_SAMPLES OFF) -set(BUILD_EXAMPLES OFF) -add_subdirectory(or-tools) #add_subdirectory(parmys) #VPR_USE_EZGL is initialized in the root CMakeLists. diff --git a/libs/EXTERNAL/or-tools b/libs/EXTERNAL/or-tools deleted file mode 160000 index d37317b17ca..00000000000 --- a/libs/EXTERNAL/or-tools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d37317b17ca16658451cafe05085fc22c39dd6c8 diff --git a/vpr/CMakeLists.txt b/vpr/CMakeLists.txt index ad0f64e3589..6aac615ee8d 100644 --- a/vpr/CMakeLists.txt +++ b/vpr/CMakeLists.txt @@ -91,6 +91,7 @@ target_link_libraries(libvpr librrgraph ) +find_package(ortools CONFIG REQUIRED) target_link_libraries(libvpr ortools::ortools) #link graphics library only when graphics set to on From fcff1509ee52d77a72c8629071a748be43725cb8 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 12 Mar 2024 19:19:50 -0400 Subject: [PATCH 10/38] move passed by value names --- libs/libvtrutil/src/vtr_time.cpp | 8 +++++--- libs/libvtrutil/src/vtr_time.h | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/libvtrutil/src/vtr_time.cpp b/libs/libvtrutil/src/vtr_time.cpp index a557f186735..5c80ff3126c 100644 --- a/libs/libvtrutil/src/vtr_time.cpp +++ b/libs/libvtrutil/src/vtr_time.cpp @@ -3,6 +3,8 @@ #include "vtr_log.h" #include "vtr_rusage.h" +#include + namespace vtr { int f_timer_depth = 0; @@ -30,7 +32,7 @@ float Timer::delta_max_rss_mib() const { ///@brief Constructor ScopedActionTimer::ScopedActionTimer(std::string action_str) - : action_(action_str) + : action_(std::move(action_str)) , depth_(f_timer_depth++) { } @@ -69,7 +71,7 @@ int ScopedActionTimer::depth() const { ///@brief Constructor ScopedFinishTimer::ScopedFinishTimer(std::string action_str) - : ScopedActionTimer(action_str) { + : ScopedActionTimer(std::move(action_str)) { } ///@brief Destructor @@ -83,7 +85,7 @@ ScopedFinishTimer::~ScopedFinishTimer() { ///@brief Constructor ScopedStartFinishTimer::ScopedStartFinishTimer(std::string action_str) - : ScopedActionTimer(action_str) { + : ScopedActionTimer(std::move(action_str)) { vtr::printf_info("%s%s\n", pad().c_str(), action().c_str()); } diff --git a/libs/libvtrutil/src/vtr_time.h b/libs/libvtrutil/src/vtr_time.h index 2a4d4ec8af0..4e389ef5026 100644 --- a/libs/libvtrutil/src/vtr_time.h +++ b/libs/libvtrutil/src/vtr_time.h @@ -39,7 +39,7 @@ class Timer { ///@brief Scoped time class which prints the time elapsed for the specifid action class ScopedActionTimer : public Timer { public: - ScopedActionTimer(const std::string action); + ScopedActionTimer(std::string action); ~ScopedActionTimer(); void quiet(bool value); @@ -71,7 +71,7 @@ class ScopedActionTimer : public Timer { */ class ScopedFinishTimer : public ScopedActionTimer { public: - ScopedFinishTimer(const std::string action); + ScopedFinishTimer(std::string action); ~ScopedFinishTimer(); }; @@ -91,7 +91,7 @@ class ScopedFinishTimer : public ScopedActionTimer { */ class ScopedStartFinishTimer : public ScopedActionTimer { public: - ScopedStartFinishTimer(const std::string action); + ScopedStartFinishTimer(std::string action); ~ScopedStartFinishTimer(); }; } // namespace vtr From 38fb924bf1d6775e36ec6862135dc52072992991 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 12 Mar 2024 19:22:24 -0400 Subject: [PATCH 11/38] invoke sat routing at the end of placement when NoC congestion is not resolved --- vpr/src/noc/sat_routing.cpp | 41 +++++++++++++++++-------- vpr/src/noc/sat_routing.h | 3 +- vpr/src/place/initial_noc_placement.cpp | 24 --------------- vpr/src/place/noc_place_utils.cpp | 4 +++ vpr/src/place/place.cpp | 35 +++++++++++++++++++++ 5 files changed, 69 insertions(+), 38 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 237eed183c8..7e8b1357872 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -4,6 +4,7 @@ #include "move_utils.h" #include "globals.h" +#include "vtr_time.h" #include @@ -15,9 +16,11 @@ static constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 1024; -std::vector get_flow_link_vars(const std::unordered_map, operations_research::sat::BoolVar>& map, - const std::vector& traffic_flow_ids, - const std::vector& noc_link_ids) { +typedef std::unordered_map, operations_research::sat::BoolVar> t_flow_link_var_map; + +static std::vector get_flow_link_vars(const t_flow_link_var_map& map, + const std::vector& traffic_flow_ids, + const std::vector& noc_link_ids) { std::vector results; for (auto traffic_flow_id : traffic_flow_ids) { for (auto noc_link_id : noc_link_ids) { @@ -30,7 +33,7 @@ std::vector get_flow_link_vars(const std::uno return results; } -static void forbid_illegal_turns(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, +static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, operations_research::sat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -69,7 +72,7 @@ static vtr::vector rescale_traffic_flow_bandwidths() { return rescaled_traffic_flow_bandwidths; } -static void add_congestion_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, +static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, operations_research::sat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -90,7 +93,7 @@ static void add_congestion_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, +static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, operations_research::sat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); @@ -148,7 +151,7 @@ static void add_continuity_constraints(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, +static void add_distance_constraints(t_flow_link_var_map& flow_link_vars, operations_research::sat::CpModelBuilder& cp_model, const std::vector& up, const std::vector& down, @@ -263,7 +266,7 @@ static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) } -std::vector sort_noc_links_in_chain_order(const std::vector& links) { +static std::vector sort_noc_links_in_chain_order(const std::vector& links) { std::vector route; if (links.empty()) { return route; @@ -307,7 +310,7 @@ std::vector sort_noc_links_in_chain_order(const std::vector> convert_vars_to_routes(std::unordered_map, operations_research::sat::BoolVar>& flow_link_vars, +static vtr::vector> convert_vars_to_routes(t_flow_link_var_map& flow_link_vars, const operations_research::sat::CpSolverResponse& response) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -333,7 +336,10 @@ static vtr::vector> convert_vars_to_rou return routes; } -vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth) { +vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, + int seed) { + vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); + const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -346,7 +352,7 @@ vtr::vector> noc_sat_route(bool minimiz * When a variable associated with traffic flow t and NoC link l is set, * it means that t is routed through l. */ - std::unordered_map, operations_research::sat::BoolVar> flow_link_vars; + t_flow_link_var_map flow_link_vars; /* * Each traffic flow latency constraint is translated to how many NoC links @@ -405,7 +411,16 @@ vtr::vector> noc_sat_route(bool minimiz cp_model.Minimize(latency_overrun_sum); - operations_research::sat::CpSolverResponse response = operations_research::sat::Solve(cp_model.Build()); + operations_research::sat::Model model; + + operations_research::sat::SatParameters sat_params; + sat_params.set_num_workers(1); + sat_params.set_num_search_workers(1); + sat_params.set_random_seed(seed); + + model.Add(NewSatParameters(sat_params)); + + operations_research::sat::CpSolverResponse response = operations_research::sat::SolveCpModel(cp_model.Build(), &model); if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { @@ -414,7 +429,7 @@ vtr::vector> noc_sat_route(bool minimiz auto routes = convert_vars_to_routes(flow_link_vars, response); return routes; } else { - int latency_overrun_value = operations_research::sat::SolutionIntegerValue(response, latency_overrun_sum); + int latency_overrun_value = (int)operations_research::sat::SolutionIntegerValue(response, latency_overrun_sum); cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 5128727f6e3..234b67da448 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -7,7 +7,8 @@ #include "vtr_hash.h" #include "vtr_vector.h" -vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth); +vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, + int seed); namespace std { template<> diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index 2bb68ffb453..1396f23b8b3 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -1,7 +1,6 @@ #include "initial_noc_placment.h" #include "initial_placement.h" -#include "sat_routing.h" #include "noc_place_utils.h" #include "noc_place_checkpoint.h" #include "place_constraints.h" @@ -293,27 +292,4 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { "At least one cycle was found in NoC channel dependency graph. This may cause a deadlock " "when packets wait on each other in a cycle.\n"); } - - - auto traffic_flow_routes = noc_sat_route(true); - if (!traffic_flow_routes.empty()) { - has_cycle = noc_routing_has_cycle(traffic_flow_routes); - if (has_cycle) { - std::cout << "SAT NoC routing has cycles" << std::endl; - } - - - t_placer_costs costs; - reinitialize_noc_routing(costs, traffic_flow_routes); - - std::cout << "Initial NoC placement costs: " - << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth - << " Latency: " << costs.noc_cost_terms.latency - << " Latency Over: " << costs.noc_cost_terms.latency_overrun - << " Congestion: " << costs.noc_cost_terms.congestion << std::endl; - } else { - std::cout << "SAT routing failed" << std::endl; - } - - exit(0); } \ No newline at end of file diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index c46bbeec67b..e6a4704f547 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -75,6 +75,10 @@ void initial_noc_routing(const vtr::vector& curr_traffic_flow_route = new_traffic_flow_routes.empty() ? route_traffic_flow(traffic_flow_id, noc_ctx.noc_model,noc_traffic_flows_storage, *noc_ctx.noc_flows_router) : new_traffic_flow_routes[traffic_flow_id]; + if (!new_traffic_flow_routes.empty()) { + noc_traffic_flows_storage.get_mutable_traffic_flow_route(traffic_flow_id) = curr_traffic_flow_route; + } + // update the links used in the found traffic flow route, links' bandwidth should be incremented since the traffic flow is routed update_traffic_flow_link_usage(curr_traffic_flow_route, noc_ctx.noc_model, 1, curr_traffic_flow.traffic_flow_bandwidth); } diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 982f87244dd..2b2d8142856 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -69,6 +69,7 @@ #include "cluster_placement.h" #include "noc_place_utils.h" +#include "sat_routing.h" /* define the RL agent's reward function factor constant. This factor controls the weight of bb cost * * compared to the timing cost in the agent's reward function. The reward is calculated as * @@ -1241,6 +1242,40 @@ void try_place(const Netlist<>& net_list, costs.noc_cost_terms.congestion, get_total_congestion_bandwidth_ratio(), get_number_of_congested_noc_links()); + + if (costs.noc_cost_terms.congestion > 0.0) { + VTR_LOG("NoC routing configuration is congested. Invoking the SAT NoC router.\n"); + auto traffic_flow_routes = noc_sat_route(true, placer_opts.seed); + + if (!traffic_flow_routes.empty()) { + bool has_cycle = noc_routing_has_cycle(traffic_flow_routes); + if (has_cycle) { + VTR_LOG("SAT NoC routing has cycles.\n"); + } + + reinitialize_noc_routing(costs, traffic_flow_routes); + + VTR_LOG("\nNoC Placement Costs after SAT routing. " + "cost: %g, " + "aggregate_bandwidth_cost: %g, " + "latency_cost: %g, " + "n_met_latency_constraints: %d, " + "latency_overrun_cost: %g, " + "congestion_cost: %g, " + "accum_congested_ratio: %g, " + "n_congested_links: %d \n", + calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), + costs.noc_cost_terms.aggregate_bandwidth, + costs.noc_cost_terms.latency, + get_number_of_traffic_flows_with_latency_cons_met(), + costs.noc_cost_terms.latency_overrun, + costs.noc_cost_terms.congestion, + get_total_congestion_bandwidth_ratio(), + get_number_of_congested_noc_links()); + } else { + VTR_LOG("SAT routing failed.\n"); + } + } } update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); // Print out swap statistics From a37458c9dd01f7890225c55ce51c578363e2d724 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 12 Mar 2024 22:30:00 -0400 Subject: [PATCH 12/38] first try at solving NoC placement and routing in a single shot --- vpr/src/noc/sat_routing.cpp | 195 +++++++++++++++++++++++++++++++----- vpr/src/noc/sat_routing.h | 11 ++ 2 files changed, 182 insertions(+), 24 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 7e8b1357872..d8c76c79b46 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -94,8 +94,7 @@ static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, } static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model) -{ + operations_research::sat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const auto& place_ctx = g_vpr_ctx.placement(); @@ -336,31 +335,13 @@ static vtr::vector> convert_vars_to_rou return routes; } -vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, - int seed) { - vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); - +static void create_flow_link_vars(operations_research::sat::CpModelBuilder& cp_model, + t_flow_link_var_map& flow_link_vars, + std::map& latency_overrun_vars) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - // Used to add variables and constraints to a CP-SAT model - operations_research::sat::CpModelBuilder cp_model; - - /* - * For each traffic flow and NoC link pair, we create a boolean variable. - * When a variable associated with traffic flow t and NoC link l is set, - * it means that t is routed through l. - */ - t_flow_link_var_map flow_link_vars; - - /* - * Each traffic flow latency constraint is translated to how many NoC links - * the traffic flow can traverse without violating the constraint. - * These integer variables specify the number of additional links traversed - * beyond the maximum allowed number of links. - */ - std::map latency_overrun_vars; // TODO: specify the domain based on NoC topology operations_research::Domain latency_overrun_domain(0, 20); @@ -380,6 +361,13 @@ vtr::vector> noc_sat_route(bool minimiz flow_link_vars[{traffic_flow_id, noc_link_id}] = cp_model.NewBoolVar(); } } +} + +static void constrain_latency_overrun_vars(operations_research::sat::CpModelBuilder& cp_model, + t_flow_link_var_map& flow_link_vars, + std::map& latency_overrun_vars) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { int n_max_links = comp_max_number_of_traversed_links(traffic_flow_id); @@ -392,6 +380,37 @@ vtr::vector> noc_sat_route(bool minimiz cp_model.AddMaxEquality(latency_overrun_var, {latency_overrun_expr, 0}); } +} + +vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, + int seed) { + vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); + + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + // Used to add variables and constraints to a CP-SAT model + operations_research::sat::CpModelBuilder cp_model; + + /* + * For each traffic flow and NoC link pair, we create a boolean variable. + * When a variable associated with traffic flow t and NoC link l is set, + * it means that t is routed through l. + */ + t_flow_link_var_map flow_link_vars; + + /* + * Each traffic flow latency constraint is translated to how many NoC links + * the traffic flow can traverse without violating the constraint. + * These integer variables specify the number of additional links traversed + * beyond the maximum allowed number of links. + */ + std::map latency_overrun_vars; + + create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); + + constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); forbid_illegal_turns(flow_link_vars, cp_model); @@ -415,7 +434,6 @@ vtr::vector> noc_sat_route(bool minimiz operations_research::sat::SatParameters sat_params; sat_params.set_num_workers(1); - sat_params.set_num_search_workers(1); sat_params.set_random_seed(seed); model.Add(NewSatParameters(sat_params)); @@ -451,4 +469,133 @@ vtr::vector> noc_sat_route(bool minimiz } return {}; +} + +static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_vars, + std::map& x_loc_vars, + std::map& y_loc_vars, + operations_research::sat::CpModelBuilder& cp_model) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + const auto& place_ctx = g_vpr_ctx.placement(); + auto& cluster_ctx = g_vpr_ctx.clustering(); + + // Get the logical block type for router + const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); + + // Get the compressed grid for NoC + const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; + + std::unordered_map, operations_research::sat::BoolVar> logical_physical_mapped; + + for (auto& [key, x_loc_var] : x_loc_vars) { + auto& y_loc_var = y_loc_vars[key]; + + for (auto noc_router_id : noc_model.get_noc_routers().keys()) { + const auto& noc_router = noc_model.get_single_noc_router(noc_router_id); + const auto noc_router_pos = noc_router.get_router_physical_location(); + auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; + + operations_research::sat::BoolVar x_condition = cp_model.NewBoolVar(); + cp_model.AddEquality(x_loc_var, compressed_loc.x).OnlyEnforceIf(x_condition); + cp_model.AddNotEqual(x_loc_var, compressed_loc.x).OnlyEnforceIf(Not(x_condition)); + + operations_research::sat::BoolVar y_condition = cp_model.NewBoolVar(); + cp_model.AddEquality(y_loc_var, compressed_loc.y).OnlyEnforceIf(y_condition); + cp_model.AddNotEqual(y_loc_var, compressed_loc.y).OnlyEnforceIf(Not(y_condition)); + + // Combine conditions using AddBoolAnd + operations_research::sat::BoolVar both_conds_met = cp_model.NewBoolVar(); + cp_model.AddBoolAnd({x_condition, y_condition}).OnlyEnforceIf(both_conds_met); + cp_model.AddBoolOr({Not(x_condition), Not(y_condition)}).OnlyEnforceIf(Not(both_conds_met)); + + logical_physical_mapped[{key, noc_router_id}] = both_conds_met; + } + } + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + // get the source and destination logical router blocks in the current traffic flow + ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; + ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; + + // each NoC router has at most one incoming and one outgoing link activated + for (auto noc_router_id : noc_ctx.noc_model.get_noc_routers().keys()) { + + auto& src_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; + auto& dst_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; + + operations_research::sat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); + + cp_model.AddImplication(src_is_mapped , nor_src_dst_mapped.Not()); + cp_model.AddImplication(dst_is_mapped , nor_src_dst_mapped.Not()); + cp_model.AddBoolOr({src_is_mapped.Not(), dst_is_mapped.Not()}).OnlyEnforceIf(nor_src_dst_mapped); + + const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); + auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); + cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); + cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); + cp_model.AddEquality(operations_research::sat::LinearExpr::Sum(vars), 0).OnlyEnforceIf(src_is_mapped); + + operations_research::sat::LinearExpr lhs; + lhs = operations_research::sat::LinearExpr::Sum(vars); + + const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); + vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); + cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); + cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); + cp_model.AddEquality(operations_research::sat::LinearExpr::Sum(vars), 0).OnlyEnforceIf(dst_is_mapped); + + operations_research::sat::LinearExpr rhs; + rhs = operations_research::sat::LinearExpr::Sum(vars); + + cp_model.AddEquality(lhs, rhs).OnlyEnforceIf(nor_src_dst_mapped); + } + } +} + +void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, + bool minimize_aggregate_bandwidth, + int seed) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + operations_research::sat::CpModelBuilder cp_model; + + t_flow_link_var_map flow_link_vars; + + std::map latency_overrun_vars; + + const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); + operations_research::Domain loc_domain(0, 9); + std::map x_loc_vars; + std::map y_loc_vars; + std::vector> loc_intervals; + + + for (auto router_blk_id : router_blk_ids) { + x_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); + y_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); + + loc_intervals.emplace_back(cp_model.NewIntervalVar(x_loc_vars[router_blk_id], 1, x_loc_vars[router_blk_id]+1), + cp_model.NewIntervalVar(y_loc_vars[router_blk_id], 1, y_loc_vars[router_blk_id]+1)); + } + + operations_research::sat::NoOverlap2DConstraint no_overlap_2d = cp_model.AddNoOverlap2D(); + + for (auto& [x_interval, y_interval] : loc_intervals) { + no_overlap_2d.AddRectangle(x_interval, y_interval); + } + + create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); + + constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); + + forbid_illegal_turns(flow_link_vars, cp_model); + + add_movable_continuity_constraints(flow_link_vars, x_loc_vars, y_loc_vars, cp_model); + } \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 234b67da448..3dc6b1aee22 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -6,6 +6,7 @@ #include "noc_data_types.h" #include "vtr_hash.h" #include "vtr_vector.h" +#include "clustered_netlist_fwd.h" vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, int seed); @@ -19,6 +20,16 @@ struct hash> { return seed; } }; + +template<> +struct hash> { + std::size_t operator()(const std::pair& block_router) const noexcept { + std::size_t seed = std::hash{}(block_router.first); + vtr::hash_combine(seed, block_router.second); + return seed; + } +}; + } // namespace std From e1af609998f1c0681840ab092dd3a40f543aedfe Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 13 Mar 2024 13:54:06 -0400 Subject: [PATCH 13/38] add noc_sat_place_and_route() --- vpr/src/noc/sat_routing.cpp | 181 ++++++++++++++++++++---- vpr/src/noc/sat_routing.h | 7 + vpr/src/place/initial_noc_placement.cpp | 65 ++++++--- 3 files changed, 202 insertions(+), 51 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index d8c76c79b46..e4c529fadb6 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -164,7 +164,7 @@ static void add_distance_constraints(t_flow_link_var_map& flow_link_vars, const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); // Get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); + const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); // Get the compressed grid for NoC const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; @@ -386,10 +386,6 @@ vtr::vector> noc_sat_route(bool minimiz int seed) { vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& noc_model = noc_ctx.noc_model; - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - // Used to add variables and constraints to a CP-SAT model operations_research::sat::CpModelBuilder cp_model; @@ -479,23 +475,26 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const auto& place_ctx = g_vpr_ctx.placement(); - auto& cluster_ctx = g_vpr_ctx.clustering(); + const auto& cluster_ctx = g_vpr_ctx.clustering(); - // Get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); + // get the logical block type for router + const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); - // Get the compressed grid for NoC + // get the compressed grid for NoC const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; std::unordered_map, operations_research::sat::BoolVar> logical_physical_mapped; - for (auto& [key, x_loc_var] : x_loc_vars) { - auto& y_loc_var = y_loc_vars[key]; + // Create a boolean variable for each physical and logical NoC router pair + // When set, this variable indicates that the logical NoC router is mapped + // to its corresponding logical router + for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { + auto& y_loc_var = y_loc_vars[router_blk_id]; for (auto noc_router_id : noc_model.get_noc_routers().keys()) { const auto& noc_router = noc_model.get_single_noc_router(noc_router_id); const auto noc_router_pos = noc_router.get_router_physical_location(); - auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; + const auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; operations_research::sat::BoolVar x_condition = cp_model.NewBoolVar(); cp_model.AddEquality(x_loc_var, compressed_loc.x).OnlyEnforceIf(x_condition); @@ -510,10 +509,16 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va cp_model.AddBoolAnd({x_condition, y_condition}).OnlyEnforceIf(both_conds_met); cp_model.AddBoolOr({Not(x_condition), Not(y_condition)}).OnlyEnforceIf(Not(both_conds_met)); - logical_physical_mapped[{key, noc_router_id}] = both_conds_met; + logical_physical_mapped[{router_blk_id, noc_router_id}] = both_conds_met; } } + /* + * Iterate over all traffic flows and physical NoC routers + * apply a constraint on the number of activated incoming and outgoing + * links based on whether the NoC router is the source or destination + * (or neither) of the traffic flow. + */ for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); @@ -521,48 +526,118 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; - // each NoC router has at most one incoming and one outgoing link activated for (auto noc_router_id : noc_ctx.noc_model.get_noc_routers().keys()) { auto& src_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; - auto& dst_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; + auto& dst_is_mapped = logical_physical_mapped[{logical_sink_router_block_id, noc_router_id}]; operations_research::sat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); - cp_model.AddImplication(src_is_mapped , nor_src_dst_mapped.Not()); cp_model.AddImplication(dst_is_mapped , nor_src_dst_mapped.Not()); cp_model.AddBoolOr({src_is_mapped.Not(), dst_is_mapped.Not()}).OnlyEnforceIf(nor_src_dst_mapped); const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); - cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); - cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); - cp_model.AddEquality(operations_research::sat::LinearExpr::Sum(vars), 0).OnlyEnforceIf(src_is_mapped); - - operations_research::sat::LinearExpr lhs; - lhs = operations_research::sat::LinearExpr::Sum(vars); +// cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); +// cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); + operations_research::sat::LinearExpr lhs = operations_research::sat::LinearExpr::Sum(vars); + cp_model.AddEquality(lhs, 0).OnlyEnforceIf(src_is_mapped); + cp_model.AddLessOrEqual(lhs, 1).OnlyEnforceIf(nor_src_dst_mapped); + cp_model.AddEquality(lhs, 1).OnlyEnforceIf(dst_is_mapped); const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); - cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); - cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); - cp_model.AddEquality(operations_research::sat::LinearExpr::Sum(vars), 0).OnlyEnforceIf(dst_is_mapped); - - operations_research::sat::LinearExpr rhs; - rhs = operations_research::sat::LinearExpr::Sum(vars); +// cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); +// cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); + operations_research::sat::LinearExpr rhs = operations_research::sat::LinearExpr::Sum(vars); + cp_model.AddEquality(rhs, 0).OnlyEnforceIf(dst_is_mapped); + cp_model.AddLessOrEqual(rhs, 1).OnlyEnforceIf(nor_src_dst_mapped); + cp_model.AddEquality(rhs, 1).OnlyEnforceIf(src_is_mapped); cp_model.AddEquality(lhs, rhs).OnlyEnforceIf(nor_src_dst_mapped); } } } +static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars, + operations_research::sat::CpModelBuilder& cp_model, + std::map& x_loc_vars, + std::map& y_loc_vars, + const std::vector& up, + const std::vector& down, + const std::vector& right, + const std::vector& left) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + // get the source and destination logical router blocks in the current traffic flow + ClusterBlockId logical_src_router_block_id = traffic_flow.source_router_cluster_id; + ClusterBlockId logical_dst_router_block_id = traffic_flow.sink_router_cluster_id; + + auto right_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, right); + auto left_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, left); + auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); + auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); + + operations_research::sat::LinearExpr horizontal_expr; + horizontal_expr += operations_research::sat::LinearExpr::Sum(right_vars) - operations_research::sat::LinearExpr::Sum(left_vars); + operations_research::sat::LinearExpr horizontal_dist_expr; + horizontal_dist_expr += x_loc_vars[logical_dst_router_block_id]; + horizontal_dist_expr -= x_loc_vars[logical_src_router_block_id]; + cp_model.AddEquality(horizontal_expr, horizontal_dist_expr); + + operations_research::sat::LinearExpr vertical_expr; + vertical_expr += operations_research::sat::LinearExpr::Sum(up_vars) - operations_research::sat::LinearExpr::Sum(down_vars); + operations_research::sat::LinearExpr vertical_dist_expr; + vertical_dist_expr += y_loc_vars[logical_dst_router_block_id]; + vertical_dist_expr -= y_loc_vars[logical_src_router_block_id]; + cp_model.AddEquality(vertical_expr, vertical_dist_expr); + } +} + +static void convert_vars_to_locs(std::map& noc_router_locs, + std::map& x_loc_vars, + std::map& y_loc_vars, + const operations_research::sat::CpSolverResponse& response) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + const auto& cluster_ctx = g_vpr_ctx.clustering(); + +// const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); + + // Get the logical block type for router + const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); + + noc_router_locs.clear(); + + VTR_ASSERT(response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || + response.status() == operations_research::sat::CpSolverStatus::OPTIMAL); + + for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { + auto& y_loc_var = y_loc_vars[router_blk_id]; + int x_value = (int)operations_research::sat::SolutionIntegerValue(response, x_loc_var); + int y_value = (int)operations_research::sat::SolutionIntegerValue(response, y_loc_var); + + t_pl_loc mapped_loc; + compressed_grid_to_loc(router_block_type, {x_value, y_value, 0}, mapped_loc); + noc_router_locs[router_blk_id] = mapped_loc; + } +} + void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, + std::map& noc_router_locs, bool minimize_aggregate_bandwidth, int seed) { + vtr::ScopedStartFinishTimer timer("NoC SAT Placement and Routing"); const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + traffic_flow_routes.clear(); + noc_router_locs.clear(); + operations_research::sat::CpModelBuilder cp_model; t_flow_link_var_map flow_link_vars; @@ -598,4 +673,52 @@ void noc_sat_place_and_route(vtr::vector up, down, right, left; + group_noc_links_based_on_direction(up, down, right, left); + + add_movable_distance_constraints(flow_link_vars, cp_model, x_loc_vars, y_loc_vars, up, down, right, left); + + operations_research::sat::LinearExpr latency_overrun_sum; + for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { + latency_overrun_sum += latency_overrun_var; + } + + cp_model.Minimize(latency_overrun_sum); + + operations_research::sat::SatParameters sat_params; + sat_params.set_random_seed(seed); + sat_params.set_log_search_progress(true); + + operations_research::sat::Model model; + model.Add(NewSatParameters(sat_params)); + + operations_research::sat::CpSolverResponse response = operations_research::sat::SolveCpModel(cp_model.Build(), &model); + + if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || + response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { + + if (!minimize_aggregate_bandwidth) { + traffic_flow_routes = convert_vars_to_routes(flow_link_vars, response); + convert_vars_to_locs(noc_router_locs, x_loc_vars, y_loc_vars, response); + } else { + int latency_overrun_value = (int)operations_research::sat::SolutionIntegerValue(response, latency_overrun_sum); + cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); + + auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + operations_research::sat::LinearExpr agg_bw_expr; + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; + agg_bw_expr += operations_research::sat::LinearExpr(var * rescaled_traffic_flow_bandwidths[traffic_flow_id]); + } + + cp_model.Minimize(agg_bw_expr); + response = operations_research::sat::SolveCpModel(cp_model.Build(), &model); + + if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || + response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { + traffic_flow_routes = convert_vars_to_routes(flow_link_vars, response); + convert_vars_to_locs(noc_router_locs, x_loc_vars, y_loc_vars, response); + } + } + } } \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 3dc6b1aee22..d8931789443 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -2,8 +2,10 @@ #define VTR_SATROUTING_H #include +#include #include "noc_data_types.h" +#include "vpr_types.h" #include "vtr_hash.h" #include "vtr_vector.h" #include "clustered_netlist_fwd.h" @@ -11,6 +13,11 @@ vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, int seed); +void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, + std::map& noc_router_locs, + bool minimize_aggregate_bandwidth, + int seed); + namespace std { template<> struct hash> { diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index 1396f23b8b3..fef3ff28128 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -5,6 +5,8 @@ #include "noc_place_checkpoint.h" #include "place_constraints.h" +#include "sat_routing.h" + #include "vtr_math.h" /** @@ -254,36 +256,55 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) { } void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { - auto& noc_ctx = g_vpr_ctx.noc(); +// auto& noc_ctx = g_vpr_ctx.noc(); // Get all the router clusters - const std::vector& router_blk_ids = noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist(); - - // Holds all the routers that are not fixed into a specific location by constraints - std::vector unfixed_routers; - - // Check for floorplanning constraints and place constrained NoC routers - for (auto router_blk_id : router_blk_ids) { - // The block is fixed and was placed in mark_fixed_blocks() - if (is_block_placed((router_blk_id))) { - continue; - } - - if (is_cluster_constrained(router_blk_id)) { - place_constrained_noc_router(router_blk_id); - } else { - unfixed_routers.push_back(router_blk_id); +// const std::vector& router_blk_ids = noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist(); + +// // Holds all the routers that are not fixed into a specific location by constraints +// std::vector unfixed_routers; +// +// // Check for floorplanning constraints and place constrained NoC routers +// for (auto router_blk_id : router_blk_ids) { +// // The block is fixed and was placed in mark_fixed_blocks() +// if (is_block_placed((router_blk_id))) { +// continue; +// } +// +// if (is_cluster_constrained(router_blk_id)) { +// place_constrained_noc_router(router_blk_id); +// } else { +// unfixed_routers.push_back(router_blk_id); +// } +// } +// +// // Place unconstrained NoC routers randomly +// place_noc_routers_randomly(unfixed_routers, seed); + + vtr::vector> traffic_flow_routes; + std::map noc_router_locs; + + noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, true, 4); + + for (auto& [router_blk_id, loc] : noc_router_locs) { + // Create a macro with a single member + t_pl_macro_member macro_member; + macro_member.blk_index = router_blk_id; + macro_member.offset = t_pl_offset(0, 0, 0, 0); + t_pl_macro pl_macro; + pl_macro.members.push_back(macro_member); + + bool legal = try_place_macro(pl_macro, loc); + if (!legal) { + VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Could not place a router cluster into an empty physical router."); } } - // Place unconstrained NoC routers randomly - place_noc_routers_randomly(unfixed_routers, seed); - // populate internal data structures to maintain route, bandwidth usage, and latencies - initial_noc_routing({}); + initial_noc_routing(traffic_flow_routes); // Run the simulated annealing optimizer for NoC routers - noc_routers_anneal(noc_opts); +// noc_routers_anneal(noc_opts); // check if there is any cycles bool has_cycle = noc_routing_has_cycle(); From 936f6c6db3f7f6a91556e85d13e21f5c4bd23a18 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 13 Mar 2024 15:16:57 -0400 Subject: [PATCH 14/38] remove lexicographic optimization in noc_sat_place_and_route() --- vpr/src/noc/sat_routing.cpp | 72 ++++++++++++++----------- vpr/src/noc/sat_routing.h | 2 +- vpr/src/place/initial_noc_placement.cpp | 2 +- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index e4c529fadb6..579f9f65c51 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -14,7 +14,7 @@ #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_solver.h" -static constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 1024; +static constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 128; typedef std::unordered_map, operations_research::sat::BoolVar> t_flow_link_var_map; @@ -538,8 +538,8 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); -// cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); -// cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); + // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); + // cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); operations_research::sat::LinearExpr lhs = operations_research::sat::LinearExpr::Sum(vars); cp_model.AddEquality(lhs, 0).OnlyEnforceIf(src_is_mapped); cp_model.AddLessOrEqual(lhs, 1).OnlyEnforceIf(nor_src_dst_mapped); @@ -547,8 +547,8 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); -// cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); -// cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); + // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); + // cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); operations_research::sat::LinearExpr rhs = operations_research::sat::LinearExpr::Sum(vars); cp_model.AddEquality(rhs, 0).OnlyEnforceIf(dst_is_mapped); cp_model.AddLessOrEqual(rhs, 1).OnlyEnforceIf(nor_src_dst_mapped); @@ -606,7 +606,7 @@ static void convert_vars_to_locs(std::map& noc_router_ const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const auto& cluster_ctx = g_vpr_ctx.clustering(); -// const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); + // const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); // Get the logical block type for router const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); @@ -629,7 +629,7 @@ static void convert_vars_to_locs(std::map& noc_router_ void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, std::map& noc_router_locs, - bool minimize_aggregate_bandwidth, + int seed) { vtr::ScopedStartFinishTimer timer("NoC SAT Placement and Routing"); const auto& noc_ctx = g_vpr_ctx.noc(); @@ -683,11 +683,21 @@ void noc_sat_place_and_route(vtr::vector> noc_sat_route(bool minimiz void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, std::map& noc_router_locs, - bool minimize_aggregate_bandwidth, + int seed); namespace std { diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index fef3ff28128..8bb9802bc16 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -284,7 +284,7 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { vtr::vector> traffic_flow_routes; std::map noc_router_locs; - noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, true, 4); + noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, 4); for (auto& [router_blk_id, loc] : noc_router_locs) { // Create a macro with a single member From c570313f069510d1d10d0a113d8a3f67cc0ade6e Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 13 Mar 2024 15:46:40 -0400 Subject: [PATCH 15/38] namespace alias for operations_research::sat --- vpr/src/noc/sat_routing.cpp | 199 ++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 111 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 579f9f65c51..3b432b3cf5b 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -8,20 +8,20 @@ #include - -#include "ortools/base/logging.h" #include "ortools/sat/cp_model.h" #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_solver.h" +namespace orsat = operations_research::sat; + static constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 128; -typedef std::unordered_map, operations_research::sat::BoolVar> t_flow_link_var_map; +typedef std::unordered_map, orsat::BoolVar> t_flow_link_var_map; -static std::vector get_flow_link_vars(const t_flow_link_var_map& map, - const std::vector& traffic_flow_ids, - const std::vector& noc_link_ids) { - std::vector results; +static std::vector get_flow_link_vars(const t_flow_link_var_map& map, + const std::vector& traffic_flow_ids, + const std::vector& noc_link_ids) { + std::vector results; for (auto traffic_flow_id : traffic_flow_ids) { for (auto noc_link_id : noc_link_ids) { auto it = map.find({traffic_flow_id, noc_link_id}); @@ -34,7 +34,7 @@ static std::vector get_flow_link_vars(const t } static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model) { + orsat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -73,7 +73,7 @@ static vtr::vector rescale_traffic_flow_bandwidths() { } static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model) { + orsat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -82,11 +82,11 @@ static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, // add NoC link congestion constraints for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { const NocLinkId noc_link_id = noc_link.get_link_id(); - operations_research::sat::LinearExpr lhs; + orsat::LinearExpr lhs; for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - operations_research::sat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; - lhs += operations_research::sat::LinearExpr(binary_var * rescaled_traffic_flow_bandwidths[traffic_flow_id]); + orsat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; + lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); } cp_model.AddLessOrEqual(lhs, NOC_LINK_BANDWIDTH_RESOLUTION); @@ -94,7 +94,7 @@ static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, } static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model) { + orsat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const auto& place_ctx = g_vpr_ctx.placement(); @@ -110,7 +110,7 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, NocRouterId source_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_source_router_block_id].loc); NocRouterId sink_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_sink_router_block_id].loc); - std::vector vars; + std::vector vars; // exactly one outgoing link of the source must be selected const auto& src_outgoing_link_ids = noc_ctx.noc_model.get_noc_router_outgoing_links(source_router_id); @@ -135,15 +135,15 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); cp_model.AddAtMostOne(vars); - operations_research::sat::LinearExpr lhs; - lhs = operations_research::sat::LinearExpr::Sum(vars); + orsat::LinearExpr lhs; + lhs = orsat::LinearExpr::Sum(vars); const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); cp_model.AddAtMostOne(vars); - operations_research::sat::LinearExpr rhs; - rhs = operations_research::sat::LinearExpr::Sum(vars); + orsat::LinearExpr rhs; + rhs = orsat::LinearExpr::Sum(vars); cp_model.AddEquality(lhs, rhs); } @@ -151,7 +151,7 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, } static void add_distance_constraints(t_flow_link_var_map& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model, + orsat::CpModelBuilder& cp_model, const std::vector& up, const std::vector& down, const std::vector& right, @@ -201,12 +201,12 @@ static void add_distance_constraints(t_flow_link_var_map& flow_link_vars, auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); - operations_research::sat::LinearExpr horizontal_expr; - horizontal_expr += operations_research::sat::LinearExpr::Sum(right_vars) - operations_research::sat::LinearExpr::Sum(left_vars); + orsat::LinearExpr horizontal_expr; + horizontal_expr += (orsat::LinearExpr::Sum(right_vars) - orsat::LinearExpr::Sum(left_vars)); cp_model.AddEquality(horizontal_expr, delta_x); - operations_research::sat::LinearExpr vertical_expr; - vertical_expr += operations_research::sat::LinearExpr::Sum(up_vars) - operations_research::sat::LinearExpr::Sum(down_vars); + orsat::LinearExpr vertical_expr; + vertical_expr += (orsat::LinearExpr::Sum(up_vars) - orsat::LinearExpr::Sum(down_vars)); cp_model.AddEquality(vertical_expr, delta_y); } } @@ -310,19 +310,19 @@ static std::vector sort_noc_links_in_chain_order(const std::vector> convert_vars_to_routes(t_flow_link_var_map& flow_link_vars, - const operations_research::sat::CpSolverResponse& response) { + const orsat::CpSolverResponse& response) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - VTR_ASSERT(response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || - response.status() == operations_research::sat::CpSolverStatus::OPTIMAL); + VTR_ASSERT(response.status() == orsat::CpSolverStatus::FEASIBLE || + response.status() == orsat::CpSolverStatus::OPTIMAL); vtr::vector> routes; routes.resize(traffic_flow_storage.get_number_of_traffic_flows()); for (auto& [key, var] : flow_link_vars) { auto [traffic_flow_id, noc_link_id] = key; - bool value = operations_research::sat::SolutionBooleanValue(response, var); + bool value = orsat::SolutionBooleanValue(response, var); if (value) { routes[traffic_flow_id].push_back(noc_link_id); } @@ -335,9 +335,9 @@ static vtr::vector> convert_vars_to_rou return routes; } -static void create_flow_link_vars(operations_research::sat::CpModelBuilder& cp_model, +static void create_flow_link_vars(orsat::CpModelBuilder& cp_model, t_flow_link_var_map& flow_link_vars, - std::map& latency_overrun_vars) { + std::map& latency_overrun_vars) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -363,9 +363,9 @@ static void create_flow_link_vars(operations_research::sat::CpModelBuilder& cp_m } } -static void constrain_latency_overrun_vars(operations_research::sat::CpModelBuilder& cp_model, +static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, t_flow_link_var_map& flow_link_vars, - std::map& latency_overrun_vars) { + std::map& latency_overrun_vars) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; @@ -374,8 +374,8 @@ static void constrain_latency_overrun_vars(operations_research::sat::CpModelBuil auto link_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, {noc_model.get_noc_links().keys().begin(), noc_model.get_noc_links().keys().end()}); - operations_research::sat::LinearExpr latency_overrun_expr; - latency_overrun_expr += operations_research::sat::LinearExpr::Sum(link_vars); + orsat::LinearExpr latency_overrun_expr; + latency_overrun_expr += orsat::LinearExpr::Sum(link_vars); latency_overrun_expr -= n_max_links; cp_model.AddMaxEquality(latency_overrun_var, {latency_overrun_expr, 0}); @@ -387,7 +387,7 @@ vtr::vector> noc_sat_route(bool minimiz vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); // Used to add variables and constraints to a CP-SAT model - operations_research::sat::CpModelBuilder cp_model; + orsat::CpModelBuilder cp_model; /* * For each traffic flow and NoC link pair, we create a boolean variable. @@ -402,7 +402,7 @@ vtr::vector> noc_sat_route(bool minimiz * These integer variables specify the number of additional links traversed * beyond the maximum allowed number of links. */ - std::map latency_overrun_vars; + std::map latency_overrun_vars; create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); @@ -419,45 +419,45 @@ vtr::vector> noc_sat_route(bool minimiz add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); - operations_research::sat::LinearExpr latency_overrun_sum; + orsat::LinearExpr latency_overrun_sum; for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { latency_overrun_sum += latency_overrun_var; } cp_model.Minimize(latency_overrun_sum); - operations_research::sat::Model model; + orsat::Model model; - operations_research::sat::SatParameters sat_params; + orsat::SatParameters sat_params; sat_params.set_num_workers(1); sat_params.set_random_seed(seed); model.Add(NewSatParameters(sat_params)); - operations_research::sat::CpSolverResponse response = operations_research::sat::SolveCpModel(cp_model.Build(), &model); + orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); - if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || - response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { + if (response.status() == orsat::CpSolverStatus::FEASIBLE || + response.status() == orsat::CpSolverStatus::OPTIMAL) { if (!minimize_aggregate_bandwidth) { auto routes = convert_vars_to_routes(flow_link_vars, response); return routes; } else { - int latency_overrun_value = (int)operations_research::sat::SolutionIntegerValue(response, latency_overrun_sum); + int latency_overrun_value = (int)orsat::SolutionIntegerValue(response, latency_overrun_sum); cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); - operations_research::sat::LinearExpr agg_bw_expr; + orsat::LinearExpr agg_bw_expr; for (auto& [key, var] : flow_link_vars) { auto [traffic_flow_id, noc_link_id] = key; - agg_bw_expr += operations_research::sat::LinearExpr(var * rescaled_traffic_flow_bandwidths[traffic_flow_id]); + agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); } cp_model.Minimize(agg_bw_expr); - response = operations_research::sat::Solve(cp_model.Build()); + response = orsat::Solve(cp_model.Build()); - if (response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || - response.status() == operations_research::sat::CpSolverStatus::OPTIMAL) { + if (response.status() == orsat::CpSolverStatus::FEASIBLE || + response.status() == orsat::CpSolverStatus::OPTIMAL) { auto routes = convert_vars_to_routes(flow_link_vars, response); return routes; } @@ -468,9 +468,9 @@ vtr::vector> noc_sat_route(bool minimiz } static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_vars, - std::map& x_loc_vars, - std::map& y_loc_vars, - operations_research::sat::CpModelBuilder& cp_model) { + std::map& x_loc_vars, + std::map& y_loc_vars, + orsat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -483,7 +483,7 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va // get the compressed grid for NoC const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; - std::unordered_map, operations_research::sat::BoolVar> logical_physical_mapped; + std::unordered_map, orsat::BoolVar> logical_physical_mapped; // Create a boolean variable for each physical and logical NoC router pair // When set, this variable indicates that the logical NoC router is mapped @@ -496,16 +496,16 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va const auto noc_router_pos = noc_router.get_router_physical_location(); const auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; - operations_research::sat::BoolVar x_condition = cp_model.NewBoolVar(); + orsat::BoolVar x_condition = cp_model.NewBoolVar(); cp_model.AddEquality(x_loc_var, compressed_loc.x).OnlyEnforceIf(x_condition); cp_model.AddNotEqual(x_loc_var, compressed_loc.x).OnlyEnforceIf(Not(x_condition)); - operations_research::sat::BoolVar y_condition = cp_model.NewBoolVar(); + orsat::BoolVar y_condition = cp_model.NewBoolVar(); cp_model.AddEquality(y_loc_var, compressed_loc.y).OnlyEnforceIf(y_condition); cp_model.AddNotEqual(y_loc_var, compressed_loc.y).OnlyEnforceIf(Not(y_condition)); // Combine conditions using AddBoolAnd - operations_research::sat::BoolVar both_conds_met = cp_model.NewBoolVar(); + orsat::BoolVar both_conds_met = cp_model.NewBoolVar(); cp_model.AddBoolAnd({x_condition, y_condition}).OnlyEnforceIf(both_conds_met); cp_model.AddBoolOr({Not(x_condition), Not(y_condition)}).OnlyEnforceIf(Not(both_conds_met)); @@ -531,16 +531,14 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va auto& src_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; auto& dst_is_mapped = logical_physical_mapped[{logical_sink_router_block_id, noc_router_id}]; - operations_research::sat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); - cp_model.AddImplication(src_is_mapped , nor_src_dst_mapped.Not()); - cp_model.AddImplication(dst_is_mapped , nor_src_dst_mapped.Not()); - cp_model.AddBoolOr({src_is_mapped.Not(), dst_is_mapped.Not()}).OnlyEnforceIf(nor_src_dst_mapped); + orsat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); + cp_model.AddExactlyOne({src_is_mapped, dst_is_mapped, nor_src_dst_mapped}); const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); // cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); - operations_research::sat::LinearExpr lhs = operations_research::sat::LinearExpr::Sum(vars); + orsat::LinearExpr lhs = orsat::LinearExpr::Sum(vars); cp_model.AddEquality(lhs, 0).OnlyEnforceIf(src_is_mapped); cp_model.AddLessOrEqual(lhs, 1).OnlyEnforceIf(nor_src_dst_mapped); cp_model.AddEquality(lhs, 1).OnlyEnforceIf(dst_is_mapped); @@ -549,7 +547,7 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); // cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); - operations_research::sat::LinearExpr rhs = operations_research::sat::LinearExpr::Sum(vars); + orsat::LinearExpr rhs = orsat::LinearExpr::Sum(vars); cp_model.AddEquality(rhs, 0).OnlyEnforceIf(dst_is_mapped); cp_model.AddLessOrEqual(rhs, 1).OnlyEnforceIf(nor_src_dst_mapped); cp_model.AddEquality(rhs, 1).OnlyEnforceIf(src_is_mapped); @@ -560,9 +558,9 @@ static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_va } static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars, - operations_research::sat::CpModelBuilder& cp_model, - std::map& x_loc_vars, - std::map& y_loc_vars, + orsat::CpModelBuilder& cp_model, + std::map& x_loc_vars, + std::map& y_loc_vars, const std::vector& up, const std::vector& down, const std::vector& right, @@ -582,16 +580,16 @@ static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); - operations_research::sat::LinearExpr horizontal_expr; - horizontal_expr += operations_research::sat::LinearExpr::Sum(right_vars) - operations_research::sat::LinearExpr::Sum(left_vars); - operations_research::sat::LinearExpr horizontal_dist_expr; + orsat::LinearExpr horizontal_expr; + horizontal_expr += (orsat::LinearExpr::Sum(right_vars) - orsat::LinearExpr::Sum(left_vars)); + orsat::LinearExpr horizontal_dist_expr; horizontal_dist_expr += x_loc_vars[logical_dst_router_block_id]; horizontal_dist_expr -= x_loc_vars[logical_src_router_block_id]; cp_model.AddEquality(horizontal_expr, horizontal_dist_expr); - operations_research::sat::LinearExpr vertical_expr; - vertical_expr += operations_research::sat::LinearExpr::Sum(up_vars) - operations_research::sat::LinearExpr::Sum(down_vars); - operations_research::sat::LinearExpr vertical_dist_expr; + orsat::LinearExpr vertical_expr; + vertical_expr += (orsat::LinearExpr::Sum(up_vars) - orsat::LinearExpr::Sum(down_vars)); + orsat::LinearExpr vertical_dist_expr; vertical_dist_expr += y_loc_vars[logical_dst_router_block_id]; vertical_dist_expr -= y_loc_vars[logical_src_router_block_id]; cp_model.AddEquality(vertical_expr, vertical_dist_expr); @@ -599,9 +597,9 @@ static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars } static void convert_vars_to_locs(std::map& noc_router_locs, - std::map& x_loc_vars, - std::map& y_loc_vars, - const operations_research::sat::CpSolverResponse& response) { + std::map& x_loc_vars, + std::map& y_loc_vars, + const orsat::CpSolverResponse& response) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const auto& cluster_ctx = g_vpr_ctx.clustering(); @@ -613,13 +611,13 @@ static void convert_vars_to_locs(std::map& noc_router_ noc_router_locs.clear(); - VTR_ASSERT(response.status() == operations_research::sat::CpSolverStatus::FEASIBLE || - response.status() == operations_research::sat::CpSolverStatus::OPTIMAL); + VTR_ASSERT(response.status() == orsat::CpSolverStatus::FEASIBLE || + response.status() == orsat::CpSolverStatus::OPTIMAL); for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { auto& y_loc_var = y_loc_vars[router_blk_id]; - int x_value = (int)operations_research::sat::SolutionIntegerValue(response, x_loc_var); - int y_value = (int)operations_research::sat::SolutionIntegerValue(response, y_loc_var); + int x_value = (int)orsat::SolutionIntegerValue(response, x_loc_var); + int y_value = (int)orsat::SolutionIntegerValue(response, y_loc_var); t_pl_loc mapped_loc; compressed_grid_to_loc(router_block_type, {x_value, y_value, 0}, mapped_loc); @@ -638,17 +636,17 @@ void noc_sat_place_and_route(vtr::vector latency_overrun_vars; + std::map latency_overrun_vars; const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); operations_research::Domain loc_domain(0, 9); - std::map x_loc_vars; - std::map y_loc_vars; - std::vector> loc_intervals; + std::map x_loc_vars; + std::map y_loc_vars; + std::vector> loc_intervals; for (auto router_blk_id : router_blk_ids) { @@ -659,7 +657,7 @@ void noc_sat_place_and_route(vtr::vector Date: Thu, 14 Mar 2024 20:01:01 -0400 Subject: [PATCH 16/38] replace congestion constraints with an objective to minimize the number of congested links --- vpr/src/noc/sat_routing.cpp | 130 +++++++++++++++++++++++++++++------- 1 file changed, 107 insertions(+), 23 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 3b432b3cf5b..86f1d1431c5 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -93,6 +93,31 @@ static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, } } +static void create_congested_link_vars(vtr::vector& congested_link_vars, + t_flow_link_var_map& flow_link_vars, + orsat::CpModelBuilder& cp_model) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + + // add NoC link congestion constraints + for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { + const NocLinkId noc_link_id = noc_link.get_link_id(); + orsat::LinearExpr lhs; + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + orsat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; + lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); + } + + orsat::BoolVar congested = cp_model.NewBoolVar(); + cp_model.AddLessOrEqual(lhs, NOC_LINK_BANDWIDTH_RESOLUTION).OnlyEnforceIf(congested.Not()); + cp_model.AddGreaterThan(lhs, NOC_LINK_BANDWIDTH_RESOLUTION).OnlyEnforceIf(congested); + congested_link_vars.push_back(congested); + } +} + static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, orsat::CpModelBuilder& cp_model) { const auto& noc_ctx = g_vpr_ctx.noc(); @@ -396,6 +421,8 @@ vtr::vector> noc_sat_route(bool minimiz */ t_flow_link_var_map flow_link_vars; + vtr::vector link_congested_vars; + /* * Each traffic flow latency constraint is translated to how many NoC links * the traffic flow can traverse without violating the constraint. @@ -410,7 +437,8 @@ vtr::vector> noc_sat_route(bool minimiz forbid_illegal_turns(flow_link_vars, cp_model); - add_congestion_constraints(flow_link_vars, cp_model); +// add_congestion_constraints(flow_link_vars, cp_model); + create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); add_continuity_constraints(flow_link_vars, cp_model); @@ -419,18 +447,40 @@ vtr::vector> noc_sat_route(bool minimiz add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { + cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); + } + } + orsat::LinearExpr latency_overrun_sum; for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { latency_overrun_sum += latency_overrun_var; } - cp_model.Minimize(latency_overrun_sum); + latency_overrun_sum *= 1024; + + auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + orsat::LinearExpr agg_bw_expr; + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; + agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); + } + + orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); + congested_link_sum *= (1024 * 16); + + cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); orsat::Model model; orsat::SatParameters sat_params; - sat_params.set_num_workers(1); +// sat_params.set_num_workers(1); sat_params.set_random_seed(seed); + sat_params.set_log_search_progress(true); model.Add(NewSatParameters(sat_params)); @@ -439,29 +489,29 @@ vtr::vector> noc_sat_route(bool minimiz if (response.status() == orsat::CpSolverStatus::FEASIBLE || response.status() == orsat::CpSolverStatus::OPTIMAL) { - if (!minimize_aggregate_bandwidth) { +// if (!minimize_aggregate_bandwidth) { auto routes = convert_vars_to_routes(flow_link_vars, response); return routes; - } else { - int latency_overrun_value = (int)orsat::SolutionIntegerValue(response, latency_overrun_sum); - cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); - - auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); - orsat::LinearExpr agg_bw_expr; - for (auto& [key, var] : flow_link_vars) { - auto [traffic_flow_id, noc_link_id] = key; - agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); - } +// } else { +// int latency_overrun_value = (int)orsat::SolutionIntegerValue(response, latency_overrun_sum); +// cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); + +// auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); +// orsat::LinearExpr agg_bw_expr; +// for (auto& [key, var] : flow_link_vars) { +// auto [traffic_flow_id, noc_link_id] = key; +// agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); +// } cp_model.Minimize(agg_bw_expr); response = orsat::Solve(cp_model.Build()); - if (response.status() == orsat::CpSolverStatus::FEASIBLE || - response.status() == orsat::CpSolverStatus::OPTIMAL) { - auto routes = convert_vars_to_routes(flow_link_vars, response); - return routes; - } - } +// if (response.status() == orsat::CpSolverStatus::FEASIBLE || +// response.status() == orsat::CpSolverStatus::OPTIMAL) { +// auto routes = convert_vars_to_routes(flow_link_vars, response); +// return routes; +// } +// } } return {}; @@ -625,9 +675,33 @@ static void convert_vars_to_locs(std::map& noc_router_ } } +static void constrain_fixed_noc_routers(std::map& x_loc_vars, + std::map& y_loc_vars, + orsat::CpModelBuilder& cp_model) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + const auto& place_ctx = g_vpr_ctx.mutable_placement(); + const auto& cluster_ctx = g_vpr_ctx.clustering(); + + const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); + const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); + const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; + + const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); + + for (auto router_blk_id : router_blk_ids) { + const auto& router_loc = place_ctx.block_locs[router_blk_id]; + if (router_loc.is_fixed) { + auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[router_loc.loc.layer]; + std::cout << compressed_loc.x << " " << compressed_loc.y << std::endl; + cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); + cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); + } + } +} + void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, std::map& noc_router_locs, - int seed) { vtr::ScopedStartFinishTimer timer("NoC SAT Placement and Routing"); const auto& noc_ctx = g_vpr_ctx.noc(); @@ -642,6 +716,8 @@ void noc_sat_place_and_route(vtr::vector latency_overrun_vars; + vtr::vector link_congested_vars; + const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); operations_research::Domain loc_domain(0, 9); std::map x_loc_vars; @@ -669,6 +745,9 @@ void noc_sat_place_and_route(vtr::vector up, down, right, left; @@ -676,6 +755,8 @@ void noc_sat_place_and_route(vtr::vector Date: Fri, 15 Mar 2024 11:06:01 -0400 Subject: [PATCH 17/38] add hints for cp-sat --- vpr/src/noc/sat_routing.cpp | 39 ++++++++++- vpr/src/place/initial_noc_placement.cpp | 93 +++++++++++++++---------- 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 86f1d1431c5..6abeee4b5c0 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -693,7 +693,6 @@ static void constrain_fixed_noc_routers(std::map& const auto& router_loc = place_ctx.block_locs[router_blk_id]; if (router_loc.is_fixed) { auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[router_loc.loc.layer]; - std::cout << compressed_loc.x << " " << compressed_loc.y << std::endl; cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); } @@ -706,6 +705,8 @@ void noc_sat_place_and_route(vtr::vectorindex]; + for (auto router_blk_id : router_blk_ids) { + auto router_loc = placement_ctx.block_locs[router_blk_id]; + + auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[0]; + + cp_model.AddHint(x_loc_vars[router_blk_id], compressed_loc.x); + cp_model.AddHint(y_loc_vars[router_blk_id], compressed_loc.y); +// cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); +// cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); + } + orsat::LinearExpr latency_overrun_sum; for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { latency_overrun_sum += latency_overrun_var; @@ -771,10 +790,26 @@ void noc_sat_place_and_route(vtr::vector activated_links; + for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { + cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); +// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, route_link_id}], true); + activated_links.push_back(route_link_id); + } + + for (auto noc_link_id : noc_ctx.noc_model.get_noc_links().keys()) { + if (std::find(activated_links.begin(), activated_links.end(), noc_link_id) == activated_links.end()) { + cp_model.AddHint(flow_link_vars[{traffic_flow_id, noc_link_id}], false); +// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, noc_link_id}], false); + } + } + } + orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); congested_link_sum *= (1024 * 16); - cp_model.Minimize(latency_overrun_sum + agg_bw_expr); + cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); orsat::SatParameters sat_params; sat_params.set_random_seed(seed); diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index 8bb9802bc16..47184b688ac 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -8,6 +8,7 @@ #include "sat_routing.h" #include "vtr_math.h" +#include "vtr_time.h" /** * @brief Evaluates whether a NoC router swap should be accepted or not. @@ -251,42 +252,76 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) { << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth << " Latency: " << costs.noc_cost_terms.latency << " Latency Over: " << costs.noc_cost_terms.latency_overrun - << " Congestion: " << costs.noc_cost_terms.congestion << std::endl; + << " Congestion: " << costs.noc_cost_terms.congestion + << " Congested Links: " << get_number_of_congested_noc_links() << std::endl; } void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { -// auto& noc_ctx = g_vpr_ctx.noc(); + vtr::ScopedStartFinishTimer timer("Initial NoC Placement"); + auto& noc_ctx = g_vpr_ctx.noc(); // Get all the router clusters -// const std::vector& router_blk_ids = noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist(); - -// // Holds all the routers that are not fixed into a specific location by constraints -// std::vector unfixed_routers; -// -// // Check for floorplanning constraints and place constrained NoC routers -// for (auto router_blk_id : router_blk_ids) { -// // The block is fixed and was placed in mark_fixed_blocks() -// if (is_block_placed((router_blk_id))) { -// continue; -// } + const std::vector& router_blk_ids = noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist(); // -// if (is_cluster_constrained(router_blk_id)) { -// place_constrained_noc_router(router_blk_id); -// } else { -// unfixed_routers.push_back(router_blk_id); -// } -// } -// -// // Place unconstrained NoC routers randomly -// place_noc_routers_randomly(unfixed_routers, seed); + // Holds all the routers that are not fixed into a specific location by constraints + std::vector unfixed_routers; + + // Check for floorplanning constraints and place constrained NoC routers + for (auto router_blk_id : router_blk_ids) { + // The block is fixed and was placed in mark_fixed_blocks() + if (is_block_placed((router_blk_id))) { + continue; + } + + if (is_cluster_constrained(router_blk_id)) { + place_constrained_noc_router(router_blk_id); + } else { + unfixed_routers.push_back(router_blk_id); + } + } + + // Place unconstrained NoC routers randomly + place_noc_routers_randomly(unfixed_routers, seed); + + // populate internal data structures to maintain route, bandwidth usage, and latencies + initial_noc_routing({}); + + // Run the simulated annealing optimizer for NoC routers + noc_routers_anneal(noc_opts); + + // check if there is any cycles + bool has_cycle = noc_routing_has_cycle(); + if (has_cycle) { + VPR_FATAL_ERROR(VPR_ERROR_PLACE, + "At least one cycle was found in NoC channel dependency graph. This may cause a deadlock " + "when packets wait on each other in a cycle.\n"); + } + + + + const auto& placement_ctx = g_vpr_ctx.placement(); vtr::vector> traffic_flow_routes; std::map noc_router_locs; noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, 4); + t_placer_costs costs; + reinitialize_noc_routing(costs, traffic_flow_routes); + + std::cout << "Initial NoC placement costs: " + << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth + << " Latency: " << costs.noc_cost_terms.latency + << " Latency Over: " << costs.noc_cost_terms.latency_overrun + << " Congestion: " << costs.noc_cost_terms.congestion + << " Congested Links: " << get_number_of_congested_noc_links() << std::endl; + for (auto& [router_blk_id, loc] : noc_router_locs) { + if (placement_ctx.block_locs[router_blk_id].is_fixed) { + continue; + } + // Create a macro with a single member t_pl_macro_member macro_member; macro_member.blk_index = router_blk_id; @@ -299,18 +334,4 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Could not place a router cluster into an empty physical router."); } } - - // populate internal data structures to maintain route, bandwidth usage, and latencies - initial_noc_routing(traffic_flow_routes); - - // Run the simulated annealing optimizer for NoC routers -// noc_routers_anneal(noc_opts); - - // check if there is any cycles - bool has_cycle = noc_routing_has_cycle(); - if (has_cycle) { - VPR_FATAL_ERROR(VPR_ERROR_PLACE, - "At least one cycle was found in NoC channel dependency graph. This may cause a deadlock " - "when packets wait on each other in a cycle.\n"); - } } \ No newline at end of file From 6d5679199080152025e6a25c97e29ccb82a73282 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 15 Mar 2024 12:19:18 -0400 Subject: [PATCH 18/38] report NoC metrics after sat routing --- vpr/src/place/initial_noc_placement.cpp | 78 +++++++++++-------------- vpr/src/place/place.cpp | 47 +-------------- vtr_flow/parse/parse_config/vpr_noc.txt | 8 +++ 3 files changed, 45 insertions(+), 88 deletions(-) diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index 47184b688ac..c412a612e24 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -247,14 +247,6 @@ static void noc_routers_anneal(const t_noc_opts& noc_opts) { if (checkpoint.get_cost() < costs.cost) { checkpoint.restore_checkpoint(costs); } - - std::cout << "Initial NoC placement costs: " - << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth - << " Latency: " << costs.noc_cost_terms.latency - << " Latency Over: " << costs.noc_cost_terms.latency_overrun - << " Congestion: " << costs.noc_cost_terms.congestion - << " Congested Links: " << get_number_of_congested_noc_links() << std::endl; - } void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { @@ -298,40 +290,38 @@ void initial_noc_placement(const t_noc_opts& noc_opts, int seed) { "when packets wait on each other in a cycle.\n"); } - - - const auto& placement_ctx = g_vpr_ctx.placement(); - - vtr::vector> traffic_flow_routes; - std::map noc_router_locs; - - noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, 4); - - t_placer_costs costs; - reinitialize_noc_routing(costs, traffic_flow_routes); - - std::cout << "Initial NoC placement costs: " - << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth - << " Latency: " << costs.noc_cost_terms.latency - << " Latency Over: " << costs.noc_cost_terms.latency_overrun - << " Congestion: " << costs.noc_cost_terms.congestion - << " Congested Links: " << get_number_of_congested_noc_links() << std::endl; - - for (auto& [router_blk_id, loc] : noc_router_locs) { - if (placement_ctx.block_locs[router_blk_id].is_fixed) { - continue; - } - - // Create a macro with a single member - t_pl_macro_member macro_member; - macro_member.blk_index = router_blk_id; - macro_member.offset = t_pl_offset(0, 0, 0, 0); - t_pl_macro pl_macro; - pl_macro.members.push_back(macro_member); - - bool legal = try_place_macro(pl_macro, loc); - if (!legal) { - VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Could not place a router cluster into an empty physical router."); - } - } +// const auto& placement_ctx = g_vpr_ctx.placement(); +// +// vtr::vector> traffic_flow_routes; +// std::map noc_router_locs; +// +// noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, 4); +// +// t_placer_costs costs; +// reinitialize_noc_routing(costs, traffic_flow_routes); +// +// std::cout << "Initial NoC placement costs: " +// << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth +// << " Latency: " << costs.noc_cost_terms.latency +// << " Latency Over: " << costs.noc_cost_terms.latency_overrun +// << " Congestion: " << costs.noc_cost_terms.congestion +// << " Congested Links: " << get_number_of_congested_noc_links() << std::endl; +// +// for (auto& [router_blk_id, loc] : noc_router_locs) { +// if (placement_ctx.block_locs[router_blk_id].is_fixed) { +// continue; +// } +// +// // Create a macro with a single member +// t_pl_macro_member macro_member; +// macro_member.blk_index = router_blk_id; +// macro_member.offset = t_pl_offset(0, 0, 0, 0); +// t_pl_macro pl_macro; +// pl_macro.members.push_back(macro_member); +// +// bool legal = try_place_macro(pl_macro, loc); +// if (!legal) { +// VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Could not place a router cluster into an empty physical router."); +// } +// } } \ No newline at end of file diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 2b2d8142856..6e1c69194ed 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -823,11 +823,11 @@ void try_place(const Netlist<>& net_list, placer_opts.place_algorithm, noc_opts); - //Initial pacement statistics + //Initial placement statistics VTR_LOG("Initial placement cost: %g bb_cost: %g td_cost: %g\n", costs.cost, costs.bb_cost, costs.timing_cost); if (noc_opts.noc) { - VTR_LOG("NoC Placement Costs. " + VTR_LOG("Initial NoC Placement Costs. " "cost: %g, " "aggregate_bandwidth_cost: %g, " "latency_cost: %g, " @@ -875,29 +875,7 @@ void try_place(const Netlist<>& net_list, sprintf(msg, "Initial Placement. Cost: %g BB Cost: %g TD Cost %g \t Channel Factor: %d", costs.cost, costs.bb_cost, costs.timing_cost, width_fac); - if (noc_opts.noc) { - sprintf(msg, - "\nInitial NoC Placement Costs. " - "cost: %g, " - "aggregate_bandwidth_cost: %g, " - "latency_cost: %g, " - "n_met_latency_constraints: %d, " - "latency_overrun_cost: %g, " - "congestion_cost: %g, " - "accum_congested_ratio: %g, " - "n_congested_links: %d \n", - calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), - costs.noc_cost_terms.aggregate_bandwidth, - costs.noc_cost_terms.latency, - get_number_of_traffic_flows_with_latency_cons_met(), - costs.noc_cost_terms.latency_overrun, - costs.noc_cost_terms.congestion, - get_total_congestion_bandwidth_ratio(), - get_number_of_congested_noc_links()); - - - } //Draw the initial placement update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); @@ -1206,25 +1184,6 @@ void try_place(const Netlist<>& net_list, costs.bb_cost, costs.timing_cost); // print the noc costs info if (noc_opts.noc) { - sprintf(msg, - "\nNoC Placement Costs. " - "cost: %g, " - "aggregate_bandwidth_cost: %g, " - "latency_cost: %g, " - "n_met_latency_constraints: %d, " - "latency_overrun_cost: %g, " - "congestion_cost: %g, " - "accum_congested_ratio: %g, " - "n_congested_links: %d \n", - calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), - costs.noc_cost_terms.aggregate_bandwidth, - costs.noc_cost_terms.latency, - get_number_of_traffic_flows_with_latency_cons_met(), - costs.noc_cost_terms.latency_overrun, - costs.noc_cost_terms.congestion, - get_total_congestion_bandwidth_ratio(), - get_number_of_congested_noc_links()); - VTR_LOG("\nNoC Placement Costs. " "cost: %g, " "aggregate_bandwidth_cost: %g, " @@ -3392,7 +3351,7 @@ static void update_bb(ClusterNetId net_id, bb_edge_new.xmax = curr_bb_edge->xmax - 1; bb_coord_new.xmax = curr_bb_coord->xmax; } - } else { /* Move to left, old postion was not at xmax. */ + } else { /* Move to left, old position was not at xmax. */ bb_coord_new.xmax = curr_bb_coord->xmax; bb_edge_new.xmax = curr_bb_edge->xmax; } diff --git a/vtr_flow/parse/parse_config/vpr_noc.txt b/vtr_flow/parse/parse_config/vpr_noc.txt index 51b7c194712..5a916529cac 100644 --- a/vtr_flow/parse/parse_config/vpr_noc.txt +++ b/vtr_flow/parse/parse_config/vpr_noc.txt @@ -18,3 +18,11 @@ NoC_latency_overrun;vpr.out;NoC Placement Costs. cost: .*, aggregate_bandwidth_c NoC_congested_bw;vpr.out;NoC Placement Costs. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: (.*), accum_congested_ratio: .*, n_congested_links: .* NoC_congestion_ratio;vpr.out;NoC Placement Costs. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: (.*), n_congested_links: .* NoC_n_congested_links;vpr.out;NoC Placement Costs. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: .*, n_congested_links: (.*) +SAT_agg_bandwidth;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: (.*), latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: .*, n_congested_links: .* +SAT_latency;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: (.*), n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: .*, n_congested_links: .* +SAT_n_met_latency_constraints;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: (.*), latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: .*, n_congested_links: .* +SAT_latency_overrun;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: (.*), congestion_cost: .*, accum_congested_ratio: .*, n_congested_links: .* +SAT_congested_bw;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: (.*), accum_congested_ratio: .*, n_congested_links: .* +SAT_congestion_ratio;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: (.*), n_congested_links: .* +SAT_n_congested_links;vpr.out;NoC Placement Costs after SAT routing. cost: .*, aggregate_bandwidth_cost: .*, latency_cost: .*, n_met_latency_constraints: .*, latency_overrun_cost: .*, congestion_cost: .*, accum_congested_ratio: .*, n_congested_links: (.*) + From 7d7c2f820d8e6c66da3b0029887098740d9e5a7c Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 19 Mar 2024 10:44:47 -0400 Subject: [PATCH 19/38] types and const ref --- vpr/src/base/place_and_route.cpp | 8 ++++---- vpr/src/base/place_and_route.h | 4 ++-- vpr/src/base/vpr_api.cpp | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/vpr/src/base/place_and_route.cpp b/vpr/src/base/place_and_route.cpp index 186193744ce..2701b46cc09 100644 --- a/vpr/src/base/place_and_route.cpp +++ b/vpr/src/base/place_and_route.cpp @@ -65,8 +65,8 @@ int binary_search_place_and_route(const Netlist<>& placement_net_list, t_det_routing_arch* det_routing_arch, std::vector& segment_inf, NetPinsMatrix& net_delay, - std::shared_ptr timing_info, - std::shared_ptr delay_calc, + const std::shared_ptr& timing_info, + const std::shared_ptr& delay_calc, bool is_flat) { vtr::vector> best_routing; /* Saves the best routing found so far. */ int current, low, high, final; @@ -101,7 +101,7 @@ int binary_search_place_and_route(const Netlist<>& placement_net_list, graph_directionality = (det_routing_arch->directionality == BI_DIRECTIONAL ? GRAPH_BIDIR : GRAPH_UNIDIR); } - VTR_ASSERT(net_delay.size()); + VTR_ASSERT(!net_delay.empty()); if (det_routing_arch->directionality == BI_DIRECTIONAL) udsd_multiplier = 1; @@ -298,7 +298,7 @@ int binary_search_place_and_route(const Netlist<>& placement_net_list, current = current + current % udsd_multiplier; } - /* The binary search above occassionally does not find the minimum * + /* The binary search above occasionally does not find the minimum * * routeable channel width. Sometimes a circuit that will not route * * in 19 channels will route in 18, due to router flukiness. If * * verify_binary_search is set, the code below will ensure that FPGAs * diff --git a/vpr/src/base/place_and_route.h b/vpr/src/base/place_and_route.h index 7a59fa02795..b4735ed8af4 100644 --- a/vpr/src/base/place_and_route.h +++ b/vpr/src/base/place_and_route.h @@ -36,8 +36,8 @@ int binary_search_place_and_route(const Netlist<>& placement_net_list, t_det_routing_arch* det_routing_arch, std::vector& segment_inf, NetPinsMatrix& net_delay, - std::shared_ptr timing_info, - std::shared_ptr delay_calc, + const std::shared_ptr& timing_info, + const std::shared_ptr& delay_calc, bool is_flat); t_chan_width init_chan(int cfactor, diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 47733286088..07535cbb591 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -507,7 +507,7 @@ void vpr_create_device_grid(const t_vpr_setup& vpr_setup, const t_arch& Arch) { if (!device_ctx.grid.limiting_resources().empty()) { std::vector limiting_block_names; for (auto blk_type : device_ctx.grid.limiting_resources()) { - limiting_block_names.push_back(blk_type->name); + limiting_block_names.emplace_back(blk_type->name); } VTR_LOG("FPGA size limited by block type(s): %s\n", vtr::join(limiting_block_names, " ").c_str()); VTR_LOG("\n"); @@ -598,7 +598,7 @@ bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) { check_netlist(packer_opts.pack_verbosity); /* Output the netlist stats to console and optionally to file. */ - writeClusteredNetlistStats(vpr_setup.FileNameOpts.write_block_usage.c_str()); + writeClusteredNetlistStats(vpr_setup.FileNameOpts.write_block_usage); // print the total number of used physical blocks for each // physical block type after finishing the packing stage @@ -1422,15 +1422,15 @@ void vpr_analysis(const Netlist<>& net_list, generate_setup_timing_stats(/*prefix=*/"", *timing_info, *analysis_delay_calc, vpr_setup.AnalysisOpts, vpr_setup.RouterOpts.flat_routing); - //Write the post-syntesis netlist + //Write the post-synthesis netlist if (vpr_setup.AnalysisOpts.gen_post_synthesis_netlist) { - netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc, + netlist_writer(atom_ctx.nlist.netlist_name(), analysis_delay_calc, vpr_setup.AnalysisOpts); } //Write the post-implementation merged netlist if (vpr_setup.AnalysisOpts.gen_post_implementation_merged_netlist) { - merged_netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc, vpr_setup.AnalysisOpts); + merged_netlist_writer(atom_ctx.nlist.netlist_name(), analysis_delay_calc, vpr_setup.AnalysisOpts); } //Do power analysis From 0bf839cdd08e55d7071a0fc66443ede1382203e4 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 23 May 2024 13:03:05 -0400 Subject: [PATCH 20/38] add comments --- vpr/src/noc/sat_routing.cpp | 350 +++++++++++++++++++------------ vpr/src/noc/sat_routing.h | 15 +- vpr/src/noc/turn_model_routing.h | 18 ++ 3 files changed, 252 insertions(+), 131 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 6abeee4b5c0..e47debfac4f 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -16,8 +16,89 @@ namespace orsat = operations_research::sat; static constexpr int NOC_LINK_BANDWIDTH_RESOLUTION = 128; +/** + * For each traffic flow and NoC link pair, we create a boolean variable. + * When a variable associated with traffic flow t and NoC link l is set, + * it means that t is routed through l. + */ typedef std::unordered_map, orsat::BoolVar> t_flow_link_var_map; + +/** + * @brief Creates a boolean variable for each (traffic flow, link) pair. + * It also create integer variables for latency-constrained traffic flows. + * + * @param cp_model The CP model builder object. Created variables are added + * to this model builder object. + * @param flow_link_vars The created boolean variables for (traffic flow, link) pairs + * are stored in this container to be used for adding constraints and defining objective + * functions. + * @param latency_overrun_vars The created integer variables for latency-constrained + * traffic flows are added to this container for future use, e.g. adding constraints + * and defining objective functions. + */ +static void create_flow_link_vars(orsat::CpModelBuilder& cp_model, + t_flow_link_var_map& flow_link_vars, + std::map& latency_overrun_vars); + +/** + * @brief Translates a latency constraint for a traffic flow to the maximum number + * of links that the traffic flow can traverse without violating the latency constraint. + * + * @param traffic_flow_id The unique ID of the latency-constrained traffic flow. + * @return The maximum number links that can travelled by the given traffic flow without + * violating the latency constraint. + */ +static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id); + +/** + * @brief Performs an outer product between traffic_flow_ids and noc_link_ids + * and returns all boolean variables for the resulting (traffic flow, link) pairs. + * + * @param map The container that stores all boolean variables for all + * (traffic flow, link) pairs. + * @param traffic_flow_ids Traffic flows whose boolean variables are requested. + * @param noc_link_ids NoC links whose boolean variables are requested. + * @return A vector of boolean variables for the requested (traffic flow, link) pairs. + */ +static std::vector get_flow_link_vars(const t_flow_link_var_map& map, + const std::vector& traffic_flow_ids, + const std::vector& noc_link_ids); + +/** + * @brief Adds constraints for latency_overrun_vars variables to make sure + * that they count the number of extra links a traffic flow is traversing + * beyond what its latency constraint allows. For example, if a traffic flow + * latency constraint allows the traffic flow to traverse at most 3 links, + * but 4 (traffic flow, link) boolean variables are activated for this traffic flow, + * the corresponding integer variable in latency_overrun_vars should take a value + * of 1 because an extra link beyond the maximum 3 links has been activated. + * + * @param cp_model The CP model builder object. Created variables are added + * to this model builder object. + * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. + * @param latency_overrun_vars The integer variables that are to be constrained. + */ +static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, + t_flow_link_var_map& flow_link_vars, + std::map& latency_overrun_vars); + +/** + * @brief Forbids specific turns that traffic flows can take. + * Turn model routing algorithms forbid specific turns in a mesh topology + * to make sure that deadlock does not happen. A turn can be determined by + * specifying two consecutive links. A turn can be forbidden in the SAT + * formulation by making sure that at most one of two consecutive links + * that specify a turn is activated. + * + * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. + * @param cp_model The CP model builder object. Created variables are added + * to this model builder object. + */ +static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, + orsat::CpModelBuilder& cp_model); + + static std::vector get_flow_link_vars(const t_flow_link_var_map& map, const std::vector& traffic_flow_ids, const std::vector& noc_link_ids) { @@ -30,6 +111,7 @@ static std::vector get_flow_link_vars(const t_flow_link_var_map& } } } + return results; } @@ -39,6 +121,7 @@ static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; auto noc_routing_alg = dynamic_cast (noc_ctx.noc_flows_router.get()); + // ensure that the routing algorithm is a turn model algorithm VTR_ASSERT(noc_routing_alg != nullptr); // forbid illegal turns based on the routing algorithm @@ -47,6 +130,7 @@ static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { auto& first_var = flow_link_vars[{traffic_flow_id, link1}]; auto& second_var = flow_link_vars[{traffic_flow_id, link2}]; + // at most one of two consecutive links that form a turn can be activated cp_model.AddBoolOr({first_var.Not(), second_var.Not()}); } } @@ -270,26 +354,6 @@ static void group_noc_links_based_on_direction(std::vector& up, } } -static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& noc_model = noc_ctx.noc_model; - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - - const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); - - const double noc_link_latency = noc_model.get_noc_link_latency(); - const double noc_router_latency = noc_model.get_noc_router_latency(); - const double traffic_flow_latency_constraint = traffic_flow.max_traffic_flow_latency; - - VTR_ASSERT(traffic_flow_latency_constraint < 0.1); - - int n_max_links = std::floor((traffic_flow_latency_constraint - noc_router_latency) / (noc_link_latency + noc_router_latency)); - - return n_max_links; - -} - - static std::vector sort_noc_links_in_chain_order(const std::vector& links) { std::vector route; if (links.empty()) { @@ -388,6 +452,24 @@ static void create_flow_link_vars(orsat::CpModelBuilder& cp_model, } } +static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& noc_model = noc_ctx.noc_model; + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + + const double noc_link_latency = noc_model.get_noc_link_latency(); + const double noc_router_latency = noc_model.get_noc_router_latency(); + const double traffic_flow_latency_constraint = traffic_flow.max_traffic_flow_latency; + + VTR_ASSERT(traffic_flow_latency_constraint < 0.1); + + int n_max_links = std::floor((traffic_flow_latency_constraint - noc_router_latency) / (noc_link_latency + noc_router_latency)); + + return n_max_links; +} + static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, t_flow_link_var_map& flow_link_vars, std::map& latency_overrun_vars) { @@ -396,127 +478,23 @@ static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { int n_max_links = comp_max_number_of_traversed_links(traffic_flow_id); + // get all boolean variables for this traffic flow auto link_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, {noc_model.get_noc_links().keys().begin(), noc_model.get_noc_links().keys().end()}); orsat::LinearExpr latency_overrun_expr; + // count the number of activated links for this traffic flow latency_overrun_expr += orsat::LinearExpr::Sum(link_vars); + // subtract the maximum number of permissible links from the number of activated links latency_overrun_expr -= n_max_links; + // if latency_overrun_expr is non-positive, the latency constraint is met and + // latency_overrun_var should be zero. Otherwise, should be equal to latency_overrun_expr + // This is like pushing latency_overrun_expr through a ReLU function to get latency_overrun_var. cp_model.AddMaxEquality(latency_overrun_var, {latency_overrun_expr, 0}); } } -vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, - int seed) { - vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); - - // Used to add variables and constraints to a CP-SAT model - orsat::CpModelBuilder cp_model; - - /* - * For each traffic flow and NoC link pair, we create a boolean variable. - * When a variable associated with traffic flow t and NoC link l is set, - * it means that t is routed through l. - */ - t_flow_link_var_map flow_link_vars; - - vtr::vector link_congested_vars; - - /* - * Each traffic flow latency constraint is translated to how many NoC links - * the traffic flow can traverse without violating the constraint. - * These integer variables specify the number of additional links traversed - * beyond the maximum allowed number of links. - */ - std::map latency_overrun_vars; - - create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); - - constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); - - forbid_illegal_turns(flow_link_vars, cp_model); - -// add_congestion_constraints(flow_link_vars, cp_model); - create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); - - add_continuity_constraints(flow_link_vars, cp_model); - - std::vector up, down, right, left; - group_noc_links_based_on_direction(up, down, right, left); - - add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); - - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { - cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); - } - } - - orsat::LinearExpr latency_overrun_sum; - for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { - latency_overrun_sum += latency_overrun_var; - } - - latency_overrun_sum *= 1024; - - auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); - orsat::LinearExpr agg_bw_expr; - for (auto& [key, var] : flow_link_vars) { - auto [traffic_flow_id, noc_link_id] = key; - agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); - } - - orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); - congested_link_sum *= (1024 * 16); - - cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); - - orsat::Model model; - - orsat::SatParameters sat_params; -// sat_params.set_num_workers(1); - sat_params.set_random_seed(seed); - sat_params.set_log_search_progress(true); - - model.Add(NewSatParameters(sat_params)); - - orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); - - if (response.status() == orsat::CpSolverStatus::FEASIBLE || - response.status() == orsat::CpSolverStatus::OPTIMAL) { - -// if (!minimize_aggregate_bandwidth) { - auto routes = convert_vars_to_routes(flow_link_vars, response); - return routes; -// } else { -// int latency_overrun_value = (int)orsat::SolutionIntegerValue(response, latency_overrun_sum); -// cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); - -// auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); -// orsat::LinearExpr agg_bw_expr; -// for (auto& [key, var] : flow_link_vars) { -// auto [traffic_flow_id, noc_link_id] = key; -// agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); -// } - - cp_model.Minimize(agg_bw_expr); - response = orsat::Solve(cp_model.Build()); - -// if (response.status() == orsat::CpSolverStatus::FEASIBLE || -// response.status() == orsat::CpSolverStatus::OPTIMAL) { -// auto routes = convert_vars_to_routes(flow_link_vars, response); -// return routes; -// } -// } - } - - return {}; -} - static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_vars, std::map& x_loc_vars, std::map& y_loc_vars, @@ -827,4 +805,116 @@ void noc_sat_place_and_route(vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, + int seed) { + vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); + + // Used to add variables and constraints to a CP-SAT model + orsat::CpModelBuilder cp_model; + + /* For each traffic flow and NoC link pair, we create a boolean variable. + * When a variable associated with traffic flow t and NoC link l is set, + * it means that t is routed through l.*/ + t_flow_link_var_map flow_link_vars; + + /* A boolean variable is associated with each NoC link to indicate + * whether it is congested.*/ + vtr::vector link_congested_vars; + + /* Each traffic flow latency constraint is translated to how many NoC links + * the traffic flow can traverse without violating the constraint. + * These integer variables specify the number of additional links traversed + * beyond the maximum allowed number of links. + */ + std::map latency_overrun_vars; + + create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); + + constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); + + forbid_illegal_turns(flow_link_vars, cp_model); + + // add_congestion_constraints(flow_link_vars, cp_model); + create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); + + add_continuity_constraints(flow_link_vars, cp_model); + + std::vector up, down, right, left; + group_noc_links_based_on_direction(up, down, right, left); + + add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); + + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { + cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); + } + } + + orsat::LinearExpr latency_overrun_sum; + for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { + latency_overrun_sum += latency_overrun_var; + } + + latency_overrun_sum *= 1024; + + auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + orsat::LinearExpr agg_bw_expr; + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; + agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); + } + + orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); + congested_link_sum *= (1024 * 16); + + cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); + + orsat::Model model; + + orsat::SatParameters sat_params; + // sat_params.set_num_workers(1); + sat_params.set_random_seed(seed); + sat_params.set_log_search_progress(true); + + model.Add(NewSatParameters(sat_params)); + + orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); + + if (response.status() == orsat::CpSolverStatus::FEASIBLE || + response.status() == orsat::CpSolverStatus::OPTIMAL) { + + // if (!minimize_aggregate_bandwidth) { + auto routes = convert_vars_to_routes(flow_link_vars, response); + return routes; + // } else { + // int latency_overrun_value = (int)orsat::SolutionIntegerValue(response, latency_overrun_sum); + // cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); + + // auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + // orsat::LinearExpr agg_bw_expr; + // for (auto& [key, var] : flow_link_vars) { + // auto [traffic_flow_id, noc_link_id] = key; + // agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); + // } + + cp_model.Minimize(agg_bw_expr); + response = orsat::Solve(cp_model.Build()); + + // if (response.status() == orsat::CpSolverStatus::FEASIBLE || + // response.status() == orsat::CpSolverStatus::OPTIMAL) { + // auto routes = convert_vars_to_routes(flow_link_vars, response); + // return routes; + // } + // } + } + + return {}; } \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 1cae5eae311..5e53a33b345 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -10,12 +10,25 @@ #include "vtr_vector.h" #include "clustered_netlist_fwd.h" +/** + * @brief Assuming that logical NoC routers are fixed, + * this function formulates routing traffic flows as a SAT + * problem and tries to find a deadlock-free and congestion-free + * routing with the minimum aggregate bandwidth while meeting + * traffic flow latency constraints. + * + * @param minimize_aggregate_bandwidth Indicates whether the SAT solver + * should minimize the aggregate bandwidth or not. A congestion-free + * and deadlock-free solution can be found faster if the solver does not + * need to minimize the aggregate bandwidth. + * @param seed An integer seed to initialize the SAT solver. + * @return The generated routes for all traffic flows. + */ vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, int seed); void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, std::map& noc_router_locs, - int seed); namespace std { diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 2c879b4f5c7..68d64f4e12f 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -91,6 +91,15 @@ class TurnModelRouting : public NocRouting { std::vector& flow_route, const NocStorage& noc_model) override; + /** + * @brief Turn model algorithms forbid specific turns in the mesh topology + * to guarantee deadlock-freedom. This function finds all illegal turns + * implied by a turn model routing algorithm. + * + * @param noc_model Contains NoC router and link connectivity information. + * @return A vector of std::pair. In each pair, + * a traffic flow cannot traverse the second link after the first link. + */ std::vector> get_all_illegal_turns(const NocStorage& noc_model) const; protected: @@ -240,6 +249,15 @@ class TurnModelRouting : public NocRouting { const NocStorage& noc_model) = 0; + /** + * @brief Determines whether a turn specified by 3 NoC routers visited in the turn + * is legal. Turn model routing algorithms forbid specific turns in the mesh topology + * to guarantee deadlock-freedom. In addition to turns forbidden by the turn model algorithm, + * 180-degree turns are also illegal. + * + * @param noc_routers Three NoC routers visited in a turn. + * @return True if the turn is legal, otherwise false. + */ virtual bool is_turn_legal(const std::array, 3>& noc_routers) const = 0; protected: From edf3191fba54c66ff4ed8c1cce478085d3d70536 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 23 May 2024 13:24:41 -0400 Subject: [PATCH 21/38] add --noc_sat_routing_bandwidth_resolution command line option --- vpr/src/base/SetupVPR.cpp | 1 + vpr/src/base/ShowSetup.cpp | 1 + vpr/src/base/read_options.cpp | 8 + vpr/src/base/read_options.h | 1 + vpr/src/base/vpr_types.h | 1 + vpr/src/noc/sat_routing.cpp | 285 +++++++++++++++++----------------- vpr/src/noc/sat_routing.h | 7 +- vpr/src/place/place.cpp | 2 +- 8 files changed, 160 insertions(+), 146 deletions(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 99368f3093d..1d11785eb22 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -740,6 +740,7 @@ static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { NocOpts->noc_latency_weighting = Options.noc_latency_weighting; NocOpts->noc_congestion_weighting = Options.noc_congestion_weighting; NocOpts->noc_swap_percentage = Options.noc_swap_percentage; + NocOpts->noc_sat_routing_bandwidth_resolution = Options.noc_sat_routing_bandwidth_resolution; NocOpts->noc_placement_file_name = Options.noc_placement_file_name; } diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 9a35246287a..db003a74308 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -800,6 +800,7 @@ static void ShowNocOpts(const t_noc_opts& NocOpts) { VTR_LOG("NocOpts.noc_latency_weighting: %f\n", NocOpts.noc_latency_weighting); VTR_LOG("NocOpts.noc_congestion_weighting: %f\n", NocOpts.noc_congestion_weighting); VTR_LOG("NocOpts.noc_swap_percentage: %d%%\n", NocOpts.noc_swap_percentage); + VTR_LOG("NocOpts.noc_sat_routing_bandwidth_resolution: %d\n", NocOpts.noc_sat_routing_bandwidth_resolution); VTR_LOG("NocOpts.noc_routing_algorithm: %s\n", NocOpts.noc_placement_file_name.c_str()); VTR_LOG("\n"); } \ No newline at end of file diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index bd181078c34..9cc0bf71bee 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2867,6 +2867,14 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("0") .show_in(argparse::ShowIn::HELP_ONLY); + noc_grp.add_argument(args.noc_sat_routing_bandwidth_resolution, "--noc_sat_routing_bandwidth_resolution") + .help( + "Specifies the resolution by which traffic flow bandwidths are converted into integers in SAT routing algorithm.\n" + "The higher this number is, the more accurate the congestion estimation and aggregate bandwidth minimization is.\n" + "Higher resolution for bandwidth conversion increases the number of variables in the SAT formulation.") + .default_value("128") + .show_in(argparse::ShowIn::HELP_ONLY); + noc_grp.add_argument(args.noc_placement_file_name, "--noc_placement_file_name") .help( "Name of the output file that contains the NoC placement information." diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 26505c13bc9..0b26fb26457 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -157,6 +157,7 @@ struct t_options { argparse::ArgValue noc_latency_weighting; argparse::ArgValue noc_congestion_weighting; argparse::ArgValue noc_swap_percentage; + argparse::ArgValue noc_sat_routing_bandwidth_resolution; argparse::ArgValue noc_placement_file_name; /* Timing-driven placement options only */ diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index fc77c8aedd0..e17b3f3bf34 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1500,6 +1500,7 @@ struct t_noc_opts { double noc_latency_weighting; /// rescale_traffic_flow_bandwidths() { +static vtr::vector rescale_traffic_flow_bandwidths(int bandwidth_resolution) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; @@ -149,7 +147,7 @@ static vtr::vector rescale_traffic_flow_bandwidths() { for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); double bandwidth = traffic_flow.traffic_flow_bandwidth; - int rescaled_bandwidth = (int)std::floor((bandwidth / link_bandwidth) * NOC_LINK_BANDWIDTH_RESOLUTION); + int rescaled_bandwidth = (int)std::floor((bandwidth / link_bandwidth) * bandwidth_resolution); rescaled_traffic_flow_bandwidths[traffic_flow_id] = rescaled_bandwidth; } @@ -157,11 +155,12 @@ static vtr::vector rescale_traffic_flow_bandwidths() { } static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, - orsat::CpModelBuilder& cp_model) { + orsat::CpModelBuilder& cp_model, + int bandwidth_resolution) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(bandwidth_resolution); // add NoC link congestion constraints for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { @@ -173,17 +172,18 @@ static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); } - cp_model.AddLessOrEqual(lhs, NOC_LINK_BANDWIDTH_RESOLUTION); + cp_model.AddLessOrEqual(lhs, bandwidth_resolution); } } static void create_congested_link_vars(vtr::vector& congested_link_vars, t_flow_link_var_map& flow_link_vars, - orsat::CpModelBuilder& cp_model) { + orsat::CpModelBuilder& cp_model, + int bandwidth_resolution) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(bandwidth_resolution); // add NoC link congestion constraints for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { @@ -196,8 +196,8 @@ static void create_congested_link_vars(vtr::vector& } orsat::BoolVar congested = cp_model.NewBoolVar(); - cp_model.AddLessOrEqual(lhs, NOC_LINK_BANDWIDTH_RESOLUTION).OnlyEnforceIf(congested.Not()); - cp_model.AddGreaterThan(lhs, NOC_LINK_BANDWIDTH_RESOLUTION).OnlyEnforceIf(congested); + cp_model.AddLessOrEqual(lhs, bandwidth_resolution).OnlyEnforceIf(congested.Not()); + cp_model.AddGreaterThan(lhs, bandwidth_resolution).OnlyEnforceIf(congested); congested_link_vars.push_back(congested); } } @@ -677,140 +677,141 @@ static void constrain_fixed_noc_routers(std::map& } } -void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, - std::map& noc_router_locs, - int seed) { - vtr::ScopedStartFinishTimer timer("NoC SAT Placement and Routing"); - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - const auto& placement_ctx = g_vpr_ctx.placement(); - const auto& cluster_ctx = g_vpr_ctx.clustering(); - - traffic_flow_routes.clear(); - noc_router_locs.clear(); - - orsat::CpModelBuilder cp_model; - - t_flow_link_var_map flow_link_vars; - - std::map latency_overrun_vars; - - vtr::vector link_congested_vars; - - const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); - operations_research::Domain loc_domain(0, 9); - std::map x_loc_vars; - std::map y_loc_vars; - std::vector> loc_intervals; - - - for (auto router_blk_id : router_blk_ids) { - x_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); - y_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); - - loc_intervals.emplace_back(cp_model.NewIntervalVar(x_loc_vars[router_blk_id], 1, x_loc_vars[router_blk_id]+1), - cp_model.NewIntervalVar(y_loc_vars[router_blk_id], 1, y_loc_vars[router_blk_id]+1)); - } - - orsat::NoOverlap2DConstraint no_overlap_2d = cp_model.AddNoOverlap2D(); - - for (auto& [x_interval, y_interval] : loc_intervals) { - no_overlap_2d.AddRectangle(x_interval, y_interval); - } - - create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); - - constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); - - forbid_illegal_turns(flow_link_vars, cp_model); - -// add_congestion_constraints(flow_link_vars, cp_model); - create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); - - add_movable_continuity_constraints(flow_link_vars, x_loc_vars, y_loc_vars, cp_model); - - std::vector up, down, right, left; - group_noc_links_based_on_direction(up, down, right, left); - - add_movable_distance_constraints(flow_link_vars, cp_model, x_loc_vars, y_loc_vars, up, down, right, left); - - constrain_fixed_noc_routers(x_loc_vars, y_loc_vars, cp_model); - - const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); - - // Get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); - - // Get the compressed grid for NoC - const auto& compressed_noc_grid = placement_ctx.compressed_block_grids[router_block_type->index]; - for (auto router_blk_id : router_blk_ids) { - auto router_loc = placement_ctx.block_locs[router_blk_id]; - - auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[0]; - - cp_model.AddHint(x_loc_vars[router_blk_id], compressed_loc.x); - cp_model.AddHint(y_loc_vars[router_blk_id], compressed_loc.y); -// cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); -// cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); - } - - orsat::LinearExpr latency_overrun_sum; - for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { - latency_overrun_sum += latency_overrun_var; - } - - latency_overrun_sum *= 1024; - - auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); - orsat::LinearExpr agg_bw_expr; - for (auto& [key, var] : flow_link_vars) { - auto [traffic_flow_id, noc_link_id] = key; - agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); - } - - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - std::vector activated_links; - for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { - cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); -// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, route_link_id}], true); - activated_links.push_back(route_link_id); - } - - for (auto noc_link_id : noc_ctx.noc_model.get_noc_links().keys()) { - if (std::find(activated_links.begin(), activated_links.end(), noc_link_id) == activated_links.end()) { - cp_model.AddHint(flow_link_vars[{traffic_flow_id, noc_link_id}], false); -// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, noc_link_id}], false); - } - } - } - - orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); - congested_link_sum *= (1024 * 16); - - cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); - - orsat::SatParameters sat_params; - sat_params.set_random_seed(seed); - sat_params.set_log_search_progress(true); - sat_params.set_max_time_in_seconds(10*60); - - orsat::Model model; - model.Add(NewSatParameters(sat_params)); - - orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); - - if (response.status() == orsat::CpSolverStatus::FEASIBLE || - response.status() == orsat::CpSolverStatus::OPTIMAL) { - - traffic_flow_routes = convert_vars_to_routes(flow_link_vars, response); - convert_vars_to_locs(noc_router_locs, x_loc_vars, y_loc_vars, response); - } -} +//void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, +// std::map& noc_router_locs, +// int seed) { +// vtr::ScopedStartFinishTimer timer("NoC SAT Placement and Routing"); +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; +// const auto& placement_ctx = g_vpr_ctx.placement(); +// const auto& cluster_ctx = g_vpr_ctx.clustering(); +// +// traffic_flow_routes.clear(); +// noc_router_locs.clear(); +// +// orsat::CpModelBuilder cp_model; +// +// t_flow_link_var_map flow_link_vars; +// +// std::map latency_overrun_vars; +// +// vtr::vector link_congested_vars; +// +// const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); +// operations_research::Domain loc_domain(0, 9); +// std::map x_loc_vars; +// std::map y_loc_vars; +// std::vector> loc_intervals; +// +// +// for (auto router_blk_id : router_blk_ids) { +// x_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); +// y_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); +// +// loc_intervals.emplace_back(cp_model.NewIntervalVar(x_loc_vars[router_blk_id], 1, x_loc_vars[router_blk_id]+1), +// cp_model.NewIntervalVar(y_loc_vars[router_blk_id], 1, y_loc_vars[router_blk_id]+1)); +// } +// +// orsat::NoOverlap2DConstraint no_overlap_2d = cp_model.AddNoOverlap2D(); +// +// for (auto& [x_interval, y_interval] : loc_intervals) { +// no_overlap_2d.AddRectangle(x_interval, y_interval); +// } +// +// create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); +// +// constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); +// +// forbid_illegal_turns(flow_link_vars, cp_model); +// +//// add_congestion_constraints(flow_link_vars, cp_model); +// create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); +// +// add_movable_continuity_constraints(flow_link_vars, x_loc_vars, y_loc_vars, cp_model); +// +// std::vector up, down, right, left; +// group_noc_links_based_on_direction(up, down, right, left); +// +// add_movable_distance_constraints(flow_link_vars, cp_model, x_loc_vars, y_loc_vars, up, down, right, left); +// +// constrain_fixed_noc_routers(x_loc_vars, y_loc_vars, cp_model); +// +// const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); +// +// // Get the logical block type for router +// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); +// +// // Get the compressed grid for NoC +// const auto& compressed_noc_grid = placement_ctx.compressed_block_grids[router_block_type->index]; +// for (auto router_blk_id : router_blk_ids) { +// auto router_loc = placement_ctx.block_locs[router_blk_id]; +// +// auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[0]; +// +// cp_model.AddHint(x_loc_vars[router_blk_id], compressed_loc.x); +// cp_model.AddHint(y_loc_vars[router_blk_id], compressed_loc.y); +//// cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); +//// cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); +// } +// +// orsat::LinearExpr latency_overrun_sum; +// for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { +// latency_overrun_sum += latency_overrun_var; +// } +// +// latency_overrun_sum *= 1024; +// +// auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); +// orsat::LinearExpr agg_bw_expr; +// for (auto& [key, var] : flow_link_vars) { +// auto [traffic_flow_id, noc_link_id] = key; +// agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); +// } +// +// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { +// std::vector activated_links; +// for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { +// cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); +//// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, route_link_id}], true); +// activated_links.push_back(route_link_id); +// } +// +// for (auto noc_link_id : noc_ctx.noc_model.get_noc_links().keys()) { +// if (std::find(activated_links.begin(), activated_links.end(), noc_link_id) == activated_links.end()) { +// cp_model.AddHint(flow_link_vars[{traffic_flow_id, noc_link_id}], false); +//// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, noc_link_id}], false); +// } +// } +// } +// +// orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); +// congested_link_sum *= (1024 * 16); +// +// cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); +// +// orsat::SatParameters sat_params; +// sat_params.set_random_seed(seed); +// sat_params.set_log_search_progress(true); +// sat_params.set_max_time_in_seconds(10*60); +// +// orsat::Model model; +// model.Add(NewSatParameters(sat_params)); +// +// orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); +// +// if (response.status() == orsat::CpSolverStatus::FEASIBLE || +// response.status() == orsat::CpSolverStatus::OPTIMAL) { +// +// traffic_flow_routes = convert_vars_to_routes(flow_link_vars, response); +// convert_vars_to_locs(noc_router_locs, x_loc_vars, y_loc_vars, response); +// } +//} vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, + int bandwidth_resolution, int seed) { vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); @@ -840,7 +841,7 @@ vtr::vector> noc_sat_route(bool minimiz forbid_illegal_turns(flow_link_vars, cp_model); // add_congestion_constraints(flow_link_vars, cp_model); - create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); + create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model, bandwidth_resolution); add_continuity_constraints(flow_link_vars, cp_model); @@ -865,7 +866,7 @@ vtr::vector> noc_sat_route(bool minimiz latency_overrun_sum *= 1024; - auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); + auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(bandwidth_resolution); orsat::LinearExpr agg_bw_expr; for (auto& [key, var] : flow_link_vars) { auto [traffic_flow_id, noc_link_id] = key; diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 5e53a33b345..67de67731fc 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -25,11 +25,12 @@ * @return The generated routes for all traffic flows. */ vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, + int bandwidth_resolution, int seed); -void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, - std::map& noc_router_locs, - int seed); +//void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, +// std::map& noc_router_locs, +// int seed); namespace std { template<> diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 4fa5ecc6d7f..12b2a42cc24 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1203,7 +1203,7 @@ void try_place(const Netlist<>& net_list, if (costs.noc_cost_terms.congestion > 0.0) { VTR_LOG("NoC routing configuration is congested. Invoking the SAT NoC router.\n"); - auto traffic_flow_routes = noc_sat_route(true, placer_opts.seed); + auto traffic_flow_routes = noc_sat_route(true, noc_opts.noc_sat_routing_bandwidth_resolution, placer_opts.seed); if (!traffic_flow_routes.empty()) { bool has_cycle = noc_routing_has_cycle(traffic_flow_routes); From 8f3bae3ad854fb0d3ca002240acf61411f76210c Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 23 May 2024 17:41:20 -0400 Subject: [PATCH 22/38] add more comments --- vpr/src/noc/sat_routing.cpp | 486 +++++++++++++++++++++--------------- 1 file changed, 278 insertions(+), 208 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index cfa20066436..2fedef0dff0 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -72,7 +72,7 @@ static std::vector get_flow_link_vars(const t_flow_link_var_map& * the corresponding integer variable in latency_overrun_vars should take a value * of 1 because an extra link beyond the maximum 3 links has been activated. * - * @param cp_model The CP model builder object. Created variables are added + * @param cp_model The CP model builder object. New constraints are added * to this model builder object. * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. * @param latency_overrun_vars The integer variables that are to be constrained. @@ -90,12 +90,71 @@ static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, * that specify a turn is activated. * * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. - * @param cp_model The CP model builder object. Created variables are added + * @param cp_model The CP model builder object. New constraints are added * to this model builder object. */ static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, orsat::CpModelBuilder& cp_model); +/** + * @brief Creates a boolean variable for each link to indicate + * whether it is congested. This function adds some constraints + * to enforce congested_link_vars boolean variables to be set to 1 + * when their corresponding link congested. + * + * Since the SAT solver cannot work with floating point numbers, + * all link and traffic flow bandwidth are quantized. + * + * @param congested_link_vars To be filled with created boolean variables + * to indicate whether links are congested. + * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. + * @param cp_model The CP model builder object. Created variables are added + * to this model builder object. Constraints are also added to this object. + * @param bandwidth_resolution Specifies the resolution by which bandwidth + * values are quantized. + */ +static void create_congested_link_vars(vtr::vector& congested_link_vars, + t_flow_link_var_map& flow_link_vars, + orsat::CpModelBuilder& cp_model, + int bandwidth_resolution); + +/** + * @brief Quantize traffic flow bandwidths. The maximum NoC link bandwidth is + * quantized to the specified bandwidth resolution, and traffic flow bandwidths + * are quantized accordingly. + * + * @param bandwidth_resolution The resolution by which traffic flow bandwidth are + * quantized. + * @return A vector of quantized traffic flow bandwidths. + */ +static vtr::vector quantize_traffic_flow_bandwidths(int bandwidth_resolution); + +/** + * @brief Adds constraints to ensure that activated (traffic flow, link) + * boolean variables for a specific traffic flow create a continuous route + * starting from the source router and arriving at the destination. + * + * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. + * @param cp_model The CP model builder object. New constraints are added + * to this model builder object. + */ +static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, + orsat::CpModelBuilder& cp_model); + +/** + * @brief Group NoC links into four groups based on their direction in + * a mesh topology. + * + * @param up To be filled with vertical NoC links going upward. + * @param down To be filled with vertical NoC links going downward. + * @param right To be filled with horizontal NoC links moving towards right. + * @param left To be filled with horizontal NoC links moving towards left. + */ +static void group_noc_links_based_on_direction(std::vector& up, + std::vector& down, + std::vector& right, + std::vector& left); + static std::vector get_flow_link_vars(const t_flow_link_var_map& map, const std::vector& traffic_flow_ids, @@ -134,10 +193,11 @@ static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, } } -static vtr::vector rescale_traffic_flow_bandwidths(int bandwidth_resolution) { +static vtr::vector quantize_traffic_flow_bandwidths(int bandwidth_resolution) { const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + //TODO: support heterogeneous bandwidth const double link_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth(); vtr::vector rescaled_traffic_flow_bandwidths; @@ -160,7 +220,7 @@ static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(bandwidth_resolution); + vtr::vector rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); // add NoC link congestion constraints for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { @@ -183,21 +243,23 @@ static void create_congested_link_vars(vtr::vector& const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - vtr::vector rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(bandwidth_resolution); + // quantize traffic flow bandwidth + vtr::vector rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); - // add NoC link congestion constraints + // go over all NoC links and create a boolean variable for each one to indicate if it is congested for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { const NocLinkId noc_link_id = noc_link.get_link_id(); - orsat::LinearExpr lhs; + orsat::LinearExpr bandwidth_load; + // compute the total bandwidth routed through this link for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { orsat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; - lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); + bandwidth_load += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); } orsat::BoolVar congested = cp_model.NewBoolVar(); - cp_model.AddLessOrEqual(lhs, bandwidth_resolution).OnlyEnforceIf(congested.Not()); - cp_model.AddGreaterThan(lhs, bandwidth_resolution).OnlyEnforceIf(congested); + cp_model.AddLessOrEqual(bandwidth_load, bandwidth_resolution).OnlyEnforceIf(congested.Not()); + cp_model.AddGreaterThan(bandwidth_load, bandwidth_resolution).OnlyEnforceIf(congested); congested_link_vars.push_back(congested); } } @@ -208,6 +270,8 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; const auto& place_ctx = g_vpr_ctx.placement(); + // constrain the links that can be activated for each traffic flow in a way that they + // form a continuous route for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); @@ -219,42 +283,48 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, NocRouterId source_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_source_router_block_id].loc); NocRouterId sink_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_sink_router_block_id].loc); - std::vector vars; - // exactly one outgoing link of the source must be selected const auto& src_outgoing_link_ids = noc_ctx.noc_model.get_noc_router_outgoing_links(source_router_id); - vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, src_outgoing_link_ids); - cp_model.AddExactlyOne(vars); + auto src_outgoing_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, src_outgoing_link_ids); + cp_model.AddExactlyOne(src_outgoing_vars); // exactly one incoming link of the sink must be selected const auto& dst_incoming_link_ids = noc_ctx.noc_model.get_noc_router_incoming_links(sink_router_id); - vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, dst_incoming_link_ids); - cp_model.AddExactlyOne(vars); + auto dst_incoming_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, dst_incoming_link_ids); + cp_model.AddExactlyOne(dst_incoming_vars); // each NoC router has at most one incoming and one outgoing link activated for (const auto& noc_router : noc_ctx.noc_model.get_noc_routers()) { const int noc_router_user_id = noc_router.get_router_user_id(); const NocRouterId noc_router_id = noc_ctx.noc_model.convert_router_id(noc_router_user_id); + // the links connected to source and destination routers have already been constrained if (noc_router_id == source_router_id || noc_router_id == sink_router_id) { continue; } - const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); - vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); - cp_model.AddAtMostOne(vars); - orsat::LinearExpr lhs; - lhs = orsat::LinearExpr::Sum(vars); + // for each intermediate router, at most one incoming link can be activated to route this traffic flow + const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); + auto incoming_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); + cp_model.AddAtMostOne(incoming_vars); + // for each intermediate router, at most one outgoing link can be activated to route this traffic flow const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); - vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); - cp_model.AddAtMostOne(vars); + auto outgoing_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); + cp_model.AddAtMostOne(outgoing_vars); + + // count the number of activated incoming links for this traffic flow + orsat::LinearExpr incoming_vars_sum = orsat::LinearExpr::Sum(incoming_vars); - orsat::LinearExpr rhs; - rhs = orsat::LinearExpr::Sum(vars); + // count the number of activated outgoing links for this traffic flow + orsat::LinearExpr outgoing_vars_sum = orsat::LinearExpr::Sum(outgoing_vars); - cp_model.AddEquality(lhs, rhs); + /* the number activated incoming and outgoing links must be equal/ + * Either they are both 0, meaning that this NoC routers is not on the + * traffic flow router, or they are both 1, implying the traffic flow route + * goes through this NoC router.*/ + cp_model.AddEquality(incoming_vars_sum, outgoing_vars_sum); } } } @@ -495,187 +565,187 @@ static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, } } -static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_vars, - std::map& x_loc_vars, - std::map& y_loc_vars, - orsat::CpModelBuilder& cp_model) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& noc_model = noc_ctx.noc_model; - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - const auto& place_ctx = g_vpr_ctx.placement(); - const auto& cluster_ctx = g_vpr_ctx.clustering(); - - // get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); - - // get the compressed grid for NoC - const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; - - std::unordered_map, orsat::BoolVar> logical_physical_mapped; - - // Create a boolean variable for each physical and logical NoC router pair - // When set, this variable indicates that the logical NoC router is mapped - // to its corresponding logical router - for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { - auto& y_loc_var = y_loc_vars[router_blk_id]; - - for (auto noc_router_id : noc_model.get_noc_routers().keys()) { - const auto& noc_router = noc_model.get_single_noc_router(noc_router_id); - const auto noc_router_pos = noc_router.get_router_physical_location(); - const auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; - - orsat::BoolVar x_condition = cp_model.NewBoolVar(); - cp_model.AddEquality(x_loc_var, compressed_loc.x).OnlyEnforceIf(x_condition); - cp_model.AddNotEqual(x_loc_var, compressed_loc.x).OnlyEnforceIf(Not(x_condition)); - - orsat::BoolVar y_condition = cp_model.NewBoolVar(); - cp_model.AddEquality(y_loc_var, compressed_loc.y).OnlyEnforceIf(y_condition); - cp_model.AddNotEqual(y_loc_var, compressed_loc.y).OnlyEnforceIf(Not(y_condition)); - - // Combine conditions using AddBoolAnd - orsat::BoolVar both_conds_met = cp_model.NewBoolVar(); - cp_model.AddBoolAnd({x_condition, y_condition}).OnlyEnforceIf(both_conds_met); - cp_model.AddBoolOr({Not(x_condition), Not(y_condition)}).OnlyEnforceIf(Not(both_conds_met)); - - logical_physical_mapped[{router_blk_id, noc_router_id}] = both_conds_met; - } - } - - /* - * Iterate over all traffic flows and physical NoC routers - * apply a constraint on the number of activated incoming and outgoing - * links based on whether the NoC router is the source or destination - * (or neither) of the traffic flow. - */ - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); - - // get the source and destination logical router blocks in the current traffic flow - ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; - ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; - - for (auto noc_router_id : noc_ctx.noc_model.get_noc_routers().keys()) { - - auto& src_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; - auto& dst_is_mapped = logical_physical_mapped[{logical_sink_router_block_id, noc_router_id}]; - - orsat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); - cp_model.AddExactlyOne({src_is_mapped, dst_is_mapped, nor_src_dst_mapped}); - - const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); - auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); - // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); - // cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); - orsat::LinearExpr lhs = orsat::LinearExpr::Sum(vars); - cp_model.AddEquality(lhs, 0).OnlyEnforceIf(src_is_mapped); - cp_model.AddLessOrEqual(lhs, 1).OnlyEnforceIf(nor_src_dst_mapped); - cp_model.AddEquality(lhs, 1).OnlyEnforceIf(dst_is_mapped); - - const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); - vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); - // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); - // cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); - orsat::LinearExpr rhs = orsat::LinearExpr::Sum(vars); - cp_model.AddEquality(rhs, 0).OnlyEnforceIf(dst_is_mapped); - cp_model.AddLessOrEqual(rhs, 1).OnlyEnforceIf(nor_src_dst_mapped); - cp_model.AddEquality(rhs, 1).OnlyEnforceIf(src_is_mapped); - - cp_model.AddEquality(lhs, rhs).OnlyEnforceIf(nor_src_dst_mapped); - } - } -} - -static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars, - orsat::CpModelBuilder& cp_model, - std::map& x_loc_vars, - std::map& y_loc_vars, - const std::vector& up, - const std::vector& down, - const std::vector& right, - const std::vector& left) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); - - // get the source and destination logical router blocks in the current traffic flow - ClusterBlockId logical_src_router_block_id = traffic_flow.source_router_cluster_id; - ClusterBlockId logical_dst_router_block_id = traffic_flow.sink_router_cluster_id; - - auto right_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, right); - auto left_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, left); - auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); - auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); - - orsat::LinearExpr horizontal_expr; - horizontal_expr += (orsat::LinearExpr::Sum(right_vars) - orsat::LinearExpr::Sum(left_vars)); - orsat::LinearExpr horizontal_dist_expr; - horizontal_dist_expr += x_loc_vars[logical_dst_router_block_id]; - horizontal_dist_expr -= x_loc_vars[logical_src_router_block_id]; - cp_model.AddEquality(horizontal_expr, horizontal_dist_expr); - - orsat::LinearExpr vertical_expr; - vertical_expr += (orsat::LinearExpr::Sum(up_vars) - orsat::LinearExpr::Sum(down_vars)); - orsat::LinearExpr vertical_dist_expr; - vertical_dist_expr += y_loc_vars[logical_dst_router_block_id]; - vertical_dist_expr -= y_loc_vars[logical_src_router_block_id]; - cp_model.AddEquality(vertical_expr, vertical_dist_expr); - } -} - -static void convert_vars_to_locs(std::map& noc_router_locs, - std::map& x_loc_vars, - std::map& y_loc_vars, - const orsat::CpSolverResponse& response) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - const auto& cluster_ctx = g_vpr_ctx.clustering(); - - // const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); - - // Get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); - - noc_router_locs.clear(); - - VTR_ASSERT(response.status() == orsat::CpSolverStatus::FEASIBLE || - response.status() == orsat::CpSolverStatus::OPTIMAL); - - for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { - auto& y_loc_var = y_loc_vars[router_blk_id]; - int x_value = (int)orsat::SolutionIntegerValue(response, x_loc_var); - int y_value = (int)orsat::SolutionIntegerValue(response, y_loc_var); - - t_pl_loc mapped_loc; - compressed_grid_to_loc(router_block_type, {x_value, y_value, 0}, mapped_loc); - noc_router_locs[router_blk_id] = mapped_loc; - } -} - -static void constrain_fixed_noc_routers(std::map& x_loc_vars, - std::map& y_loc_vars, - orsat::CpModelBuilder& cp_model) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - const auto& place_ctx = g_vpr_ctx.mutable_placement(); - const auto& cluster_ctx = g_vpr_ctx.clustering(); - - const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); - const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); - const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; - - const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); - - for (auto router_blk_id : router_blk_ids) { - const auto& router_loc = place_ctx.block_locs[router_blk_id]; - if (router_loc.is_fixed) { - auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[router_loc.loc.layer]; - cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); - cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); - } - } -} +//static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_vars, +// std::map& x_loc_vars, +// std::map& y_loc_vars, +// orsat::CpModelBuilder& cp_model) { +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& noc_model = noc_ctx.noc_model; +// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; +// const auto& place_ctx = g_vpr_ctx.placement(); +// const auto& cluster_ctx = g_vpr_ctx.clustering(); +// +// // get the logical block type for router +// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); +// +// // get the compressed grid for NoC +// const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; +// +// std::unordered_map, orsat::BoolVar> logical_physical_mapped; +// +// // Create a boolean variable for each physical and logical NoC router pair +// // When set, this variable indicates that the logical NoC router is mapped +// // to its corresponding logical router +// for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { +// auto& y_loc_var = y_loc_vars[router_blk_id]; +// +// for (auto noc_router_id : noc_model.get_noc_routers().keys()) { +// const auto& noc_router = noc_model.get_single_noc_router(noc_router_id); +// const auto noc_router_pos = noc_router.get_router_physical_location(); +// const auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; +// +// orsat::BoolVar x_condition = cp_model.NewBoolVar(); +// cp_model.AddEquality(x_loc_var, compressed_loc.x).OnlyEnforceIf(x_condition); +// cp_model.AddNotEqual(x_loc_var, compressed_loc.x).OnlyEnforceIf(Not(x_condition)); +// +// orsat::BoolVar y_condition = cp_model.NewBoolVar(); +// cp_model.AddEquality(y_loc_var, compressed_loc.y).OnlyEnforceIf(y_condition); +// cp_model.AddNotEqual(y_loc_var, compressed_loc.y).OnlyEnforceIf(Not(y_condition)); +// +// // Combine conditions using AddBoolAnd +// orsat::BoolVar both_conds_met = cp_model.NewBoolVar(); +// cp_model.AddBoolAnd({x_condition, y_condition}).OnlyEnforceIf(both_conds_met); +// cp_model.AddBoolOr({Not(x_condition), Not(y_condition)}).OnlyEnforceIf(Not(both_conds_met)); +// +// logical_physical_mapped[{router_blk_id, noc_router_id}] = both_conds_met; +// } +// } +// +// /* +// * Iterate over all traffic flows and physical NoC routers +// * apply a constraint on the number of activated incoming and outgoing +// * links based on whether the NoC router is the source or destination +// * (or neither) of the traffic flow. +// */ +// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { +// const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); +// +// // get the source and destination logical router blocks in the current traffic flow +// ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; +// ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; +// +// for (auto noc_router_id : noc_ctx.noc_model.get_noc_routers().keys()) { +// +// auto& src_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; +// auto& dst_is_mapped = logical_physical_mapped[{logical_sink_router_block_id, noc_router_id}]; +// +// orsat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); +// cp_model.AddExactlyOne({src_is_mapped, dst_is_mapped, nor_src_dst_mapped}); +// +// const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); +// auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); +// // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); +// // cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); +// orsat::LinearExpr lhs = orsat::LinearExpr::Sum(vars); +// cp_model.AddEquality(lhs, 0).OnlyEnforceIf(src_is_mapped); +// cp_model.AddLessOrEqual(lhs, 1).OnlyEnforceIf(nor_src_dst_mapped); +// cp_model.AddEquality(lhs, 1).OnlyEnforceIf(dst_is_mapped); +// +// const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); +// vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); +// // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); +// // cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); +// orsat::LinearExpr rhs = orsat::LinearExpr::Sum(vars); +// cp_model.AddEquality(rhs, 0).OnlyEnforceIf(dst_is_mapped); +// cp_model.AddLessOrEqual(rhs, 1).OnlyEnforceIf(nor_src_dst_mapped); +// cp_model.AddEquality(rhs, 1).OnlyEnforceIf(src_is_mapped); +// +// cp_model.AddEquality(lhs, rhs).OnlyEnforceIf(nor_src_dst_mapped); +// } +// } +//} +// +//static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars, +// orsat::CpModelBuilder& cp_model, +// std::map& x_loc_vars, +// std::map& y_loc_vars, +// const std::vector& up, +// const std::vector& down, +// const std::vector& right, +// const std::vector& left) { +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; +// +// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { +// const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); +// +// // get the source and destination logical router blocks in the current traffic flow +// ClusterBlockId logical_src_router_block_id = traffic_flow.source_router_cluster_id; +// ClusterBlockId logical_dst_router_block_id = traffic_flow.sink_router_cluster_id; +// +// auto right_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, right); +// auto left_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, left); +// auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); +// auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); +// +// orsat::LinearExpr horizontal_expr; +// horizontal_expr += (orsat::LinearExpr::Sum(right_vars) - orsat::LinearExpr::Sum(left_vars)); +// orsat::LinearExpr horizontal_dist_expr; +// horizontal_dist_expr += x_loc_vars[logical_dst_router_block_id]; +// horizontal_dist_expr -= x_loc_vars[logical_src_router_block_id]; +// cp_model.AddEquality(horizontal_expr, horizontal_dist_expr); +// +// orsat::LinearExpr vertical_expr; +// vertical_expr += (orsat::LinearExpr::Sum(up_vars) - orsat::LinearExpr::Sum(down_vars)); +// orsat::LinearExpr vertical_dist_expr; +// vertical_dist_expr += y_loc_vars[logical_dst_router_block_id]; +// vertical_dist_expr -= y_loc_vars[logical_src_router_block_id]; +// cp_model.AddEquality(vertical_expr, vertical_dist_expr); +// } +//} +// +//static void convert_vars_to_locs(std::map& noc_router_locs, +// std::map& x_loc_vars, +// std::map& y_loc_vars, +// const orsat::CpSolverResponse& response) { +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; +// const auto& cluster_ctx = g_vpr_ctx.clustering(); +// +// // const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); +// +// // Get the logical block type for router +// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); +// +// noc_router_locs.clear(); +// +// VTR_ASSERT(response.status() == orsat::CpSolverStatus::FEASIBLE || +// response.status() == orsat::CpSolverStatus::OPTIMAL); +// +// for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { +// auto& y_loc_var = y_loc_vars[router_blk_id]; +// int x_value = (int)orsat::SolutionIntegerValue(response, x_loc_var); +// int y_value = (int)orsat::SolutionIntegerValue(response, y_loc_var); +// +// t_pl_loc mapped_loc; +// compressed_grid_to_loc(router_block_type, {x_value, y_value, 0}, mapped_loc); +// noc_router_locs[router_blk_id] = mapped_loc; +// } +//} +// +//static void constrain_fixed_noc_routers(std::map& x_loc_vars, +// std::map& y_loc_vars, +// orsat::CpModelBuilder& cp_model) { +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; +// const auto& place_ctx = g_vpr_ctx.mutable_placement(); +// const auto& cluster_ctx = g_vpr_ctx.clustering(); +// +// const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); +// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); +// const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; +// +// const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); +// +// for (auto router_blk_id : router_blk_ids) { +// const auto& router_loc = place_ctx.block_locs[router_blk_id]; +// if (router_loc.is_fixed) { +// auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[router_loc.loc.layer]; +// cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); +// cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); +// } +// } +//} //void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, // std::map& noc_router_locs, @@ -866,7 +936,7 @@ vtr::vector> noc_sat_route(bool minimiz latency_overrun_sum *= 1024; - auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(bandwidth_resolution); + auto rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); orsat::LinearExpr agg_bw_expr; for (auto& [key, var] : flow_link_vars) { auto [traffic_flow_id, noc_link_id] = key; From 959e18815333999ffe700e1e41616c867d19cf15 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Thu, 23 May 2024 18:16:07 -0400 Subject: [PATCH 23/38] remove add_distance_constraints() and add command line options for weighting factors in SAT routing --- vpr/src/base/SetupVPR.cpp | 2 + vpr/src/base/ShowSetup.cpp | 2 + vpr/src/base/read_options.cpp | 34 ++++++++----- vpr/src/base/read_options.h | 2 + vpr/src/base/vpr_types.h | 24 +++++----- vpr/src/noc/sat_routing.cpp | 89 +++-------------------------------- vpr/src/noc/sat_routing.h | 2 + vpr/src/place/place.cpp | 6 ++- 8 files changed, 55 insertions(+), 106 deletions(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 1d11785eb22..ead1a5251ca 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -741,6 +741,8 @@ static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { NocOpts->noc_congestion_weighting = Options.noc_congestion_weighting; NocOpts->noc_swap_percentage = Options.noc_swap_percentage; NocOpts->noc_sat_routing_bandwidth_resolution = Options.noc_sat_routing_bandwidth_resolution; + NocOpts->noc_sat_routing_latency_overrun_weighting = Options.noc_sat_routing_latency_overrun_weighting_factor; + NocOpts->noc_sat_routing_congestion_weighting = Options.noc_sat_routing_congestion_weighting_factor; NocOpts->noc_placement_file_name = Options.noc_placement_file_name; } diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index db003a74308..da5794daa08 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -801,6 +801,8 @@ static void ShowNocOpts(const t_noc_opts& NocOpts) { VTR_LOG("NocOpts.noc_congestion_weighting: %f\n", NocOpts.noc_congestion_weighting); VTR_LOG("NocOpts.noc_swap_percentage: %d%%\n", NocOpts.noc_swap_percentage); VTR_LOG("NocOpts.noc_sat_routing_bandwidth_resolution: %d\n", NocOpts.noc_sat_routing_bandwidth_resolution); + VTR_LOG("NocOpts.noc_sat_routing_latency_overrun_weighting: %d\n", NocOpts.noc_sat_routing_latency_overrun_weighting); + VTR_LOG("NocOpts.noc_sat_routing_congestion_weighting: %d\n", NocOpts.noc_sat_routing_congestion_weighting); VTR_LOG("NocOpts.noc_routing_algorithm: %s\n", NocOpts.noc_placement_file_name.c_str()); VTR_LOG("\n"); } \ No newline at end of file diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 9cc0bf71bee..7194c89ed85 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2783,8 +2783,8 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio noc_grp.add_argument(args.noc, "--noc") .help( - "Enables a NoC-driven placer that optimizes the placement of routers on the NoC." - "Also enables an option in the graphical display that can be used to display the NoC on the FPGA." + "Enables a NoC-driven placer that optimizes the placement of routers on the NoC. " + "Also enables an option in the graphical display that can be used to display the NoC on the FPGA. " "This should be on only when the FPGA device contains a NoC and the provided netlist connects to the NoC.") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); @@ -2800,7 +2800,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .help( "Controls the algorithm used by the NoC to route packets.\n" "* xy_routing: Uses the direction oriented routing algorithm. This is recommended to be used with mesh NoC topologies.\n" - "* bfs_routing: Uses the breadth first search algorithm. The objective is to find a route that uses a minimum number of links." + "* bfs_routing: Uses the breadth first search algorithm. The objective is to find a route that uses a minimum number of links. " " This algorithm is not guaranteed to generate deadlock-free traffic flow routes, but can be used with any NoC topology\n" "* west_first_routing: Uses the west-first routing algorithm. This is recommended to be used with mesh NoC topologies.\n" "* north_last_routing: Uses the north-last routing algorithm. This is recommended to be used with mesh NoC topologies.\n" @@ -2813,9 +2813,9 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio noc_grp.add_argument(args.noc_placement_weighting, "--noc_placement_weighting") .help( - "Controls the importance of the NoC placement parameters relative to timing and wirelength of the design." - "This value can be >=0, where 0 would mean the placement is based solely on timing and wirelength." - "A value of 1 would mean noc placement is considered equal to timing and wirelength" + "Controls the importance of the NoC placement parameters relative to timing and wirelength of the design. " + "This value can be >=0, where 0 would mean the placement is based solely on timing and wirelength. " + "A value of 1 would mean noc placement is considered equal to timing and wirelength " "A value greater than 1 would mean the placement is increasingly dominated by NoC parameters.") .default_value("5.0") .show_in(argparse::ShowIn::HELP_ONLY); @@ -2825,7 +2825,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio "Controls the importance of minimizing the NoC aggregate bandwidth.\n" "This value can be >=0, where 0 would mean the aggregate bandwidth has no relevance to placement.\n" "Other positive numbers specify the importance of minimizing the NoC aggregate bandwidth to other NoC-related cost terms.\n" - "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and" + "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and " "only their relative ratios determine the importance of each cost term.") .default_value("0.38") .show_in(argparse::ShowIn::HELP_ONLY); @@ -2835,7 +2835,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio "Controls the importance of meeting all the NoC traffic flow latency constraints.\n" "This value can be >=0, where 0 would mean the latency constraints have no relevance to placement.\n" "Other positive numbers specify the importance of meeting latency constraints to other NoC-related cost terms.\n" - "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and" + "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and " "only their relative ratios determine the importance of each cost term.") .default_value("0.6") .show_in(argparse::ShowIn::HELP_ONLY); @@ -2845,7 +2845,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio "Controls the importance of reducing the latencies of the NoC traffic flows.\n" "This value can be >=0, where 0 would mean the latencies have no relevance to placement.\n" "Other positive numbers specify the importance of minimizing aggregate latency to other NoC-related cost terms.\n" - "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and" + "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and " "only their relative ratios determine the importance of each cost term.") .default_value("0.02") .show_in(argparse::ShowIn::HELP_ONLY); @@ -2855,14 +2855,14 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio "Controls the importance of reducing the congestion of the NoC links.\n" "This value can be >=0, where 0 would mean the congestion has no relevance to placement.\n" "Other positive numbers specify the importance of minimizing congestion to other NoC-related cost terms.\n" - "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and" + "Weighting factors for NoC-related cost terms are normalized internally. Therefore, their absolute values are not important, and " "only their relative ratios determine the importance of each cost term.") .default_value("0.25") .show_in(argparse::ShowIn::HELP_ONLY); noc_grp.add_argument(args.noc_swap_percentage, "--noc_swap_percentage") .help( - "Sets the minimum fraction of swaps attempted by the placer that are NoC blocks." + "Sets the minimum fraction of swaps attempted by the placer that are NoC blocks. " "This value is an integer ranging from 0-100. 0 means NoC blocks will be moved at the same rate as other blocks. 100 means all swaps attempted by the placer are NoC router blocks.") .default_value("0") .show_in(argparse::ShowIn::HELP_ONLY); @@ -2875,6 +2875,18 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("128") .show_in(argparse::ShowIn::HELP_ONLY); + noc_grp.add_argument(args.noc_sat_routing_latency_overrun_weighting_factor, "--noc_sat_routing_latency_overrun_weighting_factor") + .help( + "Controls the importance of reducing traffic flow latency overrun in SAT routing.") + .default_value("1024") + .show_in(argparse::ShowIn::HELP_ONLY); + + noc_grp.add_argument(args.noc_sat_routing_congestion_weighting_factor, "--noc_sat_routing_congestion_weighting_factor") + .help( + "Controls the importance of reducing the number of congested NoC links in SAT routing.") + .default_value("16384") + .show_in(argparse::ShowIn::HELP_ONLY); + noc_grp.add_argument(args.noc_placement_file_name, "--noc_placement_file_name") .help( "Name of the output file that contains the NoC placement information." diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 0b26fb26457..f79a5115616 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -158,6 +158,8 @@ struct t_options { argparse::ArgValue noc_congestion_weighting; argparse::ArgValue noc_swap_percentage; argparse::ArgValue noc_sat_routing_bandwidth_resolution; + argparse::ArgValue noc_sat_routing_latency_overrun_weighting_factor; + argparse::ArgValue noc_sat_routing_congestion_weighting_factor; argparse::ArgValue noc_placement_file_name; /* Timing-driven placement options only */ diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index e17b3f3bf34..491bd3fb89e 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1491,17 +1491,19 @@ struct t_analysis_opts { // used to store NoC specific options, when supplied as an input by the user struct t_noc_opts { - bool noc; /// quantize_traffic_flow_bandwidths(int b static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, orsat::CpModelBuilder& cp_model); -/** - * @brief Group NoC links into four groups based on their direction in - * a mesh topology. - * - * @param up To be filled with vertical NoC links going upward. - * @param down To be filled with vertical NoC links going downward. - * @param right To be filled with horizontal NoC links moving towards right. - * @param left To be filled with horizontal NoC links moving towards left. - */ -static void group_noc_links_based_on_direction(std::vector& up, - std::vector& down, - std::vector& right, - std::vector& left); - static std::vector get_flow_link_vars(const t_flow_link_var_map& map, const std::vector& traffic_flow_ids, @@ -329,67 +315,6 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, } } -static void add_distance_constraints(t_flow_link_var_map& flow_link_vars, - orsat::CpModelBuilder& cp_model, - const std::vector& up, - const std::vector& down, - const std::vector& right, - const std::vector& left) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - const auto& place_ctx = g_vpr_ctx.placement(); - const auto& cluster_ctx = g_vpr_ctx.clustering(); - - const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); - - // Get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); - - // Get the compressed grid for NoC - const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; - - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); - - // get the source and destination logical router blocks in the current traffic flow - ClusterBlockId logical_src_router_block_id = traffic_flow.source_router_cluster_id; - ClusterBlockId logical_dst_router_block_id = traffic_flow.sink_router_cluster_id; - - // get the ids of the hard router blocks where the logical router cluster blocks have been placed - NocRouterId src_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_src_router_block_id].loc); - NocRouterId dst_router_id = noc_ctx.noc_model.get_router_at_grid_location(place_ctx.block_locs[logical_dst_router_block_id].loc); - - // get source, current, and destination NoC routers - const auto& src_router = noc_ctx.noc_model.get_single_noc_router(src_router_id); - const auto& dst_router = noc_ctx.noc_model.get_single_noc_router(dst_router_id); - - // get the position of source, current, and destination NoC routers - const auto src_router_pos = src_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); - - // get the compressed location for source, current, and destination NoC routers - auto compressed_src_loc = get_compressed_loc(compressed_noc_grid, t_pl_loc{src_router_pos, 0}, num_layers)[src_router_pos.layer_num]; - auto compressed_dst_loc = get_compressed_loc(compressed_noc_grid, t_pl_loc{dst_router_pos, 0}, num_layers)[dst_router_pos.layer_num]; - - // calculate the distance between the current router and the destination - const int delta_x = compressed_dst_loc.x - compressed_src_loc.x; - const int delta_y = compressed_dst_loc.y - compressed_src_loc.y; - - auto right_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, right); - auto left_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, left); - auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); - auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); - - orsat::LinearExpr horizontal_expr; - horizontal_expr += (orsat::LinearExpr::Sum(right_vars) - orsat::LinearExpr::Sum(left_vars)); - cp_model.AddEquality(horizontal_expr, delta_x); - - orsat::LinearExpr vertical_expr; - vertical_expr += (orsat::LinearExpr::Sum(up_vars) - orsat::LinearExpr::Sum(down_vars)); - cp_model.AddEquality(vertical_expr, delta_y); - } -} - static void group_noc_links_based_on_direction(std::vector& up, std::vector& down, std::vector& right, @@ -882,6 +807,8 @@ static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, int bandwidth_resolution, + int latency_overrun_weight, + int congestion_weight, int seed) { vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); @@ -915,14 +842,11 @@ vtr::vector> noc_sat_route(bool minimiz add_continuity_constraints(flow_link_vars, cp_model); - std::vector up, down, right, left; - group_noc_links_based_on_direction(up, down, right, left); - - add_distance_constraints(flow_link_vars, cp_model, up, down, right, left); - const auto& noc_ctx = g_vpr_ctx.noc(); const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + // use the current routing solution as a hint for the SAT solver + // This will help the solver by giving a good starting point and tighter initial lower bound on the objective function for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); @@ -933,8 +857,7 @@ vtr::vector> noc_sat_route(bool minimiz for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { latency_overrun_sum += latency_overrun_var; } - - latency_overrun_sum *= 1024; + latency_overrun_sum *= latency_overrun_weight; auto rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); orsat::LinearExpr agg_bw_expr; @@ -944,7 +867,7 @@ vtr::vector> noc_sat_route(bool minimiz } orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); - congested_link_sum *= (1024 * 16); + congested_link_sum *= congestion_weight; cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 67de67731fc..7329516d399 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -26,6 +26,8 @@ */ vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, int bandwidth_resolution, + int latency_overrun_weight, + int congestion_weight, int seed); //void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 12b2a42cc24..b58667106f5 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1203,7 +1203,11 @@ void try_place(const Netlist<>& net_list, if (costs.noc_cost_terms.congestion > 0.0) { VTR_LOG("NoC routing configuration is congested. Invoking the SAT NoC router.\n"); - auto traffic_flow_routes = noc_sat_route(true, noc_opts.noc_sat_routing_bandwidth_resolution, placer_opts.seed); + auto traffic_flow_routes = noc_sat_route(true, + noc_opts.noc_sat_routing_bandwidth_resolution, + noc_opts.noc_sat_routing_latency_overrun_weighting, + noc_opts.noc_sat_routing_congestion_weighting, + placer_opts.seed); if (!traffic_flow_routes.empty()) { bool has_cycle = noc_routing_has_cycle(traffic_flow_routes); From 87aed0155e38e3ba70570840ac158e180c832fdb Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 24 May 2024 14:33:32 -0400 Subject: [PATCH 24/38] add create_objective() --- vpr/src/noc/sat_routing.cpp | 132 +++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 53 deletions(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index 4f30af901fb..411da29f2b7 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -1,7 +1,6 @@ #include "sat_routing.h" #include "turn_model_routing.h" -#include "move_utils.h" #include "globals.h" #include "vtr_time.h" @@ -141,6 +140,38 @@ static vtr::vector quantize_traffic_flow_bandwidths(int b static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, orsat::CpModelBuilder& cp_model); +/** + * @brief Creates a linear expression to be minimized by the SAT solver. + * This objective function is a linear combination of latency overrun, + * the number of congested links, and the quantized aggregate bandwidth. + * + * @param cp_model + * @param flow_link_vars + * @param latency_overrun_vars Integer variables for latency-constrained + * traffic flows. Each integer variable shows how many extra links a constrained + * traffic flow has traversed beyond what its latency constraint allows. + * @param congested_link_vars Boolean variables indicating whether a link is + * congested or not. + * @param bandwidth_resolution The resolution by which traffic flow bandwidths + * are quantized. + * @param latency_overrun_weight Specifies the importance of minimizing latency overrun + * for latency-constrained traffic flows. + * @param congestion_weight Specifies the importance of avoiding congestion in links. + * @param minimize_aggregate_bandwidth Specifies whether the objective includes an + * aggregate bandwidth term. + * + * @return A linear expression including latency overrun, the number of congested links, + * and the aggregate bandwidth; + */ +static orsat::LinearExpr create_objective(orsat::CpModelBuilder& cp_model, + t_flow_link_var_map& flow_link_vars, + std::map& latency_overrun_vars, + vtr::vector& congested_link_vars, + int bandwidth_resolution, + int latency_overrun_weight, + int congestion_weight, + bool minimize_aggregate_bandwidth); + static std::vector get_flow_link_vars(const t_flow_link_var_map& map, const std::vector& traffic_flow_ids, @@ -802,7 +833,49 @@ static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, // } //} +static orsat::LinearExpr create_objective(orsat::CpModelBuilder& cp_model, + t_flow_link_var_map& flow_link_vars, + std::map& latency_overrun_vars, + vtr::vector& congested_link_vars, + int bandwidth_resolution, + int latency_overrun_weight, + int congestion_weight, + bool minimize_aggregate_bandwidth) { + const auto& noc_ctx = g_vpr_ctx.noc(); + const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + + // use the current routing solution as a hint for the SAT solver + // This will help the solver by giving a good starting point and tighter initial lower bound on the objective function + for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { + for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { + cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); + } + } + + orsat::LinearExpr latency_overrun_sum; + for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { + latency_overrun_sum += latency_overrun_var; + } + latency_overrun_sum *= latency_overrun_weight; + + auto rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); + orsat::LinearExpr agg_bw_expr; + if (minimize_aggregate_bandwidth) { + for (auto& [key, var] : flow_link_vars) { + auto [traffic_flow_id, noc_link_id] = key; + agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); + } + } else { + agg_bw_expr = 0; + } + + + orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(congested_link_vars); + congested_link_sum *= congestion_weight; + orsat::LinearExpr objective = latency_overrun_sum + agg_bw_expr + congested_link_sum; + return objective; +} vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, @@ -837,77 +910,30 @@ vtr::vector> noc_sat_route(bool minimiz forbid_illegal_turns(flow_link_vars, cp_model); - // add_congestion_constraints(flow_link_vars, cp_model); create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model, bandwidth_resolution); add_continuity_constraints(flow_link_vars, cp_model); - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + auto objective = create_objective(cp_model, flow_link_vars, latency_overrun_vars, link_congested_vars, + bandwidth_resolution, latency_overrun_weight, congestion_weight, + minimize_aggregate_bandwidth); - // use the current routing solution as a hint for the SAT solver - // This will help the solver by giving a good starting point and tighter initial lower bound on the objective function - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { - cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); - } - } - - orsat::LinearExpr latency_overrun_sum; - for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { - latency_overrun_sum += latency_overrun_var; - } - latency_overrun_sum *= latency_overrun_weight; - - auto rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); - orsat::LinearExpr agg_bw_expr; - for (auto& [key, var] : flow_link_vars) { - auto [traffic_flow_id, noc_link_id] = key; - agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); - } - - orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); - congested_link_sum *= congestion_weight; - - cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); - - orsat::Model model; + cp_model.Minimize(objective); orsat::SatParameters sat_params; // sat_params.set_num_workers(1); sat_params.set_random_seed(seed); sat_params.set_log_search_progress(true); + orsat::Model model; model.Add(NewSatParameters(sat_params)); orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); if (response.status() == orsat::CpSolverStatus::FEASIBLE || response.status() == orsat::CpSolverStatus::OPTIMAL) { - - // if (!minimize_aggregate_bandwidth) { auto routes = convert_vars_to_routes(flow_link_vars, response); return routes; - // } else { - // int latency_overrun_value = (int)orsat::SolutionIntegerValue(response, latency_overrun_sum); - // cp_model.AddEquality(latency_overrun_sum, latency_overrun_value); - - // auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); - // orsat::LinearExpr agg_bw_expr; - // for (auto& [key, var] : flow_link_vars) { - // auto [traffic_flow_id, noc_link_id] = key; - // agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); - // } - - cp_model.Minimize(agg_bw_expr); - response = orsat::Solve(cp_model.Build()); - - // if (response.status() == orsat::CpSolverStatus::FEASIBLE || - // response.status() == orsat::CpSolverStatus::OPTIMAL) { - // auto routes = convert_vars_to_routes(flow_link_vars, response); - // return routes; - // } - // } } return {}; From e697f64dd7d9dbc224f439803cbd932ef9e1019f Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 24 May 2024 16:40:49 -0400 Subject: [PATCH 25/38] noc_sat_routing_num_workers and noc_sat_routing_log_search_progress command line options --- vpr/src/base/SetupVPR.cpp | 2 + vpr/src/base/ShowSetup.cpp | 1 + vpr/src/base/read_options.cpp | 13 ++++ vpr/src/base/read_options.h | 2 + vpr/src/base/vpr_types.h | 2 + vpr/src/noc/sat_routing.cpp | 125 +++++++++++++++++----------------- vpr/src/noc/sat_routing.h | 4 +- vpr/src/place/place.cpp | 4 +- 8 files changed, 86 insertions(+), 67 deletions(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index ead1a5251ca..970f46082bc 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -743,6 +743,8 @@ static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { NocOpts->noc_sat_routing_bandwidth_resolution = Options.noc_sat_routing_bandwidth_resolution; NocOpts->noc_sat_routing_latency_overrun_weighting = Options.noc_sat_routing_latency_overrun_weighting_factor; NocOpts->noc_sat_routing_congestion_weighting = Options.noc_sat_routing_congestion_weighting_factor; + NocOpts->noc_sat_routing_num_workers = Options.noc_sat_routing_num_workers; + NocOpts->noc_sat_routing_log_search_progress = Options.noc_sat_routing_log_search_progress; NocOpts->noc_placement_file_name = Options.noc_placement_file_name; } diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index da5794daa08..40b67455e6c 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -803,6 +803,7 @@ static void ShowNocOpts(const t_noc_opts& NocOpts) { VTR_LOG("NocOpts.noc_sat_routing_bandwidth_resolution: %d\n", NocOpts.noc_sat_routing_bandwidth_resolution); VTR_LOG("NocOpts.noc_sat_routing_latency_overrun_weighting: %d\n", NocOpts.noc_sat_routing_latency_overrun_weighting); VTR_LOG("NocOpts.noc_sat_routing_congestion_weighting: %d\n", NocOpts.noc_sat_routing_congestion_weighting); + VTR_LOG("NocOpts.noc_sat_routing_num_workers: %d\n", NocOpts.noc_sat_routing_num_workers); VTR_LOG("NocOpts.noc_routing_algorithm: %s\n", NocOpts.noc_placement_file_name.c_str()); VTR_LOG("\n"); } \ No newline at end of file diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 7194c89ed85..1df2cc66907 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2887,6 +2887,19 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("16384") .show_in(argparse::ShowIn::HELP_ONLY); + noc_grp.add_argument(args.noc_sat_routing_num_workers, "--noc_sat_routing_num_workers") + .help( + "The maximum number of parallel threads that the SAT solver can use to explore the solution space.\n" + "When set to 0, the number of parallel workers is set automatically to maximize parallelism.") + .default_value("0") + .show_in(argparse::ShowIn::HELP_ONLY); + + noc_grp.add_argument(args.noc_sat_routing_log_search_progress, "--noc_sat_routing_log_search_progress") + .help( + "Print the detailed log of the SAT solver's search progress.") + .default_value("off") + .show_in(argparse::ShowIn::HELP_ONLY); + noc_grp.add_argument(args.noc_placement_file_name, "--noc_placement_file_name") .help( "Name of the output file that contains the NoC placement information." diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index f79a5115616..4333b8d242c 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -160,6 +160,8 @@ struct t_options { argparse::ArgValue noc_sat_routing_bandwidth_resolution; argparse::ArgValue noc_sat_routing_latency_overrun_weighting_factor; argparse::ArgValue noc_sat_routing_congestion_weighting_factor; + argparse::ArgValue noc_sat_routing_num_workers; + argparse::ArgValue noc_sat_routing_log_search_progress; argparse::ArgValue noc_placement_file_name; /* Timing-driven placement options only */ diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 491bd3fb89e..7a952a31ac1 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1503,6 +1503,8 @@ struct t_noc_opts { int noc_sat_routing_bandwidth_resolution; /// quantize_traffic_flow_bandwidths(int b return rescaled_traffic_flow_bandwidths; } -static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, - orsat::CpModelBuilder& cp_model, - int bandwidth_resolution) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; - - vtr::vector rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); - - // add NoC link congestion constraints - for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { - const NocLinkId noc_link_id = noc_link.get_link_id(); - orsat::LinearExpr lhs; - - for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { - orsat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; - lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); - } - - cp_model.AddLessOrEqual(lhs, bandwidth_resolution); - } -} +//static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, +// orsat::CpModelBuilder& cp_model, +// int bandwidth_resolution) { +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; +// +// vtr::vector rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); +// +// // add NoC link congestion constraints +// for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { +// const NocLinkId noc_link_id = noc_link.get_link_id(); +// orsat::LinearExpr lhs; +// +// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { +// orsat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; +// lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); +// } +// +// cp_model.AddLessOrEqual(lhs, bandwidth_resolution); +// } +//} static void create_congested_link_vars(vtr::vector& congested_link_vars, t_flow_link_var_map& flow_link_vars, @@ -346,39 +346,39 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, } } -static void group_noc_links_based_on_direction(std::vector& up, - std::vector& down, - std::vector& right, - std::vector& left) { - const auto& noc_ctx = g_vpr_ctx.noc(); - const auto& noc_model = noc_ctx.noc_model; - - for (const auto& noc_link : noc_model.get_noc_links()) { - const NocLinkId noc_link_id = noc_link.get_link_id(); - const NocRouterId src_noc_router_id = noc_link.get_source_router(); - const NocRouterId dst_noc_router_id = noc_link.get_sink_router(); - const NocRouter& src_noc_router = noc_model.get_single_noc_router(src_noc_router_id); - const NocRouter& dst_noc_router = noc_model.get_single_noc_router(dst_noc_router_id); - auto src_loc = src_noc_router.get_router_physical_location(); - auto dst_loc = dst_noc_router.get_router_physical_location(); - - VTR_ASSERT(src_loc.x == dst_loc.x || src_loc.y == dst_loc.y); - - if (src_loc.x == dst_loc.x) { // vertical link - if (dst_loc.y > src_loc.y) { - up.push_back(noc_link_id); - } else { - down.push_back(noc_link_id); - } - } else { // horizontal link - if (dst_loc.x > src_loc.x) { - right.push_back(noc_link_id); - } else { - left.push_back(noc_link_id); - } - } - } -} +//static void group_noc_links_based_on_direction(std::vector& up, +// std::vector& down, +// std::vector& right, +// std::vector& left) { +// const auto& noc_ctx = g_vpr_ctx.noc(); +// const auto& noc_model = noc_ctx.noc_model; +// +// for (const auto& noc_link : noc_model.get_noc_links()) { +// const NocLinkId noc_link_id = noc_link.get_link_id(); +// const NocRouterId src_noc_router_id = noc_link.get_source_router(); +// const NocRouterId dst_noc_router_id = noc_link.get_sink_router(); +// const NocRouter& src_noc_router = noc_model.get_single_noc_router(src_noc_router_id); +// const NocRouter& dst_noc_router = noc_model.get_single_noc_router(dst_noc_router_id); +// auto src_loc = src_noc_router.get_router_physical_location(); +// auto dst_loc = dst_noc_router.get_router_physical_location(); +// +// VTR_ASSERT(src_loc.x == dst_loc.x || src_loc.y == dst_loc.y); +// +// if (src_loc.x == dst_loc.x) { // vertical link +// if (dst_loc.y > src_loc.y) { +// up.push_back(noc_link_id); +// } else { +// down.push_back(noc_link_id); +// } +// } else { // horizontal link +// if (dst_loc.x > src_loc.x) { +// right.push_back(noc_link_id); +// } else { +// left.push_back(noc_link_id); +// } +// } +// } +//} static std::vector sort_noc_links_in_chain_order(const std::vector& links) { std::vector route; @@ -879,9 +879,7 @@ static orsat::LinearExpr create_objective(orsat::CpModelBuilder& cp_model, vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, - int bandwidth_resolution, - int latency_overrun_weight, - int congestion_weight, + const t_noc_opts& noc_opts, int seed) { vtr::ScopedStartFinishTimer timer("NoC SAT Routing"); @@ -910,20 +908,24 @@ vtr::vector> noc_sat_route(bool minimiz forbid_illegal_turns(flow_link_vars, cp_model); - create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model, bandwidth_resolution); + create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model, noc_opts.noc_sat_routing_bandwidth_resolution); add_continuity_constraints(flow_link_vars, cp_model); auto objective = create_objective(cp_model, flow_link_vars, latency_overrun_vars, link_congested_vars, - bandwidth_resolution, latency_overrun_weight, congestion_weight, + noc_opts.noc_sat_routing_bandwidth_resolution, + noc_opts.noc_sat_routing_latency_overrun_weighting, + noc_opts.noc_sat_routing_congestion_weighting, minimize_aggregate_bandwidth); cp_model.Minimize(objective); orsat::SatParameters sat_params; - // sat_params.set_num_workers(1); + if (noc_opts.noc_sat_routing_num_workers > 0) { + sat_params.set_num_workers(noc_opts.noc_sat_routing_num_workers); + } sat_params.set_random_seed(seed); - sat_params.set_log_search_progress(true); + sat_params.set_log_search_progress(noc_opts.noc_sat_routing_log_search_progress); orsat::Model model; model.Add(NewSatParameters(sat_params)); @@ -936,5 +938,6 @@ vtr::vector> noc_sat_route(bool minimiz return routes; } + // when no feasible solution was found, return an empty vector return {}; } \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 7329516d399..97e9604c9bc 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -25,9 +25,7 @@ * @return The generated routes for all traffic flows. */ vtr::vector> noc_sat_route(bool minimize_aggregate_bandwidth, - int bandwidth_resolution, - int latency_overrun_weight, - int congestion_weight, + const t_noc_opts& noc_opts, int seed); //void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index b58667106f5..1f20453b6c9 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1204,9 +1204,7 @@ void try_place(const Netlist<>& net_list, if (costs.noc_cost_terms.congestion > 0.0) { VTR_LOG("NoC routing configuration is congested. Invoking the SAT NoC router.\n"); auto traffic_flow_routes = noc_sat_route(true, - noc_opts.noc_sat_routing_bandwidth_resolution, - noc_opts.noc_sat_routing_latency_overrun_weighting, - noc_opts.noc_sat_routing_congestion_weighting, + noc_opts, placer_opts.seed); if (!traffic_flow_routes.empty()) { From d76d7b55c2034b2a69c6e9c9c87229a079039357 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 27 May 2024 16:57:34 -0400 Subject: [PATCH 26/38] check or-tools dependency in CMakeLists.txt --- CMakeLists.txt | 5 +++-- vpr/CMakeLists.txt | 17 ++++++++++++++--- vpr/src/noc/sat_routing.cpp | 6 +++++- vpr/src/noc/sat_routing.h | 3 +++ vpr/src/place/place.cpp | 3 +++ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3326eae4168..ab4090f4922 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,7 @@ option(VTR_ENABLE_CAPNPROTO "Enable capnproto binary serialization support in VP #VPR option --enable_analytic_placer is also required for Analytic Placement option(VPR_ANALYTIC_PLACE "Enable analytic placement in VPR." ON) option(VPR_ENABLE_INTERCHANGE "Enable FPGA interchange." ON) +option(VPR_ENABLE_NOC_SAT_ROUTING "Enable NoC SAT routing." OFF) option(WITH_BLIFEXPLORER "Enable build with blifexplorer" OFF) @@ -217,12 +218,12 @@ endforeach() set(FLEX_BISON_WARN_SUPPRESS_FLAGS "") set(FLEX_BISON_WARN_SUPPRESS_FLAGS_TO_CHECK "-Wno-redundant-decls" #Flex/bison generate code with redundant declarations - "-Wno-switch-default" #Flex/bison generate switch statments w/o default cases + "-Wno-switch-default" #Flex/bison generate switch statements w/o default cases "-Wno-unused-parameter" #Flex produces functions with unused params in re-entrant mode "-Wno-missing-declarations" #Flex misses some declarations in re-entrant mode "-Wimplicit-fallthrough=0" #Bison produces some cases with explicit "-Wno-sign-compare" #Flex generates code which performs some signed/unsigned comparison - "-Wno-null-dereference" #Bison produces some cases with potenetial null derefs + "-Wno-null-dereference" #Bison produces some cases with potential null derefs ) foreach(flag ${FLEX_BISON_WARN_SUPPRESS_FLAGS_TO_CHECK}) CHECK_CXX_COMPILER_FLAG(${flag} CXX_COMPILER_SUPPORTS_${flag}) diff --git a/vpr/CMakeLists.txt b/vpr/CMakeLists.txt index 316f7fafa83..18931053b86 100644 --- a/vpr/CMakeLists.txt +++ b/vpr/CMakeLists.txt @@ -73,6 +73,20 @@ if(${VPR_ANALYTIC_PLACE}) endif(TARGET Eigen3::Eigen) endif() +if (${VPR_ENABLE_NOC_SAT_ROUTING}) + message(STATUS "VPR NoC SAT Routing: Requested") + find_package(ortools CONFIG REQUIRED) + if (TARGET ortools::ortools) + message(STATUS "VPR NoC SAT Routing dependency (or-tools): Found") + message(STATUS "VPR NoC SAT Routing: Enabled") + target_link_libraries(libvpr ortools::ortools) + target_compile_definitions(libvpr PUBLIC -DENABLE_NOC_SAT_ROUTING) + else () + message(STATUS "VPR NoC SAT Routing dependency (or-tools): Not Found (You may need to set CMAKE_PREFIX_PATH in order for CMake to find your OR-Tools installation)") + message(STATUS "VPR NoC SAT Routing: Disabled") + endif (TARGET ortools::ortools) +endif () + set_target_properties(libvpr PROPERTIES PREFIX "") #Avoid extra 'lib' prefix #Specify link-time dependencies @@ -87,9 +101,6 @@ target_link_libraries(libvpr librrgraph ) -find_package(ortools CONFIG REQUIRED) -target_link_libraries(libvpr ortools::ortools) - #link graphics library only when graphics set to on if (VPR_USE_EZGL STREQUAL "on") target_link_libraries(libvpr diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index e06ab6f5c74..fec9b655fe9 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -1,3 +1,5 @@ +#ifdef ENABLE_NOC_SAT_ROUTING + #include "sat_routing.h" #include "turn_model_routing.h" @@ -940,4 +942,6 @@ vtr::vector> noc_sat_route(bool minimiz // when no feasible solution was found, return an empty vector return {}; -} \ No newline at end of file +} + +#endif //ENABLE_NOC_SAT_ROUTING \ No newline at end of file diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 97e9604c9bc..7f4f024bb02 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -1,6 +1,8 @@ #ifndef VTR_SATROUTING_H #define VTR_SATROUTING_H +#ifdef ENABLE_NOC_SAT_ROUTING + #include #include @@ -54,4 +56,5 @@ struct hash> { } // namespace std +#endif #endif \ No newline at end of file diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 1f20453b6c9..d228f925f17 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -1201,6 +1201,7 @@ void try_place(const Netlist<>& net_list, get_total_congestion_bandwidth_ratio(), get_number_of_congested_noc_links()); +#ifdef ENABLE_NOC_SAT_ROUTING if (costs.noc_cost_terms.congestion > 0.0) { VTR_LOG("NoC routing configuration is congested. Invoking the SAT NoC router.\n"); auto traffic_flow_routes = noc_sat_route(true, @@ -1236,7 +1237,9 @@ void try_place(const Netlist<>& net_list, VTR_LOG("SAT routing failed.\n"); } } +#endif //ENABLE_NOC_SAT_ROUTING } + update_screen(ScreenUpdatePriority::MAJOR, msg, PLACEMENT, timing_info); // Print out swap statistics print_resources_utilization(); From 2aac47882837fd15e526c3b692cc60587297efd1 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 28 May 2024 11:25:48 -0400 Subject: [PATCH 27/38] fix unit test compilation error --- vpr/test/test_noc_place_utils.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vpr/test/test_noc_place_utils.cpp b/vpr/test/test_noc_place_utils.cpp index 5475205d933..c854adf321e 100644 --- a/vpr/test/test_noc_place_utils.cpp +++ b/vpr/test/test_noc_place_utils.cpp @@ -189,7 +189,7 @@ TEST_CASE("test_initial_noc_placement", "[noc_place_utils]") { } // now call the test function - initial_noc_routing(); + initial_noc_routing({}); // now verify the function by comparing the link bandwidths in the noc model (should have been updated by the test function) to the golden set int number_of_links = golden_link_bandwidths.size(); @@ -379,7 +379,7 @@ TEST_CASE("test_initial_comp_cost_functions", "[noc_place_utils]") { // assume this works // this is needed to set up the global noc packet router and also global datastructures - initial_noc_routing(); + initial_noc_routing({}); SECTION("test_comp_noc_aggregate_bandwidth_cost") { //initialize all the cost calculator datastructures @@ -664,7 +664,7 @@ TEST_CASE("test_find_affected_noc_routers_and_update_noc_costs, test_commit_noc_ // assume this works // this is needed to set up the global noc packet router and also global datastructures - initial_noc_routing(); + initial_noc_routing({}); // datastructure below will store the bandwidth usages of all the links // and will be updated throughout this test. @@ -1523,7 +1523,7 @@ TEST_CASE("test_revert_noc_traffic_flow_routes", "[noc_place_utils]") { // assume this works // this is needed to set up the global noc packet router and also global datastructures - initial_noc_routing(); + initial_noc_routing({}); // datastructure below will store the bandwidth usages of all the links // and will be updated throughout this test. From 85c5ba2ad7ac6c033d8cb49bac9b01249c2304b0 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 28 May 2024 18:54:33 -0400 Subject: [PATCH 28/38] fix test_setup_noc.cpp compilation error --- vpr/test/test_setup_noc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index 575e058a849..0e0d6f6cb2b 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -689,7 +689,7 @@ TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { router_connection = noc_info.router_list[router_id - 1].connection_list.begin(); - for (auto noc_link = noc_model.get_noc_router_outgoing_links(current_source_router_id).begin(); noc_link != noc_model.get_noc_router_connections(current_source_router_id).end(); noc_link++) { + for (auto noc_link = noc_model.get_noc_router_outgoing_links(current_source_router_id).begin(); noc_link != noc_model.get_noc_router_outgoing_links(current_source_router_id).end(); noc_link++) { // get the connecting link const NocLink& connecting_link = noc_model.get_single_noc_link(*noc_link); @@ -711,7 +711,7 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { t_noc_inf noc_info; // pointer to each logical router - t_router* temp_router = NULL; + t_router* temp_router = nullptr; // start by creating all the logical routers // this is similiar to the user provided a config file From c1b7aa819560b0d80ed9da90880ad36cff16a908 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 29 May 2024 11:45:54 -0400 Subject: [PATCH 29/38] change the converter for --noc_sat_routing_log_search_progress --- vpr/src/base/read_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index d65eeb95a37..40f493a2367 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2901,7 +2901,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .default_value("0") .show_in(argparse::ShowIn::HELP_ONLY); - noc_grp.add_argument(args.noc_sat_routing_log_search_progress, "--noc_sat_routing_log_search_progress") + noc_grp.add_argument(args.noc_sat_routing_log_search_progress, "--noc_sat_routing_log_search_progress") .help( "Print the detailed log of the SAT solver's search progress.") .default_value("off") From 63e7cfc8243751d89e21cdaccee36078b58e498a Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 31 May 2024 17:31:08 -0400 Subject: [PATCH 30/38] check if all links have the same bandwidth in SAT router --- vpr/src/noc/sat_routing.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index fec9b655fe9..a376e9fde54 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -217,7 +217,21 @@ static vtr::vector quantize_traffic_flow_bandwidths(int b const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; //TODO: support heterogeneous bandwidth - const double link_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth(); + const auto& noc_links = noc_ctx.noc_model.get_noc_links(); + const double link_bandwidth = noc_links.front().get_bandwidth(); + auto it = std::adjacent_find(noc_links.begin(), noc_links.end(), [](const NocLink& a, const NocLink& b){ + return a.get_bandwidth() != b.get_bandwidth(); + }); + + if (it != noc_links.end()) { + const NocLink& first_link = *it; + const NocLink& second_link = *(it + 1); + VTR_LOG_ERROR( + "SAT router assumes all NoC links have the same bandwidth. " + "NoC links %d and %d have different bandwidth: %g and %g", + (size_t)first_link.get_link_id(), (size_t)second_link.get_link_id(), + first_link.get_bandwidth(), second_link.get_bandwidth()); + } vtr::vector rescaled_traffic_flow_bandwidths; rescaled_traffic_flow_bandwidths.resize(traffic_flow_storage.get_number_of_traffic_flows()); From 3fa4fa8102a06ce15f3494c7d3c4bbc0ccb99ae7 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 31 May 2024 18:00:20 -0400 Subject: [PATCH 31/38] check latency equality for routers and links --- vpr/src/noc/sat_routing.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index a376e9fde54..fe8d1ae093a 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -501,8 +501,33 @@ static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); + const auto& noc_links = noc_model.get_noc_links(); + const auto& noc_routers = noc_model.get_noc_routers(); const double noc_link_latency = noc_model.get_noc_link_latency(); const double noc_router_latency = noc_model.get_noc_router_latency(); + + auto router_it = std::find_if(noc_routers.begin(), noc_routers.end(), [noc_router_latency](const NocRouter& r) { + return (noc_router_latency != r.get_latency()); + }); + + if (router_it != noc_routers.end()) { + VTR_LOG_ERROR( + "SAT router assumes all NoC routers have the same latency. " + "NoC router with the user if %d has a different latency (%g) than the NoC-wide router latency (%g).\n", + router_it->get_router_user_id(), router_it->get_latency()); + } + + auto link_it = std::find_if(noc_links.begin(), noc_links.end(), [noc_link_latency](const NocLink& l) { + return (noc_link_latency != l.get_latency()); + }); + + if (link_it != noc_links.end()) { + VTR_LOG_ERROR( + "SAT router assumes all NoC links have the same latency. " + "NoC link %d has a different latency (%g) than the NoC-wide link latency (%g).\n", + (size_t)link_it->get_link_id(), link_it->get_latency()); + } + const double traffic_flow_latency_constraint = traffic_flow.max_traffic_flow_latency; VTR_ASSERT(traffic_flow_latency_constraint < 0.1); From d509ecdd90efcb5941408d183b7e105712891211 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 5 Jun 2024 12:09:48 -0400 Subject: [PATCH 32/38] add comments and subroutines --- libs/EXTERNAL/CMakeLists.txt | 2 - vpr/src/base/echo_files.cpp | 13 +++--- vpr/src/base/echo_files.h | 2 +- vpr/src/draw/draw_noc.cpp | 32 +++++++------- vpr/src/noc/noc_storage.cpp | 11 +++-- vpr/src/noc/noc_storage.h | 25 ++++++----- vpr/src/noc/turn_model_routing.cpp | 6 +++ vpr/src/place/noc_place_utils.cpp | 57 ++++++++++++++++++++++-- vpr/src/place/noc_place_utils.h | 64 ++++++++++++++++++++------- vpr/src/place/place.cpp | 69 ++---------------------------- 10 files changed, 154 insertions(+), 127 deletions(-) diff --git a/libs/EXTERNAL/CMakeLists.txt b/libs/EXTERNAL/CMakeLists.txt index 2ee6b06b1fe..a60c48958eb 100644 --- a/libs/EXTERNAL/CMakeLists.txt +++ b/libs/EXTERNAL/CMakeLists.txt @@ -9,8 +9,6 @@ add_subdirectory(libsdcparse) add_subdirectory(libblifparse) add_subdirectory(libtatum) add_subdirectory(libcatch2) - -#SET(BUILD_DEPS ON CACHE BOOL "Build libfoo shared library") #add_subdirectory(parmys) #VPR_USE_SERVER is initialized in the root CMakeLists diff --git a/vpr/src/base/echo_files.cpp b/vpr/src/base/echo_files.cpp index 9228aa13ae4..9627ba84f96 100644 --- a/vpr/src/base/echo_files.cpp +++ b/vpr/src/base/echo_files.cpp @@ -32,8 +32,7 @@ void setEchoEnabled(bool echo_enabled) { } void setAllEchoFileEnabled(bool value) { - int i; - for (i = 0; i < (int)E_ECHO_END_TOKEN; i++) { + for (int i = 0; i < (int)E_ECHO_END_TOKEN; i++) { echoFileEnabled[i] = value; } } @@ -67,7 +66,7 @@ void alloc_and_load_echo_file_info() { echoFileNames = new char*[(int)E_ECHO_END_TOKEN]; for (auto i = 0; i < (int)E_ECHO_END_TOKEN; i++) { echoFileEnabled[i] = false; - echoFileNames[i] = NULL; + echoFileNames[i] = nullptr; } setAllEchoFileEnabled(getEchoEnabled()); @@ -136,9 +135,8 @@ void alloc_and_load_echo_file_info() { } void free_echo_file_info() { - int i; if (echoFileEnabled != nullptr) { - for (i = 0; i < (int)E_ECHO_END_TOKEN; i++) { + for (int i = 0; i < (int)E_ECHO_END_TOKEN; i++) { if (echoFileNames[i] != nullptr) { delete[] echoFileNames[i]; } @@ -165,7 +163,7 @@ char* getOutputFileName(enum e_output_files ename) { return outputFileNames[(int)ename]; } -void alloc_and_load_output_file_names(const std::string default_name) { +void alloc_and_load_output_file_names(const std::string& default_name) { std::string name; if (outputFileNames == nullptr) { @@ -185,9 +183,8 @@ void alloc_and_load_output_file_names(const std::string default_name) { } void free_output_file_names() { - int i; if (outputFileNames != nullptr) { - for (i = 0; i < (int)E_FILE_END_TOKEN; i++) { + for (int i = 0; i < (int)E_FILE_END_TOKEN; i++) { if (outputFileNames[i] != nullptr) { delete[] outputFileNames[i]; outputFileNames[i] = nullptr; diff --git a/vpr/src/base/echo_files.h b/vpr/src/base/echo_files.h index 548d6a9fe49..ea02d58bc92 100644 --- a/vpr/src/base/echo_files.h +++ b/vpr/src/base/echo_files.h @@ -92,7 +92,7 @@ void free_echo_file_info(); void setOutputFileName(enum e_output_files ename, const char* name, const char* default_name); char* getOutputFileName(enum e_output_files ename); -void alloc_and_load_output_file_names(const std::string default_name); +void alloc_and_load_output_file_names(const std::string& default_name); void free_output_file_names(); #endif diff --git a/vpr/src/draw/draw_noc.cpp b/vpr/src/draw/draw_noc.cpp index e3d39ed4294..83b45d152eb 100644 --- a/vpr/src/draw/draw_noc.cpp +++ b/vpr/src/draw/draw_noc.cpp @@ -34,8 +34,8 @@ void draw_noc(ezgl::renderer* g) { return; } - // check that the NoC tile has a capacity greater than 0 (can we assume it always will?) and if not then we cant draw anythign as the NoC tile wont be drawn - /* since the vector of routers all have a reference positions on the grid to the corresponding physical tile, just use the first router in the vector and get its position, then use this to get the capcity of a noc router tile + // check that the NoC tile has a capacity greater than 0 (can we assume it always will?) and if not then we cant draw anything as the NoC tile won't be drawn + /* since the vector of routers all have a reference positions on the grid to the corresponding physical tile, just use the first router in the vector and get its position, then use this to get the capacity of a noc router tile */ const auto& type = device_ctx.grid.get_physical_type({router_list.begin()->get_router_grid_position_x(), router_list.begin()->get_router_grid_position_y(), @@ -239,7 +239,7 @@ void draw_noc_links(ezgl::renderer* g, t_logical_block_type_ptr noc_router_logic NocLinkType link_type; // get half the width and height of the noc connection marker - // we will shift the links based on this parameters since the links will be drawn at the boundaries of connection marker instead of the center + // we will shift the links based on these parameters since the links will be drawn at the boundaries of connection marker instead of the center double noc_connection_marker_quarter_width = (noc_connection_marker_bbox.center().x - noc_connection_marker_bbox.bottom_left().x) / 2; double noc_connection_marker_quarter_height = (noc_connection_marker_bbox.center().y - noc_connection_marker_bbox.bottom_left().y) / 2; @@ -293,7 +293,7 @@ void determine_direction_to_shift_noc_links(vtr::vector int number_of_links = list_of_noc_link_shift_directions.size(); - // store the parallel link of wach link we process + // store the parallel link of each link we process NocLinkId parallel_link; // go through all the noc links and assign how the link should be shifted @@ -301,7 +301,7 @@ void determine_direction_to_shift_noc_links(vtr::vector // convert the link to a link id NocLinkId link_id(link); - // only assign a shift direction if we havent already + // only assign a shift direction if we haven't already if (list_of_noc_link_shift_directions[link_id] == NocLinkShift::NO_SHIFT) { // the current link will always have a TOP_shift list_of_noc_link_shift_directions[link_id] = NocLinkShift::TOP_SHIFT; @@ -310,8 +310,8 @@ void determine_direction_to_shift_noc_links(vtr::vector parallel_link = noc_ctx.noc_model.get_parallel_link(link_id); // check first if a legal link id was found - if (parallel_link == INVALID_LINK_ID) { - // if we are here, then a parallel link wasnt found, so that means there is only a single link and there is no need to perform any shifting on the single link + if (parallel_link == NocLinkId::INVALID()) { + // if we are here, then a parallel link wasn't found, so that means there is only a single link and there is no need to perform any shifting on the single link list_of_noc_link_shift_directions[link_id] = NocLinkShift::NO_SHIFT; continue; @@ -334,13 +334,13 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 double x_coord_horizontal_start = link_start_point.x; double y_coord_horizontal_start = link_start_point.y; - double x_coord_horziontal_end = x_coord_horizontal_start + HORIZONTAL_LINE_LENGTH; + double x_coord_horizontal_end = x_coord_horizontal_start + HORIZONTAL_LINE_LENGTH; double y_coord_horizontal_end = link_start_point.y; // stores the link type NocLinkType result = NocLinkType::INVALID_TYPE; - // we can check quickly if the link is vertical or horizontal without calculating the dot product. If it is vertical or horizontal then we just return. Otherwise we have to calculate it. + // we can check quickly if the link is vertical or horizontal without calculating the dot product. If it is vertical or horizontal then we just return. Otherwise, we have to calculate it. // check if the link is vertical by determining if there is any horizontal change if (vtr::isclose(x_coord_end - x_coord_start, 0.0)) { @@ -349,7 +349,7 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 return result; } - // check if the link is horizontal by determinig if there is any vertical shift + // check if the link is horizontal by determining if there is any vertical shift if (vtr::isclose(y_coord_end - y_coord_start, 0.0)) { result = NocLinkType::HORIZONTAL; @@ -361,11 +361,11 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 // get the magnitude of the link double link_magnitude = sqrt(pow(x_coord_end - x_coord_start, 2.0) + pow(y_coord_end - y_coord_start, 2.0)); // get the dot product of the two connecting line - double dot_product_of_link_and_horizontal_line = (x_coord_end - x_coord_start) * (x_coord_horziontal_end - x_coord_horizontal_start) + (y_coord_end - y_coord_start) * (y_coord_horizontal_end - y_coord_horizontal_start); + double dot_product_of_link_and_horizontal_line = (x_coord_end - x_coord_start) * (x_coord_horizontal_end - x_coord_horizontal_start) + (y_coord_end - y_coord_start) * (y_coord_horizontal_end - y_coord_horizontal_start); // calculate the angle double angle = acos(dot_product_of_link_and_horizontal_line / (link_magnitude * HORIZONTAL_LINE_LENGTH)); - // the angle is in the first or fourth quandrant of the unit circle + // the angle is in the first or fourth quadrant of the unit circle if ((angle > 0) && (angle < (PI_RADIAN / 2))) { // if the link is a positive sloped line, then its end point must be higher than its start point (must be higher than the connected horizontal line) if (y_coord_end > y_coord_horizontal_end) { @@ -375,7 +375,7 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 result = NocLinkType::NEGATIVE_SLOPE; } - } else { // the case where the angle is in the 3rd and 4th quandrant of the unit cirle + } else { // the case where the angle is in the 3rd and 4th quadrant of the unit circle // if the link is a positive sloped line, then its end point must be lower than its start point (must be lower than the connected horizontal line) if (y_coord_end < y_coord_horizontal_end) { @@ -415,7 +415,7 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d link_coords.start.x += noc_connection_marker_quarter_width; link_coords.end.x += noc_connection_marker_quarter_width; } - // dont change anything if we arent shifting at all + // don't change anything if we aren't shifting at all break; case NocLinkType::HORIZONTAL: if (link_shift_direction == NocLinkShift::TOP_SHIFT) { @@ -427,7 +427,7 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d link_coords.start.y -= noc_connection_marker_quarter_height; link_coords.end.y -= noc_connection_marker_quarter_height; } - // dont change anything if we arent shifting at all + // don't change anything if we aren't shifting at all break; case NocLinkType::POSITVE_SLOPE: if (link_shift_direction == NocLinkShift::TOP_SHIFT) { @@ -445,7 +445,7 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d link_coords.start.y -= noc_connection_marker_quarter_height; link_coords.end.y -= noc_connection_marker_quarter_height; } - // dont change anything if we arent shifting at all + // don't change anything if we aren't shifting at all break; case NocLinkType::NEGATIVE_SLOPE: if (link_shift_direction == NocLinkShift::TOP_SHIFT) { diff --git a/vpr/src/noc/noc_storage.cpp b/vpr/src/noc/noc_storage.cpp index 94f97d1c641..f3fe939eecc 100644 --- a/vpr/src/noc/noc_storage.cpp +++ b/vpr/src/noc/noc_storage.cpp @@ -1,5 +1,8 @@ #include "noc_storage.h" +#include "vtr_assert.h" +#include "vpr_error.h" + #include @@ -20,7 +23,7 @@ const vtr::vector& NocStorage::get_noc_routers() const { return router_storage; } -int NocStorage::get_number_of_noc_routers(void) const { +int NocStorage::get_number_of_noc_routers() const { return router_storage.size(); } @@ -281,12 +284,12 @@ NocLinkId NocStorage::get_parallel_link(NocLinkId current_link) const { NocRouterId curr_sink_router = link_storage[current_link].get_sink_router(); // get the link list of the sink router - const std::vector* sink_router_links = &(router_outgoing_links_list[curr_sink_router]); + const std::vector& sink_router_links = router_outgoing_links_list[curr_sink_router]; - NocLinkId parallel_link = INVALID_LINK_ID; + NocLinkId parallel_link = NocLinkId::INVALID(); // go through the links of the sink router and the link that has the current source router as the sink router of the link is the parallel link we are looking for - for (auto sink_router_link : *sink_router_links) { + for (auto sink_router_link : sink_router_links) { if (link_storage[sink_router_link].get_sink_router() == curr_source_router) { parallel_link = sink_router_link; break; diff --git a/vpr/src/noc/noc_storage.h b/vpr/src/noc/noc_storage.h index fe545436ba1..bbefe9b4fa9 100644 --- a/vpr/src/noc/noc_storage.h +++ b/vpr/src/noc/noc_storage.h @@ -35,7 +35,6 @@ * */ -#include #include #include #include @@ -43,13 +42,6 @@ #include "vtr_vector.h" #include "noc_router.h" #include "noc_link.h" -#include "vtr_assert.h" -#include "vpr_error.h" -#include "echo_files.h" -// \cond -// represents the id of a link that does not exist in the NoC -constexpr NocLinkId INVALID_LINK_ID(-1); -// \endcond class NocStorage { private: @@ -61,10 +53,14 @@ class NocStorage { * @brief Stores outgoing links for each router in the NoC. These * links can be used by the router to communicate to other routers * in the NoC. - * */ vtr::vector> router_outgoing_links_list; + /** + * @brief Stores incoming links for each router in the NoC. These + * links can be used by the router to communicate to other routers + * in the NoC. + */ vtr::vector> router_incoming_links_list; /** Contains all the links in the NoC*/ @@ -78,7 +74,6 @@ class NocStorage { * are dense since it is used to index the routers. The datastructure * below is a conversiont able that maps the user router IDs to the * corresponding internal ones. - * */ std::unordered_map router_id_conversion_table; @@ -180,7 +175,7 @@ class NocStorage { /** * @brief Gets a vector of outgoing links for a given router - * in the NoC. THe link vector cannot be modified. + * in the NoC. The link vector cannot be modified. * * @param id A unique identifier that represents a router * @return A vector of links. The links are represented by a unique @@ -188,6 +183,14 @@ class NocStorage { */ const std::vector& get_noc_router_outgoing_links(NocRouterId id) const; + /** + * @brief Gets a vector of incoming links for a given router + * in the NoC. + * + * @param id A unique identifier that represents a router + * @return A vector of links. The links are represented by a unique + * identifier. + */ const std::vector& get_noc_router_incoming_links(NocRouterId id) const; /** diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index 0586ea076eb..802a2fa5104 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -237,6 +237,12 @@ TurnModelRouting::Direction TurnModelRouting::select_direction_other_than(const std::vector> TurnModelRouting::get_all_illegal_turns(const NocStorage& noc_model) const { std::vector> illegal_turns; + /* Iterate over all sets of three routers that can be traversed in sequence. + * Check if traversing these three routes involves any turns, and if so, + * check if the resulting turn is illegal under the restrictions of a turn model + * routing algorithm. Store all illegal turns and return them. + */ + for (const auto& noc_router : noc_model.get_noc_routers()) { const int noc_router_user_id = noc_router.get_router_user_id(); const NocRouterId noc_router_id = noc_model.convert_router_id(noc_router_user_id); diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index a2cd925fe0d..36eb1449b04 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -11,6 +11,7 @@ #include "noc_routing.h" #include "place_constraints.h" #include "move_transactions.h" +#include "sat_routing.h" #include @@ -67,13 +68,18 @@ void initial_noc_routing(const vtr::vector& curr_traffic_flow_route = new_traffic_flow_routes.empty() ? route_traffic_flow(traffic_flow_id, noc_ctx.noc_model, noc_traffic_flows_storage, *noc_ctx.noc_flows_router) : new_traffic_flow_routes[traffic_flow_id]; + /* Update the traffic flow route based on where the router cluster blocks are placed. + * If the caller has not provided traffic flow routes, route traffic flow, otherwise use the provided route. + */ + const std::vector& curr_traffic_flow_route = new_traffic_flow_routes.empty() + ? route_traffic_flow(traffic_flow_id, noc_ctx.noc_model, noc_traffic_flows_storage, *noc_ctx.noc_flows_router) + : new_traffic_flow_routes[traffic_flow_id]; if (!new_traffic_flow_routes.empty()) { noc_traffic_flows_storage.get_mutable_traffic_flow_route(traffic_flow_id) = curr_traffic_flow_route; @@ -217,7 +223,10 @@ std::vector& route_traffic_flow(NocTrafficFlowId traffic_flow_id, return curr_traffic_flow_route; } -void update_traffic_flow_link_usage(const std::vector& traffic_flow_route, NocStorage& noc_model, int inc_or_dec, double traffic_flow_bandwidth) { +void update_traffic_flow_link_usage(const std::vector& traffic_flow_route, + NocStorage& noc_model, + int inc_or_dec, + double traffic_flow_bandwidth) { // go through the links within the traffic flow route and update their bandwidth usage for (auto& link_in_route_id : traffic_flow_route) { // get the link to update and its current bandwidth @@ -920,6 +929,46 @@ bool noc_routing_has_cycle(const vtr::vector find_affected_links_by_flow_reroute(std::vector& prev_links, std::vector& curr_links) { // Sort both link containers diff --git a/vpr/src/place/noc_place_utils.h b/vpr/src/place/noc_place_utils.h index 5f537477ceb..2f34a895f17 100644 --- a/vpr/src/place/noc_place_utils.h +++ b/vpr/src/place/noc_place_utils.h @@ -1,6 +1,7 @@ #ifndef NOC_PLACE_UTILS_H #define NOC_PLACE_UTILS_H +#include #include "move_utils.h" #include "place_util.h" @@ -38,23 +39,27 @@ struct TrafficFlowPlaceCost { }; /** - * @brief Routes all the traffic flows within the NoC and updates the link usage - * for all links. This should be called after initial placement, where all the - * logical NoC router blocks have been placed for the first time and no traffic - * flows have been routed yet. This function should also only be used once as - * its intended use is to initialize the routes for all the traffic flows. - * - * This is different from a complete re-route of the traffic flows as this - * function assumes the traffic flows have not been routed yet, whereas a - * complete re-route function assumes the traffic flows have already been - * routed. This is why this function should only be used once. - * + * @brief Initializes the link bandwidth usage for all NoC links. + * + * If traffic flow routes are not passed to this function, it uses a NoC routing algorithm + * to route all traffic flows. The caller can prevent this function from routing traffic flows + * by passing routes for all traffic flows. This should be called after initial placement, + * where all the logical NoC router blocks have been placed for the first time and no traffic + * flows have been routed yet. In this case an empty vector should be passed to the function. + * This function can also be called after modification of traffic flow routes. For example, + * NoC SAT routing algorithm generates new traffic flow routes to avoid congestion. The routes + * generate by the SAT router should be passed to this function + * + * + * @param new_traffic_flow_routes Traffic flow routes used to initialize link bandwidth utilization. + * If an empty vector is passed, this function uses a routing algorithm to route traffic flows. */ void initial_noc_routing(const vtr::vector>& new_traffic_flow_routes); /** - * @brief Zeros out all link bandwidth usage an re-routes traffic flows. - * Initializes static variables in noc_place_utils.cpp that are used to + * @brief Re-initializes all link bandwidth usages by either re-routing + * all traffic flows or using the provided traffic flow routes. This functions + * also initializes static variables in noc_place_utils.cpp that are used to * keep track of NoC-related costs. * * This function should be called when a placement checkpoint is restored. @@ -63,7 +68,12 @@ void initial_noc_routing(const vtr::vector>& new_traffic_flow_routes); @@ -475,7 +485,6 @@ std::vector get_top_n_congestion_ratios(int n); * initialize the datastructures here. * * This should be called before starting the simulated annealing placement. - * */ void allocate_and_load_noc_placement_structs(); @@ -535,7 +544,6 @@ e_create_move propose_router_swap(t_pl_blocks_to_be_moved& blocks_affected, floa * information. * */ - void write_noc_placement_file(const std::string& file_name); /** @@ -553,6 +561,32 @@ void write_noc_placement_file(const std::string& file_name); */ bool noc_routing_has_cycle(); +/** + * @brief Check if the channel dependency graph created from the given traffic flow routes + * has any cycles. + * @param routes The user provided traffic flow routes. + * @return True if there is any cycles in the channel dependency graph. + */ bool noc_routing_has_cycle(const vtr::vector>& routes); +/** + * @brief Invokes NoC SAT router and print new NoC cost terms after SAT router + * solved the NoC routing problem. + * + * @param costs To be updated with new NoC-related cost terms after traffic flow routes + * generated by the SAT router replace the old traffic flow routes. + * @param noc_opts Contains NoC-related cost weighting factor used in the SAT router. + * @param seed The initialization seed used in the SAT solver. + */ +void invoke_sat_router(t_placer_costs& costs, const t_noc_opts& noc_opts, int seed); + +/** + * @brief Prints NoC related costs terms and metrics. + * + * @param header The string with which the report starts. + * @param costs Contains NoC-related cost terms. + * @param noc_opts Used to compute total NoC cost. + */ +void print_noc_costs(std::string_view header, const t_placer_costs& costs, const t_noc_opts& noc_opts); + #endif \ No newline at end of file diff --git a/vpr/src/place/place.cpp b/vpr/src/place/place.cpp index 3b1b2beaf32..f7290afb374 100644 --- a/vpr/src/place/place.cpp +++ b/vpr/src/place/place.cpp @@ -826,23 +826,7 @@ void try_place(const Netlist<>& net_list, VTR_LOG("Initial placement cost: %g bb_cost: %g td_cost: %g\n", costs.cost, costs.bb_cost, costs.timing_cost); if (noc_opts.noc) { - VTR_LOG("Initial NoC Placement Costs. " - "cost: %g, " - "aggregate_bandwidth_cost: %g, " - "latency_cost: %g, " - "n_met_latency_constraints: %d, " - "latency_overrun_cost: %g, " - "congestion_cost: %g, " - "accum_congested_ratio: %g, " - "n_congested_links: %d \n", - calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), - costs.noc_cost_terms.aggregate_bandwidth, - costs.noc_cost_terms.latency, - get_number_of_traffic_flows_with_latency_cons_met(), - costs.noc_cost_terms.latency_overrun, - costs.noc_cost_terms.congestion, - get_total_congestion_bandwidth_ratio(), - get_number_of_congested_noc_links()); + print_noc_costs("Initial NoC Placement Costs", costs, noc_opts); } if (placer_opts.place_algorithm.is_timing_driven()) { VTR_LOG( @@ -1184,59 +1168,12 @@ void try_place(const Netlist<>& net_list, costs.bb_cost, costs.timing_cost); // print the noc costs info if (noc_opts.noc) { - VTR_LOG("\nNoC Placement Costs. " - "cost: %g, " - "aggregate_bandwidth_cost: %g, " - "latency_cost: %g, " - "n_met_latency_constraints: %d, " - "latency_overrun_cost: %g, " - "congestion_cost: %g, " - "accum_congested_ratio: %g, " - "n_congested_links: %d \n", - calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), - costs.noc_cost_terms.aggregate_bandwidth, - costs.noc_cost_terms.latency, - get_number_of_traffic_flows_with_latency_cons_met(), - costs.noc_cost_terms.latency_overrun, - costs.noc_cost_terms.congestion, - get_total_congestion_bandwidth_ratio(), - get_number_of_congested_noc_links()); + print_noc_costs("\nNoC Placement Costs", costs, noc_opts); #ifdef ENABLE_NOC_SAT_ROUTING if (costs.noc_cost_terms.congestion > 0.0) { VTR_LOG("NoC routing configuration is congested. Invoking the SAT NoC router.\n"); - auto traffic_flow_routes = noc_sat_route(true, - noc_opts, - placer_opts.seed); - - if (!traffic_flow_routes.empty()) { - bool has_cycle = noc_routing_has_cycle(traffic_flow_routes); - if (has_cycle) { - VTR_LOG("SAT NoC routing has cycles.\n"); - } - - reinitialize_noc_routing(costs, traffic_flow_routes); - - VTR_LOG("\nNoC Placement Costs after SAT routing. " - "cost: %g, " - "aggregate_bandwidth_cost: %g, " - "latency_cost: %g, " - "n_met_latency_constraints: %d, " - "latency_overrun_cost: %g, " - "congestion_cost: %g, " - "accum_congested_ratio: %g, " - "n_congested_links: %d \n", - calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), - costs.noc_cost_terms.aggregate_bandwidth, - costs.noc_cost_terms.latency, - get_number_of_traffic_flows_with_latency_cons_met(), - costs.noc_cost_terms.latency_overrun, - costs.noc_cost_terms.congestion, - get_total_congestion_bandwidth_ratio(), - get_number_of_congested_noc_links()); - } else { - VTR_LOG("SAT routing failed.\n"); - } + invoke_sat_router(costs, noc_opts, placer_opts.seed); } #endif //ENABLE_NOC_SAT_ROUTING } From 2fe22e8ea10a9b20c9a5523e2d7c7520338cd039 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 5 Jun 2024 12:40:13 -0400 Subject: [PATCH 33/38] add comments in is_turn_legal() overrides --- vpr/src/noc/negative_first_routing.cpp | 7 +++++++ vpr/src/noc/north_last_routing.cpp | 6 ++++++ vpr/src/noc/odd_even_routing.cpp | 3 ++- vpr/src/noc/west_first_routing.cpp | 6 ++++++ vpr/src/noc/xy_routing.cpp | 1 + 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index 00ea2ac7ea5..eaec531a554 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -119,6 +119,7 @@ bool NegativeFirstRouting::is_turn_legal(const std::array x1 && y3 < y2) { return false; } + /* In negative-first routing algorithm, a traffic flow + * can't take a left turn if it is travelling upwards. + */ if (y2 > y1 && x3 < x2) { return false; } diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index bf9655962e1..7bfc58791c0 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -108,6 +108,7 @@ bool NorthLastRouting::is_turn_legal(const std::array y1 && x2 != x3) { return false; } diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 1897b6fee23..daa2114864d 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -171,13 +171,13 @@ bool OddEvenRouting::is_turn_legal(const std::array Date: Wed, 5 Jun 2024 15:09:09 -0400 Subject: [PATCH 34/38] move DEFAULT_MAX_TRAFFIC_FLOW_LATENCY to NocTrafficFlows --- vpr/src/noc/noc_traffic_flows.cpp | 22 +++++----------- vpr/src/noc/noc_traffic_flows.h | 26 ++++++++++++++----- .../noc/read_xml_noc_traffic_flows_file.cpp | 14 ++-------- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 5 ---- vpr/src/noc/sat_routing.cpp | 4 +-- 5 files changed, 30 insertions(+), 41 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 9d80f4c692f..795a0316cb6 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -9,7 +9,7 @@ NocTrafficFlows::NocTrafficFlows() { // getters for the traffic flows -int NocTrafficFlows::get_number_of_traffic_flows(void) const { +int NocTrafficFlows::get_number_of_traffic_flows() const { return noc_traffic_flows.size(); } @@ -33,7 +33,7 @@ const std::vector& NocTrafficFlows::get_traffic_flows_associat } } -int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { +int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows() { return traffic_flows_associated_to_router_blocks.size(); } @@ -49,11 +49,11 @@ const vtr::vector>& NocTrafficFlows::ge return traffic_flow_routes; } -const std::vector& NocTrafficFlows::get_router_clusters_in_netlist(void) const { +const std::vector& NocTrafficFlows::get_router_clusters_in_netlist() const { return router_cluster_in_netlist; } -const std::vector& NocTrafficFlows::get_all_traffic_flow_id(void) const { +const std::vector& NocTrafficFlows::get_all_traffic_flow_id() const { return noc_traffic_flows_ids; } @@ -84,8 +84,6 @@ void NocTrafficFlows::create_noc_traffic_flow(const std::string& source_router_m // now add the new traffic flow to flows associated with the current source and sink router add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id); add_traffic_flow_to_associated_routers(curr_traffic_flow_id, sink_router_cluster_id); - - return; } void NocTrafficFlows::set_router_cluster_in_netlist(const std::vector& routers_cluster_id_in_netlist) { @@ -98,18 +96,16 @@ void NocTrafficFlows::set_router_cluster_in_netlist(const std::vectorsecond.emplace_back(traffic_flow_id); } - - return; } void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { @@ -208,6 +200,4 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { } vtr::fclose(fp); - - return; } \ No newline at end of file diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index dac054d4bef..7db9041a05d 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -154,7 +154,7 @@ class NocTrafficFlows { * @return int An integer that represents the number of unique traffic * flows within the NoC. */ - int get_number_of_traffic_flows(void) const; + int get_number_of_traffic_flows() const; /** * @brief Given a unique id of a traffic flow (t_noc_traffic_flow) @@ -192,7 +192,7 @@ class NocTrafficFlows { * @return int The total number of unique routers used in * the traffic flows provided by the user. */ - int get_number_of_routers_used_in_traffic_flows(void); + int get_number_of_routers_used_in_traffic_flows(); /** * @brief Gets the routed path of traffic flow. This cannot be @@ -229,13 +229,13 @@ class NocTrafficFlows { * @return a vector ([0..num_logical_router-1]) where each entry gives the clusterBlockId * of a logical NoC router. Used for fast lookups in the placer. */ - const std::vector& get_router_clusters_in_netlist(void) const; + const std::vector& get_router_clusters_in_netlist() const; /** * @return provides access to all traffic flows' ids to allow a range-based * loop through all traffic flows, used in noc_place_utils.cpp functions. */ - const std::vector& get_all_traffic_flow_id(void) const; + const std::vector& get_all_traffic_flow_id() const; // setters @@ -294,14 +294,14 @@ class NocTrafficFlows { * */ - void finished_noc_traffic_flows_setup(void); + void finished_noc_traffic_flows_setup(); /** * @brief Resets the class by clearing internal * datastructures. * */ - void clear_traffic_flows(void); + void clear_traffic_flows(); /** * @brief Given a block from the clustered netlist, determine @@ -331,6 +331,20 @@ class NocTrafficFlows { * traffic flow information */ void echo_noc_traffic_flows(char* file_name); + + + /** + * @brief Defines the latency constraint of a traffic flow + * when not provided by the user. + * + * This value has to be significantly larger than latencies + * seen within the NoC so that the net effect in the placement + * cost is 0 (the latency constraint has no effect since there is none). + * Since the traffic flow latencies will be in nanoseconds, + * setting this value to 1 second which is significantly larger + * than what will be seen in the NoC. + */ + static constexpr double DEFAULT_MAX_TRAFFIC_FLOW_LATENCY = 1.; }; #endif \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 07bd53be7ce..3f12c02ed2d 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -3,7 +3,7 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { // start by checking that the provided file is a ".flows" file - if (vtr::check_file_name_extension(noc_flows_file, ".flows") == false) { + if (!vtr::check_file_name_extension(noc_flows_file, ".flows")) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "NoC traffic flows file '%s' has an unknown extension. Expecting .flows for NoC traffic flow files.", noc_flows_file); } @@ -72,8 +72,6 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_NOC_TRAFFIC_FLOWS)) { noc_ctx.noc_traffic_flows_storage.echo_noc_traffic_flows(getEchoFileName(E_ECHO_NOC_TRAFFIC_FLOWS)); } - - return; } void process_single_flow(pugi::xml_node single_flow_tag, @@ -125,8 +123,6 @@ void process_single_flow(pugi::xml_node single_flow_tag, traffic_flow_bandwidth, max_traffic_flow_latency, traffic_flow_priority); - - return; } double get_traffic_flow_bandwidth(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data) { @@ -144,7 +140,7 @@ double get_traffic_flow_bandwidth(pugi::xml_node single_flow_tag, const pugiutil double get_max_traffic_flow_latency(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data) { // "set to large value, indicating no constraint - double max_traffic_flow_latency = DEFAULT_MAX_TRAFFIC_FLOW_LATENCY; + double max_traffic_flow_latency = NocTrafficFlows::DEFAULT_MAX_TRAFFIC_FLOW_LATENCY; // holds the latency value as a string so that it can be used to convert to a floating point value (this is done so that scientific notation is supported) std::string max_traffic_flow_latency_intermediate_val; @@ -194,8 +190,6 @@ void verify_traffic_flow_router_modules(const std::string& source_router_name, c // Cannot have the source and sink routers have the same name (they need to be different). A flow cant go to a single router. vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and sink NoC routers cannot be the same modules."); } - - return; } void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, int traffic_flow_priority, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data) { @@ -213,8 +207,6 @@ void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_tr if (traffic_flow_priority <= 0) { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The traffic flow priorities expected to be positive, non-zero integer values."); } - - return; } ClusterBlockId get_router_module_cluster_id(const std::string& router_module_name, @@ -254,8 +246,6 @@ void check_traffic_flow_router_module_type(const std::string& router_module_name if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)) { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied module name '%s' is not a NoC router.", router_module_name.c_str()); } - - return; } t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx) { diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 55cecc38bc1..7abd685d82e 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -39,11 +39,6 @@ // identifier when an integer conversion failed while reading an attribute value in an xml file constexpr int NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE = -1; -// defines the latency constraint of a traffic flow when not provided by the user -// This value has to be significantly larger than latencies seen within the NoC so that the net effect in the placement cost is 0 (the latency constraint has no effect since there is none) -// Since the traffic flow latencies will be in nanoseconds, setting this value to 1 second which is significantly larger that what will be seen in the NoC -constexpr double DEFAULT_MAX_TRAFFIC_FLOW_LATENCY = 1.; - // defines the priority of a traffic flow when not specified by a user constexpr int DEFAULT_TRAFFIC_FLOW_PRIORITY = 1; diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index fe8d1ae093a..dad1fe22251 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -482,7 +482,7 @@ static void create_flow_link_vars(orsat::CpModelBuilder& cp_model, const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); // create an integer variable for each latency-constrained traffic flow - if (traffic_flow.max_traffic_flow_latency < 0.1) { + if (traffic_flow.max_traffic_flow_latency < NocTrafficFlows::DEFAULT_MAX_TRAFFIC_FLOW_LATENCY) { latency_overrun_vars[traffic_flow_id] = cp_model.NewIntVar(latency_overrun_domain); } @@ -530,7 +530,7 @@ static int comp_max_number_of_traversed_links(NocTrafficFlowId traffic_flow_id) const double traffic_flow_latency_constraint = traffic_flow.max_traffic_flow_latency; - VTR_ASSERT(traffic_flow_latency_constraint < 0.1); + VTR_ASSERT(traffic_flow_latency_constraint < NocTrafficFlows::DEFAULT_MAX_TRAFFIC_FLOW_LATENCY); int n_max_links = std::floor((traffic_flow_latency_constraint - noc_router_latency) / (noc_link_latency + noc_router_latency)); From 90d49381f2ba64466d6f1143c86d25ed92dc0bc2 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 5 Jun 2024 15:37:03 -0400 Subject: [PATCH 35/38] specify the domain of latency overrun vars based on the noc dimensions --- vpr/src/base/vpr_types.h | 2 +- vpr/src/noc/odd_even_routing.cpp | 5 +- vpr/src/noc/sat_routing.cpp | 443 ++++-------------------- vpr/src/noc/sat_routing.h | 39 ++- vpr/src/place/initial_noc_placement.cpp | 35 -- vpr/src/place/initial_placement.cpp | 2 +- 6 files changed, 99 insertions(+), 427 deletions(-) diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 23a065d56e5..7e231136aad 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1504,7 +1504,7 @@ struct t_noc_opts { double noc_congestion_weighting; ///& OddEvenRouting::get_legal_direct const auto curr_router_pos = curr_router.get_router_physical_location(); const auto dst_router_pos = dst_router.get_router_physical_location(); - // get the compressed location for source, current, and destination NoC routers + /* get the compressed location for source, current, and destination NoC routers + * Odd-even routing algorithm restricts turn based on whether the current NoC router + * in an odd or even NoC column. This information can be extracted from the NoC compressed grid. + */ auto compressed_src_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{src_router_pos, 0}, num_layers)[src_router_pos.layer_num]; auto compressed_curr_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{curr_router_pos, 0}, num_layers)[curr_router_pos.layer_num]; auto compressed_dst_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{dst_router_pos, 0}, num_layers)[dst_router_pos.layer_num]; diff --git a/vpr/src/noc/sat_routing.cpp b/vpr/src/noc/sat_routing.cpp index dad1fe22251..354620c6cfa 100644 --- a/vpr/src/noc/sat_routing.cpp +++ b/vpr/src/noc/sat_routing.cpp @@ -44,6 +44,10 @@ static void create_flow_link_vars(orsat::CpModelBuilder& cp_model, * @brief Translates a latency constraint for a traffic flow to the maximum number * of links that the traffic flow can traverse without violating the latency constraint. * + * This translation is possible only when all NoC routers or links have the same latency. + * NoC routers can have a different latency than NoC links, but all router (or links) must + * have the same latency. + * * @param traffic_flow_id The unique ID of the latency-constrained traffic flow. * @return The maximum number links that can travelled by the given traffic flow without * violating the latency constraint. @@ -104,7 +108,7 @@ static void forbid_illegal_turns(t_flow_link_var_map& flow_link_vars, * when their corresponding link congested. * * Since the SAT solver cannot work with floating point numbers, - * all link and traffic flow bandwidth are quantized. + * all link and traffic flow bandwidths are quantized. * * @param congested_link_vars To be filled with created boolean variables * to indicate whether links are congested. @@ -125,7 +129,7 @@ static void create_congested_link_vars(vtr::vector& * are quantized accordingly. * * @param bandwidth_resolution The resolution by which traffic flow bandwidth are - * quantized. + * quantized. Quantized bandwidths increment by link_bandwidth/resolution. * @return A vector of quantized traffic flow bandwidths. */ static vtr::vector quantize_traffic_flow_bandwidths(int bandwidth_resolution); @@ -147,8 +151,9 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, * This objective function is a linear combination of latency overrun, * the number of congested links, and the quantized aggregate bandwidth. * - * @param cp_model - * @param flow_link_vars + * @param cp_model The CP model builder object. New constraints are added + * to this model builder object. + * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. * @param latency_overrun_vars Integer variables for latency-constrained * traffic flows. Each integer variable shows how many extra links a constrained * traffic flow has traversed beyond what its latency constraint allows. @@ -174,6 +179,38 @@ static orsat::LinearExpr create_objective(orsat::CpModelBuilder& cp_model, int congestion_weight, bool minimize_aggregate_bandwidth); +/** + * @brief Converts the activated (traffic flow, link) boolean variables to + * traffic flow routes. + * + * Note that traffic flow routes are not sorted in traversal order. Each + * traffic flow route contains NoC links that constitute the route, but these + * links may not stored in the route traversal order. For re-ordering traffic flow + * routes in route traversal order, call sort_noc_links_in_chain_order() function. + * + * @param flow_link_vars Boolean variable container for (traffic flow, link) pairs. + * @param response The SAT solver's response. This object is used to query the values + * of (traffic flow, link) variables. + * @return Traffic flow routes. NoC links may not be stored in the route traversal order. + */ +static vtr::vector> convert_vars_to_routes(t_flow_link_var_map& flow_link_vars, + const orsat::CpSolverResponse& response); + +/** + * @brief Sorts the given NoC links so that they can traversed one after another. + * + * After the SAT solver returns a solution, boolean (traffic flow, link) variables + * can be translated into traffic flow routes. The SAT solver does not have a notion + * traversal order. Therefore, activated NoC links for a traffic flow are stored in + * an arbitrary order. This function can reorder the activated links in the route + * traversal order. + * + * @param links NoC links that form a continuous route. NoC links can be stored + * in an order different than the traversal order. + * @return Sorted links in traversal order. + */ +static std::vector sort_noc_links_in_chain_order(const std::vector& links); + static std::vector get_flow_link_vars(const t_flow_link_var_map& map, const std::vector& traffic_flow_ids, @@ -247,28 +284,6 @@ static vtr::vector quantize_traffic_flow_bandwidths(int b return rescaled_traffic_flow_bandwidths; } -//static void add_congestion_constraints(t_flow_link_var_map& flow_link_vars, -// orsat::CpModelBuilder& cp_model, -// int bandwidth_resolution) { -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; -// -// vtr::vector rescaled_traffic_flow_bandwidths = quantize_traffic_flow_bandwidths(bandwidth_resolution); -// -// // add NoC link congestion constraints -// for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { -// const NocLinkId noc_link_id = noc_link.get_link_id(); -// orsat::LinearExpr lhs; -// -// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { -// orsat::BoolVar binary_var = flow_link_vars[{traffic_flow_id, noc_link_id}]; -// lhs += orsat::LinearExpr::Term(binary_var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); -// } -// -// cp_model.AddLessOrEqual(lhs, bandwidth_resolution); -// } -//} - static void create_congested_link_vars(vtr::vector& congested_link_vars, t_flow_link_var_map& flow_link_vars, orsat::CpModelBuilder& cp_model, @@ -362,40 +377,6 @@ static void add_continuity_constraints(t_flow_link_var_map& flow_link_vars, } } -//static void group_noc_links_based_on_direction(std::vector& up, -// std::vector& down, -// std::vector& right, -// std::vector& left) { -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& noc_model = noc_ctx.noc_model; -// -// for (const auto& noc_link : noc_model.get_noc_links()) { -// const NocLinkId noc_link_id = noc_link.get_link_id(); -// const NocRouterId src_noc_router_id = noc_link.get_source_router(); -// const NocRouterId dst_noc_router_id = noc_link.get_sink_router(); -// const NocRouter& src_noc_router = noc_model.get_single_noc_router(src_noc_router_id); -// const NocRouter& dst_noc_router = noc_model.get_single_noc_router(dst_noc_router_id); -// auto src_loc = src_noc_router.get_router_physical_location(); -// auto dst_loc = dst_noc_router.get_router_physical_location(); -// -// VTR_ASSERT(src_loc.x == dst_loc.x || src_loc.y == dst_loc.y); -// -// if (src_loc.x == dst_loc.x) { // vertical link -// if (dst_loc.y > src_loc.y) { -// up.push_back(noc_link_id); -// } else { -// down.push_back(noc_link_id); -// } -// } else { // horizontal link -// if (dst_loc.x > src_loc.x) { -// right.push_back(noc_link_id); -// } else { -// left.push_back(noc_link_id); -// } -// } -// } -//} - static std::vector sort_noc_links_in_chain_order(const std::vector& links) { std::vector route; if (links.empty()) { @@ -407,7 +388,7 @@ static std::vector sort_noc_links_in_chain_order(const std::vector src_map; std::unordered_map is_dst; - for (const auto& l : links) { + for (const auto l : links) { NocRouterId src_router_id = noc_model.get_single_noc_link(l).get_source_router(); NocRouterId dst_router_id = noc_model.get_single_noc_link(l).get_sink_router(); src_map[src_router_id] = l; @@ -472,9 +453,33 @@ static void create_flow_link_vars(orsat::CpModelBuilder& cp_model, const auto& noc_ctx = g_vpr_ctx.noc(); const auto& noc_model = noc_ctx.noc_model; const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; + // used to access NoC compressed grid + const auto& place_ctx = g_vpr_ctx.placement(); + // used to get NoC logical block type + const auto& cluster_ctx = g_vpr_ctx.clustering(); - // TODO: specify the domain based on NoC topology - operations_research::Domain latency_overrun_domain(0, 20); + // Get the logical block type for router + const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); + + // Get the compressed grid for NoC + const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; + + size_t max_n_cols = std::max_element(compressed_noc_grid.compressed_to_grid_x.begin(), compressed_noc_grid.compressed_to_grid_x.end(), + [](const std::vector& a, const std::vector& b) { + return a.size() < b.size(); + })->size(); + + size_t max_n_rows = std::max_element(compressed_noc_grid.compressed_to_grid_y.begin(), compressed_noc_grid.compressed_to_grid_y.end(), + [](const std::vector& a, const std::vector& b) { + return a.size() < b.size(); + })->size(); + + /* For specifying the domain, assume that the longest traffic flow route starts from + * one corner and terminates at the opposite corner. Assuming minimal routing, such a + * route traversed around H+W links, where H and W are the number of rows and columns + * of the mesh grid. + */ + operations_research::Domain latency_overrun_domain(0, (int)(max_n_rows + max_n_cols)); // create boolean variables for each traffic flow and link pair // create integer variables for traffic flows with constrained latency @@ -562,318 +567,6 @@ static void constrain_latency_overrun_vars(orsat::CpModelBuilder& cp_model, } } -//static void add_movable_continuity_constraints(t_flow_link_var_map& flow_link_vars, -// std::map& x_loc_vars, -// std::map& y_loc_vars, -// orsat::CpModelBuilder& cp_model) { -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& noc_model = noc_ctx.noc_model; -// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; -// const auto& place_ctx = g_vpr_ctx.placement(); -// const auto& cluster_ctx = g_vpr_ctx.clustering(); -// -// // get the logical block type for router -// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); -// -// // get the compressed grid for NoC -// const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; -// -// std::unordered_map, orsat::BoolVar> logical_physical_mapped; -// -// // Create a boolean variable for each physical and logical NoC router pair -// // When set, this variable indicates that the logical NoC router is mapped -// // to its corresponding logical router -// for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { -// auto& y_loc_var = y_loc_vars[router_blk_id]; -// -// for (auto noc_router_id : noc_model.get_noc_routers().keys()) { -// const auto& noc_router = noc_model.get_single_noc_router(noc_router_id); -// const auto noc_router_pos = noc_router.get_router_physical_location(); -// const auto compressed_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{noc_router_pos, 0}, 1)[noc_router_pos.layer_num]; -// -// orsat::BoolVar x_condition = cp_model.NewBoolVar(); -// cp_model.AddEquality(x_loc_var, compressed_loc.x).OnlyEnforceIf(x_condition); -// cp_model.AddNotEqual(x_loc_var, compressed_loc.x).OnlyEnforceIf(Not(x_condition)); -// -// orsat::BoolVar y_condition = cp_model.NewBoolVar(); -// cp_model.AddEquality(y_loc_var, compressed_loc.y).OnlyEnforceIf(y_condition); -// cp_model.AddNotEqual(y_loc_var, compressed_loc.y).OnlyEnforceIf(Not(y_condition)); -// -// // Combine conditions using AddBoolAnd -// orsat::BoolVar both_conds_met = cp_model.NewBoolVar(); -// cp_model.AddBoolAnd({x_condition, y_condition}).OnlyEnforceIf(both_conds_met); -// cp_model.AddBoolOr({Not(x_condition), Not(y_condition)}).OnlyEnforceIf(Not(both_conds_met)); -// -// logical_physical_mapped[{router_blk_id, noc_router_id}] = both_conds_met; -// } -// } -// -// /* -// * Iterate over all traffic flows and physical NoC routers -// * apply a constraint on the number of activated incoming and outgoing -// * links based on whether the NoC router is the source or destination -// * (or neither) of the traffic flow. -// */ -// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { -// const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); -// -// // get the source and destination logical router blocks in the current traffic flow -// ClusterBlockId logical_source_router_block_id = traffic_flow.source_router_cluster_id; -// ClusterBlockId logical_sink_router_block_id = traffic_flow.sink_router_cluster_id; -// -// for (auto noc_router_id : noc_ctx.noc_model.get_noc_routers().keys()) { -// -// auto& src_is_mapped = logical_physical_mapped[{logical_source_router_block_id, noc_router_id}]; -// auto& dst_is_mapped = logical_physical_mapped[{logical_sink_router_block_id, noc_router_id}]; -// -// orsat::BoolVar nor_src_dst_mapped = cp_model.NewBoolVar(); -// cp_model.AddExactlyOne({src_is_mapped, dst_is_mapped, nor_src_dst_mapped}); -// -// const auto& incoming_links = noc_ctx.noc_model.get_noc_router_incoming_links(noc_router_id); -// auto vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, incoming_links); -// // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); -// // cp_model.AddExactlyOne(vars).OnlyEnforceIf(dst_is_mapped); -// orsat::LinearExpr lhs = orsat::LinearExpr::Sum(vars); -// cp_model.AddEquality(lhs, 0).OnlyEnforceIf(src_is_mapped); -// cp_model.AddLessOrEqual(lhs, 1).OnlyEnforceIf(nor_src_dst_mapped); -// cp_model.AddEquality(lhs, 1).OnlyEnforceIf(dst_is_mapped); -// -// const auto& outgoing_links = noc_ctx.noc_model.get_noc_router_outgoing_links(noc_router_id); -// vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, outgoing_links); -// // cp_model.AddAtMostOne(vars).OnlyEnforceIf(nor_src_dst_mapped); -// // cp_model.AddExactlyOne(vars).OnlyEnforceIf(src_is_mapped); -// orsat::LinearExpr rhs = orsat::LinearExpr::Sum(vars); -// cp_model.AddEquality(rhs, 0).OnlyEnforceIf(dst_is_mapped); -// cp_model.AddLessOrEqual(rhs, 1).OnlyEnforceIf(nor_src_dst_mapped); -// cp_model.AddEquality(rhs, 1).OnlyEnforceIf(src_is_mapped); -// -// cp_model.AddEquality(lhs, rhs).OnlyEnforceIf(nor_src_dst_mapped); -// } -// } -//} -// -//static void add_movable_distance_constraints(t_flow_link_var_map& flow_link_vars, -// orsat::CpModelBuilder& cp_model, -// std::map& x_loc_vars, -// std::map& y_loc_vars, -// const std::vector& up, -// const std::vector& down, -// const std::vector& right, -// const std::vector& left) { -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; -// -// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { -// const auto& traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(traffic_flow_id); -// -// // get the source and destination logical router blocks in the current traffic flow -// ClusterBlockId logical_src_router_block_id = traffic_flow.source_router_cluster_id; -// ClusterBlockId logical_dst_router_block_id = traffic_flow.sink_router_cluster_id; -// -// auto right_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, right); -// auto left_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, left); -// auto up_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, up); -// auto down_vars = get_flow_link_vars(flow_link_vars, {traffic_flow_id}, down); -// -// orsat::LinearExpr horizontal_expr; -// horizontal_expr += (orsat::LinearExpr::Sum(right_vars) - orsat::LinearExpr::Sum(left_vars)); -// orsat::LinearExpr horizontal_dist_expr; -// horizontal_dist_expr += x_loc_vars[logical_dst_router_block_id]; -// horizontal_dist_expr -= x_loc_vars[logical_src_router_block_id]; -// cp_model.AddEquality(horizontal_expr, horizontal_dist_expr); -// -// orsat::LinearExpr vertical_expr; -// vertical_expr += (orsat::LinearExpr::Sum(up_vars) - orsat::LinearExpr::Sum(down_vars)); -// orsat::LinearExpr vertical_dist_expr; -// vertical_dist_expr += y_loc_vars[logical_dst_router_block_id]; -// vertical_dist_expr -= y_loc_vars[logical_src_router_block_id]; -// cp_model.AddEquality(vertical_expr, vertical_dist_expr); -// } -//} -// -//static void convert_vars_to_locs(std::map& noc_router_locs, -// std::map& x_loc_vars, -// std::map& y_loc_vars, -// const orsat::CpSolverResponse& response) { -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; -// const auto& cluster_ctx = g_vpr_ctx.clustering(); -// -// // const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); -// -// // Get the logical block type for router -// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); -// -// noc_router_locs.clear(); -// -// VTR_ASSERT(response.status() == orsat::CpSolverStatus::FEASIBLE || -// response.status() == orsat::CpSolverStatus::OPTIMAL); -// -// for (auto& [router_blk_id, x_loc_var] : x_loc_vars) { -// auto& y_loc_var = y_loc_vars[router_blk_id]; -// int x_value = (int)orsat::SolutionIntegerValue(response, x_loc_var); -// int y_value = (int)orsat::SolutionIntegerValue(response, y_loc_var); -// -// t_pl_loc mapped_loc; -// compressed_grid_to_loc(router_block_type, {x_value, y_value, 0}, mapped_loc); -// noc_router_locs[router_blk_id] = mapped_loc; -// } -//} -// -//static void constrain_fixed_noc_routers(std::map& x_loc_vars, -// std::map& y_loc_vars, -// orsat::CpModelBuilder& cp_model) { -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; -// const auto& place_ctx = g_vpr_ctx.mutable_placement(); -// const auto& cluster_ctx = g_vpr_ctx.clustering(); -// -// const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); -// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); -// const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; -// -// const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); -// -// for (auto router_blk_id : router_blk_ids) { -// const auto& router_loc = place_ctx.block_locs[router_blk_id]; -// if (router_loc.is_fixed) { -// auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[router_loc.loc.layer]; -// cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); -// cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); -// } -// } -//} - -//void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, -// std::map& noc_router_locs, -// int seed) { -// vtr::ScopedStartFinishTimer timer("NoC SAT Placement and Routing"); -// const auto& noc_ctx = g_vpr_ctx.noc(); -// const auto& traffic_flow_storage = noc_ctx.noc_traffic_flows_storage; -// const auto& placement_ctx = g_vpr_ctx.placement(); -// const auto& cluster_ctx = g_vpr_ctx.clustering(); -// -// traffic_flow_routes.clear(); -// noc_router_locs.clear(); -// -// orsat::CpModelBuilder cp_model; -// -// t_flow_link_var_map flow_link_vars; -// -// std::map latency_overrun_vars; -// -// vtr::vector link_congested_vars; -// -// const std::vector& router_blk_ids = traffic_flow_storage.get_router_clusters_in_netlist(); -// operations_research::Domain loc_domain(0, 9); -// std::map x_loc_vars; -// std::map y_loc_vars; -// std::vector> loc_intervals; -// -// -// for (auto router_blk_id : router_blk_ids) { -// x_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); -// y_loc_vars[router_blk_id] = cp_model.NewIntVar(loc_domain); -// -// loc_intervals.emplace_back(cp_model.NewIntervalVar(x_loc_vars[router_blk_id], 1, x_loc_vars[router_blk_id]+1), -// cp_model.NewIntervalVar(y_loc_vars[router_blk_id], 1, y_loc_vars[router_blk_id]+1)); -// } -// -// orsat::NoOverlap2DConstraint no_overlap_2d = cp_model.AddNoOverlap2D(); -// -// for (auto& [x_interval, y_interval] : loc_intervals) { -// no_overlap_2d.AddRectangle(x_interval, y_interval); -// } -// -// create_flow_link_vars(cp_model, flow_link_vars, latency_overrun_vars); -// -// constrain_latency_overrun_vars(cp_model, flow_link_vars, latency_overrun_vars); -// -// forbid_illegal_turns(flow_link_vars, cp_model); -// -//// add_congestion_constraints(flow_link_vars, cp_model); -// create_congested_link_vars(link_congested_vars, flow_link_vars, cp_model); -// -// add_movable_continuity_constraints(flow_link_vars, x_loc_vars, y_loc_vars, cp_model); -// -// std::vector up, down, right, left; -// group_noc_links_based_on_direction(up, down, right, left); -// -// add_movable_distance_constraints(flow_link_vars, cp_model, x_loc_vars, y_loc_vars, up, down, right, left); -// -// constrain_fixed_noc_routers(x_loc_vars, y_loc_vars, cp_model); -// -// const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); -// -// // Get the logical block type for router -// const auto router_block_type = cluster_ctx.clb_nlist.block_type(traffic_flow_storage.get_router_clusters_in_netlist()[0]); -// -// // Get the compressed grid for NoC -// const auto& compressed_noc_grid = placement_ctx.compressed_block_grids[router_block_type->index]; -// for (auto router_blk_id : router_blk_ids) { -// auto router_loc = placement_ctx.block_locs[router_blk_id]; -// -// auto compressed_loc = get_compressed_loc(compressed_noc_grid, router_loc.loc, num_layers)[0]; -// -// cp_model.AddHint(x_loc_vars[router_blk_id], compressed_loc.x); -// cp_model.AddHint(y_loc_vars[router_blk_id], compressed_loc.y); -//// cp_model.AddEquality(x_loc_vars[router_blk_id], compressed_loc.x); -//// cp_model.AddEquality(y_loc_vars[router_blk_id], compressed_loc.y); -// } -// -// orsat::LinearExpr latency_overrun_sum; -// for (auto& [traffic_flow_id, latency_overrun_var] : latency_overrun_vars) { -// latency_overrun_sum += latency_overrun_var; -// } -// -// latency_overrun_sum *= 1024; -// -// auto rescaled_traffic_flow_bandwidths = rescale_traffic_flow_bandwidths(); -// orsat::LinearExpr agg_bw_expr; -// for (auto& [key, var] : flow_link_vars) { -// auto [traffic_flow_id, noc_link_id] = key; -// agg_bw_expr += orsat::LinearExpr::Term(var, rescaled_traffic_flow_bandwidths[traffic_flow_id]); -// } -// -// for (auto traffic_flow_id : traffic_flow_storage.get_all_traffic_flow_id()) { -// std::vector activated_links; -// for (auto route_link_id : traffic_flow_storage.get_traffic_flow_route(traffic_flow_id)) { -// cp_model.AddHint(flow_link_vars[{traffic_flow_id, route_link_id}], true); -//// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, route_link_id}], true); -// activated_links.push_back(route_link_id); -// } -// -// for (auto noc_link_id : noc_ctx.noc_model.get_noc_links().keys()) { -// if (std::find(activated_links.begin(), activated_links.end(), noc_link_id) == activated_links.end()) { -// cp_model.AddHint(flow_link_vars[{traffic_flow_id, noc_link_id}], false); -//// cp_model.AddEquality(flow_link_vars[{traffic_flow_id, noc_link_id}], false); -// } -// } -// } -// -// orsat::LinearExpr congested_link_sum = orsat::LinearExpr::Sum(link_congested_vars); -// congested_link_sum *= (1024 * 16); -// -// cp_model.Minimize(latency_overrun_sum + agg_bw_expr + congested_link_sum); -// -// orsat::SatParameters sat_params; -// sat_params.set_random_seed(seed); -// sat_params.set_log_search_progress(true); -// sat_params.set_max_time_in_seconds(10*60); -// -// orsat::Model model; -// model.Add(NewSatParameters(sat_params)); -// -// orsat::CpSolverResponse response = orsat::SolveCpModel(cp_model.Build(), &model); -// -// if (response.status() == orsat::CpSolverStatus::FEASIBLE || -// response.status() == orsat::CpSolverStatus::OPTIMAL) { -// -// traffic_flow_routes = convert_vars_to_routes(flow_link_vars, response); -// convert_vars_to_locs(noc_router_locs, x_loc_vars, y_loc_vars, response); -// } -//} - static orsat::LinearExpr create_objective(orsat::CpModelBuilder& cp_model, t_flow_link_var_map& flow_link_vars, std::map& latency_overrun_vars, diff --git a/vpr/src/noc/sat_routing.h b/vpr/src/noc/sat_routing.h index 7f4f024bb02..945b5a0aabe 100644 --- a/vpr/src/noc/sat_routing.h +++ b/vpr/src/noc/sat_routing.h @@ -1,6 +1,21 @@ #ifndef VTR_SATROUTING_H #define VTR_SATROUTING_H +/** + * @file + * @brief SAT formulation of NoC traffic flow routing. + * + * This file implements a SAT formulation of NoC routing problem. + * Each (traffic flow, link) pair is associated with boolean variable. + * When one of these boolean variables are set by the SAT solver, it means + * that the corresponding traffic flow is routed through the corresponding link. + * To ensure that traffic flow routes are continuous, deadlock-free, with + * minimum link congestion, several constraints are added to the SAT formulation. + * + * For more details refer to the following paper: + * The Road Less Traveled: Congestion-Aware NoC Placement and Packet Routing for FPGAs + */ + #ifdef ENABLE_NOC_SAT_ROUTING #include @@ -30,29 +45,25 @@ vtr::vector> noc_sat_route(bool minimiz const t_noc_opts& noc_opts, int seed); -//void noc_sat_place_and_route(vtr::vector>& traffic_flow_routes, -// std::map& noc_router_locs, -// int seed); - namespace std { + template<> struct hash> { + /** + * @brief Generates a hash value for a (NocTrafficFlowId, NocLinkId) pair. + * + * This hash function is used to store SAT boolean variables for each + * (traffic flow, link) pair in a hash map. + * + * @param flow_link A (traffic flow, link) pair whose hash value is desired. + * @return The computed hash value. + */ std::size_t operator()(const std::pair& flow_link) const noexcept { std::size_t seed = std::hash{}(flow_link.first); vtr::hash_combine(seed, flow_link.second); return seed; } }; - -template<> -struct hash> { - std::size_t operator()(const std::pair& block_router) const noexcept { - std::size_t seed = std::hash{}(block_router.first); - vtr::hash_combine(seed, block_router.second); - return seed; - } -}; - } // namespace std diff --git a/vpr/src/place/initial_noc_placement.cpp b/vpr/src/place/initial_noc_placement.cpp index a55546b4e17..2cf2bf3f1f3 100644 --- a/vpr/src/place/initial_noc_placement.cpp +++ b/vpr/src/place/initial_noc_placement.cpp @@ -295,39 +295,4 @@ void initial_noc_placement(const t_noc_opts& noc_opts, const t_placer_opts& plac "At least one cycle was found in NoC channel dependency graph. This may cause a deadlock " "when packets wait on each other in a cycle.\n"); } - -// const auto& placement_ctx = g_vpr_ctx.placement(); -// -// vtr::vector> traffic_flow_routes; -// std::map noc_router_locs; -// -// noc_sat_place_and_route(traffic_flow_routes, noc_router_locs, 4); -// -// t_placer_costs costs; -// reinitialize_noc_routing(costs, traffic_flow_routes); -// -// std::cout << "Initial NoC placement costs: " -// << " Agg BW: " << costs.noc_cost_terms.aggregate_bandwidth -// << " Latency: " << costs.noc_cost_terms.latency -// << " Latency Over: " << costs.noc_cost_terms.latency_overrun -// << " Congestion: " << costs.noc_cost_terms.congestion -// << " Congested Links: " << get_number_of_congested_noc_links() << std::endl; -// -// for (auto& [router_blk_id, loc] : noc_router_locs) { -// if (placement_ctx.block_locs[router_blk_id].is_fixed) { -// continue; -// } -// -// // Create a macro with a single member -// t_pl_macro_member macro_member; -// macro_member.blk_index = router_blk_id; -// macro_member.offset = t_pl_offset(0, 0, 0, 0); -// t_pl_macro pl_macro; -// pl_macro.members.push_back(macro_member); -// -// bool legal = try_place_macro(pl_macro, loc); -// if (!legal) { -// VPR_FATAL_ERROR(VPR_ERROR_PLACE, "Could not place a router cluster into an empty physical router."); -// } -// } } \ No newline at end of file diff --git a/vpr/src/place/initial_placement.cpp b/vpr/src/place/initial_placement.cpp index e462b5b6f1e..50d65da2aa9 100644 --- a/vpr/src/place/initial_placement.cpp +++ b/vpr/src/place/initial_placement.cpp @@ -501,7 +501,7 @@ static void update_blk_type_first_loc(int blk_type_column_index, t_logical_block_type_ptr block_type, const t_pl_macro& pl_macro, std::vector* blk_types_empty_locs_in_grid) { //check if dense placement could place macro successfully - if (blk_type_column_index == -1 || blk_types_empty_locs_in_grid->size() <= abs(blk_type_column_index)) { + if (blk_type_column_index == -1 || blk_types_empty_locs_in_grid->size() <= (size_t)abs(blk_type_column_index)) { return; } From 3b8795f838a9ae50fa42d07f6902eca569339d54 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 5 Jun 2024 15:58:04 -0400 Subject: [PATCH 36/38] use --noc_sat_routing_num_workers only when it is explicitly specified Otherwise, set the number of parallel SAT solver workers to -j --- libs/EXTERNAL/libargparse/src/argparse.hpp | 2 +- vpr/src/base/SetupVPR.cpp | 8 +++++++- vpr/src/base/read_options.cpp | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libs/EXTERNAL/libargparse/src/argparse.hpp b/libs/EXTERNAL/libargparse/src/argparse.hpp index 28626fa2052..15e0237eab3 100644 --- a/libs/EXTERNAL/libargparse/src/argparse.hpp +++ b/libs/EXTERNAL/libargparse/src/argparse.hpp @@ -173,7 +173,7 @@ namespace argparse { //Sets the hlep text Argument& help(std::string help_str); - //Sets the defuault value + //Sets the default value Argument& default_value(const std::string& default_val); Argument& default_value(const std::vector& default_val); Argument& default_value(const std::initializer_list& default_val); diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 1d5b63a1e34..af73c8816a1 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -749,9 +749,15 @@ static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { NocOpts->noc_sat_routing_bandwidth_resolution = Options.noc_sat_routing_bandwidth_resolution; NocOpts->noc_sat_routing_latency_overrun_weighting = Options.noc_sat_routing_latency_overrun_weighting_factor; NocOpts->noc_sat_routing_congestion_weighting = Options.noc_sat_routing_congestion_weighting_factor; - NocOpts->noc_sat_routing_num_workers = Options.noc_sat_routing_num_workers; + if (Options.noc_sat_routing_num_workers.provenance() == argparse::Provenance::SPECIFIED) { + NocOpts->noc_sat_routing_num_workers = Options.noc_sat_routing_num_workers; + } else { + NocOpts->noc_sat_routing_num_workers = (int)Options.num_workers; + } NocOpts->noc_sat_routing_log_search_progress = Options.noc_sat_routing_log_search_progress; NocOpts->noc_placement_file_name = Options.noc_placement_file_name; + + } static void SetupServerOpts(const t_options& Options, t_server_opts* ServerOpts) { diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 29ebd6b17d0..b4f33cf8025 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -1516,7 +1516,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio gen_grp.add_argument(args.strict_checks, "--strict_checks") .help( "Controls whether VPR enforces some consistency checks strictly (as errors) or treats them as warnings." - " Usually these checks indicate an issue with either the targetted architecture, or consistency issues" + " Usually these checks indicate an issue with either the targeted architecture, or consistency issues" " with VPR's internal data structures/algorithms (possibly harming optimization quality)." " In specific circumstances on specific architectures these checks may be too restrictive and can be turned off." " However exercise extreme caution when turning this option off -- be sure you completely understand why the issue" @@ -2902,8 +2902,8 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio noc_grp.add_argument(args.noc_sat_routing_num_workers, "--noc_sat_routing_num_workers") .help( "The maximum number of parallel threads that the SAT solver can use to explore the solution space.\n" - "When set to 0, the number of parallel workers is set automatically to maximize parallelism.") - .default_value("0") + "If not explicitly specified by the user, VPR will set the number parallel SAT solver workers to the value " + "specified by -j command line option.") .show_in(argparse::ShowIn::HELP_ONLY); noc_grp.add_argument(args.noc_sat_routing_log_search_progress, "--noc_sat_routing_log_search_progress") From b7bf7b5e518eb759249801830e00b925ce7c010d Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 5 Jun 2024 19:39:27 -0400 Subject: [PATCH 37/38] conditional inclusion of sat_router --- vpr/src/place/noc_place_utils.cpp | 5 +++++ vpr/src/place/noc_place_utils.h | 2 ++ vpr/src/place/place.cpp | 1 - 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index 36eb1449b04..a917a4d5b3e 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -11,7 +11,10 @@ #include "noc_routing.h" #include "place_constraints.h" #include "move_transactions.h" + +#ifdef ENABLE_NOC_SAT_ROUTING #include "sat_routing.h" +#endif #include @@ -929,6 +932,7 @@ bool noc_routing_has_cycle(const vtr::vector Date: Thu, 6 Jun 2024 12:57:08 -0400 Subject: [PATCH 38/38] fix segfault in NoC cost report --- vpr/src/place/noc_place_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index a917a4d5b3e..0b9e274b85b 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -963,7 +963,7 @@ void print_noc_costs(std::string_view header, const t_placer_costs& costs, const "congestion_cost: %g, " "accum_congested_ratio: %g, " "n_congested_links: %d \n", - header, + header.data(), calculate_noc_cost(costs.noc_cost_terms, costs.noc_cost_norm_factors, noc_opts), costs.noc_cost_terms.aggregate_bandwidth, costs.noc_cost_terms.latency,