/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: WorkerThread.java * Written by: Andreas Uebelhoer, Alexander Bieles, Emre Selegin (Team 6) * * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) 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 3 of the License, or * (at your option) any later version. * * Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.routing.experimentalLeeMoore1; import com.sun.electric.tool.routing.RoutingFrame.*; import com.sun.electric.tool.routing.experimentalLeeMoore1.LeeMoore.Route; import com.sun.electric.tool.routing.experimentalLeeMoore1.LeeMoore.RoutingArray; import com.sun.electric.tool.routing.experimentalLeeMoore1.LeeMoore.Tupel; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BrokenBarrierException; /** * This is one thread doing routing */ public class WorkerThread implements Runnable { // for all threads the same variables public static final boolean X_DIRECTION = true; // const public static final boolean Y_DIRECTION = false; // const //protected static final Object signal = new Object(); // will be used to wait // for // segmentCounter-changes private static long DEADLINE; private static int MAXLAYER; // the number of usable layers protected static boolean[][][] regionBoundaries; private static RoutingArray ra; protected static int size_x; protected static int size_y; private static FindVirtualEndInterface findVirtualEndAlgorithm; private static int NUMPARTITIONS; // private static boolean OUTPUT = false; // thread specific variables private int id; private boolean DEBUG = false; List<WiringJob> wj=new ArrayList<WiringJob>(); /** * * @param workerObjects the WorkerObjects as an array * @param countLayers on how much layers will be routed * @param ra the RoutingArray * @param segmentsToRoute the segments to route, got from Electric * * This method has to be called before any other method! */ public static void init(WorkerThread[] workerObjects, int countLayers, RoutingArray ra, List<RoutingSegment> segmentsToRoute, int maxRunTime, boolean output) { // WorkerThread.OUTPUT = output; WorkerThread.DEADLINE = System.currentTimeMillis()+maxRunTime; WorkerThread.MAXLAYER = countLayers; WorkerThread.ra = ra; WorkerThread.NUMPARTITIONS = yana.numPartitions; WorkerThread.size_x = ra.size_x; WorkerThread.size_y = ra.size_y; // we have to initialize the workpool WorkPool.init(segmentsToRoute, NUMPARTITIONS, size_x, size_y, output); WorkPool.printPartitionBorders(); // initialize the boundary data structure regionBoundaries = new boolean[size_x][size_y][MAXLAYER]; for (int i = 0; i < size_x; i++) { for (int j = 0; j < size_y; j++) { for (int k = 0; k < MAXLAYER; k++) { regionBoundaries[i][j][k] = true; } } } // set all blocked points also as blocked in the boundary structure ArrayList<Tupel> blocked = ra.getBlocked(); for (Tupel t : blocked) { for (int i = 0; i < MAXLAYER; i++) { regionBoundaries[t.getX_InsideRoutingArray()][t.getY_InsideRoutingArray()][i] = false; } } findVirtualEndAlgorithm = new FindVirtualEnd_ProjectedAndRandomized( X_DIRECTION, Y_DIRECTION, MAXLAYER, output); // System.out.print("Init End."); } /*******************************************************************************************************************************************/ /** * * @param id must be a unique number. the numbers 0 to n-1 must be given, when n threads shall work */ public WorkerThread(int id) { this.id = id; } /** * The Worker will do the three following things: * 1.) Change the RoutingSegments to RoutingParts which have more information inside it for routing. * 2.) Get a RoutingPart out of the WorkPool. If it is completely belonging to a WorkPartition (start and end are located inside of it) assign it, * else split the RoutingPart. * 3.) Grab one WorkPartition and route the routingPart inside. If a route was found, it will be transformed into the electric data structures */ public void run() { if (DEBUG) System.out.println("Thread-" + id + " running..."); changeRoutingSegmentToRoutingPart(); if (DEBUG) System.out.println("Thread-" + id + " allocating work to partitions..."); allocateRoutingPartsToWorkPartitions(); try { yana.barrierRouting.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.gc(); RoutingPart rp; Tupel start; Tupel end; Route r; // Now get a WorkPartition and do routing & wiring WorkPartition wp = WorkPool.getWorkFromPartition(); while (wp != null) { if (DEBUG) System.out.println("Thread-" + id + ": routing partition " + wp.id + " containing " + wp.routingParts.size() + " routingparts"); rp = wp.routingParts.poll(); while (rp != null) { // XXX [fschmidt] timeout handling is here if(System.currentTimeMillis()>DEADLINE){ System.out.println("Timeout..."); return; } start = rp.start; end = rp.end; if (DEBUG) { String sys_out = "THREAD " + id + ": "; sys_out += "Routing netID " + rp.rs.getNetID() + ": "; sys_out += "[" + rp.rs.getStartEnd().getLocation().getX() + "," + rp.rs.getStartEnd().getLocation().getY() + "@" + rp.rs.getStartLayers().get(0).getName() + "]"; sys_out += "->[" + rp.rs.getFinishEnd().getLocation().getX() + "," + rp.rs.getFinishEnd().getLocation().getY() + "@" + rp.rs.getFinishLayers().get(0).getName() + "]"; sys_out += "; part " + start + "->" + end; System.out.println(sys_out); System.out.println("Borders: " + WorkPool.getLowIndexIn_X(wp.id) + "," + WorkPool.getHighIndexIn_X(wp.id) + "; " + WorkPool.getLowIndexIn_Y(wp.id) + "," + WorkPool.getHighIndexIn_Y(wp.id)); } if (!start.isEqual(end)) { r = ra.route(start, end, wp.tb, rp.rs.getNetID()); // route is found if (r != null) { // if (DEBUG) { // System.out.println("Thread-" + id + " wiring"); // } // Wiring.connect(rp, r.getEdgePoints(),r.isReversed()); wj.add(new WiringJob(rp, r.getEdgePoints(), r.isReversed())); }else{ //no route could be found yana.markSegmentAsUnroutable(rp.rs); } } yana.updateProgress(); rp = wp.routingParts.poll(); } wp = WorkPool.getWorkFromPartition(); } if (DEBUG) System.out.println("Thread-" + id + " finished routing"); //wait for other threads to finish to be able to start wiring try { yana.barrierWiring.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } //wiring for (WiringJob wjob : wj) { if(yana.isRouteable(wjob.rp.rs)){ //RoutingSegment was not marked as partly unrouted if(wjob.isConnectionPoints){ Wiring.connect(wjob.rp.rs,wjob.rp1,wjob.rp2); }else{ Wiring.connect(wjob.rp, wjob.route, wjob.isReversed); } } } if (DEBUG) System.out.println("Thread-" + id + " finished wiring"); } /*******************************************************************************************************************************************/ /** * Create RoutingParts out of RoutingSegments. They contain more information and allow splitting. */ private void changeRoutingSegmentToRoutingPart() { RoutingSegment rs = WorkPool.getRoutingSegment(); while (rs != null) { WorkPool.addPartToGlobalRoutingQueue(new RoutingPart(rs)); rs = WorkPool.getRoutingSegment(); } } /** * Allocate RoutingParts to WorkPartitions or split RoutingParts if they are located on multiple WorkPartitions */ private void allocateRoutingPartsToWorkPartitions() { RoutingPart rp; Tupel start; Tupel end; RoutingPart prefixRoutingPart; RoutingPart suffixRoutingPart; int indexStart; int indexEnd; RoutePoint[] borderPoints; while (WorkPool.getSegmentCounter() != 0) { while (WorkPool.getGlobalRoutingQueueSize() != 0) { rp = WorkPool.getPartFromGlobalRoutingQueue(); if (rp == null) { Thread.yield(); break; //make yield and break to return, because here we have just one segment left and just one thread can allocate the partitions from now } start = rp.start; end = rp.end; indexEnd = WorkPool.getResponsiblePartitionID_ForPoint(end.getX_InsideRoutingArray(), end.getY_InsideRoutingArray()); indexStart = WorkPool.getResponsiblePartitionID_ForPoint(start.getX_InsideRoutingArray(), start.getY_InsideRoutingArray()); if (indexEnd == indexStart) { // both ends are in same partition -> add to work queue // decrease segmentCounter WorkPool.addWorkToPartition(rp, indexStart); WorkPool.decreaseSegmentCounter(); } else { // if points are not in same partition => find // region-connecting-point, append prefix RoutingPart to responsible partition and suffix RoutingPart to // RoutingPart queue; do NOT decrease segmentCounter ConnectionPoints connectionPoints = findVirtualEndAlgorithm.findVirtualEnd(rp, indexStart); // making the find-method synchronized, so we can // delete the while loop => better performance? while (connectionPoints.areValid() && blockConnectingPoint(connectionPoints.getInnerPoint(), connectionPoints.getOuterPoint()) == false) { connectionPoints = findVirtualEndAlgorithm.findVirtualEnd(rp, indexStart); } if (!connectionPoints.areValid()) { // a routing segment will not be routed, because a part // is missing if (DEBUG) System.out.println("Part of a RoutingSegment could not be routed"); yana.markSegmentAsUnroutable(rp.rs); WorkPool.decreaseSegmentCounter(); } else { // now we create a wire between the connectionPoints // borderPoints=Wiring.connect(rp.rs, connectionPoints.getInnerPoint(), // connectionPoints.getOuterPoint()); borderPoints=Wiring.getRoutePoints(connectionPoints.getInnerPoint(), connectionPoints.getOuterPoint()); wj.add(new WiringJob(rp,borderPoints[0],borderPoints[1],false)); // mark both tupels as blocked ra.setBlocked(connectionPoints.getTupels()); // split the RoutingSegment into two RoutingSegments prefixRoutingPart = rp.getPrefixPart(connectionPoints.getInnerPoint(),borderPoints[0]); suffixRoutingPart = rp.getSuffixPart(connectionPoints.getOuterPoint(),borderPoints[1]); WorkPool.addPartToGlobalRoutingQueue(suffixRoutingPart); WorkPool.addWorkToPartition(prefixRoutingPart, indexStart); WorkPool.increaseAdditionalSegments(); } } } } } private synchronized boolean blockConnectingPoint(Tupel pointA, Tupel pointB) { int PAX = pointA.getX_InsideRoutingArray(); int PBX = pointB.getX_InsideRoutingArray(); int PAY = pointA.getY_InsideRoutingArray(); int PBY = pointB.getY_InsideRoutingArray(); if (PAX == -1 || PAY == -1 || PBX == -1 || PBY == -1) { System.out.println(" CRITICAL ERROR: we've got company! (a crash is approaching)"); } if (Math.abs(PAX - PBX) == 1) { // check if points are neighbored in // x-direction if ((PAY - PBY) != 0 || (pointA.getLayer() - pointB.getLayer()) != 0) { return false;// because they are not neighbored } // neighbored points in x direction int minX = (PAX < PBX) ? PAX : PBX; if (regionBoundaries[minX][PAY][pointA.getLayer()] == true) {// free // point regionBoundaries[minX][PAY][pointA.getLayer()] = false; regionBoundaries[minX + 1][PAY][pointA.getLayer()] = false; return true; } else { return false; } } else if (Math.abs(PAY - PBY) == 1) {// check if points are neighbored // in y-direction if ((PAX - PBX) != 0 || (pointA.getLayer() - pointB.getLayer()) != 0) { return false;// because they are not neighbored } // neighbored in y direction int minY = (PAY < PBY) ? PAY : PBY; if (regionBoundaries[PAX][minY][pointA.getLayer()] == true) {// free // point regionBoundaries[PAX][minY][pointA.getLayer()] = false; regionBoundaries[PAX][minY + 1][pointA.getLayer()] = false; return true; } else { return false; } } return false; // because they are not neighbored } protected static Tupel getMiddlePoint(Tupel p) { int x = p.getX_InsideRoutingArray(); int y = p.getY_InsideRoutingArray(); int workerID = WorkPool.getResponsiblePartitionID_ForPoint(x, y); int lowX = WorkPool.getLowIndexIn_X(workerID); int hiX = WorkPool.getHighIndexIn_X(workerID); int lowY = WorkPool.getLowIndexIn_Y(workerID); int hiY = WorkPool.getHighIndexIn_Y(workerID); return new Tupel((int) ((hiX - lowX) / 2) + lowX, (int) ((hiY - lowY) / 2) + lowY, p.getLayer(), false); } class WiringJob{ RoutingPart rp; List<Tupel> route; RoutePoint rp1,rp2; boolean isConnectionPoints; boolean isReversed; public WiringJob(RoutingPart rp, List<Tupel> route, boolean isReversed) { super(); this.rp = rp; this.route = route; this.isConnectionPoints = false; this.isReversed = isReversed; this.rp1=null; this.rp2=null; } public WiringJob(RoutingPart rp, RoutePoint rp1, RoutePoint rp2, boolean isReversed) { super(); this.rp = rp; this.route = null; this.rp1 = rp1; this.rp2 = rp2; this.isConnectionPoints = true; this.isReversed = isReversed; } } }