// 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 #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 map OccurrencesLUT; OccurrencesLUT occurrencesLUT; for_each_occurrence(occurrence, _cell->getLeafInstanceOccurrences()) { Instance* instance = static_cast(occurrence.getEntity()); if (!instance->isFixed()) { OccurrencesLUT::iterator duplicated = occurrencesLUT.find(instance); if (duplicated != occurrencesLUT.end()) { throw Error("MetisEngine limitation: Each unplaced instance must have one occurrence only.\n" "Model %s is intanciated as:\n. %s\n. %s\n (at least)." ,getString(instance->getMasterCell()->getName()).c_str() ,occurrence.getCompactString().c_str() ,(*duplicated).second.getCompactString().c_str() ); } occurrencesLUT.insert(make_pair(instance,occurrence)); _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 */