From 13357159f0a8f981bbe04d6c46a408747c6636c2 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 13 Jun 2010 21:06:23 +0000 Subject: [PATCH] * ./metis: - New: Initial port from Coriolis 1. --- metis/CMakeLists.txt | 62 +++ metis/cmake_modules/CMakeLists.txt | 1 + metis/cmake_modules/FindMETIS.cmake | 48 +++ metis/src/CMakeLists.txt | 37 ++ metis/src/Configuration.cpp | 161 ++++++++ metis/src/MetisEngine.cpp | 318 ++++++++++++++ metis/src/MetisGraph.cpp | 621 ++++++++++++++++++++++++++++ metis/src/metis/Configuration.h | 152 +++++++ metis/src/metis/MetisEngine.h | 119 ++++++ metis/src/metis/MetisGraph.h | 82 ++++ metis/src/metis/hmetis.h | 21 + 11 files changed, 1622 insertions(+) create mode 100644 metis/CMakeLists.txt create mode 100644 metis/cmake_modules/CMakeLists.txt create mode 100644 metis/cmake_modules/FindMETIS.cmake create mode 100644 metis/src/CMakeLists.txt create mode 100644 metis/src/Configuration.cpp create mode 100644 metis/src/MetisEngine.cpp create mode 100644 metis/src/MetisGraph.cpp create mode 100644 metis/src/metis/Configuration.h create mode 100644 metis/src/metis/MetisEngine.h create mode 100644 metis/src/metis/MetisGraph.h create mode 100644 metis/src/metis/hmetis.h diff --git a/metis/CMakeLists.txt b/metis/CMakeLists.txt new file mode 100644 index 00000000..683b5ebb --- /dev/null +++ b/metis/CMakeLists.txt @@ -0,0 +1,62 @@ +PROJECT(METIS) + +CMAKE_MINIMUM_REQUIRED(VERSION 2.4.0) + +SET(CMAKE_C_FLAGS_DEBUG "-g -Wall" CACHE STRING "Debug options." FORCE) +SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) +#SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "-pg" CACHE STRING "Debug options." FORCE) + +IF(COMMAND CMAKE_POLICY) + CMAKE_POLICY(SET CMP0003 NEW) +ENDIF(COMMAND CMAKE_POLICY) + +# This macro has to be included in all the tools CMakeLists.txt as it's +# the sole means of localizing other tools/projects. +MACRO(SETUP_PROJECT_PATHS project) + IF( NOT("$ENV{${project}_TOP}" STREQUAL "") ) + MESSAGE("-- ${project}_TOP is set to $ENV{${project}_TOP}") + SET(PROJECT_MODULE_PATH "${DESTDIR}$ENV{${project}_TOP}/share/cmake/Modules/") + LIST(INSERT CMAKE_MODULE_PATH 0 "${PROJECT_MODULE_PATH}") + ENDIF( NOT("$ENV{${project}_TOP}" STREQUAL "") ) + + IF( NOT("$ENV{${project}_USER_TOP}" STREQUAL "") ) + MESSAGE("-- ${project}_USER_TOP is set to $ENV{${project}_USER_TOP}") + SET(PROJECT_MODULE_PATH "${DESTDIR}$ENV{${project}_USER_TOP}/share/cmake/Modules/") + LIST(INSERT CMAKE_MODULE_PATH 0 "${PROJECT_MODULE_PATH}") + ENDIF( NOT("$ENV{${project}_USER_TOP}" STREQUAL "") ) + + LIST(REMOVE_DUPLICATES CMAKE_MODULE_PATH) +ENDMACRO(SETUP_PROJECT_PATHS project) + +SETUP_PROJECT_PATHS(VLSISAPD) +SETUP_PROJECT_PATHS(CORIOLIS) + +MESSAGE("-- Components of CMAKE_MODULE_PATH:") +FOREACH(PATH IN LISTS CMAKE_MODULE_PATH) + MESSAGE("-- ${PATH}") +ENDFOREACH(PATH) + +SET(QT_USE_QTXML "true") + +FIND_PACKAGE(Qt4 REQUIRED) # find and setup Qt4 for this project +FIND_PACKAGE(HURRICANE REQUIRED) +FIND_PACKAGE(CORIOLIS REQUIRED) +FIND_PACKAGE(NIMBUS REQUIRED) + +SET(HMETIS_INCLUDE_PATH METIS_INCLUDE_PATH) +FIND_LIBRARY(HMETIS_LIBRARY_PATH + NAMES hmetis + PATHS ${CORIOLIS_DIR_SEARCH} /opt/coriolis + PATH_SUFFIXES lib${LIB_SUFFIX} + # Help the user find it if we cannot. + DOC "The hmetis static library" +) +SET_LIBRARIES_PATH(HMETIS HMETIS) + +SET_LIB_LINK_MODE() + +ADD_SUBDIRECTORY(src) +ADD_SUBDIRECTORY(cmake_modules) diff --git a/metis/cmake_modules/CMakeLists.txt b/metis/cmake_modules/CMakeLists.txt new file mode 100644 index 00000000..d8380106 --- /dev/null +++ b/metis/cmake_modules/CMakeLists.txt @@ -0,0 +1 @@ +install ( FILES FindMETIS.cmake DESTINATION share/cmake/Modules ) diff --git a/metis/cmake_modules/FindMETIS.cmake b/metis/cmake_modules/FindMETIS.cmake new file mode 100644 index 00000000..197977a2 --- /dev/null +++ b/metis/cmake_modules/FindMETIS.cmake @@ -0,0 +1,48 @@ +# - Find the Metis includes and libraries. +# The following variables are set if Coriolis is found. If METIS is not +# found, METIS_FOUND is set to false. +# METIS_FOUND - True when the Coriolis include directory is found. +# METIS_INCLUDE_DIR - the path to where the Coriolis include files are. +# METIS_LIBRARIES - The path to where the Coriolis library files are. + + +SET(METIS_INCLUDE_PATH_DESCRIPTION "directory containing the Metis/hmetis include files. E.g /usr/local/include/coriolis or /asim/coriolis/include/coriolis") + +SET(METIS_DIR_MESSAGE "Set the METIS_INCLUDE_DIR cmake cache entry to the ${METIS_INCLUDE_PATH_DESCRIPTION}") + +# don't even bother under WIN32 +IF(UNIX) + # + # Look for an installation. + # + FIND_PATH(METIS_INCLUDE_PATH NAMES metis/MetisEngine.h PATHS + # Look in other places. + ${CORIOLIS_DIR_SEARCH} + PATH_SUFFIXES include/coriolis2 + # Help the user find it if we cannot. + DOC "The ${METIS_INCLUDE_PATH_DESCRIPTION}" + ) + + FIND_LIBRARY(METIS_LIBRARY_PATH + NAMES metis + PATHS ${CORIOLIS_DIR_SEARCH} + PATH_SUFFIXES lib${LIB_SUFFIX} + # Help the user find it if we cannot. + DOC "The ${METIS_INCLUDE_PATH_DESCRIPTION}" + ) + + SET(HMETIS_INCLUDE_PATH METIS_INCLUDE_PATH) + + FIND_LIBRARY(HMETIS_LIBRARY_PATH + NAMES hmetis + PATHS ${CORIOLIS_DIR_SEARCH} /opt/coriolis + PATH_SUFFIXES lib${LIB_SUFFIX} + # Help the user find it if we cannot. + DOC "The ${METIS_INCLUDE_PATH_DESCRIPTION}" + ) + + SET_LIBRARIES_PATH(METIS METIS) + SET_LIBRARIES_PATH(HMETIS HMETIS) + HURRICANE_CHECK_LIBRARIES(METIS) + +ENDIF(UNIX) diff --git a/metis/src/CMakeLists.txt b/metis/src/CMakeLists.txt new file mode 100644 index 00000000..5393e6da --- /dev/null +++ b/metis/src/CMakeLists.txt @@ -0,0 +1,37 @@ + +if ( HMETIS_FOUND ) + add_definitions ( -DHAVE_HMETIS_LIB ) +endif ( HMETIS_FOUND ) + + include ( ${QT_USE_FILE} ) + + include_directories ( ${METIS_SOURCE_DIR}/src + ${HURRICANE_INCLUDE_DIR} + ${CORIOLIS_INCLUDE_DIR} + ) + set ( includes metis/hmetis.h + metis/MetisGraph.h + metis/Configuration.h + metis/MetisEngine.h + ) +# set ( mocIncludes metis/ConfigurationWidget.h +# metis/GraphicMaukaEngine.h ) + set ( cpps MetisGraph.cpp + Configuration.cpp + MetisEngine.cpp + ) +# qt4_wrap_cpp ( mocCpps ${mocIncludes} ) + + + add_library ( metis ${cpps} ${mocCpps} ) + target_link_libraries ( metis ${HMETIS_LIBRARIES} + ${NIMBUS_LIBRARIES} + ${CORIOLIS_LIBRARIES} + ${HURRICANE_LIBRARIES} + ${HURRICANE_GRAPHICAL_LIBRARIES} + ${QT_LIBRARIES} + ${LEFDEF_LIBRARIES} + ${OA_LIBRARIES} + ) + install ( TARGETS metis DESTINATION lib${LIB_SUFFIX} ) + install ( FILES ${includes} ${mocIncludes} DESTINATION include/coriolis2/metis ) diff --git a/metis/src/Configuration.cpp b/metis/src/Configuration.cpp new file mode 100644 index 00000000..b44aea90 --- /dev/null +++ b/metis/src/Configuration.cpp @@ -0,0 +1,161 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved +// +// =================================================================== +// +// $Id$ +// +// x-----------------------------------------------------------------x +// | | +// | C O R I O L I S | +// | M e t i s - h M e t i s W r a p p e r | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +// | =============================================================== | +// | C++ Module : "./Configuration.cpp" | +// | *************************************************************** | +// | U p d a t e s | +// | | +// x-----------------------------------------------------------------x + + +#include +#include + +#include "hurricane/Cell.h" +#include "crlcore/Utilities.h" +#include "metis/Configuration.h" + + +namespace Metis { + + + using std::cout; + using std::cerr; + using std::endl; + using std::setprecision; + using std::ostringstream; + using std::string; + using Hurricane::tab; + using Hurricane::inltrace; + using Hurricane::Cell; + + +// ------------------------------------------------------------------- +// Class : "Metis::Configuration". + + + Configuration* Configuration::_default = NULL; + + + Configuration* Configuration::getDefault () + { + if ( _default == NULL ) { + _default = new Configuration (); + } + return _default; + } + + + Configuration::Configuration () + : _refreshCb () + , _partOrKWayHMetis (true) + , _numberOfInstancesStopCriterion(45) + , _globalConnectionsWeightRatio (1) + , _ubFactor (0) + , _hmetisOptions () + { + _hmetisOptions[CustomOptions ] = 1; + _hmetisOptions[HMetisNRuns ] = 10; + _hmetisOptions[HMetisCType ] = CTypeHFC; + _hmetisOptions[HMetisRType ] = RTypeFM; + _hmetisOptions[HMetisVCycle ] = VCycleDisable; + _hmetisOptions[HMetisReconst ] = ReconstRemoveCutHE; + _hmetisOptions[HMetisPreAssign ] = 1; + _hmetisOptions[HMetisRandom ] = -1; + _hmetisOptions[HMetisDebugLevel] = DebugDisable; + } + + + Configuration::Configuration ( const Configuration& other ) + : _refreshCb (other._refreshCb) + , _partOrKWayHMetis (other._partOrKWayHMetis) + , _numberOfInstancesStopCriterion(other._numberOfInstancesStopCriterion) + , _globalConnectionsWeightRatio (other._globalConnectionsWeightRatio) + , _ubFactor (other._ubFactor) + , _hmetisOptions () + { + for ( unsigned int option=0 ; option for Cell <" << cell->getName() << ">" << endl; + cout << Dots::asBool(" - Part / KWay hMETIS" ,_partOrKWayHMetis) << endl; + cout << Dots::asUInt(" - Instances stop criterion" ,_numberOfInstancesStopCriterion) << endl; + cout << Dots::asInt (" - Global connections weight ratio" ,_globalConnectionsWeightRatio) << endl; + cout << Dots::asInt (" - UB factor" ,_ubFactor) << endl; + cout << Dots::asInt (" - hMETIS Custom options" ,_hmetisOptions[CustomOptions]) << endl; + cout << Dots::asInt (" - hMETIS NRuns" ,_hmetisOptions[HMetisNRuns]) << endl; + cout << Dots::asInt (" - hMETIS CType" ,_hmetisOptions[HMetisCType]) << endl; + cout << Dots::asInt (" - hMETIS RType" ,_hmetisOptions[HMetisRType]) << endl; + cout << Dots::asInt (" - hMETIS V-Cycle" ,_hmetisOptions[HMetisVCycle]) << endl; + cout << Dots::asInt (" - hMETIS Reconstruct Edges" ,_hmetisOptions[HMetisReconst]) << endl; + cout << Dots::asInt (" - hMETIS Pre-Assignment" ,_hmetisOptions[HMetisPreAssign]) << endl; + cout << Dots::asInt (" - hMETIS Random" ,_hmetisOptions[HMetisRandom]) << endl; + cout << Dots::asInt (" - hMETIS Debug Level" ,_hmetisOptions[HMetisDebugLevel]) << endl; + } + + + string Configuration::_getTypeName () const + { + return "Metis::Configuration"; + } + + + string Configuration::_getString () const + { + ostringstream os; + + os << "<" << _getTypeName() << ">"; + + return os.str(); + } + + + Record* Configuration::_getRecord () const + { + Record* record = new Record ( _getString() ); + record->add ( getSlot("_partOrKWayHMetis" , _partOrKWayHMetis ) ); + record->add ( getSlot("_numberOfInstancesStopCriterion" , _numberOfInstancesStopCriterion ) ); + record->add ( getSlot("_globalConnectionsWeightRatio" , _globalConnectionsWeightRatio ) ); + record->add ( getSlot("_ubFactor" , _ubFactor ) ); + record->add ( getSlot("_hmetisOptions[CustomOptions]" , _hmetisOptions[CustomOptions] ) ); + record->add ( getSlot("_hmetisOptions[HMetisNRuns]" , _hmetisOptions[HMetisNRuns ] ) ); + record->add ( getSlot("_hmetisOptions[HMetisCType]" , _hmetisOptions[HMetisCType ] ) ); + record->add ( getSlot("_hmetisOptions[HMetisRType]" , _hmetisOptions[HMetisRType ] ) ); + record->add ( getSlot("_hmetisOptions[HMetisVCycle]" , _hmetisOptions[HMetisVCycle ] ) ); + record->add ( getSlot("_hmetisOptions[HMetisReconst]" , _hmetisOptions[HMetisReconst] ) ); + record->add ( getSlot("_hmetisOptions[HMetisPreAssign]" , _hmetisOptions[HMetisPreAssign] ) ); + record->add ( getSlot("_hmetisOptions[HMetisRandom]" , _hmetisOptions[HMetisRandom ] ) ); + record->add ( getSlot("_hmetisOptions[HMetisDebugLevel]", _hmetisOptions[HMetisDebugLevel]) ); + + return ( record ); + } + + +} // End of Metis namespace. diff --git a/metis/src/MetisEngine.cpp b/metis/src/MetisEngine.cpp new file mode 100644 index 00000000..395e084d --- /dev/null +++ b/metis/src/MetisEngine.cpp @@ -0,0 +1,318 @@ + +// This file is part of the Coriolis Project. +// Copyright (C) Laboratoire LIP6 - Departement ASIM +// Universite Pierre et Marie Curie +// +// Main contributors : +// Christophe Alexandre +// Hugo Clément +// Jean-Paul Chaput +// Christian Masson +// +// The Coriolis Project is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// The Coriolis Project is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with the Coriolis Project; if not, write to the Free Software +// Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// +// License-Tag +// +// Date : 29/01/2004 +// Author : Christophe Alexandre +// +// Authors-Tag + + +#include +using namespace std; + +#include "hurricane/Warning.h" +#include "hurricane/Net.h" +#include "hurricane/Instance.h" +#include "hurricane/Plug.h" +#include "hurricane/Timer.h" +#include "crlcore/ToolBox.h" +#include "crlcore/AllianceFramework.h" +using namespace CRL; + +#include "nimbus/NimbusEngine.h" +using namespace Nimbus; + +#ifdef HAVE_HMETIS_LIB +#include "metis/MetisGraph.h" +#endif +#include "metis/MetisEngine.h" + + +namespace Metis { + + + const Name MetisEngine::_toolName = "Metis"; + + + MetisEngine::MetisEngine ( Cell* cell ) + : Inherit (cell) + , _configuration(Configuration::getDefault()->clone()) + , _step (0) + , _actualGraphs () + , _newGraphs () + , _globalEdgeCut(0) + { +#ifdef HAVE_HMETIS_LIB + + NimbusEngine* nimbus = NimbusEngine::get ( getCell() ); + if ( nimbus == NULL ) + throw Error ("Nimbus must be created before Metis, on cell <%s>" + ,getString(getCell()->getName()).c_str()); + + _actualGraphs = new MetisGraphs(); + _newGraphs = new MetisGraphs(); + _actualGraphs->push_back ( new MetisGraph(this,nimbus->getGrid()->getRoot()) ); + + // What the fuck does this loop do? + // forEach ( Net*, inet, getCell()->getNets() ) { + // if ( inet->isGlobal() ) continue; + // if ( inet->isSupply() ) continue; + // } +#endif // HAVE_HMETIS_LIB + } + + + MetisEngine::~MetisEngine () + { delete _configuration; } + + + MetisEngine* MetisEngine::create ( Cell* cell ) + { + MetisEngine* metis = new MetisEngine(cell); + + metis->_postCreate(); + return metis; + } + + + void MetisEngine::_preDestroy () + { +#ifdef HAVE_HMETIS_LIB + for (MetisGraphs::iterator mgit = _actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit) + delete *mgit; + for (MetisGraphs::iterator mgit = _newGraphs->begin(); mgit != _newGraphs->end(); ++mgit) + delete *mgit; + + delete _actualGraphs; + delete _newGraphs; +#endif // HAVE_HMETIS_LIB + Inherit::_preDestroy(); + } + + + bool MetisEngine::isHMetisCapable () + { +#ifdef HAVE_HMETIS_LIB + return true; +#else + return false; +#endif // HAVE_HMETIS_LIB + } + + + Record* MetisEngine::_getRecord () const + { + Record* record = Inherit::_getRecord(); + if (record) { + record->add ( getSlot("step", _step) ); + } + return record; + } + + + void MetisEngine::run () + { +#ifdef HAVE_HMETIS_LIB + cmess2 << " o hMetis quadri-partition step." << endl; + + Timer timer; + timer.start(); + + NimbusEngine* nimbus = NimbusEngine::get ( getCell() ); + + forEach ( GCell*, igcell, nimbus->getPlacementLeaves() ) { + if ( not igcell->hasSubGCells() ) + throw Warning("You must first progress in Nimbus before calling Metis"); + + if ( igcell->getSubGCells().getSize() < 2 ) + throw Error("Metis needs at least 2 Nimbus subboxes"); + } + + _globalEdgeCut = 0; + + linefill output (" ",cmess2); + + for ( MetisGraphs::iterator mgit = _actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit ) { + MetisGraph* graph = *mgit; + + try { + _globalEdgeCut += graph->part ( output ); + } + catch ( MetisGraph::TooLowNVTXSException& e ) { + cerr << Warning("Impossible to part graph, only %d nodes",e._nvtxs); + } + + for ( size_t id=0; id < graph->_partResultVector.size(); ++id ) { + _newGraphs->push_back + ( new MetisGraph(this + ,graph + ,graph->_partResultVector[id]->first + ,graph->_partResultVector[id]->second + ) ); + } + } + + output << endl; + + for ( MetisGraphs::iterator mgit=_actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit ) + delete *mgit; + delete _actualGraphs; + + _actualGraphs = _newGraphs; + _newGraphs = new MetisGraphs (); + + save ( ++_step ); + + timer.stop(); + cmess2 << " - Refine placement done in " << getString(timer.getUserTime()) << "s." << endl; + + if ( getRefreshCb() != NULL ) getRefreshCb() (); +#else + throw Warning ( "hmetis library is needed to use Metis ToolEngine" ); +#endif // HAVE_HMETIS_LIB + } + + + void MetisEngine::save ( unsigned step ) + { +#ifdef HAVE_HMETIS_LIB + //for ( MetisGraphs::iterator mgit=_actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit) + // (*mgit)->save ( step ); + grabPlacementModificationFlag (); +#else + throw Warning ( "hmetis library is needed to use Metis ToolEngine" ); +#endif /* HAVE_HMETIS_LIB */ + } + + + int MetisEngine::getGlobalEdgeCut () const + { return _globalEdgeCut; } + + + const Name& MetisEngine::staticGetName () + { return _toolName; } + + + const Name& MetisEngine::getName () const + { return _toolName; } + + + MetisEngine* MetisEngine::get ( Cell* cell ) + { return dynamic_cast ( ToolEngine::get(cell,_toolName) ); } + + + bool MetisEngine::_reInit() + { +#if 0 +#ifdef HAVE_HMETIS_LIB + for (MetisGraphs::iterator mgit=_actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit) + delete *mgit; + for (MetisGraphs::iterator mgit=_newGraphs->begin(); mgit != _newGraphs->end(); ++mgit) + delete *mgit; + + delete _actualGraphs; + delete _newGraphs; + + _actualGraphs = new MetisGraphs(); + _newGraphs = new MetisGraphs(); + + NimbusEngine* nimbus = NimbusEngine::get ( getCell() ); + bool partToBeDone = false; + + forEach ( GCell*, igcell, nimbus->getPlacementLeaves() ) { + Instances instances = getCell()->getInstancesUnder(**igcell); + + if ( instances.getSize() >= getNumberOfInstancesStopCriterion() ) { + if ( not partToBeDone ) { + partToBeDone = true; + ++_step; + } + _actualGraphs->push_back ( new MetisGraph(this,instances,igcell) ); + } + } + + if ( not partToBeDone ) + throw Warning("Not enough instances to part, minimum is %d",getNumberOfInstancesStopCriterion()); + + return true; +#else + throw Warning ( "hmetis library is needed to use Metis ToolEngine" ); +#endif // HAVE_HMETIS_LIB +#else + return false; +#endif +} + + + unsigned int MetisEngine::computeQuadriPartitions ( Cell* cell ) + { + size_t gates = getInstancesCount ( cell ); + + double partitions = log((double)gates / (double)Configuration::getDefault() + ->getNumberOfInstancesStopCriterion() ) / log(4.0) + 1.0; + + return (unsigned int)(partitions); + } + + + void MetisEngine::doQuadriPart ( Cell* cell ) + { + if ( not isHMetisCapable() ) + throw Error ("Metis::doQuadriPart(): HMetis wasn't found at compile time <%s>" + ,getString(cell->getName()).c_str()); + + // MetisEngine* metis = MetisEngine::get ( cell ); + // if ( metis != NULL ) + // throw Error ("Metis::doQuadriPart(): Metis already exists on <%s>" + // ,getString(cell->getName()).c_str()); + + // NimbusEngine* nimbus = NimbusEngine::get ( cell ); + // if ( nimbus != NULL ) + // throw Error ("Metis::doQuadriPart(): Nimbus already exists on <%s>" + // ,getString(cell->getName()).c_str()); + + // nimbus = NimbusEngine::create ( cell, AllianceFramework::get()->getLibrary(1) ); + // metis = MetisEngine ::create ( cell ); + + NimbusEngine* nimbus = NimbusEngine::get ( cell ); + if ( nimbus == NULL ) + nimbus = NimbusEngine::create ( cell ); + + MetisEngine* metis = MetisEngine::get ( cell ); + if ( metis == NULL ) + metis = MetisEngine ::create ( cell ); + + size_t partitions = computeQuadriPartitions ( cell ); + for ( size_t part=0 ; partprogress (); + metis-> run (); + } + } + + +} // End of Metis namespace. diff --git a/metis/src/MetisGraph.cpp b/metis/src/MetisGraph.cpp new file mode 100644 index 00000000..a34d1787 --- /dev/null +++ b/metis/src/MetisGraph.cpp @@ -0,0 +1,621 @@ + +// This file is part of the Coriolis Project. +// Copyright (C) Laboratoire LIP6 - Departement ASIM +// Universite Pierre et Marie Curie +// +// Main contributors : +// Christophe Alexandre +// Hugo Clément +// Jean-Paul Chaput +// Christian Masson +// +// The Coriolis Project is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// The Coriolis Project is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with the Coriolis Project; if not, write to the Free Software +// Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// +// License-Tag +// +// Date : 29/01/2004 +// Author : Christophe Alexandre +// +// Authors-Tag + +#ifdef HAVE_HMETIS_LIB + +#include "hurricane/Net.h" +#include "hurricane/Instance.h" +#include "hurricane/Plug.h" +#include "hurricane/Pin.h" +#include "hurricane/UpdateSession.h" +using namespace Hurricane; + +#include "crlcore/Utilities.h" +#include "crlcore/ToolBox.h" +using namespace CRL; + +#include "nimbus/Splitter.h" +#include "nimbus/GCell.h" +#include "nimbus/SplitterContact.h" +#include "nimbus/StepProperty.h" +#include "nimbus/NimbusEngine.h" +using namespace Nimbus; + +#include "metis/hmetis.h" +#include "metis/MetisGraph.h" + +namespace { + +using namespace Metis; + +typedef map Id2OccurrencesMap; + +struct removeEmptyPartResult +{ + removeEmptyPartResult() {} + bool operator()(MetisGraph::PartResult* partresult) + { + if (partresult->second.size() == 0) + { + delete partresult; + return true; + } + return false; + } +}; + + +void VerifyHGraph(int nvtxs, int nhedges, int* vwgts, int* eptr + , int* eind, int* hewgts, int nparts, int* part + , Id2OccurrencesMap& hypernetidmap) +{ + cerr << "nparts = " << nparts << endl; + cerr << "nvtxs = " << nvtxs << endl; + + cerr << "vwgts" << endl; + for (int i=0; i < nvtxs; i++) + { + cerr << vwgts[i] << " "; + } + cerr << endl; + + cerr << "nhedges = " << nhedges << endl; + + cerr << "eptr" << endl; + for (int i=0; i <= nhedges; i++) + { + cerr << eptr[i] << " "; + } + cerr << endl; + + cerr << "eind" << endl; + for (int i=0; i < eptr[nhedges]; i++) + { + cerr << eind[i] << " "; + } + cerr << endl; + + if (hewgts) + { + cerr << "hewgts" << endl; + for (int i=0; i < nhedges; i++) + { + cerr << hewgts[i] << " "; + } + cerr << endl; + } + + cerr << "part" << endl; + for (int i=0; i < nvtxs; i++) + { + cerr << part[i] << " "; + } + cerr << endl; + + cerr << "nets" << endl; + for (int i=0; i < nhedges; i++) + { + cerr << hypernetidmap[i] << " "; + if (hewgts) + { + cerr << "(" << hewgts[i] << ") : "; + } + else + { + cerr << ": " << endl; + } + for (int j=eptr[i]; j < eptr[i+1]; j++) + { + cerr << "(" << eind[j] << "," << vwgts[eind[j]] << ") " ; + } + cerr << endl; + } +} + + +} // End of anonymous namespace. + + +namespace Metis { + +MetisGraph::MetisGraph ( MetisEngine* metis, GCell* gcell ) + : _metis(metis) + , _cell(_metis->getCell()) + , _gcell(gcell) + , _toPlaceInstanceOccurrencesSet() + , _rootNetOccurrencesSet() + , _partResultVector() + , _edgeCut(INT_MAX) +{ + typedef set InstanceSet; + InstanceSet instanceSet; + + for_each_occurrence(occurrence, _cell->getLeafInstanceOccurrences()) + { + Instance* instance = static_cast(occurrence.getEntity()); + if (!instance->isFixed()) + { + if (instanceSet.find(instance) != instanceSet.end()) + throw Error("MetisEngine limitation : only one occurrence of unplaced instance"); + instanceSet.insert(instance); + _toPlaceInstanceOccurrencesSet.insert(occurrence); //treat this later + } + end_for; + } + + for_each_occurrence(occurrence, _cell->getHyperNetRootNetOccurrences()) + { + Net* net = static_cast(occurrence.getEntity()); + if (net->isGlobal() || net->isPower() || net->isGround()) + continue; + if (net->getCell()->isLeaf()) + continue; + _rootNetOccurrencesSet.insert(occurrence); + end_for; + } +} + +MetisGraph::MetisGraph(MetisEngine* metis, MetisGraph* previous, GCell* gcell, OccurrenceSet& toplaceinstanceoccurrences) + : _metis(metis) + , _cell(_metis->getCell()) + , _gcell(gcell) + , _toPlaceInstanceOccurrencesSet(toplaceinstanceoccurrences) + , _rootNetOccurrencesSet() + , _partResultVector() +{ + for (OccurrenceSet::iterator osit = previous->_rootNetOccurrencesSet.begin(); + osit != previous->_rootNetOccurrencesSet.end(); + osit++) + { + HyperNet hyperNet(*osit); + for_each_occurrence(leafPlugOccurrence, hyperNet.getLeafPlugOccurrences()) + { + Path path = leafPlugOccurrence.getPath(); + Instance* instance = (static_cast(leafPlugOccurrence.getEntity()))->getInstance(); + Occurrence instanceOccurrence(instance, path); + OccurrenceSet::const_iterator iosit = _toPlaceInstanceOccurrencesSet.find(instanceOccurrence); + if (iosit != _toPlaceInstanceOccurrencesSet.end()) + { + _rootNetOccurrencesSet.insert(*osit); //treat later fixed points. + break; + } + end_for; + } + } + //treat fixed points in Part method +} + +MetisGraph::~MetisGraph() +{ + for (PartResultVector::iterator prvit = _partResultVector.begin(); + prvit != _partResultVector.end(); + prvit++) + { + delete (*prvit); + } + +} + +int MetisGraph::part ( linefill& output ) +{ + typedef vector GCellVector; + GCellVector subGCells; + + if (not _gcell->hasSubGCells()) + throw Error("Metis: GCell doesn't have any sub-GCells"); + for_each_gcell(gcell, _gcell->getSubGCells()) + { + subGCells.push_back(gcell); + end_for; + } + + unsigned subGCellsCount = subGCells.size(); + + if (subGCellsCount < 2) + throw Error("Metis, Less than 2 sub-GCells (%d)",subGCellsCount); + + vector subGCellsCountOccupation(subGCellsCount, 0.0); + typedef list InstanceOccurrencesList; + typedef vector BoxesInstanceOccurrencesVector; + typedef vector > BoxesInstanceOccurrencesWeights; + BoxesInstanceOccurrencesVector subGCellsFixedInstanceOccurrences(subGCellsCount, InstanceOccurrencesList()); + BoxesInstanceOccurrencesWeights subGCellsFixedInstanceOccurrenceWeights(subGCellsCount, list()); + + vector vwgts_vector; + vector hewgts_vector; + vector part_vector; + + typedef map Occurrences2IdMap; + Occurrences2IdMap instanceOccurrencesMap; + + Id2OccurrencesMap toPlaceInstanceOccurrencesMap; + + for (unsigned gcellCount = 0; gcellCount != subGCells.size(); gcellCount++) + { + GCell* gcell = subGCells[gcellCount]; + for_each_occurrence(instanceOccurrence, _cell->getLeafInstanceOccurrencesUnder(gcell->getBox())) + { + Instance* instance = static_cast(instanceOccurrence.getEntity()); + if (instance->isFixed()) + { + Box instanceOccurrenceABox = instance->getAbutmentBox(); + instanceOccurrence.getPath().getTransformation().applyOn(instanceOccurrenceABox); + if (gcell->contains(instanceOccurrenceABox)) + { + double instanceWeight = + DbU::getLambda(instance->getMasterCell()->getAbutmentBox().getWidth()) + * DbU::getLambda(instance->getMasterCell()->getAbutmentBox().getHeight()); + subGCellsCountOccupation[gcellCount] += instanceWeight; + subGCellsFixedInstanceOccurrenceWeights[gcellCount].push_back(instanceWeight); + subGCellsFixedInstanceOccurrences[gcellCount].push_back(instanceOccurrence); + continue; + } + else + { + Box intersection = gcell->getIntersection(instanceOccurrenceABox); + if (!intersection.isEmpty()) + { + double intersectionWeight = + DbU::getLambda(intersection.getWidth()) * DbU::getLambda(intersection.getHeight()); + + subGCellsCountOccupation[gcellCount] += intersectionWeight; + subGCellsFixedInstanceOccurrenceWeights[gcellCount].push_back(intersectionWeight); + subGCellsFixedInstanceOccurrences[gcellCount].push_back(instanceOccurrence); + //FIXME only the last part of the fixed point will be taken into account + } + } + } + end_for; + } + } + + + unsigned nodeId = 0; + + //treat fixed instances occurrences + for (unsigned gcellCount = 0; gcellCount != subGCells.size(); gcellCount++) + { + GCell* gcell = subGCells[gcellCount]; + double gcellArea = DbU::getLambda(gcell->getWidth()) * DbU::getLambda(gcell->getHeight()); + if (((gcellArea - subGCellsCountOccupation[gcellCount])/gcellArea) < 0.10) + { + cerr << "surOccupied gcell : " << gcell << endl; + } + else + { + _partResultVector.push_back(new PartResult(gcell, OccurrenceSet())); + unsigned gcellId = _partResultVector.size() - 1; + unsigned fixedNodesCount = subGCellsFixedInstanceOccurrences[gcellCount].size(); + list::const_iterator dlit = + subGCellsFixedInstanceOccurrenceWeights[gcellCount].begin(); + InstanceOccurrencesList::const_iterator iolit = + subGCellsFixedInstanceOccurrences[gcellCount].begin(); + for (unsigned id = 0; id != fixedNodesCount; id++) + { + vwgts_vector.push_back((int)*dlit); + instanceOccurrencesMap[*iolit] = nodeId++; + ++dlit; ++iolit; + } + part_vector.insert(part_vector.end(), fixedNodesCount, gcellId); + } + } + + //now treat instance occurrences to place + + typedef vector OccurrenceVector; + OccurrenceVector instanceOccurrenceVector(_toPlaceInstanceOccurrencesSet.begin(), _toPlaceInstanceOccurrencesSet.end()); + random_shuffle(instanceOccurrenceVector.begin(), instanceOccurrenceVector.end()); + + for (OccurrenceVector::const_iterator ovit = instanceOccurrenceVector.begin(); + ovit != instanceOccurrenceVector.end(); + ovit++) + { + Instance* instance = static_cast(ovit->getEntity()); + double instanceWeight = + DbU::getLambda(instance->getMasterCell()->getAbutmentBox().getWidth()) + * DbU::getLambda(instance->getMasterCell()->getAbutmentBox().getHeight()); + vwgts_vector.push_back((int)instanceWeight); + part_vector.push_back(-1); + toPlaceInstanceOccurrencesMap[nodeId] = *ovit; + instanceOccurrencesMap[*ovit] = nodeId++; + } + + output << _toPlaceInstanceOccurrencesSet.size(); + + // constructing edges from hypernets + vector eptr_vector; + vector eind_vector; + eptr_vector.push_back(0); + int hyperEdgesCount = 0; + +#ifdef METISSE_DEBUG + Id2OccurrencesMap hyperNetIdMap; + Id2OccurrencesMap nodesIdMap; +#endif + + OccurrenceVector netOccurrenceVector(_rootNetOccurrencesSet.begin(), _rootNetOccurrencesSet.end()); + +#if 0 + for (OccurrenceSet::iterator osit = _rootNetOccurrencesSet.begin(); + osit != _rootNetOccurrencesSet.end(); + osit++) +#endif + for (OccurrenceVector::iterator ovit = netOccurrenceVector.begin(); + ovit != netOccurrenceVector.end(); + ovit++) + { + HyperNet hyperNet(*ovit); + list hyperNetNodes; + typedef list OccurrenceList; + OccurrenceList terminals; + unsigned nodesToPlace = 0; + + //look for pins, pins are on the root net + Net* rootNet = static_cast(ovit->getEntity()); + for_each_pin(pin, rootNet->getPins()) + { + Path path = ovit->getPath(); + Occurrence pinOccurrence(pin, path); + terminals.push_back(pinOccurrence); + end_for; + } + + OccurrenceSet instanceOccurrencesSet; //to detect multi connection of a single instance + for_each_occurrence(leafPlugOccurrence, hyperNet.getLeafPlugOccurrences()) + { + Path path = leafPlugOccurrence.getPath(); + Instance* instance = (static_cast(leafPlugOccurrence.getEntity()))->getInstance(); + Occurrence instanceOccurrence(instance, path); + OccurrenceSet::const_iterator iosit = instanceOccurrencesSet.find(instanceOccurrence); + if (iosit != instanceOccurrencesSet.end()) + continue; + instanceOccurrencesSet.insert(instanceOccurrence); + Occurrences2IdMap::const_iterator imit = instanceOccurrencesMap.find(instanceOccurrence); + if (imit == instanceOccurrencesMap.end()) + { + terminals.push_back(instanceOccurrence); + } + else + { + unsigned nodeId = imit->second; + hyperNetNodes.push_back(nodeId); + if (part_vector[nodeId] == -1) + ++nodesToPlace; + } + end_for; + } + + unsigned terminalsCount = terminals.size(); + + if (nodesToPlace > 1 || ((nodesToPlace > 0) && (terminalsCount > 0))) + { +#ifdef METISSE_DEBUG + hyperNetIdMap[hyperEdgesCount] = *ovit; +#endif + ++hyperEdgesCount; + if (terminalsCount > 0) + { + DbU::Unit x = 0; + DbU::Unit y = 0; + for (OccurrenceList::iterator olit = terminals.begin(); + olit != terminals.end(); + olit++) + { + Point center = olit->getBoundingBox().getCenter(); + x += center.getX() / terminalsCount; + y += center.getY() / terminalsCount; + } + Point barycenter(x,y); + //recherche brute force de la meilleure gcell + GCell* targetGCell = NULL; + unsigned targetGCellId = 0; + DbU::Unit bestDistance = LONG_MAX; + for (unsigned gcellid = 0; gcellid < _partResultVector.size(); gcellid++) + { + GCell* gcell = _partResultVector[gcellid]->first; + DbU::Unit distance = gcell->manhattanDistance(barycenter); + if (distance < bestDistance) + { + bestDistance = distance; + targetGCell = gcell; + targetGCellId = gcellid; + } + } + assert(targetGCell); + //insert fixed point + hyperNetNodes.push_back(nodeId++); + vwgts_vector.push_back(0); + part_vector.push_back(targetGCellId); + assert(_metis->getGlobalConnectionsWeightRatio()); + if (_metis->getGlobalConnectionsWeightRatio() > 0) + hewgts_vector.push_back(_metis->getGlobalConnectionsWeightRatio()); + else + hewgts_vector.push_back(1); + } + else + { + assert(_metis->getGlobalConnectionsWeightRatio()); + if (_metis->getGlobalConnectionsWeightRatio() < 0) + hewgts_vector.push_back(-_metis->getGlobalConnectionsWeightRatio()); + else + hewgts_vector.push_back(1); + } + assert(hyperNetNodes.size() > 1); + eind_vector.insert(eind_vector.end(), hyperNetNodes.begin(), hyperNetNodes.end()); + eptr_vector.push_back(eptr_vector.back() + hyperNetNodes.size()); + } + } + + + //OK now the real thing ... call hmetis + + size_t nvtxs = part_vector.size(); + if (nvtxs < _metis->getNumberOfInstancesStopCriterion()) + throw TooLowNVTXSException(nvtxs); + + size_t nhedges = eptr_vector.size() - 1; + size_t nparts = _partResultVector.size(); + + assert(part_vector.size() == vwgts_vector.size()); + assert (nhedges == (size_t)hyperEdgesCount); + assert (nhedges == static_cast(hewgts_vector.size())); + + int* eind = new int[eind_vector.size()]; + for (unsigned id = 0; id < eind_vector.size(); id++) + { + eind[id] = eind_vector[id]; + } + + int* eptr = new int[eptr_vector.size()]; + for (unsigned id = 0; id < eptr_vector.size(); id++) + { + eptr[id] = eptr_vector[id]; + } + + int* vwgts = new int[vwgts_vector.size()]; + for (unsigned id = 0; id < vwgts_vector.size(); id++) + { + vwgts[id] = vwgts_vector[id]; + } + + int* hewgts = new int[hewgts_vector.size()]; + for (unsigned id = 0; id < hewgts_vector.size(); id++) + { + hewgts[id] = hewgts_vector[id]; + } + + bool preAssignment = false; + int* part = new int[nvtxs]; + for (unsigned id = 0; id < part_vector.size(); id++) + { + part[id] = part_vector[id]; + if (part_vector[id] != -1) + preAssignment = true; + } + + //verification + + for (int id = 0; id < eptr[nhedges] ; id++) + { + assert(eind[id] < (int)nvtxs); + } + + for (size_t id = 0; id < nvtxs ; id++) + { + assert((part[id] == -1) || (part[id] < (int)nparts)); + } + + _metis->setHMetisOption ( Configuration::HMetisRandom, -1 ); //use random + + + if (preAssignment) + _metis->setHMetisOption ( Configuration::HMetisPreAssign, 1 ); + else + _metis->setHMetisOption ( Configuration::HMetisPreAssign, 0 ); + +#ifdef METISSE_DEBUG + VerifyHGraph(nvtxs, nhedges, vwgts, eptr, eind, hewgts, nparts, part, hyperNetIdMap); +#endif + + if (_metis->getPartOrKWayHMetis()) + { + int ubFactor = _metis->getUbFactor(); + if (!ubFactor) + ubFactor = 2; // the minimal value is 1, but let's try a bit of amplitude. + HMETIS_PartRecursive(nvtxs, nhedges, vwgts + , eptr, eind, hewgts, nparts + , ubFactor + , _metis->getHMetisOptions() + , part, &_edgeCut); + } + else + { + int ubFactor = _metis->getUbFactor(); + if (!ubFactor) + ubFactor = 5; //minimal value + HMETIS_PartKway(nvtxs, nhedges, vwgts + , eptr, eind, hewgts, nparts + , ubFactor, _metis->getHMetisOptions(), part, &_edgeCut); + } + + UpdateSession::open(); + for (Id2OccurrencesMap::const_iterator omit = toPlaceInstanceOccurrencesMap.begin(); + omit != toPlaceInstanceOccurrencesMap.end(); + omit++) + { + unsigned instanceId = omit->first; + unsigned gcellId = part[instanceId]; + Occurrence instanceOccurrence = omit->second; + Instance* instance = static_cast(instanceOccurrence.getEntity()); + GCell* gcell = _partResultVector[gcellId]->first; + + _partResultVector[gcellId]->second.insert(instanceOccurrence); + + DbU::Unit xPos = gcell->getCenter().getX(); + DbU::Unit yPos = gcell->getCenter().getY(); + Box masterABox = instance->getMasterCell()->getAbutmentBox(); + Transformation instanceTransformation = getTransformation(masterABox + , xPos - masterABox.getHalfWidth() + , yPos - masterABox.getHalfHeight() + , Transformation::Orientation::ID); + instanceOccurrence.getPath().getTransformation().invert().applyOn(instanceTransformation); + instance->setTransformation(instanceTransformation); + instance->setPlacementStatus(Instance::PlacementStatus::PLACED); + } + + _partResultVector.erase( + remove_if(_partResultVector.begin(), _partResultVector.end(), removeEmptyPartResult()) + , _partResultVector.end() + ); + + for (PartResultVector::iterator prvit = _partResultVector.begin(); + prvit != _partResultVector.end(); + prvit++) + { + (*prvit)->first->setAsPlacementLeaf(); + } + + UpdateSession::close(); + + delete[] eind; + delete[] eptr; + delete[] hewgts; + delete[] vwgts; + delete[] part; + + return _edgeCut; +} + +} + +#endif /* HAVE_HMETIS_LIB */ diff --git a/metis/src/metis/Configuration.h b/metis/src/metis/Configuration.h new file mode 100644 index 00000000..48fec4cf --- /dev/null +++ b/metis/src/metis/Configuration.h @@ -0,0 +1,152 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved +// +// =================================================================== +// +// $Id$ +// +// x-----------------------------------------------------------------x +// | | +// | C O R I O L I S | +// | M e t i s - h M e t i s W r a p p e r | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@asim.lip6.fr | +// | =============================================================== | +// | C++ Header : "./Configuration.h" | +// | *************************************************************** | +// | U p d a t e s | +// | | +// x-----------------------------------------------------------------x + + +#ifndef __METIS_CONFIGURATION__ +#define __METIS_CONFIGURATION__ + +#include +#include + +namespace Hurricane { + class Record; + class Cell; +} + + +namespace Metis { + + using Hurricane::Record; + using Hurricane::Cell; + + +// ------------------------------------------------------------------- +// Class : "Metis::Configuration". + + + class Configuration { + public: + typedef boost::function< void(void) > RefreshCb_t; + public: + enum MetisOption { CustomOptions =0 + , HMetisNRuns =1 + , HMetisCType =2 + , HMetisRType =3 + , HMetisVCycle =4 + , HMetisReconst =5 + , HMetisPreAssign =6 + , HMetisRandom =7 + , HMetisDebugLevel =8 + , HMetisOptionsSize=9 + }; + enum HMetisCTypeValues { CTypeHFC =1 // Hybrid First Choice Scheme. + , CTypeFC =2 // First Choice Scheme. + , CTypeGFC =3 // Greedy First Choice Scheme. + , CTypeHyperEdge =4 // Hyper-Edge Scheme. + , CTypeEdge =5 // Edge Scheme. + }; + enum HMetisRTypeValues { RTypeFM =1 // Uncoarsening Fiduccia-Mattheyses. + , RTypeOneWayFM =2 // Uncoarsening One Way Fiduccia-Mattheyses. + , RTypeEarlyExitFM =3 // Uncoarsening Early Exit Fiduccia-Mattheyses. + }; + enum HMetisVCycleValues { VCycleDisable =0 // Do not perform any V-Cycle Reffinment. + , VCycleFinal =1 // Perform V-Cycle on each final bisection step. + , VCycleBestIntermed =2 // Perform V-Cycle on each intermediate solution. + , VCycleAllIntermed =3 // Perform V-Cycle on all intermediate solution. + }; + enum HMetisReconstValues { ReconstRemoveCutHE =0 // Remove cut hyperedges. + , ReconstKeepCutHE =1 // Keep each part of the cuts hyperedges. + }; + enum HMetisDebugValues { DebugDisable =0 // Disable debugging. + , DebugCoarseningStage=1 // Debug coarsening stage. + , DebugInitialPart =2 // Debug initial partition stage. + , DebugRefinement =4 // Debug refinement stage. + , DebugMultRuns =8 // Debug multiple runs stage. + , DebugMoreMultRuns =16 // More debug of the multiple runs stage. + }; + public: + static Configuration* getDefault (); + public: + // Constructor & Destructor. + Configuration (); + ~Configuration (); + Configuration* clone () const; + // Methods. + void print ( Cell* ) const; + inline RefreshCb_t& getRefreshCb (); + inline bool getPartOrKWayHMetis () const; + inline unsigned int getNumberOfInstancesStopCriterion () const; + inline int getGlobalConnectionsWeightRatio () const; + inline int getUbFactor () const; + inline int* getHMetisOptions (); + inline int getHMetisOption ( MetisOption ); + inline void setRefreshCb ( Configuration::RefreshCb_t ); + inline void setPartOrKWayHMetis ( bool usePart ); + inline void setNumberOfInstancesStopCriterion ( unsigned int ); + inline void setGlobalConnectionsWeightRatio ( int ); + inline void setUbFactor ( int ); + inline void setHMetisOption ( MetisOption, int value ); + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + private: + // Attributes. + static Configuration* _default; + RefreshCb_t _refreshCb; + bool _partOrKWayHMetis; // True for Recursive 2-part, false for KWay. + unsigned int _numberOfInstancesStopCriterion; // Minimal number of instances to partition. + int _globalConnectionsWeightRatio; + int _ubFactor; + int _hmetisOptions[HMetisOptionsSize]; + private: + Configuration ( const Configuration& ); + Configuration& operator= ( const Configuration& ); + }; + + +// Inline Methods. + inline Configuration::RefreshCb_t& + Configuration::getRefreshCb () { return _refreshCb; } + inline bool Configuration::getPartOrKWayHMetis () const { return _partOrKWayHMetis; } + inline unsigned int Configuration::getNumberOfInstancesStopCriterion () const { return _numberOfInstancesStopCriterion; } + inline int Configuration::getGlobalConnectionsWeightRatio () const { return _globalConnectionsWeightRatio; } + inline int Configuration::getUbFactor () const { return _ubFactor; } + inline int* Configuration::getHMetisOptions () { return _hmetisOptions; } + inline int Configuration::getHMetisOption ( MetisOption option ) { return (option +// Hugo Clément +// Jean-Paul Chaput +// Christian Masson +// +// The Coriolis Project is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// The Coriolis Project is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with the Coriolis Project; if not, write to the Free Software +// Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// +// License-Tag +// +// Date : 29/01/2004 +// Author : Christophe Alexandre +// +// Authors-Tag + + +#ifndef __METIS_ENGINE_H__ +#define __METIS_ENGINE_H__ + +#include "hurricane/Cell.h" +#include "crlcore/ToolEngine.h" +#include "crlcore/ToolEngine.h" + +#include "metis/Configuration.h" + + +namespace Metis { + + using Hurricane::Record; + using Hurricane::Name; + using Hurricane::Cell; + + class MetisGraph; + + class MetisEngine: public CRL::ToolEngine + { + public: + // Types. + typedef ToolEngine Inherit; + typedef std::vector MetisGraphs; + public: + // Constructor. + static MetisEngine* create ( Cell* ); + static MetisEngine* get ( Cell* ); + // Methods. + static unsigned int computeQuadriPartitions ( Cell* ); + static void doQuadriPart ( Cell* ); + static bool isHMetisCapable (); + static const Name& staticGetName (); + virtual const Name& getName () const; + int getGlobalEdgeCut () const; + inline Configuration* getConfiguration (); + inline Configuration::RefreshCb_t& + getRefreshCb (); + inline bool getPartOrKWayHMetis () const; + inline unsigned int getNumberOfInstancesStopCriterion () const; + inline int getGlobalConnectionsWeightRatio () const; + inline int getUbFactor () const; + inline int* getHMetisOptions (); + inline int getHMetisOption ( Configuration::MetisOption ); + inline void setHMetisOption ( Configuration::MetisOption, int value ); + void run (); + void save ( unsigned step ); + inline void setRefreshCb ( Configuration::RefreshCb_t ); + virtual std::string _getTypeName () const {return "Metis::MetisEngine";}; + virtual Record* _getRecord () const; + + private: + // Attributes. + static const Name _toolName; + Configuration* _configuration; + unsigned _step; + MetisGraphs* _actualGraphs; + MetisGraphs* _newGraphs; + int _globalEdgeCut; + private: + // Internals. + MetisEngine ( Cell* ); + virtual ~MetisEngine (); + virtual void _preDestroy (); + bool _reInit (); + }; + + +// Inline Methods. + inline Configuration* MetisEngine::getConfiguration () { return _configuration; } + inline Configuration::RefreshCb_t& MetisEngine::getRefreshCb () { return _configuration->getRefreshCb(); } + inline bool MetisEngine::getPartOrKWayHMetis () const { return _configuration->getPartOrKWayHMetis(); } + inline unsigned int MetisEngine::getNumberOfInstancesStopCriterion () const { return _configuration->getNumberOfInstancesStopCriterion(); } + inline int MetisEngine::getGlobalConnectionsWeightRatio () const { return _configuration->getGlobalConnectionsWeightRatio(); } + inline int MetisEngine::getUbFactor () const { return _configuration->getUbFactor(); } + inline int* MetisEngine::getHMetisOptions () { return _configuration->getHMetisOptions(); } + inline int MetisEngine::getHMetisOption ( Configuration::MetisOption option ) { return _configuration->getHMetisOption(option); } + inline void MetisEngine::setRefreshCb ( Configuration::RefreshCb_t cb ) { _configuration->setRefreshCb(cb); } + inline void MetisEngine::setHMetisOption ( Configuration::MetisOption option, int value ) { _configuration->setHMetisOption(option,value); } + + +} // End of Metis namespace. + + +#endif // __METIS_ENGINE_H__ diff --git a/metis/src/metis/MetisGraph.h b/metis/src/metis/MetisGraph.h new file mode 100644 index 00000000..420212d9 --- /dev/null +++ b/metis/src/metis/MetisGraph.h @@ -0,0 +1,82 @@ + +// This file is part of the Coriolis Project. +// Copyright (C) Laboratoire LIP6 - Departement ASIM +// Universite Pierre et Marie Curie +// +// Main contributors : +// Christophe Alexandre +// Hugo Clément +// Jean-Paul Chaput +// Christian Masson +// +// The Coriolis Project is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// The Coriolis Project is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with the Coriolis Project; if not, write to the Free Software +// Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// +// License-Tag +// +// Date : 29/01/2004 +// Author : Christophe Alexandre +// +// Authors-Tag + + +#ifndef __METISGRAPH_H +#define __METISGRAPH_H + +#ifdef HAVE_HMETIS_LIB + +#include "metis/MetisEngine.h" + +namespace Metis { + + class MetisGraph + { + friend class MetisEngine; + public: + typedef set OccurrenceSet; + typedef pair PartResult; + typedef vector PartResultVector; + public: + class TooLowNVTXSException + { + public: + int _nvtxs; + public: + TooLowNVTXSException(int nvtxs): _nvtxs(nvtxs) {} + }; + private: + MetisEngine* _metis; + Cell* _cell; + GCell* _gcell; // Placement zone + OccurrenceSet _toPlaceInstanceOccurrencesSet; + OccurrenceSet _rootNetOccurrencesSet; + PartResultVector _partResultVector; + int _edgeCut; // EdgeCut from last part + public: + MetisGraph ( MetisEngine*, GCell* box); + MetisGraph ( MetisEngine* metis + , MetisGraph* previous + , GCell* gcell + , OccurrenceSet& toplaceinstanceoccurrences); + ~MetisGraph (); + int part ( linefill& ); + }; + +} // End of Metis namespace. + + +#endif /* HAVE_HMETIS_LIB */ + +#endif /* __METISGRAPH_H */ diff --git a/metis/src/metis/hmetis.h b/metis/src/metis/hmetis.h new file mode 100644 index 00000000..85064c0a --- /dev/null +++ b/metis/src/metis/hmetis.h @@ -0,0 +1,21 @@ + +#ifndef __HMETIS_H__ +#define __HMETIS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void HMETIS_PartRecursive( int nvtxs, int nhedges, int *vwgts, int *eptr + , int *eind, int *hewgts, int nparts, int ubfactor + , int *options, int *part, int *edgecut ); + +void HMETIS_PartKway( int nvtxs, int nhedges, int *vwgts + , int *eptr, int *eind, int *hewgts, int nparts + , int ubfactor, int *options, int *part, int *edgecut); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // __HMETIS_H__