Commit 6a8c0801 authored by Mahesh Tripunitara's avatar Mahesh Tripunitara
Browse files

Merge branch 'master' of https://bitbucket.org/jshahen/vagabond into ReduceToCNFSAT

parents cfa4a69d f72281e6
......@@ -10,5 +10,6 @@
<classpathentry kind="lib" path="lib/oplall.jar"/>
<classpathentry kind="lib" path="lib/commons-csv-1.3/commons-csv-1.3.jar"/>
<classpathentry kind="lib" path="lib/commons-math3-3.6.1/commons-math3-3.6.1.jar"/>
<classpathentry kind="lib" path="lib/circuit.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
......@@ -240,12 +240,13 @@ public class VagabondInstance {
"Placement Map at the END of Epoch " + epochNum + "\n" + epochHistory._latestPlacementMap);
}
/* Timing */stats.addEpochTime(timing.stopTimer(tp + "VagabondInstance::main()::epochLoop::totalTime"));
// Must be after the STATS
if (settings.reductionAlgorithm == VagabondOptionString.REDUCTION_NOMAD) {
logger.info("Exiting the EPOCH LOOP because Nomad does its own EPOCH LOOP.");
break;
}
/* Timing */stats.addEpochTime(timing.stopTimer(tp + "VagabondInstance::main()::epochLoop::totalTime"));
}
/** *****************************************************************************
* ******************************************************************************
......@@ -259,6 +260,7 @@ public class VagabondInstance {
// Results Final Placement
settings.results.finalPlacement = epochHistory._latestPlacementMap;
settings.results.finalCCIL = epochHistory.get(0);
settings.results.eh = epochHistory;
// Add a custom Stat event for the
timing.putRawTimeEvent("averageEpochTime", stats.getAvgEpochTimeEvent());
......@@ -445,12 +447,12 @@ public class VagabondInstance {
value = prop.getProperty(VagabondOptionString.NUMCLIENTS.toString(), null);
if (value != null) {
mustContain.remove(VagabondOptionString.NUMCLIENTS.toString());
settings.numberOfClients = Integer.valueOf(value);
}
value = prop.getProperty(VagabondOptionString.NUMVMS.toString(), null);
if (value != null) {
mustContain.remove(VagabondOptionString.NUMVMS.toString());
settings.numberOfClients = Integer.valueOf(value);
settings.numberOfVMsPerClient = Integer.valueOf(value);
}
} else {
......
......@@ -347,4 +347,15 @@ public class ClientToClientInformationLeakage {
return sb.toString();
}
public int getSumInformationLeak() {
int sum = 0;
for (Integer c0 : _clientIDs) {
for (Integer c1 : _clientIDs) {
sum += get(c0, c1);
}
}
return sum;
}
}
......@@ -34,7 +34,7 @@ public class PlacementMap {
/**
* Stores the next available Global VM ID (there are functions to deal with this)
*/
private Integer _nextAvailableVMID = 1;
private Integer _nextAvailableVMID = 0;
/**
* Creates a PlacementMap and initializes all of the machines
......@@ -93,7 +93,7 @@ public class PlacementMap {
* @return the VM ID
*/
public Integer getNextAvailableVMID() {
Integer out = _nextAvailableVMID;
int out = _nextAvailableVMID;
_nextAvailableVMID++;
return out;
}
......@@ -107,7 +107,7 @@ public class PlacementMap {
*/
public Boolean isMachineFull(Integer machineID) throws IllegalArgumentException {
if (machineID >= _machines.size() || machineID < 0) { throw new IllegalArgumentException(
"No machine exists with that ID, it must be in the range of " +
"No machine exists with that ID(" + machineID + "), it must be in the range of " +
"0 (inclusive) and " + _machines.size() + "(exclusive)"); }
return _machines.get(machineID).isFull();
......@@ -351,6 +351,9 @@ public class PlacementMap {
for (int m = 0; m < getNumberOfMachines(); m++) {
if (!_machines.get(m).equals(p._machines.get(m))) {
System.out.println("Machine ID " + m + " is not equal!");
System.out.println("Our Machine: " + _machines.get(m));
System.out.println("Their Machine: " + p._machines.get(m));
return false;
}
}
......
......@@ -67,6 +67,11 @@ public class VM {
return "Global ID,Client ID,Service ID";
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public boolean equals(Object obj) {
return equals(obj, false);
......@@ -83,21 +88,21 @@ public class VM {
if (!_clientID.equals(v._clientID)) {
if (writeOutReason) {
System.out.println("Client IDs do not match");
System.out.println("Client IDs do not match; this." + _clientID + " != " + v._clientID);
}
return false;
}
if (!_serviceID.equals(v._serviceID)) {
if (writeOutReason) {
System.out.println("Service IDs do not match");
System.out.println("Service IDs do not match; this." + _serviceID + " != " + v._serviceID);
}
return false;
}
if (!_globalID.equals(v._globalID)) {
if (writeOutReason) {
System.out.println("Global IDs do not match");
System.out.println("Global IDs do not match; this." + _globalID + " != " + v._globalID);
}
return false;
}
......
package vagabond.placement;
import static org.junit.Assert.assertTrue;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.*;
......@@ -10,13 +8,10 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.csv.*;
import org.junit.Test;
import vagabond.enums.PlacementMapDisplayStyle;
import vagabond.pieces.PlacementMap;
import vagabond.pieces.VM;
import vagabond.pieces.*;
import vagabond.singleton.VagabondSettings;
import vagabond.testing.PlacementMapExamples;
/**
* Helper class for reading and writing PlacementMaps
......@@ -29,6 +24,26 @@ public class PlacementMapFile {
*/
public static ArrayList<String> commentStrs = new ArrayList<String>(Arrays.asList("//", "#"));
public static PlacementMap arrangePlacementMap(Hashtable<Integer, ArrayList<VM>> flexiblePlacement) {
Integer numberOfMachines = flexiblePlacement.size();
Integer maxSlots = 0;
for (Integer mID : flexiblePlacement.keySet()) {
if (maxSlots < flexiblePlacement.get(mID).size()) {
maxSlots = flexiblePlacement.get(mID).size();
}
}
PlacementMap place = new PlacementMap(numberOfMachines, maxSlots);
for (Integer mID : flexiblePlacement.keySet()) {
for (VM vm : flexiblePlacement.get(mID)) {
place.addNewVMToMachine(vm, mID);
}
}
return place;
}
/**
* Reads in a placement map that can be written by hand or taken from the NOMAD edited test-cases or from
* PlacementMapFile::writePlacementMap(). All lines that start with one of the strings from
......@@ -105,14 +120,6 @@ public class PlacementMapFile {
return place;
}
@Test
public void testReadPlacementMap() throws IOException {
PlacementMap pTest = readPlacementMap("tests/nomadSubOptimalRCPlacement.csv");
PlacementMap pControl = PlacementMapExamples.nomadSubOptimalRCPlacement();
assertTrue(pControl.equals(pTest));
}
/**
* Will write a placement map to the file 'filename', it will create the file and folders if needed.
* BEWARE: this function will APPEND to files, thus making it hard to read the PlacementMap back in
......@@ -144,4 +151,88 @@ public class PlacementMapFile {
return success;
}
public static EpochHistory readEpochHistory(File input) throws IOException {
Logger logger = VagabondSettings.getInstance().getLogger();
if (!input.exists()) { throw new IOException(
"The filename given does not point to a file that exists! Filename = " + input.getAbsolutePath()); }
CSVParser parser = CSVParser.parse(input, Charset.defaultCharset(), CSVFormat.RFC4180);
// Machine ID => VMs
Hashtable<Integer, ArrayList<VM>> flexiblePlacement = new Hashtable<>();
Integer machineID;
Integer globalID;
Integer clientID;
Integer serviceID;
Integer currentEpoch = null;
ArrayList<VM> vms;
Hashtable<Integer, PlacementMap> outOfOrderPlacementMaps = new Hashtable<>();
for (CSVRecord record : parser) {
// SKIP THE HEADER IF IT HAS ONE
if (record.get(0).equals("Machine ID")) {
continue;
}
// The start of a new Placement Map
if (record.get(0).equals("Epoch")) {
if (currentEpoch != null) {
if (outOfOrderPlacementMaps.get(currentEpoch) != null) { throw new IllegalArgumentException(
"Two placement maps have the same Epoch Number! " + "epochNumber=" + currentEpoch); }
if (logger.isLoggable(Level.FINE)) {
logger.fine("flexiblePlacement: " + flexiblePlacement);
}
PlacementMap place = arrangePlacementMap(flexiblePlacement);
outOfOrderPlacementMaps.put(currentEpoch, place);
flexiblePlacement.clear();
}
currentEpoch = Integer.decode(record.get(1));
continue;
}
// Error Checking
if (currentEpoch == null) { throw new IllegalArgumentException(
"Before a Placement Map starts you need to have a line: \"Epoch,epochNumber\""); }
if (record.size() != 4) { throw new IllegalArgumentException(
"Record is not formatted in the proper CSV format!"); }
// Decode the VM information
machineID = Integer.decode(record.get(0));
globalID = Integer.decode(record.get(1));
clientID = Integer.decode(record.get(2));
serviceID = Integer.decode(record.get(3));
vms = flexiblePlacement.getOrDefault(machineID, new ArrayList<VM>());
vms.add(new VM(clientID, serviceID, globalID));
flexiblePlacement.put(machineID, vms);
}
// Add the last placement map
if (logger.isLoggable(Level.FINE)) {
logger.fine("flexiblePlacement: " + flexiblePlacement);
}
PlacementMap place = arrangePlacementMap(flexiblePlacement);
outOfOrderPlacementMaps.put(currentEpoch, place);
flexiblePlacement.clear();
EpochHistory eh = new EpochHistory(outOfOrderPlacementMaps.size());
PlacementMap tmp = null;
for (int i = outOfOrderPlacementMaps.size() - 1; i >= 0; i--) {
tmp = outOfOrderPlacementMaps.get(i);
if (tmp == null) { throw new IllegalArgumentException("Missing the Epoch: " + i); }
eh.add(tmp);
}
// Update the settings file
VagabondSettings s = VagabondSettings.getInstance();
s.numberOfClients = tmp.getNumberOfClients();
s.numberOfMachines = tmp.getNumberOfMachines();
s.numberOfMachineSlots = tmp.getMaxNumberOfSlotsPerMachine();
s.numberOfVMsPerClient = tmp.getMaxNumberOfVMsPerClient();
return eh;
}
}
......@@ -23,6 +23,7 @@ public class ReduceToNomad implements ReduceTo {
public File nomadProgram;
public File nomadSettings;
public File nomadPlacement;
public File nomadResultsFile;
public ReduceToNomad() {
settings = VagabondSettings.getInstance();
......@@ -32,6 +33,7 @@ public class ReduceToNomad implements ReduceTo {
nomadProgram = settings.getNomadExceutable();
nomadSettings = settings.getNomadSettingsFile();
nomadPlacement = settings.getNomadPlacementFile();
nomadResultsFile = settings.getNomadResultsFile();
}
@Override
......@@ -70,12 +72,16 @@ public class ReduceToNomad implements ReduceTo {
fws.write("numVMRequest=" + place.getMaxNumberOfVMsPerClient() + "\n");
fws.write("PlacementMap=" + nomadPlacement.getName() + "\n");
fws.write("\n# You can ignore the lines below\n");
if (settings.randomSeed == -1) {
fws.write("SEED=10\n");
} else {
fws.write("SEED=" + settings.randomSeed + "\n");
}
fws.write("<R,C>_Mode=1\n");
fws.write("percentInsert=0\n");
fws.write("<R,C>_Mode=0\n");
fws.write("Greedy=1\n");
fws.write("numRun=1\n");
fws.write("Opensys=0\n");
fws.write("SEED=10\n");
fws.close();
/*TIMING*/timing.toggleTimer(tp + "ReduceToNomad::reduce::writeSettingsFile");
......
package vagabond.reduction.nomad;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import vagabond.pieces.EpochHistory;
import vagabond.placement.PlacementMapFile;
import vagabond.reduction.ReduceTo;
import vagabond.reduction.RunSolver;
import vagabond.singleton.VagabondSettings;
import vagabond.timing.TimingManager;
public class RunSolverNomad implements RunSolver {
public static VagabondSettings settings;
public static Logger logger;
public static TimingManager timing;
public String tp = "Epoch_Unknown";
public ReduceToNomad rt;
public RunSolverNomad() {
settings = VagabondSettings.getInstance();
logger = settings.getLogger();
timing = settings.timing;
}
@Override
public void setTimerKeyPrefix(String keyPrefix) {
......@@ -14,20 +32,68 @@ public class RunSolverNomad implements RunSolver {
@Override
public boolean load(ReduceTo r) {
// TODO Auto-generated method stub
rt = (ReduceToNomad) r;
if (rt.nomadPlacement.exists() && rt.nomadSettings.exists()) { return true; }
return false;
}
@Override
public boolean checkIfSolverIsReachable() {
// TODO Auto-generated method stub
return false;
return settings.getNomadExceutable().exists();
}
@Override
public EpochHistory run() {
// TODO Auto-generated method stub
return null;
public EpochHistory run() throws IOException, InterruptedException {
if (!checkIfSolverIsReachable()) { throw new IOException(
"Nomad Executable not found! Should be here: " + rt.nomadProgram.getAbsolutePath()); }
/*TIMING*/timing.toggleTimer(tp + "RunSolverNomad::run::totalTime");
// Delete any old results file
if (rt.nomadResultsFile.exists()) {
if (!rt.nomadResultsFile.delete()) { throw new IOException(
"Could not delete the previous Nomad results! Please delete them manually."); }
}
/*TIMING*/timing.toggleTimer(tp + "RunSolverNomad::run::start()");
ProcessBuilder pb = new ProcessBuilder(rt.nomadProgram.getAbsolutePath());
pb.directory(rt.nomadProgram.getParentFile());
Process process = pb.start();
logger.info("Running Nomad: " + pb.command() + " in the folder:" + pb.directory().getAbsolutePath());
int success;
if (settings.numberOfSecondsSolverCanRunPerEpoch > 0) {
process.waitFor(settings.numberOfSecondsSolverCanRunPerEpoch, TimeUnit.SECONDS);
success = process.exitValue();
} else {
success = process.waitFor();
}
/*TIMING*/timing.toggleTimer(tp + "RunSolverNomad::run::start()");
if (success == 0) {
// Check to make sure that the Results file was created
if (!rt.nomadResultsFile.exists()) {
/*TIMING*/timing.cancelTimer(tp + "RunSolverNomad::run::totalTime");
logger.severe("ProcessBuilder: " + pb);
logger.severe("Process: " + process);
throw new IOException("Nomad did not produce any results file! It should be located here: "
+ rt.nomadResultsFile.getAbsolutePath());
}
/*TIMING*/timing.toggleTimer(tp + "RunSolverNomad::run::readEpochHistory");
EpochHistory eh = PlacementMapFile.readEpochHistory(rt.nomadResultsFile);
/*TIMING*/timing.toggleTimer(tp + "RunSolverNomad::run::readEpochHistory");
/*TIMING*/timing.toggleTimer(tp + "RunSolverNomad::run::totalTime");
return eh;
} else {
process.destroyForcibly();
/*TIMING*/timing.cancelTimer(tp + "RunSolverNomad::run::totalTime");
throw new IOException("Nomad exited with an exit value of " + success);
}
}
}
......@@ -4,8 +4,7 @@ import java.io.FileWriter;
import java.io.IOException;
import vagabond.enums.PlacementMapDisplayStyle;
import vagabond.pieces.ClientToClientInformationLeakage;
import vagabond.pieces.PlacementMap;
import vagabond.pieces.*;
import vagabond.singleton.VagabondSettings;
public class ResultsManager {
......@@ -17,6 +16,8 @@ public class ResultsManager {
public ClientToClientInformationLeakage initialCCIL = null;
public ClientToClientInformationLeakage finalCCIL = null;
public EpochHistory eh = null;
public boolean writeOut(String filePath) throws IOException {
boolean result = true;
......@@ -25,7 +26,7 @@ public class ResultsManager {
FileWriter fw = new FileWriter(filePath);
fw.write("Settings:\n");
fw.write(settings.toString().replace(", ", "\n"));
fw.write(settings.toString().replace(", ", "\n").replace("{", "{\n"));
fw.write(separator);
......@@ -35,6 +36,8 @@ public class ResultsManager {
fw.write(separator);
fw.write("Initial Client-To-Client Information Leakage:\n");
fw.write("Max Information Leak of: " + initialCCIL.getMaxInformationLeak() + "\n");
fw.write("Sum Information Leak of: " + initialCCIL.getSumInformationLeak() + "\n");
fw.write(initialCCIL.getFormatString(PlacementMapDisplayStyle.VAGABOND, 0));
fw.write(separator);
......@@ -45,8 +48,19 @@ public class ResultsManager {
fw.write(separator);
fw.write("Final Client-To-Client Information Leakage:\n");
fw.write("Max Information Leak of: " + finalCCIL.getMaxInformationLeak() + "\n");
fw.write("Sum Information Leak of: " + finalCCIL.getSumInformationLeak() + "\n");
fw.write(finalCCIL.getFormatString(PlacementMapDisplayStyle.VAGABOND, 0));
fw.write(separator);
fw.write("Summation of Client-To-Client Information Leakage over a Sliding Window of " + eh.size() + "\n");
fw.write("Max Information Leak of: " + eh._sumOfInformationLeakage.getMaxInformationLeak() + "\n");
fw.write("Do Nothing Max Information Leak of: " + (eh.size() * initialCCIL.getMaxInformationLeak()) + "\n");
fw.write("Sum Information Leak of: " + eh._sumOfInformationLeakage.getSumInformationLeak() + "\n");
fw.write("Do Nothing sum Information Leak of: " + (eh.size() * initialCCIL.getSumInformationLeak()) + "\n");
fw.write(eh._sumOfInformationLeakage.getFormatString(PlacementMapDisplayStyle.VAGABOND, 0));
fw.close();
return result;
......
......@@ -90,15 +90,15 @@ public class VagabondSettings {
// ################################################################
// PROGRAMS
/**
* Filename of the Nomad executable;
* Filename of the CNF Solver executable;
* can change this if you are on Linux/Mac to the binary compiled for that system.
*/
public String nomadProgram = "nomad.exe";
public String cnfSolverProgram = "lingeling.exe";
/**
* Filename of the CNF Solver executable;
* Filename of the Nomad executable;
* can change this if you are on Linux/Mac to the binary compiled for that system.
*/
public String cnfSolverProgram = "lingeling.exe";
public String nomadProgram = "nomad.exe";
/**
* Holds the specific filename of the settings.ini file that Nomad is expecting
* @see #getNomadSettingsFile()
......@@ -110,6 +110,12 @@ public class VagabondSettings {
* @see VagabondSettings#getNomadPlacementFile()
*/
public String nomadPlacementFile = "inputPlacement.txt";
/**
* Holds the specific filename of the output placement map history file that Nomad produces; must be referenced in
* the {@link #getNomadResultsFile()} file.
* @see VagabondSettings#getNomadPlacementFile()
*/
public String nomadResultsFile = "placementMapHistory.csv";
// ################################################################
// LOGGING
......@@ -222,6 +228,11 @@ public class VagabondSettings {
* @vagabond.category ILP Optimization Parameter
*/
public double relativeMIPGapTolerance = 1e-3;
/**
* The number of seconds that a reduction solver can run per EPOCH before it is forced to stop.
* The default is 0 (less than 1) which means that it can run indefinitely.
*/
public long numberOfSecondsSolverCanRunPerEpoch = 0;
// ################################################################
// FUNCTIONS
......@@ -408,6 +419,14 @@ public class VagabondSettings {
return new File(programFolder + File.separator + nomadFolder + File.separator + nomadProgram);
}
/**
* Function to return the file path of the nomad executable
* @return File object to the Nomad executable
*/
public File getNomadResultsFile() {
return new File(programFolder + File.separator + nomadFolder + File.separator + nomadResultsFile);
}
/**
* Function to return the file path of the CNF Solver executable; by default it is Lingeling.
* @return File object to the CNF Solver executable
......
package vagabond.testing;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import org.junit.Test;
import vagabond.pieces.EpochHistory;
import vagabond.pieces.PlacementMap;
import vagabond.placement.PlacementMapFile;
public class PlacementMapFileTests {
@Test
public void testReadEpochHistory() throws IOException {
EpochHistory eh = PlacementMapFile.readEpochHistory(new File("tests/placementMapHistory.csv"));
PlacementMap pControl = PlacementMapExamples.nomadSubOptimalRCPlacement();
assertEquals(5, eh.size());
assertTrue(pControl.equals(eh._latestPlacementMap));
}
@Test
public void testReadPlacementMap() throws IOException {
PlacementMap pTest = PlacementMapFile.readPlacementMap("tests/nomadSubOptimalRCPlacement.csv");
PlacementMap pControl = PlacementMapExamples.nomadSubOptimalRCPlacement();
assertTrue(pControl.equals(pTest));
}
}
Machine ID,Global ID,Client ID,Service ID
0,1,0,0
0,2,0,1
0,3,3,0
1,4,1,0
1,5,1,1
1,6,3,1
2,7,2,0
2,8,2,1
2,9,3,2
\ No newline at end of file
0,0,0,0
0,1,0,1
0,2,3,0
1,3,1,0
1,4,1,1
1,5,3,1
2,6,2,0
2,7,2,1
2,8,3,2
\ No newline at end of file