org.osate.analysis.resource.management.actions.Binpack.java Source code

Java tutorial

Introduction

Here is the source code for org.osate.analysis.resource.management.actions.Binpack.java

Source

/*
*
* <copyright>
* Copyright  2004 by Carnegie Mellon University, all rights reserved.
*
* Use of the Open Source AADL Tool Environment (OSATE) is subject to the terms of the license set forth
* at http://www.eclipse.org/legal/cpl-v10.html.
*
* NO WARRANTY
*
* ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER PROPERTY OR RIGHTS GRANTED OR PROVIDED BY
* CARNEGIE MELLON UNIVERSITY PURSUANT TO THIS LICENSE (HEREINAFTER THE DELIVERABLES) ARE ON AN AS-IS BASIS.
* CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING,
* BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, INFORMATIONAL CONTENT,
* NONINFRINGEMENT, OR ERROR-FREE OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, SPECIAL OR
* CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE,
* REGARDLESS OF WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. LICENSEE AGREES THAT IT WILL NOT
* MAKE ANY WARRANTY ON BEHALF OF CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON CONCERNING THE
* APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE DELIVERABLES UNDER THIS LICENSE.
*
* Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie Mellon University, its trustees, officers,
* employees, and agents from all claims or demands made against them (and any related losses, expenses, or
* attorneys fees) arising out of, or relating to Licensees and/or its sub licensees negligent use or willful
* misuse of or negligent conduct or willful misconduct regarding the Software, facilities, or other rights or
* assistance granted by Carnegie Mellon University under this License, including, but not limited to, any claims of
* product liability, personal injury, death, damage to property, or violation of any laws or regulations.
*
* Carnegie Mellon University Software Engineering Institute authored documents are sponsored by the U.S. Department
* of Defense under Contract F19628-00-C-0003. Carnegie Mellon University retains copyrights in all material produced
* under this contract. The U.S. Government retains a non-exclusive, royalty-free license to publish or reproduce these
* documents, or allow others to do so, for U.S. Government purposes only pursuant to the copyright license
* under the contract clause at 252.227.7013.
*
* </copyright>
*
*
* %W%
* @version %I% %H%
*/
package org.osate.analysis.resource.management.actions;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.widgets.Display;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.ClassifierValue;
import org.osate.aadl2.ComponentCategory;
import org.osate.aadl2.ComponentClassifier;
import org.osate.aadl2.DataClassifier;
import org.osate.aadl2.Element;
import org.osate.aadl2.Feature;
import org.osate.aadl2.ListValue;
import org.osate.aadl2.Mode;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.ProcessorClassifier;
import org.osate.aadl2.PropertyExpression;
import org.osate.aadl2.RecordValue;
import org.osate.aadl2.SystemClassifier;
import org.osate.aadl2.instance.ComponentInstance;
import org.osate.aadl2.instance.ConnectionInstance;
import org.osate.aadl2.instance.ConnectionInstanceEnd;
import org.osate.aadl2.instance.ConnectionKind;
import org.osate.aadl2.instance.FeatureInstance;
import org.osate.aadl2.instance.InstanceObject;
import org.osate.aadl2.instance.InstanceReferenceValue;
import org.osate.aadl2.instance.ModeInstance;
import org.osate.aadl2.instance.SystemInstance;
import org.osate.aadl2.instance.SystemOperationMode;
import org.osate.aadl2.instance.util.InstanceUtil;
import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporterManager;
import org.osate.aadl2.modelsupport.modeltraversal.ForAllElement;
import org.osate.aadl2.properties.InvalidModelException;
import org.osate.aadl2.properties.PropertyNotPresentException;
import org.osate.aadl2.util.OsateDebug;
import org.osate.analysis.resource.management.ResourcemanagementPlugin;
import org.osate.ui.actions.AbstractInstanceOrDeclarativeModelReadOnlyAction;
import org.osate.xtext.aadl2.properties.util.GetProperties;
import org.osate.xtext.aadl2.properties.util.InstanceModelUtil;
import org.osate.xtext.aadl2.properties.util.PropertyUtils;
import org.osgi.framework.Bundle;

import EAnalysis.BinPacking.AssignmentResult;
import EAnalysis.BinPacking.BFCPBinPacker;
import EAnalysis.BinPacking.BandwidthComparator;
import EAnalysis.BinPacking.CapacityComparator;
import EAnalysis.BinPacking.CompositeSoftNode;
import EAnalysis.BinPacking.DFBPBinPacker;
import EAnalysis.BinPacking.DFCPBinPacker;
import EAnalysis.BinPacking.Disjoint;
import EAnalysis.BinPacking.Expansor;
import EAnalysis.BinPacking.HardwareNode;
import EAnalysis.BinPacking.LowLevelBinPacker;
import EAnalysis.BinPacking.Message;
import EAnalysis.BinPacking.NFCHoBinPacker;
import EAnalysis.BinPacking.NoExpansionExpansor;
import EAnalysis.BinPacking.OutDegreeAssignmentProblem;
import EAnalysis.BinPacking.OutDegreeComparator;
import EAnalysis.BinPacking.SetConstraint;
import EAnalysis.BinPacking.Site;
import EAnalysis.BinPacking.SiteArchitecture;
import EAnalysis.BinPacking.SiteGuest;
import EAnalysis.BinPacking.SoftwareNode;

/**
 * Action performs a binpacking on all the threads in a given system.  Tries
 * to map them to the processors based on their allowed processor bindings
 * and not_collocated property values.
 * 
 * <p>This used to extend AaxlModifyAction, but (1) that class seems to be
 * broken right now, and (2) we don't want to automatically save the resource
 * because we are going to change it using an command via the core editor.
 */
public class Binpack extends AbstractInstanceOrDeclarativeModelReadOnlyAction {
    private static final int IMMEDIATE_PARTITION = 0;
    private static final int DEFER_EXEC_TIME = 1;
    private static final int DEFER_BANDWIDTH = 2;

    private int partitionChoice;

    protected void initPropertyReferences() {
    }

    protected Bundle getBundle() {
        return ResourcemanagementPlugin.getDefault().getBundle();
    }

    protected String getMarkerType() {
        return "org.osate.analysis.resource.management.BinpackObjectMarker";
    }

    protected String getActionName() {
        return "Bind threads to processors";
    }

    // Don't allow analysis in all modes.
    protected boolean analyzeInSingleModeOnly() {
        return true;
    }

    @Override
    protected boolean initializeAction(NamedElement obj) {
        setCSVLog("Binpacking", obj);

        // Select the bin packing strategy
        partitionChoice = org.osate.ui.dialogs.Dialog.askQuestion("Choose partitioning algorithm",
                "This bin packing algorithm groups threads that "
                        + "communicate with each other in groups and try to fit them "
                        + "together. If it is not possible it will partition the groups.\n\n"
                        + "Two main partitioning strategies exist: \n"
                        + "(1) Partition group as soon as they are discovered not to fit.\n"
                        + "(2) Put them aside and continue packing all groups that fit and after "
                        + "partition those that did not fit. Additionally it can select the "
                        + "group to partition based on the amount of data being communicated or "
                        + "the amount of computing cycles required by the group.",
                new String[] { "Immediate Partition of Groups", "Defer Partition of Groups Based on Exec. Time",
                        "Defer Partition of Groups Based on Comm. Bandwidth" },
                IMMEDIATE_PARTITION);
        return partitionChoice != -1;
    }

    @Override
    protected void analyzeDeclarativeModel(IProgressMonitor monitor, AnalysisErrorReporterManager errManager,
            Element declarativeObject) {
        org.osate.ui.dialogs.Dialog.showError("Binding Error", "Can only SW/HW bind (binpack) system instances");
    }

    protected void checkBuses(ComponentInstance obj) {
        ComponentInstance bi = (ComponentInstance) obj;
        final RecordValue transTime = GetProperties.getTransmissionTime(bi);
        if (transTime == null) {
            logWarning("Bus " + bi.getComponentInstancePath()
                    + " is missing Transmission Time property. Using default of "
                    + AADLBus.DEFAULT_TRANSMISSION_TIME);
        }

    }

    @Override
    protected void analyzeInstanceModel(final IProgressMonitor monitor,
            final AnalysisErrorReporterManager errManager, final SystemInstance root,
            final SystemOperationMode som) {
        try {
            monitor.beginTask("Binding threads to processors in " + root.getName(), IProgressMonitor.UNKNOWN);

            logInfo("Binpacker Analysis Report\n");
            /* Verify that all the busses have a transmission time
             */
            final ForAllElement addBuses = new ForAllElement(errManager) {
                public void process(Element obj) {
                    checkBuses((ComponentInstance) obj);
                }
            };
            addBuses.processPreOrderComponentInstance(root, ComponentCategory.BUS);

            /* Find and report all thread and device instances that don't have a 
             * period specified.
             */
            EList incompletethreads = new ForAllElement() {
                protected boolean suchThat(Element obj) {
                    final ComponentCategory cat = ((ComponentInstance) obj).getCategory();
                    if (cat == ComponentCategory.THREAD || cat == ComponentCategory.DEVICE) {
                        return GetProperties.getPeriodinMS((ComponentInstance) obj) == 0.0;
                    } else {
                        return false;
                    }
                }
            }.processPreOrderComponentInstance(root);
            for (final Iterator i = incompletethreads.iterator(); i.hasNext();) {
                final ComponentInstance o = (ComponentInstance) i.next();
                logWarning((InstanceModelUtil.isThread(o) ? "Thread " : "Device ") + o.getComponentInstancePath()
                        + " is missing period property. Using default of 1 ns");
            }

            /* Find and report all thread instances that don't have a 
             * compute execution time specified.
             */
            incompletethreads = new ForAllElement() {
                protected boolean suchThat(Element obj) {
                    return GetProperties.getThreadExecutioninMilliSec((ComponentInstance) obj) == 0.0;
                }
            }.processPreOrderComponentInstance(root, ComponentCategory.THREAD);
            for (final Iterator i = incompletethreads.iterator(); i.hasNext();) {
                final ComponentInstance o = (ComponentInstance) i.next();
                logWarning("Thread " + o.getComponentInstancePath()
                        + " is missing compute_execution_time or InstructionsPerDispatch property. Using default of 0 ns");
            }

            /* Find if all the port connections have data size
             */
            final ForAllElement addThreadConnections = new ForAllElement(errManager) {
                public void process(Element obj) {
                    if (obj instanceof ConnectionInstance) {
                        final ConnectionInstance connInst = (ConnectionInstance) obj;
                        if (connInst.getKind() == ConnectionKind.PORT_CONNECTION
                                && connInst.getSource() instanceof ConnectionInstanceEnd) {
                            final FeatureInstance src = (FeatureInstance) connInst.getSource();

                            Feature srcAP = src.getFeature();
                            Classifier cl = srcAP.getClassifier();
                            if (cl instanceof DataClassifier) {
                                DataClassifier srcDC = (DataClassifier) cl;
                                if (GetProperties.getSourceDataSizeInBytes(srcDC) == 0) {
                                    logWarning("Data size of connection source port "
                                            + src.getComponentInstancePath() + " not specified");
                                }
                            }
                        }
                    }
                }
            };
            addThreadConnections.processPreOrderAll(root);

            /* The partitionChoice is set in initializeANalysis() */
            NoExpansionExpansor expansor = new NoExpansionExpansor();
            LowLevelBinPacker packer = null;
            if (partitionChoice == IMMEDIATE_PARTITION) {
                packer = new BFCPBinPacker(expansor);
            } else if (partitionChoice == DEFER_EXEC_TIME) {
                packer = new DFCPBinPacker(expansor);
            } else if (partitionChoice == DEFER_BANDWIDTH) {
                packer = new DFBPBinPacker(expansor);
            }

            AssignmentResult result = binPackSystem(root, expansor, packer, errManager, som);

            reportResults(som, result);

            if (result.success) {
                showResults(som, root, result);
            } else {
                showNoResults(som);
            }
        } catch (InvalidModelException e) {
            error(e.getElement(), e.getMessage());
        }
    }

    protected EList getExecutionUnits(SystemInstance root) {
        return new ForAllElement().processPreOrderComponentInstance(root, ComponentCategory.THREAD);
    }

    protected AssignmentResult binPackSystem(final SystemInstance root, Expansor expansor, LowLevelBinPacker packer,
            final AnalysisErrorReporterManager errManager, final SystemOperationMode som) {
        /* Map from AADL ComponentInstances representing threads to
         * the bin packing SoftwareNode that models the thread.
         */
        final Map threadToSoftwareNode = new HashMap();
        /* Set of thread components.  This is is the keySet of
         * threadToSoftwareNode.
         */
        final Set threads = threadToSoftwareNode.keySet();
        /* Map from AADL ComponentInstances representing threads to
         * the set of AADL ComponentInstances that cannot be collocated
         * with it.
         */
        final Map notCollocated = new HashMap();

        /* Map from AADL ComponentInstance representing processors to
         * the bin packing Processor that models them.
         */
        final Map procToHardware = new HashMap();

        /* Map from AADL BusInstance representing Buses to
         * The bin packing Link that models them.
         */
        final Map busToHardware = new HashMap();

        /* One site to rule them all!  We don't care about the site
         * architecture, so just create one site to hold everything.
         * We aren't worried about power or space issues either, so
         * we just set them to 100.0 because those are nice values.
         * The site accepts AADL processors. 
         */
        final SiteArchitecture siteArchitecture = new SiteArchitecture();
        AADLProcessor ap = AADLProcessor.PROTOTYPE;
        final Site theSite = new Site(100.0, 100.0, new SiteGuest[] { ap });
        siteArchitecture.addSite(theSite);

        /* The hardware is fixed based on the AADL specification, so we 
         * use the NoExpansionExpansor to keep the hardware from being
         * generated for us.
         */

        expansor.setSiteArchitecture(siteArchitecture);

        /* Populate the problem space based on the AADL specification.  First
         * we walk the instance model and add all the processors.  Then we 
         * walk the instance model again to add all the threads.
         */
        OutDegreeAssignmentProblem problem1 = new OutDegreeAssignmentProblem(new OutDegreeComparator(),
                new BandwidthComparator(), new CapacityComparator());
        problem1.setErrorReporter(new BinPackErrorReporter());
        final OutDegreeAssignmentProblem problem = problem1;
        // Add procs
        final ForAllElement addProcessors = new ForAllElement(errManager) {
            public void process(Element obj) {
                ComponentInstance ci = (ComponentInstance) obj;
                if (GetProperties.getMIPSCapacityInMIPS(ci, 0) > 0) {
                    final AADLProcessor proc = AADLProcessor.createInstance(ci);
                    if (proc != null) {
                        siteArchitecture.addSiteGuest(proc, theSite);
                        problem.hardwareGraph.add(proc);
                        // add reverse mapping
                        procToHardware.put(ci, proc);
                    }
                } else {
                    // report processor without capacity
                    warning(ci, "Processor " + ci.getComponentInstancePath()
                            + "has no MIPS capacity. Not used in allocation.");

                }
            }
        };
        addProcessors.processPreOrderComponentInstance(root, ComponentCategory.PROCESSOR);

        /*   Get all the links 
         */

        final ForAllElement addBuses = new ForAllElement(errManager) {
            public void process(Element obj) {
                ComponentInstance bi = (ComponentInstance) obj;

                final AADLBus bus = AADLBus.createInstance(bi);
                busToHardware.put(bi, bus);
            }
        };

        addBuses.processPreOrderComponentInstance(root, ComponentCategory.BUS);

        /* create the links between processors and busses
         * (i.e., process connections)
         */
        for (final Iterator i = root.getAllConnectionInstances().iterator(); i.hasNext();) {
            final ConnectionInstance connInst = (ConnectionInstance) i.next();
            if (connInst.getKind() == ConnectionKind.ACCESS_CONNECTION) {
                InstanceObject src = connInst.getSource();
                InstanceObject dst = connInst.getDestination();

                AADLBus bus = null;
                AADLProcessor processor = null;

                // swap if i got them in the opposite order
                if (src instanceof FeatureInstance) {
                    InstanceObject tmp = dst;
                    dst = src;
                    src = tmp;
                }

                bus = (AADLBus) busToHardware.get(src);
                FeatureInstance fi = (FeatureInstance) dst;

                processor = (AADLProcessor) procToHardware.get(fi.getContainingComponentInstance());

                if (bus != null && processor != null) {
                    bus.add(processor);
                    processor.attachToLink(bus);
                }
            }
        }

        // Now add all the links so the connectivity matrix in the problem is
        // updated correctly

        for (Iterator iBus = busToHardware.values().iterator(); iBus.hasNext();) {
            AADLBus bus = (AADLBus) iBus.next();
            problem.addLink(bus);
            siteArchitecture.addSiteGuest(bus, theSite);
        }

        // Add threads
        final ForAllElement addThreads = new ForAllElement(errManager) {
            public void process(Element obj) {
                final ComponentInstance ci = (ComponentInstance) obj;

                /**
                 * JD - check the modes according to what was
                 * suggested by Dave.
                 */
                boolean selected = true;

                if (som.getCurrentModes().size() > 0) {
                    selected = false;
                    for (ModeInstance mi : ci.getInModes()) {
                        if (mi == som.getCurrentModes().get(0)) {
                            selected = true;
                        }
                    }
                }

                if (!selected) {
                    return;
                }

                final AADLThread thread = AADLThread.createInstance(ci);
                problem.softwareGraph.add(thread);
                //            logInfo(thread.getReport());
                // add reverse mapping
                threadToSoftwareNode.put(ci, thread);

                // Process NOT_COLLOCATED property. 
                RecordValue disjunctFrom = GetProperties.getNotCollocated(ci);
                if (disjunctFrom == null)
                    return;
                final Set disjunctSet = new HashSet();
                ListValue tvl = (ListValue) PropertyUtils.getRecordFieldValue(disjunctFrom, "Targets");
                for (PropertyExpression ref : tvl.getOwnedListElements()) {
                    /* Add all the instances rooted at the named instance.
                     * For example, the thread may be declared to be disjunct 
                     * from another process, so we really want to be disjunct
                     * from the other threads contained in that process.
                     */
                    final InstanceReferenceValue rv = (InstanceReferenceValue) ref;
                    final ComponentInstance refCI = (ComponentInstance) rv.getReferencedInstanceObject();
                    disjunctSet.addAll(refCI.getAllComponentInstances());
                }
                if (!disjunctSet.isEmpty()) {
                    notCollocated.put(ci, disjunctSet);
                }
            }
        };
        addThreads.processPreOrderComponentInstance(root, ComponentCategory.THREAD);

        // Add thread connections (Messages)
        for (final Iterator i = root.getAllConnectionInstances().iterator(); i.hasNext();) {
            final ConnectionInstance connInst = (ConnectionInstance) i.next();
            if (connInst.getKind() == ConnectionKind.PORT_CONNECTION) {
                final ConnectionInstance portConnInst = (ConnectionInstance) connInst;
                if (!(portConnInst.getSource() instanceof FeatureInstance
                        && portConnInst.getDestination() instanceof FeatureInstance))
                    continue;
                final FeatureInstance src = (FeatureInstance) portConnInst.getSource();
                final FeatureInstance dst = (FeatureInstance) portConnInst.getDestination();

                final ComponentInstance ci = src.getContainingComponentInstance();
                AADLThread t1 = (AADLThread) threadToSoftwareNode.get(ci);
                AADLThread t2 = (AADLThread) threadToSoftwareNode.get(dst.getContainingComponentInstance());
                if (t1 != null && t2 != null) {
                    Feature srcAP = src.getFeature();
                    // TODO: get the property directly
                    Classifier cl = srcAP.getClassifier();
                    if (cl instanceof DataClassifier) {
                        DataClassifier srcDC = (DataClassifier) cl;
                        double dataSize = 0.0;
                        double threadPeriod = 0.0;
                        try {
                            dataSize = GetProperties.getSourceDataSizeInBytes(srcDC);
                        } catch (Exception e) {
                            errManager.warning(connInst, "No Data Size for connection");
                        }
                        try {
                            threadPeriod = GetProperties.getPeriodinNS(ci);
                        } catch (Exception e) {
                            errManager.warning(connInst, "No Period for connection");
                        }

                        // Now I can create the Message

                        Message msg = new Message((long) dataSize, (long) threadPeriod, (long) threadPeriod, t1,
                                t2);
                        System.out.println(">>>>>>>>>> Adding message (" + Long.toString((long) dataSize) + "/"
                                + Long.toString((long) threadPeriod) + ") between " + t1.getName() + " and "
                                + t2.getName() + " based on connection " + portConnInst.getName());
                        problem.addMessage(msg);
                    } else {
                        errManager.warning(connInst, "No Data Classifier for connection");
                    }
                }
            }
        }

        // Add collocation constraints
        for (final Iterator constrained = notCollocated.keySet().iterator(); constrained.hasNext();) {
            final ComponentInstance ci = (ComponentInstance) constrained.next();
            final SoftwareNode sn = (SoftwareNode) threadToSoftwareNode.get(ci);
            final Set disjunctFrom = (Set) notCollocated.get(ci);
            for (final Iterator dfIter = disjunctFrom.iterator(); dfIter.hasNext();) {
                /* Items in the disjunctFrom set do not have to be thread 
                 * instances because of the way we add items to it (see above).
                 * We are only interested in the thread instances here, in 
                 * particular because we only create SoftwareNodes for the
                 * thread instances, and we don't want to get null return 
                 * values from the threadToSoftwareNode map.
                 */
                final ComponentInstance ci2 = (ComponentInstance) dfIter.next();
                if (ci2.getCategory() == ComponentCategory.THREAD) {
                    final SoftwareNode sn2 = (SoftwareNode) threadToSoftwareNode.get(ci2);
                    final SoftwareNode[] disjunction = new SoftwareNode[] { sn, sn2 };
                    problem.addConstraint(new Disjoint(disjunction));
                }
            }
        }

        /* Add Allowed_Processor_Binding and
         * Allowed_Processor_Binding_Class constraints
         */
        for (final Iterator i = threads.iterator(); i.hasNext();) {
            final ComponentInstance thr = (ComponentInstance) i.next();
            final SoftwareNode thrSN = (SoftwareNode) threadToSoftwareNode.get(thr);
            Collection allowed = getActualProcessorBindings(thr);
            if (allowed.size() == 0) {
                allowed = getAllowedProcessorBindings(thr);
            }
            if (allowed.size() > 0) {
                final Object[] allowedProcs = new Object[allowed.size()];
                int idx = 0;
                for (Iterator j = allowed.iterator(); j.hasNext(); idx++) {
                    final ComponentInstance proc = (ComponentInstance) j.next();
                    allowedProcs[idx] = procToHardware.get(proc);
                }
                problem.addConstraint(new SetConstraint(new SoftwareNode[] { thrSN }, allowedProcs));
            }
        }

        // Try to bin pack
        final NFCHoBinPacker highPacker = new NFCHoBinPacker(packer);
        final boolean res = highPacker.solve(problem);
        return new AssignmentResult(problem, res);
    }

    private abstract static class ShowDialog implements Runnable {
        public volatile int result;
    }

    String getBindingText(final Map threadsToProc) {
        String bindings = "";
        for (Iterator iter = threadsToProc.keySet().iterator(); iter.hasNext();) {
            final ComponentInstance thread = (ComponentInstance) iter.next();
            final ComponentInstance proc = (ComponentInstance) threadsToProc.get(thread);
            bindings += "Actual_Processor_Binding => reference (" + proc.getInstanceObjectPath() + ") applies to "
                    + thread.getInstanceObjectPath() + ";\n";
        }

        return bindings;
    }

    public void showResults(final SystemOperationMode som, final SystemInstance root,
            final AssignmentResult result) {
        final Map threadsToProc = getThreadBindings(result.problem.hardwareGraph);

        final String propText = getBindingText(threadsToProc);
        boolean done = false;
        while (!done) {
            final Dialog d = new PackingSuccessfulDialog(getShell(), som, root.getSystemImplementation().getName(),
                    threadsToProc, result.problem.hardwareGraph, propText);
            final ShowDialog sd = new ShowDialog() {
                public void run() {
                    this.result = d.open();
                }
            };
            Display.getDefault().syncExec(sd);

            if (sd.result == PackingSuccessfulDialog.INSTANCE_ID) {
                setInstanceModelBindings(root, threadsToProc);
            }
            // XXX: Don't set properties in the declarative model any more?
            //            else if (button == PackingSuccessfulDialog.DECLARATIVE_ID) {
            //               setDeclarativeBindings(root, threadsToProc);
            //            } 
            else {
                done = true;
            }
        }
    }

    public void showNoResults(final SystemOperationMode som) {
        org.osate.ui.dialogs.Dialog.showError("Application Binding Results",
                "In system operation mode " + som.getName() + "the application system is not schedulable");
    }

    private Map getThreadBindings(final Set hardware) {
        final Map threadsToProc = new HashMap();
        for (Iterator iter = hardware.iterator(); iter.hasNext();) {
            HardwareNode n = (HardwareNode) iter.next();
            for (Iterator taskSet = n.getTaskSet().iterator(); taskSet.hasNext();) {
                SoftwareNode m = (SoftwareNode) taskSet.next();
                if (m instanceof CompositeSoftNode) {
                    final Set set = ((CompositeSoftNode) m).getBasicComponents();
                    for (Iterator software = set.iterator(); software.hasNext();) {
                        final SoftwareNode sn = (SoftwareNode) software.next();
                        threadsToProc.put(sn.getSemanticObject(), n.getSemanticObject());
                    }
                } else {
                    if (!(m instanceof Message)) {
                        threadsToProc.put(m.getSemanticObject(), n.getSemanticObject());
                    }
                }
            }
        }
        return threadsToProc;
    }

    public void reportResults(SystemOperationMode som, final AssignmentResult result) {
        final Map threadsToProc = getThreadBindings(result.problem.hardwareGraph);

        logInfo("\nBinpacking results"
                + (!som.getName().equalsIgnoreCase("No Modes") ? " for SOM " + som.getName() : "") + ": "
                + (result.success ? "Success" : "FAILED"));
        for (final Iterator i = result.problem.hardwareGraph.iterator(); i.hasNext();) {
            final HardwareNode hn = (HardwareNode) i.next();
            final ComponentInstance proc = (ComponentInstance) hn.getSemanticObject();
            double load = hn.cyclesPerSecond - hn.getAvailableCapacity();
            load /= hn.cyclesPerSecond;
            load *= 100.0;
            long longLoad = (long) Math.ceil(load);
            double overload = (hn.cyclesPerSecond - hn.getAvailableCapacity()) - (hn.cyclesPerSecond);
            overload /= hn.cyclesPerSecond;
            overload *= 100.0;
            long longOverload = (long) Math.ceil(overload);
            long available = longOverload * -1;
            logInfo("Processor " + proc.getInstanceObjectPath() + " (" + hn.cyclesPerSecond / 1000000
                    + " MIPS) Load: " + Long.toString(longLoad) + "%" + " Available: " + Long.toString(available)
                    + "%");
        }
        logInfo("\nThread to Processor Bindings");
        for (Iterator iter = threadsToProc.keySet().iterator(); iter.hasNext();) {
            final ComponentInstance thread = (ComponentInstance) iter.next();
            final ComponentInstance proc = (ComponentInstance) threadsToProc.get(thread);
            double threadMips = GetProperties.getThreadExecutioninMIPS(thread);
            double cpumips = GetProperties.getMIPSCapacityInMIPS(proc, 0);

            logInfo("Thread " + thread.getInstanceObjectPath() + " ==> Processor " + proc.getInstanceObjectPath()
                    + (cpumips > 0 ? (" Utilization " + threadMips / cpumips * 100 + "%") : " No CPU capacity"));
        }
    }

    private void setInstanceModelBindings(final SystemInstance root, final Map threadsToProc) {
        final EditingDomain editingDomain = AdapterFactoryEditingDomain.getEditingDomainFor(root);
        if (editingDomain != null) {
            final CommandStack cmdStack = editingDomain.getCommandStack();
            final Command setBindings = new SetInstanceModelBindings(threadsToProc);
            cmdStack.execute(setBindings);
        } else {
            internalError("Couldn't get editing domain");
        }

        /* XXX: Keep this around for now.  May want to keep the ability to
         * modify the model directly so that we can use this action without
         * using an editor. 
         */
        //      for (Iterator iter = threadsToProc.keySet().iterator(); iter.hasNext(); ) {
        //         final ComponentInstance thread = (ComponentInstance) iter.next();
        //         final ComponentInstance proc = (ComponentInstance) threadsToProc.get(thread);
        //         final InstanceReferenceValue val = InstanceFactory.eINSTANCE.createInstanceReferenceValue();
        //         val.setReferencedInstanceObject(proc);
        //         thread.setPropertyValue(Binpack.actualProcessorBinding, val);
        //      }
    }

    /* We don't want to do this anymore?  Keep the code around for the moment
     * though.
     */
    //   /** @deprecated */
    //   private void setDeclarativeBindings(
    //         final SystemInstance root, final Map threadsToProc) {
    //      final SystemImpl system = root.getSystemImpl();
    //      for (Iterator iter = threadsToProc.keySet().iterator(); iter.hasNext(); ) {
    //         final ComponentInstance thread = (ComponentInstance) iter.next();
    //         final ComponentInstance proc = (ComponentInstance) threadsToProc.get(thread);
    //         final ReferenceValue procRef = proc.getReferenceTo();
    //         final List threadPath = thread.getReferencePathTo();
    //         system.setContainedPropertyValue(
    //               Binpack.actualProcessorBinding, 
    //               threadPath, procRef);
    //      }
    //   }

    //   private Properties constructDeclarativeBindings(final Map threadsToProc) {
    //      final Properties props = PropertyFactory.eINSTANCE.createProperties();
    //      for (Iterator iter = threadsToProc.keySet().iterator(); iter.hasNext(); ) {
    //         final ComponentInstance thread = (ComponentInstance) iter.next();
    //         final ComponentInstance proc = (ComponentInstance) threadsToProc.get(thread);
    //         final ReferenceValue procRef = proc.getReferenceTo();
    //         final List threadPath = thread.getReferencePathTo();
    //         
    //         // create the Property Association
    //         final PropertyAssociation pa = 
    //            PropertyFactory.eINSTANCE.createPropertyAssociation();
    //         properties.setActualProcessorBindingDefinitionToAssociation(pa);
    //         for (final Iterator i = threadPath.iterator(); i.hasNext(); ) {
    //            pa.addAppliesTo((PropertyHolder) i.next());
    //         }
    //         pa.addPropertyValue(procRef);
    //         props.addPropertyAssociation(pa);
    //      }
    //      return props;
    //   }

    /**
     * Get the processor components that a given thread is allowed to be bound to
     * based on the thread's ACTUAL_PROCESSOR_BINDING property value. The processors are
     * search for in the same system instance that the given thread component is
     * a part of.
     *
     * @param thread
     *                 The thread.
     * @return An unmodifiable set of processor ComponentInstances.
     * @exception IllegalArgumentException
     *                      Thrown if the category of the component instance
     *                      referenced by <code>thread</code> is not
     *                      {@link ComponentCategory#THREAD_LITERAL}.
     */
    public Collection getActualProcessorBindings(final ComponentInstance thread) {
        if (thread.getCategory() != ComponentCategory.THREAD) {
            throw new IllegalArgumentException("Component \"" + thread.getName() + "\" is not a thread.");
        }
        return InstanceModelUtil.getBoundPhysicalProcessors(thread);
    }

    /**
     * Get the processor components that a given thread is allowed to be bound to
     * based on the thread's ALLOWED_PROCESSOR_BINDING and
     * ALLOWED_PROCESSOR_BINDING_CLASS property values. The processors are
     * search for in the same system instance that the given thread component is
     * a part of.
     *
     * @param thread
     *                 The thread.
     * @return An unmodifiable set of processor ComponentInstances.
     * @exception IllegalArgumentException
     *                      Thrown if the category of the component instance
     *                      referenced by <code>thread</code> is not
     *                      {@link ComponentCategory#THREAD_LITERAL}.
     */
    public Set getAllowedProcessorBindings(final ComponentInstance thread) {
        if (thread.getCategory() != ComponentCategory.THREAD) {
            throw new IllegalArgumentException("Component \"" + thread.getName() + "\" is not a thread.");
        }
        List allowedBindingsVals;
        try {
            allowedBindingsVals = GetProperties.getAllowedProcessorBinding(thread);
        } catch (PropertyNotPresentException e) {
            //Ignore this situation and move on.
            allowedBindingsVals = Collections.EMPTY_LIST;
        }
        List allowedClassVals;
        try {
            allowedClassVals = GetProperties.getAllowedProcessorBindingClass(thread);
        } catch (PropertyNotPresentException e) {
            //Ignore this situation and move on.
            allowedClassVals = Collections.EMPTY_LIST;
        }
        final Set searchRoots = new HashSet();
        if (allowedBindingsVals.isEmpty()) {
            searchRoots.add(thread.getSystemInstance());
        } else {
            for (final Iterator i = allowedBindingsVals.iterator(); i.hasNext();) {
                final ComponentInstance rv = (ComponentInstance) i.next();
                searchRoots.add(rv);
            }
        }
        final Set allowedSystemClassifiers = new HashSet();
        final Set allowedProcClassifiers = new HashSet();
        for (final Iterator i = allowedClassVals.iterator(); i.hasNext();) {
            final ClassifierValue cv = (ClassifierValue) i.next();
            final ComponentClassifier cc = (ComponentClassifier) cv.getClassifier();
            if (cc instanceof ProcessorClassifier) { //ComponentCategory.PROCESSOR) {
                allowedProcClassifiers.add(cc);
            } else if (cc instanceof SystemClassifier) {//cv.getValue() == ComponentCategory.SYSTEM_LITERAL) {
                allowedSystemClassifiers.add(cc);
            } else {
                internalError(
                        "Ill-formed allowed_processor_binding_class value: got a non-system non-processor component classifier");
            }
        }
        final Set allowedProcs = new HashSet();
        for (final Iterator i = searchRoots.iterator(); i.hasNext();) {
            final ComponentInstance ci = (ComponentInstance) i.next();
            getAllowedProcessorBindings(ci, allowedProcs, allowedProcClassifiers, allowedSystemClassifiers);
        }
        return Collections.unmodifiableSet(allowedProcs);
    }

    /**
     * Search the instance model structure rooted at the given component
     * instance and add allowed processors to the given set of processors. A
     * processor is added if it's component classifier matches the given set of
     * processor classifiers (where the empty set means all processors). A
     * system component instance is explored if it's component classifier
     * matches the given set of system classifiers (where the empty set means
     * all systems). This method does nothing if given a non-system,
     * non-processor component instance.
     *
     * @param searchRoot
     *                 The component instance to consider.
     * @param allowedProcs
     *                 The set of processors. This set is added to by this method.
     * @param allowedProcClassifiers
     *                 The set of component classifiers describing allowable
     *                 processors.
     * @param allowedSystemClassifiers
     *                 The of component classifiers describing allowable systems.
     */
    private void getAllowedProcessorBindings(final ComponentInstance searchRoot, final Set allowedProcs,
            final Set allowedProcClassifiers, final Set allowedSystemClassifiers) {
        if (searchRoot.getCategory() == ComponentCategory.PROCESSOR) {
            /* If it's a processor, only add it if the classifier is okay. */
            if (testClassifier(searchRoot, allowedProcClassifiers)) {
                allowedProcs.add(searchRoot);
            }
        } else if (searchRoot.getCategory() == ComponentCategory.SYSTEM) {
            /* If it's a system then we look inside it for processors and other
             * systems. But only look if the classifiers match.
             */
            if (testClassifier(searchRoot, allowedSystemClassifiers)) {
                for (final Iterator i = searchRoot.getComponentInstances().iterator(); i.hasNext();) {
                    getAllowedProcessorBindings((ComponentInstance) i.next(), allowedProcs, allowedProcClassifiers,
                            allowedSystemClassifiers);
                }
            }
        } else {
            // Do nothing, not interested in non-processor, non-system instance
        }
    }

    /**
     * Test a component against a set of classifiers.
     * 
     * @return Whether the component's classifier type is a descendent of any of
     *         the given component classifiers. <em>Returns <code>true</code>
     *         if the given set is empty!</em>
     */
    public boolean testClassifier(ComponentInstance ci, final Set classifiers) {
        if (classifiers.isEmpty()) {
            return true;
        }
        boolean match = false;
        ComponentClassifier cicc = InstanceUtil.getComponentClassifier(ci, 0, null);
        if (cicc == null) {
            return true;
        }
        for (final Iterator i = classifiers.iterator(); i.hasNext() && !match;) {
            final ComponentClassifier cc = (ComponentClassifier) i.next();
            match = cicc.isDescendentOf(cc);
        }
        return match;
    }
}