Commit 6f10cf51 authored by Jonathan Shahen's avatar Jonathan Shahen
Browse files

RunSolverNomad is complete; More information is in the results file; HOTFIX...

RunSolverNomad is complete; More information is in the results file; HOTFIX for random tests having the incorrect value for Clients
parent af1ae1ed
......@@ -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;
}
}
......@@ -33,7 +33,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
......@@ -92,7 +92,7 @@ public class PlacementMap {
* @return the VM ID
*/
public Integer getNextAvailableVMID() {
Integer out = _nextAvailableVMID;
int out = _nextAvailableVMID;
_nextAvailableVMID++;
return out;
}
......@@ -106,7 +106,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();
......@@ -323,6 +323,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
......
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
Machine ID,Global ID,Client ID,Service ID
Epoch,4
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
Epoch,3
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
Epoch,2
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
Epoch,1
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
Epoch,0
0,0,0,0
0,1,0,1
0,2,3,0
1,3,1,0
1,4,1,1