Skip to content

Commit

Permalink
Merge pull request #41 from johannes-manner/simulation
Browse files Browse the repository at this point in the history
Add concurrent container simulation
  • Loading branch information
johannes-manner authored Mar 14, 2019
2 parents 660268e + 37f9bf5 commit 1d15f75
Show file tree
Hide file tree
Showing 8 changed files with 571 additions and 1 deletion.
78 changes: 78 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,83 @@ performanceData/
logs/
setups/
benchmarkSetting/
simulation/*.csv


# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
.idea/*.xml
# *.ipr

# Sonarlint plugin
.idea/sonarlint

# End of https://www.gitignore.io/api/intellij
# End of https://www.gitignore.io/api/git,java,gradle,eclipse
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.uniba.dsg.serverless.cli.performance.AzurePerformanceDataUtility;
import de.uniba.dsg.serverless.cli.performance.GooglePerformanceDataUtility;
import de.uniba.dsg.serverless.cli.performance.IBMOpenWhiskPerformanceDataUtility;
import de.uniba.dsg.serverless.simulation.load.SimulationUtility;

public class UtilityFactory {

Expand All @@ -25,7 +26,10 @@ public class UtilityFactory {
new DeploymentSizeUtility("deploymentSize"),

// automated test generation
new SeMoDeUtility("awsSeMoDe")
new SeMoDeUtility("awsSeMoDe"),

// simulation
new SimulationUtility("loadSimulation")
);

public static Optional<CustomUtility> getUtilityClass(String name) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package de.uniba.dsg.serverless.simulation.load;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.uniba.dsg.serverless.model.SeMoDeException;

public class LoadPatternInterpreter {

private final Path file;

public LoadPatternInterpreter(Path file) {
super();
this.file = file;
}

// TODO configure the interval for the load interpretation phase, currently
// based on seconds
public Map<Integer, Integer> interpretLoadPattern() throws SeMoDeException {

List<String> lines = this.readAllLines(file);
Map<Integer, Integer> numberOfRequestPerSecond = this.generateDistribution(lines);

return numberOfRequestPerSecond;
}

public List<Double> getDoubleValues() throws SeMoDeException {
List<String> lines = this.readAllLines(file);
List<Double> values = new ArrayList<>();

for (String line : lines) {
try {
values.add(Double.parseDouble(line));
} catch (NumberFormatException e) {
throw new SeMoDeException("Load pattern file was corrupted. Line: " + line, e);
}
}

return values;
}

private Map<Integer, Integer> generateDistribution(List<String> lines) throws SeMoDeException {
Map<Integer, Integer> distributionMap = new HashMap<>();
for (Double doubleValue : this.getDoubleValues()) {

// converts the double to the second before the comma
int intValue = (int) doubleValue.doubleValue();
if (!distributionMap.containsKey(intValue)) {
distributionMap.put(intValue, 0);
}
distributionMap.put(intValue, distributionMap.get(intValue) + 1);
}

return distributionMap;
}

private List<String> readAllLines(Path file) throws SeMoDeException {
try {
List<String> lines = Files.readAllLines(file);
return lines;
} catch (IOException e) {
throw new SeMoDeException(e.getMessage(), e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package de.uniba.dsg.serverless.simulation.load;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.uniba.dsg.serverless.simulation.load.model.ContainerInstance;
import de.uniba.dsg.serverless.simulation.load.model.SimulationInput;

public class LoadPatternSimulator {

private static final Logger logger = LogManager.getLogger(LoadPatternSimulator.class);

private final List<Double> inputValues;

public LoadPatternSimulator(List<Double> inputValues) {
this.inputValues = inputValues;
}

public Map<Integer, Integer> simulate(SimulationInput simulationValues) {

SimulationStep simulation = new SimulationStep(simulationValues);

for (Double timestamp : inputValues) {

// checks all running container, if they are finished, moving them to idle containers
simulation.checkFinishedContainers(timestamp);

// checks all idle container, if they are longer idle than the assumed shutdown period
simulation.shutdownIdleContainer(timestamp);

// check, if a container is idle
ContainerInstance container;
if (simulation.idleContainerAvailable()) {
// pick the first idle container and serve the request
container = simulation.getArbitraryIdleContainer();
container.executeRequest(timestamp, simulationValues);
} else {
// create a new container, add them to the simulation
container = simulation.addNewContainer(timestamp);
container.executeRequestWithColdStart(timestamp, simulationValues);
}
simulation.addToExecuting(container);

logger.info(container);
}

// shutdown all containers (idle and running)
simulation.shutdownAllContainer();

// compute the distribution map
return simulation.getContainerDistribution();
}
}

class SimulationStep {

private final List<ContainerInstance> containerList;
private final List<ContainerInstance> executingContainers;
private final List<ContainerInstance> idleContainers;
private final SimulationInput simulationValues;

public SimulationStep(SimulationInput simulationValues) {
this.containerList = new ArrayList<>();
this.executingContainers = new ArrayList<>();
this.idleContainers = new ArrayList<>();
this.simulationValues = simulationValues;
}

public boolean idleContainerAvailable() {
return !idleContainers.isEmpty();
}

public ContainerInstance getArbitraryIdleContainer() {
ContainerInstance temp = idleContainers.get(0);
this.idleContainers.remove(temp);
return temp;
}

public ContainerInstance addNewContainer(double ongoingTime) {
ContainerInstance temp = new ContainerInstance(ongoingTime);
this.containerList.add(temp);
return temp;
}

public void addToExecuting(ContainerInstance container) {
this.executingContainers.add(container);
}

/**
* Checks if some executing containers are finished and move them to the idle
* list.
*/
public void checkFinishedContainers(double ongoingTime) {

List<ContainerInstance> finishedContainers = this.executingContainers.stream()
.filter((c) -> c.getBussyUntil() < ongoingTime).collect(Collectors.toList());

for (ContainerInstance container : finishedContainers) {

this.executingContainers.remove(container);
this.idleContainers.add(container);

}
}

/**
* @param timestamp
*/
public void shutdownIdleContainer(double timestamp) {

double shutdownTime = this.simulationValues.getShutdownAfter();

List<ContainerInstance> containerForShutdown = this.idleContainers.stream()
.filter((c) -> c.getBussyUntil() < (timestamp - shutdownTime)).collect(Collectors.toList());

for (ContainerInstance container : containerForShutdown) {
container.setShutdownTime(container.getBussyUntil() + shutdownTime);
this.idleContainers.remove(container);
}
}

public void shutdownAllContainer() {

double shutdownTime = this.simulationValues.getShutdownAfter();

for (ContainerInstance container : this.executingContainers) {
container.setShutdownTime(container.getBussyUntil() + shutdownTime);
}

for (ContainerInstance container : this.idleContainers) {
container.setShutdownTime(container.getBussyUntil() + shutdownTime);
}

}

public Map<Integer, Integer> getContainerDistribution() {

Map<Integer, Integer> containerDistribution = new HashMap<>();

// max value for bussy until to get the size of the array (performance reasons)
double maxBussyUntil = 0.0;
for (ContainerInstance container : this.containerList) {
if (maxBussyUntil < container.getBussyUntil()) {
maxBussyUntil = container.getBussyUntil();
}
}

// 0 to 5.2 (maxBussyUntil) means 6 values in the array
int size = (int) maxBussyUntil + 1;
int[] containerDistributionInt = new int[size];

for (int i = 0; i < size; i++) {
containerDistributionInt[i] = 0;
}

for (ContainerInstance container : this.containerList) {
for (int i = (int) container.getStartTime(); i <= (int) container.getBussyUntil(); i++) {
containerDistributionInt[i]++;
}
}

for (int i = 0; i < size; i++) {
containerDistribution.put(i, containerDistributionInt[i]);
}

return containerDistribution;
}
}
Loading

0 comments on commit 1d15f75

Please sign in to comment.