coriolis/metis/src/MetisEngine.cpp

341 lines
9.5 KiB
C++
Raw Normal View History

// This file is part of the Coriolis Project.
// Copyright (C) Laboratoire LIP6 - Departement ASIM
// Universite Pierre et Marie Curie
//
// Main contributors :
// Christophe Alexandre <Christophe.Alexandre@lip6.fr>
// Hugo Cl<43>ment <Hugo.Clement@lip6.fr>
// Jean-Paul Chaput <Jean-Paul.Chaput@lip6.fr>
// Christian Masson <Christian.Masson@lip6.fr>
//
// 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 <Christophe.Alexandre@lip6.fr>
//
// Authors-Tag
#include <cmath>
using namespace std;
#include "vlsisapd/configuration/Configuration.h"
#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(new Configuration())
, _step (0)
#ifdef HAVE_HMETIS_LIB
, _actualGraphs ()
, _newGraphs ()
#endif
, _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
ExtensionCap support and source/target terminal flags in Katabatic & Kite. Placement management: * Change: In <metis>, always disable the hMetis support regardless of it being detected or not as the placer is still unable manage the final bin contents. Routing gauge management: * Bug: In CRL Core, <vsclib/alliance.conf>, set the correct pitches and size for the routing layers and the cell gauge. * Change: In Katabatic & Kite, extract the correct extension cap for each routing layer from the layers characteristics (cache then in Katabatic::Configuration). * Change: In Katabatic, <AutoSegment>, create segment with the wire width defined in the gauge. For AutoSegment created on already existing Segment from the global routing, adjust the width. * Change: In Katabatic, <AutoSegment>, more accurate information about how a segment is connected to terminal via source and/or target. The flag SegStrongTerminal is splitted into SegSourceTerminal and SegSourceTarget (but still used as a mask). So now we can know by which end an AutoSegment is connected to a terminal. * Change: In Katabatic, ::doRp_Access(), create constraint freeing segments not only when HSmall but also when VSmall (more critical for <vsclib>). Otherwise we may see AutoSegments with incompatible source/target constraints. * Change: In Kite, BuildPowerRails, do not create blockage on PinOnly layers *but* still create power rails planes. This is a temporary workaround for <vsclib> where the METAL1 blockages overlaps the terminals (it was fine for Nero, but they shouldn't for Kite). * Change: In Kite, <RoutingEvent>, if a TrackSegment is overconstrained, directly bybass it's slackening state to DataNegociate::Slacken. Also rename the flag "_canHandleConstraints" to "_overConstrained", seems clearer to me. Miscellaneous: * Change: In CRL Core, <Utilities>, add a "pass-though" capability on the mstream to temporarily make them print everything.
2014-05-25 08:00:35 -05:00
return false;
#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 ) {
if ( cmess2.enabled() ) cerr << "\n";
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 << "\n";
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<MetisEngine*> ( 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, int& xsplits, int& ysplits )
{
size_t gates = getInstancesCount ( cell );
Box ab = cell->getAbutmentBox();
double aspectRatio = (double)(ab.getWidth()) / (double)(ab.getHeight());
if ( aspectRatio >= 1.0 ) {
xsplits = ((int)(trunc ( aspectRatio +0.5 ) )) * 2;
ysplits = 2;
} else {
xsplits = 2;
ysplits = ((int)(trunc ( (1.0/aspectRatio)+0.5 ) )) * 2;
}
size_t partitionSizeStop = Cfg::getParamInt("metis.numberOfInstancesStopCriterion",45)->asInt();
if ( gates / (xsplits*ysplits) < partitionSizeStop )
throw Error("Design &lt;%s&gt; is too small to be quadri-partionned, only %d gates."
,getString(cell->getName()).c_str(),gates);
double quadPartitions = log((double)gates / (double)(partitionSizeStop*xsplits*ysplits) ) / log(4.0) + 1.0;
return (unsigned int)(quadPartitions);
}
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());
NimbusEngine* nimbus = NimbusEngine::get ( cell );
if ( nimbus == NULL )
nimbus = NimbusEngine::create ( cell );
MetisEngine* metis = MetisEngine::get ( cell );
if ( metis == NULL )
metis = MetisEngine ::create ( cell );
int xsplits;
int ysplits;
size_t partitions = computeQuadriPartitions ( cell, xsplits, ysplits );
for ( size_t part=0 ; part<partitions ; ++part ) {
nimbus->progress ( xsplits, ysplits );
metis-> run ();
xsplits = 2;
ysplits = 2;
}
}
} // End of Metis namespace.