blob: 175b2255f4bb6a812cb223e5fd14d89bcb7da436 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2018 Dortmund University of Applied Sciences and Arts and others.
*
* 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
*
* Contributors:
* Dortmund University of Applied Sciences and Arts - initial API and implementation
*******************************************************************************/
package org.eclipse.app4mc.multicore.openmapping.algorithms.ilp.energyminimization;
import java.util.AbstractMap.SimpleEntry;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.app4mc.amalthea.model.AmaltheaFactory;
import org.eclipse.app4mc.amalthea.model.LongObject;
import org.eclipse.app4mc.amalthea.model.MappingModel;
import org.eclipse.app4mc.amalthea.model.RunnableAllocation;
import org.eclipse.app4mc.amalthea.model.Scheduler;
import org.eclipse.app4mc.amalthea.model.SchedulerAllocation;
import org.ojalgo.optimisation.Variable;
public class MappingBuilder {
private final List<VoltageLevel> lVoltageLevels = new LinkedList<>();
private final List<SimpleEntry<AdvancedCore, AdvancedRunnable>> mRunToCore = new LinkedList<>();
private final List<SimpleEntry<ExtendedCore, Scheduler>> mCoreToScheduler = new LinkedList<>();
private final Map<AdvancedCore, Long> mCoreUtilizationOrig = new HashMap<>();
private final Map<AdvancedCore, Long> mCoreUtilizationReal = new HashMap<>();
private final Map<AdvancedCore, Long> mCoreUtilizationSlower = new HashMap<>();
private final AmaltheaFactory mmInstance = AmaltheaFactory.eINSTANCE;
private final AmaltheaFactory commonInstance = AmaltheaFactory.eINSTANCE;
private MappingModel mappingModel = null;
private long lMaxUtil;
private String sAllocation;
private String sBarChart;
private String sSlowDown;
public void addRunnableToCore(final AdvancedCore c, final AdvancedRunnable r) {
this.mRunToCore.add(new SimpleEntry<AdvancedCore, AdvancedRunnable>(c, r));
}
public void generateMapping() {
generateMappingModel();
generateAllocationString();
generateBarChart();
generateSlowDownText();
}
private void generateSlowDownText() {
this.sSlowDown = "\nIncrease in execution time due to lower VoltageLevels:\n";
for (final Entry<AdvancedCore, Long> entry : this.mCoreUtilizationReal.entrySet()) {
this.sSlowDown += " " + entry.getKey().getCore().getName() + ":\t";
final long origVal = this.mCoreUtilizationOrig.get(entry.getKey());
final long realVal = entry.getValue();
this.sSlowDown += String.format("+ %.5f", ((100.0 / origVal * realVal) - 100)) + "%\n";
}
this.sSlowDown += "\nInstructions running at lower VoltageLevels:\n";
for (final Entry<AdvancedCore, Long> entry : this.mCoreUtilizationSlower.entrySet()) {
this.sSlowDown += " " + entry.getKey().getCore().getName() + ":\t";
final long origVal = this.mCoreUtilizationOrig.get(entry.getKey());
final long realVal = entry.getValue();
this.sSlowDown += String.format("+ %.5f", (100.0 / origVal * realVal)) + "%\n";
}
}
private void generateMappingModel() {
// Create "orig" MappingModel
this.mappingModel = this.mmInstance.createMappingModel();
for (final SimpleEntry<ExtendedCore, Scheduler> entry : this.mCoreToScheduler) {
final SchedulerAllocation sa = this.mmInstance.createSchedulerAllocation();
final ExtendedCore c = entry.getKey();
final Scheduler s = entry.getValue();
try {
sa.setScheduler(s);
sa.getResponsibility().add(c.getCore());
this.mappingModel.getSchedulerAllocation().add(sa);
}
catch (final Exception e) {
e.printStackTrace();
}
}
final VoltageLevel vlBest = this.lVoltageLevels.get(0);
// Add runnable allocations
for (final SimpleEntry<AdvancedCore, AdvancedRunnable> entry : this.mRunToCore) {
final AdvancedCore c = entry.getKey();
final AdvancedRunnable r = entry.getValue();
long leftCycles = r.getNumberOfInstructions();
// Prepare Utilization map
final long tmpCycles;
if (this.mCoreUtilizationOrig.containsKey(c)) {
tmpCycles = this.mCoreUtilizationOrig.get(c) + leftCycles;
}
else {
tmpCycles = leftCycles;
}
this.mCoreUtilizationOrig.put(c, tmpCycles);
long tmpProcCycles = 0;
if (this.mCoreUtilizationReal.containsKey(c)) {
tmpProcCycles = this.mCoreUtilizationReal.get(c);
}
long slowerCycles = 0;
if (this.mCoreUtilizationSlower.containsKey(c)) {
slowerCycles = this.mCoreUtilizationSlower.get(c);
}
// Iterate over all Voltage levels and determine the resp no of
// instructions
final RunnableAllocation ra = this.mmInstance.createRunnableAllocation();
ra.setEntity(r.getRunnableRef());
ra.setScheduler(c.getScheduler());
// Add the voltage levels for each runnable
final Iterator<Entry<VoltageLevel, Variable>> itVols = r.getVarNuis().entrySet().iterator();
while (itVols.hasNext()) {
final Entry<VoltageLevel, Variable> e = itVols.next();
final String vlName = e.getKey().getName();
final long vlCycles = e.getValue().getValue().longValue();
leftCycles -= vlCycles;
final LongObject v = this.commonInstance.createLongObject();
v.setValue(vlCycles);
ra.getCustomProperties().put("EnEf-VoltageLevel_" + vlName, v);
getMappingModel().getRunnableAllocation().add(ra);
// Update value of the "real" proc. cycles it takes
tmpProcCycles += Math.round(vlCycles / e.getKey().getScale());
}
// Add missing entry for highest voltage level
final LongObject v = this.commonInstance.createLongObject();
v.setValue(leftCycles);
ra.getCustomProperties().put("EnEf-VoltageLevel_" + vlBest.getName(), v);
// Store entry
getMappingModel().getRunnableAllocation().add(ra);
// System.out.println("LAST " + vlBest.getName() + "/" +
// r.getRunnableRef().getName());
// Update the number of really required processor cycles
tmpProcCycles += Math.round(leftCycles / vlBest.getScale());
this.mCoreUtilizationReal.put(c, tmpProcCycles);
this.mCoreUtilizationSlower.put(c, slowerCycles + r.getNumberOfInstructions() - leftCycles);
}
}
private void generateAllocationString() {
this.sAllocation = "";
for (final SimpleEntry<AdvancedCore, AdvancedRunnable> entry : this.mRunToCore) {
final AdvancedCore c = entry.getKey();
final AdvancedRunnable r = entry.getValue();
this.sAllocation += "Allocation: '" + r.getRunnableRef().getName() + "' <=> '" + c.getCore().getName()
+ "'\n";
}
}
private void generateBarChart() {
this.lMaxUtil = Collections.max(this.mCoreUtilizationReal.values());
System.out.println(this.lMaxUtil);
this.sBarChart = "Core (#Runnables) - Utilization - Cycles - Time (round to 5 fig.)\n";
this.sBarChart += "-------------------------------------------------------------------------------------------------------\n";
for (final Entry<AdvancedCore, Long> entry : this.mCoreUtilizationReal.entrySet()) {
final AdvancedCore c = entry.getKey();
final Long cycles = entry.getValue();
final double curUtil = 40 / (double) this.lMaxUtil * cycles;
this.sBarChart += String.format("%-12s %4s - ", c.getCore().getName(), "(" + c.getRunnables().size() + ")");
int i = 0;
while (i < 40) {
if (i < curUtil) {
this.sBarChart += "X";
}
else {
this.sBarChart += " ";
}
i++;
}
this.sBarChart += String.format(" - %-,15d - %-,18.5f ms\n", cycles,
entry.getValue() / entry.getKey().getCyclesPerSecond() * 1000);
// System.out.println("Core: " + c.getCore().getName());
// System.out.println("Time: " + entry.getValue() /
// entry.getKey().getCyclesPerSecond() * 1000);
// System.out.println("R" + this.mCoreUtilizationReal.get(c) + " O"
// + this.mCoreUtilizationOrig.get(c));
// System.out.println("CurUtil" + curUtil);
}
}
public MappingModel getMappingModel() {
return this.mappingModel;
}
public String getAllocation() {
return this.sAllocation;
}
public String getBarChart() {
return this.sBarChart;
}
public String getSlowDownText() {
return this.sSlowDown;
}
public void setVoltageLevels(final List<VoltageLevel> vl) {
// Improper usage of this method if its called more then once
assert (0 == this.lVoltageLevels.size());
this.lVoltageLevels.addAll(vl);
// Ensure highest voltage level comes first
Collections.sort(this.lVoltageLevels);
}
public void addCoreToSchedulder(final ExtendedCore c, final Scheduler s) {
this.mCoreToScheduler.add(new SimpleEntry<ExtendedCore, Scheduler>(c, s));
}
}