Skip to content

Commit

Permalink
✨ Post-Layout Optimization (#260)
Browse files Browse the repository at this point in the history
* post placement optimization

* Some improvements

* align with python implementation

* refactoring

* fix bug

* comments

* refactor

* reformat

* comments

* fix ouput bug

* fix bug

* move code to header file

* rename

* reformat code

* use tuple instead of pair

* fix windows ci error

* add basic unit test

* fix warnings

* add docstrings

* add unittests for detail functions

* also delete excess wiring in columns

* disable failing test case

* reformat

* 🎨 Refactor physical design optimization methods for general gate-level layout

The physical design optimization methods have been significantly refactored to work with general gate-level layouts. This includes making various functions template-based, replacing several types to be layout-agnostic, and adding static assertions to ensure the layouts are of appropriate types. Cleaning physical design optimization helps to reduce redundancy and improve flexibility. As a result, a broader range of gate level layouts can be optimized. This should provide performance improvements and allow for more advanced optimization techniques in future development.

* resolve first batch of todos

* optimize layout in-place

* use own types for complex structures

* add optimization algorithm to cli

* add optimiztaion algorithm to docs

* fix small bug and increase coverage

* clang-format

* simplify code

* update clang-tidy-review version

* more expressive docstrings

* reformat code

* typo

* 🎨 Improved upon the structure of the code even further and added more TODO notes

* resolve ToDos

* remove todo

* remove debug output

* clang-tidy

* update docs

* rewrite delete wires algorithm to delete all rows and columns at once

* clang-tidy

* only calculate fanins for used coordinates

* increase coverage to 100%

* fix bug

* ✨ Added a deep-copy `clone()` function to `gate_level_layout`

* 🎨 Some renaming and docstring updates

* 🎨 Some renaming and slight code cleanup

* resolve todos in experiments

* Apply suggestions from code review

Co-authored-by: Marcel Walter <[email protected]>

* resolve todos

* fix failing tests

* clang-tidy

* further improvements

* ✨ Added `clone` functions to all core layouts

* clone layout

* ✨ Added working `clone` functions to all core layouts

* 🐛 Fix compiler issue

* 🎨 ClangFormat

* 🚨 Suppress `clang-tidy` warning

* 🚨 Suppress `clang-tidy` warning

* 🎨 Final polishing

* ✅ Enabled commented-out test case

* 🔀 Fix merge conflicts

---------

Co-authored-by: Marcel Walter <[email protected]>
Co-authored-by: Marcel Walter <[email protected]>
  • Loading branch information
3 people authored Sep 15, 2023
1 parent eabe4cc commit 44d0530
Show file tree
Hide file tree
Showing 23 changed files with 2,020 additions and 15 deletions.
104 changes: 104 additions & 0 deletions cli/cmd/physical_design/optimize.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// Created by Simon Hofmann on 02.08.23.
//

#ifndef FICTION_CMD_OPTIMIZE_HPP
#define FICTION_CMD_OPTIMIZE_HPP

#include <fiction/algorithms/physical_design/post_layout_optimization.hpp>
#include <fiction/layouts/clocked_layout.hpp>
#include <fiction/layouts/gate_level_layout.hpp>
#include <fiction/traits.hpp>
#include <fiction/types.hpp>

#include <alice/alice.hpp>

#include <iostream>
#include <optional>
#include <variant>

namespace alice
{
/**
* Optimizes a 2DDWave-clocked Cartesian layout.
*/
class optimize_command : public command
{
public:
/**
* Standard constructor. Adds descriptive information, options, and flags.
*
* @param e alice::environment that specifies stores etc.
*/
explicit optimize_command(const environment::ptr& e) :
command(e, "Optimizes a 2DDWave-clocked Cartesian layout with respect to area. It achieves this objective "
"by strategically repositioning gates within the layout, removing excess wiring, and "
"effectively relocating outputs to more favorable positions.")
{}

protected:
/**
* Statistics.
*/
fiction::post_layout_optimization_stats st{};

/**
* Optimizes a 2DDWave-clocked Cartesian layout.
*/
void execute() override
{
auto& gls = store<fiction::gate_layout_t>();

// error case: empty gate-level layout store
if (gls.empty())
{
env->out() << "[w] no gate layout in store" << std::endl;
return;
}

const auto& lyt = gls.current();

const auto check_clocking_scheme = [](auto&& lyt_ptr)
{ return lyt_ptr->is_clocking_scheme(fiction::clock_name::TWODDWAVE); };

// error case: layout is not 2DDWave-clocked
if (const auto is_twoddwave_clocked = std::visit(check_clocking_scheme, lyt); !is_twoddwave_clocked)
{
env->out() << "[e] layout has to be 2DDWave-clocked" << std::endl;
return;
}

const auto apply_optimization = [&](auto&& lyt_ptr)
{
using Lyt = typename std::decay_t<decltype(lyt_ptr)>::element_type;
auto lyt_copy = lyt_ptr->clone();
const auto lyt_copy_ptr = std::make_shared<Lyt>(lyt_copy);

if constexpr (fiction::is_cartesian_layout_v<Lyt>)
{
fiction::post_layout_optimization(*lyt_copy_ptr, &st);
fiction::restore_names(*lyt_ptr, *lyt_copy_ptr);
gls.extend() = lyt_copy_ptr;
}
else
{
std::cout << "[e] layout has to be Cartesian" << std::endl;
}
};

try
{
std::visit(apply_optimization, lyt);
}
catch (...)
{
env->out() << "[e] an error occurred while optimizing" << std::endl;
}
}
};

ALICE_ADD_COMMAND(optimize, "Physical Design")

} // namespace alice

#endif // FICTION_CMD_OPTIMIZE_HPP
1 change: 1 addition & 0 deletions cli/commands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "cmd/physical_design/exact.hpp"
#include "cmd/physical_design/hex.hpp"
#include "cmd/physical_design/onepass.hpp"
#include "cmd/physical_design/optimize.hpp"
#include "cmd/physical_design/ortho.hpp"
#include "cmd/technology/area.hpp"
#include "cmd/technology/cell.hpp"
Expand Down
1 change: 1 addition & 0 deletions docs/algorithms/algorithms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Physical Design
color_routing.rst
apply_gate_library.rst
hexagonalization.rst
post_layout_optimization.rst


Verification
Expand Down
15 changes: 15 additions & 0 deletions docs/algorithms/post_layout_optimization.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _post_layout_optimization:

Optimizing 2DDWave-clocked Cartesian Layouts
--------------------------------------------

**Header:** ``fiction/algorithms/physical_design/post_layout_optimization.hpp``

This algorithm aims to decrease the overall layout area of a given 2DDWave-clocked Cartesian layout that has been
generated using either heuristic methods or machine learning techniques. It achieves this objective by strategically
repositioning gates within the layout, removing excess wiring, and effectively relocating outputs to more favorable
positions.

.. doxygenstruct:: fiction::post_layout_optimization_stats
:members:
.. doxygenfunction:: fiction::post_layout_optimization
108 changes: 108 additions & 0 deletions experiments/post_layout_optimization/post_layout_optimization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "fiction_experiments.hpp"

#include <fiction/algorithms/physical_design/orthogonal.hpp> // scalable heuristic for physical design of FCN layouts
#include <fiction/algorithms/physical_design/post_layout_optimization.hpp> // scalable heuristic for physical design of FCN layouts
#include <fiction/algorithms/properties/critical_path_length_and_throughput.hpp> // critical path and throughput calculations
#include <fiction/algorithms/verification/equivalence_checking.hpp> // SAT-based equivalence checking

#include <fmt/format.h> // output formatting
#include <lorina/lorina.hpp> // Verilog/BLIF/AIGER/... file parsing
#include <mockturtle/io/verilog_reader.hpp> // call-backs to read Verilog files into networks

#include <cassert>
#include <chrono>
#include <cstdlib>
#include <string>

int main() // NOLINT
{
using gate_lyt =
fiction::gate_level_layout<fiction::clocked_layout<fiction::tile_based_layout<fiction::cartesian_layout<>>>>;

experiments::experiment<std::string, uint32_t, uint32_t, uint32_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, uint32_t, uint32_t, uint64_t, uint64_t, double, double, float, std::string>
optimization_exp{"optimization",
"benchmark",
"inputs",
"outputs",
"initial nodes",
"ortho layout width (in tiles)",
"ortho layout height (in tiles)",
"ortho layout area (in tiles)",
"optimized layout width (in tiles)",
"optimized layout height (in tiles)",
"optimized layout area (in tiles)",
"gates",
"wires",
"critical path",
"throughput",
"runtime ortho (in sec)",
"runtime optimization (in sec)",
"improvement (%)",
"equivalent"};

// stats for SMT-based physical design
fiction::orthogonal_physical_design_stats orthogonal_stats{};
fiction::post_layout_optimization_stats post_layout_optimization_stats{};

static constexpr const uint64_t bench_select =
fiction_experiments::all & ~fiction_experiments::epfl & ~fiction_experiments::iscas85;

for (const auto& benchmark : fiction_experiments::all_benchmarks(bench_select))
{
fmt::print("[i] processing {}\n", benchmark);

fiction::technology_network network{};

const auto read_verilog_result =
lorina::read_verilog(fiction_experiments::benchmark_path(benchmark), mockturtle::verilog_reader(network));
assert(read_verilog_result == lorina::return_code::success);

// perform layout generation with an OGD-based heuristic algorithm
auto gate_level_layout = fiction::orthogonal<gate_lyt>(network, {}, &orthogonal_stats);

// compute critical path and throughput
fiction::critical_path_length_and_throughput_stats cp_tp_stats{};
fiction::critical_path_length_and_throughput(gate_level_layout, &cp_tp_stats);

// calculate bounding box
const auto bounding_box_before_optimization = fiction::bounding_box_2d(gate_level_layout);

const auto width_before_optimization = bounding_box_before_optimization.get_x_size() + 1;
const auto height_before_optimization = bounding_box_before_optimization.get_y_size() + 1;
const auto area_before_optimization = width_before_optimization * height_before_optimization;

// perform post-layout optimization
fiction::post_layout_optimization<gate_lyt>(gate_level_layout, &post_layout_optimization_stats);

// check equivalence
fiction::equivalence_checking_stats eq_stats{};
fiction::equivalence_checking<fiction::technology_network, gate_lyt>(network, gate_level_layout, &eq_stats);

const std::string eq_result = eq_stats.eq == fiction::eq_type::STRONG ? "STRONG" :
eq_stats.eq == fiction::eq_type::WEAK ? "WEAK" :
"NO";

// calculate bounding box
const auto bounding_box_after_optimization = fiction::bounding_box_2d(gate_level_layout);

const auto width_after_optimization = bounding_box_after_optimization.get_x_size() + 1;
const auto height_after_optimization = bounding_box_after_optimization.get_y_size() + 1;
const auto area_after_optimization = width_after_optimization * height_after_optimization;

const float improv = 100 * static_cast<float>((area_before_optimization - area_after_optimization)) /
static_cast<float>(area_before_optimization);
// log results
optimization_exp(benchmark, network.num_pis(), network.num_pos(), network.num_gates(),
width_before_optimization, height_before_optimization, area_before_optimization,
width_after_optimization, height_after_optimization, area_after_optimization,
gate_level_layout.num_gates(), gate_level_layout.num_wires(), cp_tp_stats.critical_path_length,
cp_tp_stats.throughput, mockturtle::to_seconds(orthogonal_stats.time_total),
mockturtle::to_seconds(post_layout_optimization_stats.time_total), improv, eq_result);

optimization_exp.save();
optimization_exp.table();
}

return EXIT_SUCCESS;
}
Loading

0 comments on commit 44d0530

Please sign in to comment.