| /*------------------------------------------------------------------------------ |
| - |
| - Copyright (c) 2015-2016 University of Padova, ITALY - Intecs SpA |
| - All rights reserved. This program and the accompanying materials |
| - are made available under the terms of the Eclipse Public License v1.0 |
| - which accompanies this distribution, and is available at |
| - http://www.eclipse.org/legal/epl-v10.html |
| - |
| - Contributors: |
| - |
| - Alessandro Zovi azovi@math.unipd.it |
| - Stefano Puri stefano.puri@intecs.it |
| - Laura Baracchi laura.baracchi@intecs.it |
| - Nicholas Pacini nicholas.pacini@intecs.it |
| - |
| - Initial API and implementation and/or initial documentation |
| ------------------------------------------------------------------------------*/package org.polarsys.chess.multicore.commands; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.transaction.RecordingCommand; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| import org.eclipse.emf.transaction.util.TransactionUtil; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.uml2.uml.Classifier; |
| import org.eclipse.uml2.uml.Component; |
| import org.eclipse.uml2.uml.Element; |
| import org.eclipse.uml2.uml.InstanceSpecification; |
| import org.eclipse.uml2.uml.Model; |
| import org.eclipse.uml2.uml.Package; |
| import org.polarsys.chess.chessmlprofile.Predictability.DeploymentConfiguration.HardwareBaseline.CH_HwProcessor; |
| import org.polarsys.chess.chessmlprofile.Predictability.RTComponentModel.CHRtSpecification; |
| import org.polarsys.chess.core.profiles.CHESSProfileManager; |
| import org.polarsys.chess.core.util.uml.ModelError; |
| import org.polarsys.chess.core.util.uml.UMLUtils; |
| import org.polarsys.chess.multicore.dialogs.SystemSelectionDialog; |
| import org.polarsys.chess.multicore.model.AbstractCommand; |
| import org.polarsys.chess.multicore.model.CHCore; |
| import org.polarsys.chess.multicore.model.CHTask; |
| import org.polarsys.chess.multicore.model.SupertaskInfo; |
| import org.polarsys.chess.multicore.partitioning.Bin; |
| import org.polarsys.chess.multicore.partitioning.BinPackerFactory; |
| import org.polarsys.chess.multicore.partitioning.RUNReduction; |
| import org.polarsys.chess.multicore.partitioning.Task; |
| import org.polarsys.chess.multicore.utils.GeneratorUtils; |
| import org.polarsys.chess.multicore.utils.QueryUtils; |
| import org.polarsys.chess.multicore.utils.QueryUtils.OccKindInfo; |
| import org.polarsys.chess.validator.constraints.StringParser; |
| |
| /** |
| * The Class GenerateTask2CoreAssignmentsCommand. |
| */ |
| public class GenerateTask2CoreAssignmentsCommand extends AbstractCommand { |
| |
| /** The operation list. */ |
| private HashMap<CHTask, EList<CHTask>> operationList; |
| |
| /** The core 2 chtask. */ |
| private Map<CHCore, LinkedHashSet<Object>> core2chtask; |
| |
| /** The processors. */ |
| private EList<InstanceSpecification> processors; |
| |
| /** The cores. */ |
| private EList<CHCore> cores = new BasicEList<CHCore>(); |
| |
| /** The assigned operations. */ |
| private Set<CHTask> assignedOperations = new HashSet<CHTask>(); |
| |
| /** The processors map. */ |
| private Map<Package, EList<InstanceSpecification>> processorsMap = new HashMap<Package, EList<InstanceSpecification>>(); |
| |
| /** The cores map. */ |
| private Map<InstanceSpecification, EList<CHCore>> coresMap = new HashMap<InstanceSpecification, EList<CHCore>>(); |
| |
| /** The hw system. */ |
| private static Component hwSystem; |
| |
| /** The hw systems list. */ |
| private EList<InstanceSpecification> hwSystemsList = new BasicEList<InstanceSpecification>(); |
| |
| /** The use RUN. */ |
| private boolean useRUN; |
| |
| /** The supertask info list. */ |
| private List<SupertaskInfo> supertaskInfoList; |
| |
| /** The core 2 supertask. */ |
| private HashMap<SupertaskInfo, LinkedHashSet<Object>> core2supertask; |
| |
| /** |
| * Open selector to choose HW system where assign tasks. |
| * |
| * @param umlModel the uml model |
| * @param hwSystemsList the hw systems list |
| * @return the instance specification |
| */ |
| private static InstanceSpecification openSystemSelector(Model umlModel, EList<InstanceSpecification> hwSystemsList) { |
| |
| // First of all show selector to select HwSystem |
| List<InstanceSpecification> systemSelection = new ArrayList<InstanceSpecification>(); |
| for (InstanceSpecification syst : hwSystemsList) { |
| systemSelection.add(syst); |
| } |
| |
| Shell activeShell = Display.getDefault().getActiveShell(); |
| SystemSelectionDialog systemDialog = new SystemSelectionDialog(activeShell, systemSelection, "Select System where to assign tasks"); |
| if (systemDialog.open() == Window.OK) { |
| String selectedSystemQN = systemDialog.getSystemName(); |
| EList<Element> allElems = umlModel.allOwnedElements(); |
| for (Element elem : allElems) { |
| InstanceSpecification theSystem; |
| if (elem instanceof InstanceSpecification) { |
| theSystem = (InstanceSpecification) elem; |
| if (theSystem.getQualifiedName() != null && theSystem.getQualifiedName().equals(selectedSystemQN)) { |
| Classifier classif = theSystem.getClassifiers().get(0); |
| hwSystem = (Component) classif; |
| return theSystem; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.polarsys.chess.multicore.model.AbstractCommand#execute() |
| */ |
| @Override |
| public void execute() throws ModelError { |
| queryContent(umlModel); |
| |
| int howMany = hwSystemsList.size(); |
| |
| InstanceSpecification theSystem = null; |
| if (howMany > 1) { |
| theSystem = openSystemSelector(umlModel, hwSystemsList); |
| } else { |
| theSystem = hwSystemsList.get(0); |
| } |
| |
| if (theSystem != null) { |
| Package pack = QueryUtils.getOwnerCHGaResourcePlatformPackage(umlModel, theSystem); |
| |
| EList<InstanceSpecification> processorList = processorsMap.get(pack); |
| |
| cores = new BasicEList<CHCore>(); |
| if (processorList != null) { |
| for (InstanceSpecification proc : processorList) { |
| EList<CHCore> coreList = coresMap.get(proc); |
| for (CHCore core : coreList) { |
| cores.add(core); |
| } |
| } |
| } |
| |
| executeTask2CoreCalculator(false); |
| |
| // printContent(); |
| if (core2chtask != null) { |
| updateModel(); |
| } |
| } |
| } |
| |
| /** |
| * Execute task 2 core calculator. |
| * |
| * @param forceUseOfRUN the force use of RUN |
| * @throws ModelError the model error |
| */ |
| protected void executeTask2CoreCalculator(boolean forceUseOfRUN) throws ModelError { |
| |
| List<Bin> allBins = new ArrayList<Bin>(); |
| List<Task> allTasks = new ArrayList<Task>(); |
| System.out.format("We have %d cores\n", cores.size()); |
| // init bins |
| for (int i = 0; i < cores.size(); i++) |
| allBins.add(new Bin(i)); |
| |
| for (CHTask chRtSpecification : operationList.keySet()) { |
| |
| String occKind = chRtSpecification.getCHRtSpecification().getOccKind(); |
| OccKindInfo info = QueryUtils.getOccKindInfo(occKind); |
| |
| double c_ = QueryUtils.getWCET(chRtSpecification.getCHRtSpecification()); |
| /* add the wcet for each operation relative to this chrtspec */ |
| for (CHTask spec : operationList.get(chRtSpecification)) { |
| double c_1 = QueryUtils.getWCET(spec.getCHRtSpecification()); |
| c_ += c_1; |
| } |
| StringParser sp = new StringParser(); |
| double d_ = sp.getValueNFP(chRtSpecification.getCHRtSpecification().getRlDl()); |
| double t_ = info.value; |
| |
| // d_ = xxx.remove(0); |
| // t_ = d_; |
| |
| String name = getTaskID(chRtSpecification.getCHRtSpecification()); |
| |
| float c = (float) c_;// exec time |
| float d = (float) d_;// deadline |
| float t = (float) t_;// period |
| float o = 0;// TODO insert offset in stereotype |
| |
| double u_ = c / t; |
| float u = (float) u_; |
| |
| System.out.println("Task " + name + " -> " + c + " " + d + " " + t + " -> " + u); |
| allTasks.add(new Task(name, new Float(c), new Float(d), new Float(t), new Float(o), null)); |
| |
| } |
| |
| Map<Bin, List<Task>> firstPack = BinPackerFactory.getBinPacker(org.polarsys.chess.multicore.partitioning.Heuristic.WORST_FIT).pack(allBins, allTasks); |
| Map<Bin, List<Task>> reductionTree = new Hashtable<Bin, List<Task>>(firstPack); |
| |
| useRUN = reductionTree.size() > allBins.size(); |
| if (forceUseOfRUN) |
| useRUN = true; |
| |
| if (useRUN) { |
| System.out.println("Starting RUN packing"); |
| allTasks = new ArrayList<Task>(); |
| for (Bin bin : reductionTree.keySet()) |
| allTasks.add(new Task(bin.getId().toString(), bin.getCapacity())); |
| reductionTree = new RUNReduction().pack(null, allTasks); |
| for (java.util.Map.Entry<Bin, List<Task>> row : reductionTree.entrySet()) { |
| System.out.print("LEVEL " + row.getKey().getLevel() + "-" + row.getKey().getId() + "(U=" + row.getKey().getCapacity() + ") -> {"); |
| for (Task t : row.getValue()) |
| System.out.print(" " + t.getId() + ","); |
| System.out.println("}"); |
| } |
| buildRUNAssociations(firstPack, reductionTree); |
| } else |
| // Build model results |
| buildAssociations(firstPack); |
| } |
| |
| /** |
| * Builds the RUN associations. |
| * |
| * @param firstPack the first pack |
| * @param reductionTree the reduction tree |
| * @throws ModelError the model error |
| */ |
| private void buildRUNAssociations(Map<Bin, List<Task>> firstPack, Map<Bin, List<Task>> reductionTree) throws ModelError { |
| // add chtasks which represent real tasks to the core map and add the |
| // related operation chain to the same core |
| // TODO solve the following problem: the related operations may be shared |
| // between tasks which can be assigned to different cores! |
| |
| core2supertask = new HashMap<SupertaskInfo, LinkedHashSet<Object>>(); |
| |
| Object[] firstPackSorted = firstPack.entrySet().toArray(); |
| Arrays.sort(firstPackSorted, new Comparator<Object>() { |
| |
| @Override |
| public int compare(Object o1, Object o2) { |
| if (((Entry<Bin, List<Task>>) o1).getKey().getId() > ((Entry<Bin, List<Task>>) o2).getKey().getId()) |
| return 1; |
| else if (((Entry<Bin, List<Task>>) o1).getKey().getId() < ((Entry<Bin, List<Task>>) o2).getKey().getId()) |
| return -1; |
| else |
| return 0; |
| } |
| }); |
| |
| Object[] allBins = reductionTree.keySet().toArray(); |
| Arrays.sort(allBins, new Comparator<Object>() { |
| |
| @Override |
| public int compare(Object o1, Object o2) { |
| if (((Bin) o1).getLevel() > ((Bin) o2).getLevel()) |
| return -1; |
| else if (((Bin) o1).getLevel() < ((Bin) o2).getLevel()) |
| return 1; |
| else |
| return 0; |
| } |
| }); |
| |
| // DEPTH-FIRST print |
| // root level |
| |
| CH_HwProcessor procInstance = QueryUtils.getAllProcessorInstances(umlModel).get(0); |
| |
| int maxLevel = ((Bin) allBins[0]).getLevel(); |
| System.out.println("-- Primary Schedulers\n"); |
| System.out.println("Scheduler ("); |
| System.out.println(" Type => Primary_Scheduler,"); |
| System.out.println(" Name => Scheduler_1,"); |
| System.out.println(" Policy => ( Type => RUN ),"); |
| System.out.println(" Host => Multicore_1 );");// TODO: depends on CHRT |
| // specification |
| System.out.println("\n-- Primary Scheduling Servers and Secondary Schedulers\n"); |
| int indexSupertask = 0; |
| // all levels of the tree in the interval (root,0] |
| supertaskInfoList = new ArrayList<SupertaskInfo>(); |
| for (int i = 1; (i < allBins.length) && (((Bin) allBins[i]).getLevel() >= 0); i++) { |
| createSupertaskInfo(procInstance, indexSupertask, ((Bin) allBins[i]).getCapacity()); |
| |
| assignedOperations = new HashSet<CHTask>(); |
| // first pack: print leaf nodes |
| if (((Bin) allBins[i]).getLevel() == 0) { |
| List<Task> tasks = reductionTree.get(((Bin) allBins[i])); |
| LinkedHashSet<Object> list = new LinkedHashSet<Object>(); |
| for (Task task : tasks) { |
| List<Task> leaves = ((Entry<Bin, List<Task>>) firstPackSorted[new Integer(task.getId())]).getValue(); |
| for (Task leaf : leaves) { |
| System.out.println("Scheduling_Server ("); |
| System.out.println(" Type => Regular,"); |
| System.out.println(" Name => " + leaf.getId() + ","); |
| System.out.println(" Server_Sched_Parameters => ("); |
| System.out.println(" Type => EDF_policy,"); |
| System.out.println(" Deadline => " + leaf.getT() + ","); |
| System.out.println(" Preassigned => No),"); |
| System.out.println(" Scheduler => SecondaryScheduler_" + indexSupertask + ");"); |
| System.out.println(); |
| |
| CHTask owningTask = getCHRTFromTask(leaf); |
| list.add(owningTask); |
| addRelatedOperations(owningTask, list); |
| |
| } |
| |
| } |
| core2supertask.put(supertaskInfoList.get(indexSupertask), list); |
| } |
| indexSupertask++; |
| } |
| } |
| |
| /** |
| * Creates the supertask info. |
| * |
| * @param ch_HwProcessor the ch hw processor |
| * @param indexSupertask the index supertask |
| * @param capacity the capacity |
| */ |
| private void createSupertaskInfo(CH_HwProcessor ch_HwProcessor, int indexSupertask, Float capacity) { |
| SupertaskInfo si = new SupertaskInfo(ch_HwProcessor.getBase_InstanceSpecification(), "SuperTask_" + indexSupertask, capacity); |
| supertaskInfoList.add(si); |
| System.out.println("--*************** BRANCH ***************"); |
| System.out.println("Scheduling_Server ("); |
| System.out.println(" Type => Regular,"); |
| System.out.println(" Name => SuperTask_" + indexSupertask + ","); |
| System.out.println(" Server_Sched_parameters => ( Type => RUN_Supertask,"); |
| System.out.println(" Utilization => " + capacity + " ),"); // FIXME: |
| // utilization |
| // is |
| // not |
| // expressed |
| // as U |
| // in |
| // Geoffrey's |
| // example |
| System.out.println(" Scheduler => Scheduler_1 );"); |
| System.out.println(); |
| System.out.println("Scheduler ("); |
| System.out.println(" Type => Secondary_Scheduler,"); |
| System.out.println(" Name => SecondaryScheduler_" + indexSupertask + ","); |
| System.out.println(" Policy => ( Type => EDF,"); |
| System.out.println(" Worst_Context_Switch => 20 ),");// FIXME: based on |
| // Compagnin paper |
| // at ECRTS2014 |
| System.out.println(" Server => SuperTask_" + indexSupertask + " );"); |
| System.out.println(); |
| } |
| |
| /** |
| * Builds the associations. |
| * |
| * @param firstPack the first pack |
| */ |
| public void buildAssociations(Map<Bin, List<Task>> firstPack) { |
| // add chtasks which represent real tasks to the core map and add the |
| // related operation chain to the same core |
| // TODO solve the following problem: the related operations may be shared |
| // between tasks which can be assigned to different cores! |
| |
| core2chtask = new HashMap<CHCore, LinkedHashSet<Object>>(); |
| int coreIndex = 0; |
| for (Bin core : firstPack.keySet()) { |
| assignedOperations = new HashSet<CHTask>(); |
| LinkedHashSet<Object> list = new LinkedHashSet<Object>(); |
| for (Task task : firstPack.get(core)) { |
| CHTask owningTask = getCHRTFromTask(task); |
| list.add(owningTask); |
| addRelatedOperations(owningTask, list); |
| } |
| core2chtask.put(cores.get(coreIndex++), list); |
| } |
| } |
| |
| // the related operations of a task are assigned to the same core of the task, |
| // TODO for now every operation shared by multiple tasks is assigned to the |
| /** |
| * Adds the related operations. |
| * |
| * @param owningTask the owning task |
| * @param list the list |
| */ |
| // same core of the first task that was processed |
| private void addRelatedOperations(CHTask owningTask, LinkedHashSet<Object> list) { |
| for (CHTask operation : operationList.get(owningTask)) { |
| if (!assignedOperations.contains(operation)) { |
| list.add(operation); |
| assignedOperations.add(operation); |
| } |
| } |
| } |
| |
| /** |
| * Gets the task ID. |
| * |
| * @param chRtSpecification the ch rt specification |
| * @return the task ID |
| */ |
| private String getTaskID(CHRtSpecification chRtSpecification) { |
| return chRtSpecification.getContext().getName() + UMLUtils.getElementID(chRtSpecification.getContext()); |
| } |
| |
| /** |
| * Gets the CHRT from task. |
| * |
| * @param task the task |
| * @return the CHRT from task |
| */ |
| private CHTask getCHRTFromTask(Task task) { |
| for (CHTask chtask : operationList.keySet()) { |
| if (getTaskID(chtask.getCHRtSpecification()).equals(task.getId())) |
| return chtask; |
| } |
| return null; |
| } |
| |
| /** |
| * Prints the content. |
| */ |
| private void printContent() { |
| System.out.println("Tasks:"); |
| for (CHTask chtask : operationList.keySet()) { |
| System.out.println(chtask); |
| } |
| } |
| |
| /** |
| * Update model. |
| */ |
| protected void updateModel() { |
| boolean b1 = core2chtask != null && !core2chtask.isEmpty(); |
| boolean b2 = core2supertask != null && !core2supertask.isEmpty(); |
| |
| if (b1 || b2) { |
| |
| TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(umlModel); |
| editingDomain.getCommandStack().execute(new Com(editingDomain)); |
| } |
| } |
| |
| /** |
| * Query content. |
| * |
| * @param owner the owner |
| * @throws ModelError the model error |
| */ |
| protected void queryContent(Model owner) throws ModelError { |
| EList<CH_HwProcessor> x = QueryUtils.getAllProcessorInstances(umlModel); |
| x = QueryUtils.filterMultiCoreProcessors(x); |
| if (x.size() > 1) |
| throw new ModelError("Assignment generation works only on single processor systems"); |
| |
| // Look for Packages stereotyped as CHGAResourcePlatform in the Deployment |
| // View |
| EList<Package> packages = QueryUtils.getResourcePlatformPackages(umlModel, CHESSProfileManager.DEPLOYMENT_VIEW); |
| |
| if (packages.size() == 0) { |
| ModelError me = new ModelError("Error in model: no Package stereotyped as CHGAResourcePlatform in the Deployment View!"); |
| throw me; |
| } |
| hwSystemsList = new BasicEList<InstanceSpecification>(); |
| |
| for (Package pack : packages) { |
| EList<InstanceSpecification> processors = new BasicEList<InstanceSpecification>(); |
| for (CH_HwProcessor ch_processor : QueryUtils.getAllProcessorInstancesInPackage(pack)) { |
| InstanceSpecification instSpec = ch_processor.getBase_InstanceSpecification(); |
| processors.add(instSpec); |
| EList<CHCore> theCores = QueryUtils.getCores(ch_processor); |
| coresMap.put(instSpec, theCores); |
| cores.addAll(theCores); |
| } |
| InstanceSpecification theSystem = UMLUtils.getRootInstanceInPackage(pack); |
| hwSystemsList.add(theSystem); |
| processorsMap.put(pack, processors); |
| } |
| |
| if (hwSystemsList.isEmpty()) { |
| ModelError me = new ModelError("Error in model: no System in the Deployment View!"); |
| throw me; |
| } |
| |
| EList<InstanceSpecification> instances = UMLUtils.getAllComponentInstances(umlModel, true); |
| EList<CHTask> chtasks = QueryUtils.getCHTasksList(instances); |
| |
| operationList = QueryUtils.getOperationChain(umlModel, chtasks); |
| |
| } |
| |
| /** |
| * The Class Com. |
| */ |
| class Com extends RecordingCommand { |
| |
| /** |
| * Instantiates a new com. |
| * |
| * @param domain the domain |
| */ |
| public Com(TransactionalEditingDomain domain) { |
| super(domain); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.emf.transaction.RecordingCommand#doExecute() |
| */ |
| @Override |
| protected void doExecute() { |
| try { |
| QueryUtils.deleteTask2CoreAssociations(hwSystem); |
| if (!useRUN) |
| GeneratorUtils.buildTask2CoreAssociations(hwSystem, core2chtask); |
| else |
| GeneratorUtils.buildTask2SuperTaskAssociations(hwSystem, core2supertask, supertaskInfoList); |
| |
| } catch (Exception e) { |
| throw new OperationCanceledException(e.getMessage()); |
| } |
| } |
| } |
| |
| } |