Location.java

/**
 * Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
 * All Rights Reserved.
 *
 * NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
 * OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
 * MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 *
 * This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 * SPDX-License-Identifier: EPL-2.0
 *
 * Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
 *
 * This program includes and/or can make use of certain third party source code, object code, documentation and other
 * files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
 * configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
 * conditions contained in any such Third Party Software or separate license file distributed with such Third Party
 * Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
 * aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
 * censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
 */
package EAnalysis.BinPacking;

import java.util.Iterator;
import java.util.TreeSet;

public class Location implements CapacityProvider {
	/**
	 * returns the simple sum of the hosting dimensions: space & power
	 *
	 * This sum can be later weighted.
	 */
	public double getAvailableHostingCapacity() {
		return availableSpace + availablePower;
	}

	@Override
	public double getAvailableCapacity() {
		return totalAvailableCapacity;
	}

	/**
	 * The potential classes of guest this site can support ordered in
	 * decreasing order of capacity
	 */
	TreeSet potentialGuests = new TreeSet(new DecreasingCapacityComparator());

	TreeSet increasingPotentialGuests = new TreeSet(new CapacityComparator());

	TreeSet guests = new TreeSet(new DecreasingCapacityComparator());

	double totalAvailableCapacity = 0.0;

	@Override
	public Object clone() {
		Location l = null;
		try {
			l = getClass().newInstance();
			l.potentialGuests = (TreeSet) potentialGuests.clone();
			l.increasingPotentialGuests = (TreeSet) increasingPotentialGuests.clone();
			l.guests = (TreeSet) guests.clone();
			l.maximumPower = maximumPower;
			l.availablePower = availablePower;
			l.basePower = basePower;
			l.maximumSpace = maximumSpace;
			l.availableSpace = availableSpace;
			l.baseSpace = baseSpace;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return l;
	}

	public SiteGuest getLargestCurrentGuest() {
		for (Iterator iter = guests.iterator(); iter.hasNext();) {
			SiteGuest guest = (SiteGuest) iter.next();
			if (guest.getPowerRequirement() <= availablePower && guest.getSpaceRequirement() <= availableSpace) {
				return guest;
			}
		}

		/* none fit */
		return null;
	}

	public SiteGuest getLargestCurrentGuest(TreeSet compatibleLinks) {
		for (Iterator iter = guests.iterator(); iter.hasNext();) {
			SiteGuest guest = (SiteGuest) iter.next();
			for (Iterator iter1 = compatibleLinks.iterator(); iter1.hasNext();) {
				SiteGuest compatibleLink = (SiteGuest) iter1.next();
				if ((guest.getClass().isAssignableFrom(compatibleLink.getClass())
						|| compatibleLink.getClass().isAssignableFrom(guest.getClass()))
						&& guest.getPowerRequirement() <= availablePower
						&& guest.getSpaceRequirement() <= availableSpace) {
					return guest;
				}
			}
		}

		/* none fit */
		return null;
	}

	public SiteGuest getLargestPotentialProcessor() {
		for (Iterator iter = potentialGuests.iterator(); iter.hasNext();) {
			SiteGuest guest = (SiteGuest) iter.next();
			if (!(guest instanceof Processor)) {
				continue;
			}

			if (guest.getPowerRequirement() <= availablePower && guest.getSpaceRequirement() <= availableSpace) {
				return guest;
			}
		}

		/* none fit */
		return null;
	}

	public HardwareNode replaceWithBestFit(HardwareNode node) {
		double cyclesPerSecondNeeded = node.getCyclesPerSecond() - node.getAvailableCapacity();
		HardwareNode replacement = null;
		for (Iterator iter = increasingPotentialGuests.iterator(); iter.hasNext();) {
			replacement = (HardwareNode) iter.next();
			if (replacement.canReplace(node)) {
				/* if processor check links */
				if (node instanceof Processor) {
					Processor proc = (Processor) node;
					boolean stillCompatible = true;
					for (Iterator nets = proc.getNetInterfaces().iterator(); stillCompatible && nets.hasNext();) {
						NetInterface net = (NetInterface) nets.next();
						Processor replace = (Processor) replacement;
						for (Iterator rNets = replace.classNetInterfaces.iterator(); stillCompatible
								&& rNets.hasNext();) {
							NetInterface rNet = (NetInterface) rNets.next();
							if (!rNet.link.canReplace(net.link)) {
								stillCompatible = false;
							}
						}
					}
					if (!stillCompatible) {
						replacement = null;
					} else {
						// this is it
						break;
					}
				} else {
					// DebugMonitor.println(DebugMonitor.channels[4], "TENTATIVE
					// REPLACEMENT LINK("+replacement.toString()+
					// ") BW("+Double.toString(replacement.cyclesPerSecond)+"
					// bits/s)");
					// if a link check compatibility with processors
					Link link = (Link) replacement;
					Link original = (Link) node;
					boolean compatible = true;
					for (Iterator procs = original.getConnectedNodes().iterator(); compatible && procs.hasNext();) {
						Processor p = (Processor) procs.next();
						if (!p.couldReplaceLink(link, original)) {
							compatible = false;
							// DebugMonitor.println(DebugMonitor.channels[4],
							// "\t NOT COMPATIBLE WITH PROC("+p.toString()+")");
							// String trace = (String)
							// Processor.creationTraces.get(p);
							// if (trace != null)
							// DebugMonitor.println(DebugMonitor.channels[4],
							// "Creation trace:\n "+trace);
							break;
						}
					}
					if (!compatible) {
						replacement = null;
					} else {
						break;
					}
				}
			} else {
				replacement = null;
			}
		}
		if (replacement != null) {
			if (replacement instanceof Processor) {
				Processor rep = (Processor) replacement;
				try {
					replacement = replacement.getClass().newInstance();
					HardwareNode.cloneTo(rep, replacement);
				} catch (Exception e) {
					e.printStackTrace();
				}

				for (Iterator iter = node.getTaskSet().iterator(); iter.hasNext();) {
					if (!replacement.addIfFeasible((ProcessingLoad) iter.next())) {
						// System.out.println("replacement.addIfFeasible FAILED
						// !!!!");
					}
				}

				Processor proc = (Processor) node;
				Processor rProc = (Processor) replacement;
				for (Iterator iter = proc.getNetInterfaces().iterator(); iter.hasNext();) {
					NetInterface net = (NetInterface) iter.next();
					rProc.attachToLink(net.link);
					net.link.remove(proc);
					net.link.add(rProc);
				}
			} else // Link
			{
				Link rep = (Link) replacement;
				try {
					replacement = replacement.getClass().newInstance();
					HardwareNode.cloneTo(rep, replacement);
				} catch (Exception e) {
					e.printStackTrace();
				}

				for (Iterator iter = node.getTaskSet().iterator(); iter.hasNext();) {
					if (!replacement.addIfFeasible((ProcessingLoad) iter.next())) {
						// System.out.println("replacement.addIfFeasible FAILED
						// !!!!");
					}
				}

				Link link = (Link) replacement;
				Link original = (Link) node;
				link.addAllNodes(original.getConnectedNodes());
				for (Iterator procs = original.getConnectedNodes().iterator(); procs.hasNext();) {
					Processor p = (Processor) procs.next();
					p.replaceLink(original, link);
				}
			}
			return replacement;
		}
		return null;
	}

	public SiteGuest getLargestPotentialGuest() {
		for (Iterator iter = potentialGuests.iterator(); iter.hasNext();) {
			SiteGuest guest = (SiteGuest) iter.next();
			if (guest.getPowerRequirement() <= availablePower && guest.getSpaceRequirement() <= availableSpace) {
				return guest;
			}
		}

		/* none fit */
		return null;
	}

	public boolean canFitGuest(HardwareNode node) {
		boolean compatible = false;
		Class nodeClass = node.getClass();
		for (Iterator iter = potentialGuests.iterator(); iter.hasNext();) {

			SiteGuest potGuest = (SiteGuest) iter.next();
			if (potGuest.getClass().isAssignableFrom(nodeClass) || nodeClass.isAssignableFrom(potGuest.getClass())) {
				compatible = true;
				break;
			}
		}
		SiteGuest guest = node;
		// System.out.println("compatible("+compatible+
		// "), enoughPower("+(guest.getPowerRequirement() <= availablePower)+
		// "), enoughSpace("+(guest.getSpaceRequirement() <=
		// availableSpace)+")");

		return (guest.getPowerRequirement() <= availablePower && guest.getSpaceRequirement() <= availableSpace
				&& compatible);
	}

	public boolean addGuest(HardwareNode node) {
		SiteGuest guest = node;
		double guestPowerReq = guest.getPowerRequirement();
		double guestSpaceReq = guest.getSpaceRequirement();
		if ((guestPowerReq <= availablePower) && (guestSpaceReq <= availableSpace)) {
			guests.add(node);
			totalAvailableCapacity += node.getAvailableCapacity();
			availablePower -= guest.getPowerRequirement();
			availableSpace -= guest.getSpaceRequirement();
			guest.setHost(this);
			return true;
		}
		return false;
	}

	public void removeGuest(HardwareNode node) {
		guests.remove(node);
		totalAvailableCapacity -= node.getAvailableCapacity();
		SiteGuest guest = node;
		availablePower += guest.getPowerRequirement();
		availableSpace += guest.getSpaceRequirement();
		((SiteGuest) node).setHost(null);
	}

	/**
	 * power initially configure to be able to supply -- it can grow to
	 * maximumPower in watts.
	 */
	double basePower;

	/**
	 * unused power in watts
	 */
	double availablePower;

	/**
	 * Cost in dollars
	 */
	double basePowerCost;

	/**
	 * Cost of the additionl watt
	 */
	double powerCostFactor;

	/**
	 * Maximum power in watts
	 */
	double maximumPower;

	/**
	 * The space initially configured -- it can grow to maximumSpace in square
	 * centimeters
	 */
	double baseSpace;

	/**
	 * currently available space
	 */
	double availableSpace;

	/**
	 * in dollars
	 */
	double baseSpaceCost;

	/**
	 * cost of square centimeter additional to base space
	 */
	double spaceCostFactor;

	/**
	 * maximum possible space this site can be enlarge to
	 */
	double maximumSpace;

	public Location() {
	}

	public Location(double maxPower, double maxSpace, TreeSet supportedGuests) {
		maximumPower = maxPower;
		availablePower = maxPower;
		basePower = maxPower;
		maximumSpace = maxSpace;
		availableSpace = maxSpace;
		baseSpace = maxSpace;
		for (Iterator iter = supportedGuests.iterator(); iter.hasNext();) {
			SiteGuest o = (SiteGuest) iter.next();

			potentialGuests.add(o);
			increasingPotentialGuests.add(o);
		}
	}

	public Location(double maxPower, double maxSpace, SiteGuest[] supportedGuests) {
		maximumPower = maxPower;
		availablePower = maxPower;
		basePower = maxPower;
		maximumSpace = maxSpace;
		availableSpace = maxSpace;
		baseSpace = maxSpace;
		for (int i = 0; i < supportedGuests.length; i++) {
			potentialGuests.add(supportedGuests[i]);
			increasingPotentialGuests.add(supportedGuests[i]);
		}
	}
}