Skip to content
Snippets Groups Projects
Commit 7b4e64df authored by Marcel Samir Becker's avatar Marcel Samir Becker
Browse files

Simplified Results, added optimalInstances map and expanded Result tests

parent 7aed1e45
No related branches found
No related tags found
1 merge request!215Redesign Strategy, Load, and Resources data types
This commit is part of merge request !215. Comments created here will be created in the context of that merge request.
...@@ -149,7 +149,7 @@ class TheodoliteExecutor( ...@@ -149,7 +149,7 @@ class TheodoliteExecutor(
} }
private fun calculateDemandMetric(loads: List<Int>, results: Results): List<List<String>> { private fun calculateDemandMetric(loads: List<Int>, results: Results): List<List<String>> {
return loads.map { listOf(it.toString(), results.getMinRequiredYDimensionValue(it).toString()) } return loads.map { listOf(it.toString(), results.getOptYDimensionValue(it).toString()) }
} }
} }
...@@ -12,8 +12,8 @@ class LowerBoundRestriction(results: Results) : RestrictionStrategy(results) { ...@@ -12,8 +12,8 @@ class LowerBoundRestriction(results: Results) : RestrictionStrategy(results) {
override fun apply(xValue: Int, yValues: List<Int>): List<Int> { override fun apply(xValue: Int, yValues: List<Int>): List<Int> {
val maxXValue: Int? = this.results.getMaxBenchmarkedXDimensionValue(xValue) val maxXValue: Int? = this.results.getMaxBenchmarkedXDimensionValue(xValue)
var lowerBound: Int = this.results.getMinRequiredYDimensionValue(maxXValue) var lowerBound: Int? = this.results.getOptYDimensionValue(maxXValue)
if (lowerBound == Int.MIN_VALUE || lowerBound == Int.MAX_VALUE) { if (lowerBound == null) {
lowerBound = yValues[0] lowerBound = yValues[0]
} }
return yValues.filter { x -> x >= lowerBound } return yValues.filter { x -> x >= lowerBound }
......
...@@ -40,8 +40,7 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStra ...@@ -40,8 +40,7 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStra
// Getting the lastLowestResource from results and calling firstGuess() with it // Getting the lastLowestResource from results and calling firstGuess() with it
if (!results.isEmpty()) { if (!results.isEmpty()) {
val maxLoad: Int? = this.results.getMaxBenchmarkedXDimensionValue(load) val maxLoad: Int? = this.results.getMaxBenchmarkedXDimensionValue(load)
lastLowestResource = this.results.getMinRequiredYDimensionValue(maxLoad) lastLowestResource = this.results.getOptYDimensionValue(maxLoad)
if (lastLowestResource == Int.MAX_VALUE) lastLowestResource = null
} }
lastLowestResource = this.guessStrategy.firstGuess(resources, lastLowestResource) lastLowestResource = this.guessStrategy.firstGuess(resources, lastLowestResource)
...@@ -110,8 +109,7 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStra ...@@ -110,8 +109,7 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStra
// Getting the lastLowestLoad from results and calling firstGuess() with it // Getting the lastLowestLoad from results and calling firstGuess() with it
if (!results.isEmpty()) { if (!results.isEmpty()) {
val maxResource: Int? = this.results.getMaxBenchmarkedXDimensionValue(resource) val maxResource: Int? = this.results.getMaxBenchmarkedXDimensionValue(resource)
lastMaxLoad = this.results.getMaxRequiredYDimensionValue(maxResource) lastMaxLoad = this.results.getOptYDimensionValue(maxResource)
if (lastMaxLoad == Int.MIN_VALUE) lastMaxLoad = null
} }
lastMaxLoad = this.guessStrategy.firstGuess(loads, lastMaxLoad) lastMaxLoad = this.guessStrategy.firstGuess(loads, lastMaxLoad)
......
...@@ -9,27 +9,57 @@ import theodolite.strategies.Metric ...@@ -9,27 +9,57 @@ import theodolite.strategies.Metric
* perform the [theodolite.strategies.restriction.RestrictionStrategy]. * perform the [theodolite.strategies.restriction.RestrictionStrategy].
*/ */
@RegisterForReflection @RegisterForReflection
//TODO: Initializing überall anpassen
class Results (val metric: Metric) { class Results (val metric: Metric) {
//TODO: enum statt Boolean //TODO: enum statt Boolean für successful
// (load,resource) -> Boolean map
private val results: MutableMap<Pair<Int, Int>, Boolean> = mutableMapOf() private val results: MutableMap<Pair<Int, Int>, Boolean> = mutableMapOf()
//TODO: min instance (or max respectively) also as fields so we do not loop over results, speichert alle results für alle load/resource pairs // if metric is "demand" : load -> resource
// if metric is "capacity": resource -> load
private var optInstances: MutableMap<Int, Int> = mutableMapOf()
/** /**
* Set the result for an experiment. * Set the result for an experiment and update the [optInstances] list accordingly.
* *
* @param experiment A pair that identifies the experiment by the LoadDimension and Resource. * @param experiment A pair that identifies the experiment by the Load and Resource.
* @param successful the result of the experiment. Successful == true and Unsuccessful == false. * @param successful the result of the experiment. Successful == true and Unsuccessful == false.
*/ */
fun setResult(experiment: Pair<Int, Int>, successful: Boolean) { fun setResult(experiment: Pair<Int, Int>, successful: Boolean) {
this.results[experiment] = successful this.results[experiment] = successful
if(metric.value == "demand" && optInstances.containsKey(experiment.first)){
if (optInstances[experiment.first]!! > experiment.second){
optInstances[experiment.first] = experiment.second
}
}
else if(metric.value == "demand" && !optInstances.containsKey(experiment.first)){
if(!successful){
optInstances[experiment.first] = Int.MAX_VALUE
}else {
optInstances[experiment.first] = experiment.second
}
}
else if(metric.value == "capacity" && optInstances.containsKey(experiment.second)){
if (optInstances[experiment.second]!! < experiment.first){
optInstances[experiment.second] = experiment.first
}
}
else if(metric.value == "capacity" && !optInstances.containsKey(experiment.second)){
if(!successful){
optInstances[experiment.second] = Int.MIN_VALUE
} else {
optInstances[experiment.second] = experiment.first
}
}
} }
/** /**
* Get the result for an experiment. * Get the result for an experiment.
* *
* @param experiment A pair that identifies the experiment by the LoadDimension and Resource. * @param experiment A pair that identifies the experiment by the Load and Resource.
* @return true if the experiment was successful and false otherwise. If the result has not been reported so far, * @return true if the experiment was successful and false otherwise. If the result has not been reported so far,
* null is returned. * null is returned.
* *
...@@ -39,84 +69,48 @@ class Results (val metric: Metric) { ...@@ -39,84 +69,48 @@ class Results (val metric: Metric) {
} }
/** /**
* Get the smallest suitable number of instances for a specified LoadDimension. * Get the smallest suitable number of instances for a specified x-Value.
* The x-Value corresponds to the...
* - load, if the metric is "demand".
* - resource, if the metric is "capacity".
* *
* @param xValue the Value of the x-dimension of the current metric * @param xValue the Value of the x-dimension of the current metric
* *
* @return the smallest suitable number of resources/loads (depending on metric). * @return the smallest suitable number of resources/loads (depending on metric).
* If there is no experiment that has been executed yet, Int.MIN_VALUE is returned. * If there is no experiment that has been executed yet, there is no experiment
* If there is no experiment for the given [xValue] or there is none marked successful yet, * for the given [xValue] or there is none marked successful yet, null is returned.
* Int.MAX_VALUE is returned.
*/ */
fun getMinRequiredYDimensionValue(xValue: Int?): Int { fun getOptYDimensionValue(xValue: Int?): Int? {
if (this.results.isEmpty()) { //should add || xValue == null if (xValue != null) {
return Int.MIN_VALUE val res = optInstances[xValue]
} if (res != Int.MAX_VALUE && res != Int.MIN_VALUE) {
return res
var minRequiredYValue = Int.MAX_VALUE
for (experiment in results) {
// Get all successful experiments for requested xValue
if (getXDimensionValue(experiment.key) == xValue && experiment.value) {
val experimentYValue = getYDimensionValue(experiment.key)
if (experimentYValue < minRequiredYValue) {
// Found new smallest resources
minRequiredYValue = experimentYValue
}
} }
} }
return minRequiredYValue return null
} }
/** /**
* Get the largest y-Value for which the given x-Value has a positive experiment outcome. * Get the largest x-Value that has been tested and reported so far (successful or unsuccessful),
* x- and y-values depend on the metric in use. * which is smaller than the specified x-Value.
*
* @param xValue the Value of the x-dimension of the current metric
* *
* @return the largest suitable number of resources/loads (depending on metric). * The x-Value corresponds to the...
* If there wasn't any experiment executed yet, Int.MAX_VALUE is returned. * - load, if the metric is "demand".
* If the experiments for the specified [xValue] wasn't executed yet or the experiments were not successful * - resource, if the metric is "capacity".
* Int.MIN_VALUE is returned.
*/
fun getMaxRequiredYDimensionValue(xValue: Int?): Int {
if (this.results.isEmpty()) { //should add || xValue == null
return Int.MAX_VALUE
}
var maxRequiredYValue = Int.MIN_VALUE
for (experiment in results) {
// Get all successful experiments for requested xValue
if (getXDimensionValue(experiment.key) == xValue && experiment.value) {
val experimentYValue = getYDimensionValue(experiment.key)
if (experimentYValue > maxRequiredYValue) {
// Found new largest value
maxRequiredYValue = experimentYValue
}
}
}
return maxRequiredYValue
}
// TODO: SÖREN FRAGEN WARUM WIR DAS BRAUCHEN UND NICHT EINFACH PREV, WEIL NICHT DURCHGELAUFEN?
// TODO Kommentar zu XDimension und YDimension
/**
* Get the largest LoadDimension that has been reported executed successfully (or unsuccessfully) so far, for a
* LoadDimension and is smaller than the given LoadDimension.
* *
* @param load the LoadDimension * @param xValue the Value of the x-dimension of the current metric
* *
* @return the largest LoadDimension or null, if there is none for this LoadDimension * @return the largest tested x-Value or null, if there wasn't any tested which is smaller than the [xValue].
*/ */
fun getMaxBenchmarkedXDimensionValue(xValue: Int): Int? { fun getMaxBenchmarkedXDimensionValue(xValue: Int): Int? {
var maxBenchmarkedXValue: Int? = null var maxBenchmarkedXValue: Int? = null
for (experiment in results) { for (instance in optInstances) {
val experimentXValue = getXDimensionValue(experiment.key) val instanceXValue= instance.key
if (experimentXValue <= xValue) { //warum \leq? if (instanceXValue <= xValue) {
if (maxBenchmarkedXValue == null) { if (maxBenchmarkedXValue == null) {
maxBenchmarkedXValue = experimentXValue maxBenchmarkedXValue = instanceXValue
} else if (maxBenchmarkedXValue < experimentXValue) { } else if (maxBenchmarkedXValue < instanceXValue) {
maxBenchmarkedXValue = experimentXValue maxBenchmarkedXValue = instanceXValue
} }
} }
} }
...@@ -131,18 +125,4 @@ class Results (val metric: Metric) { ...@@ -131,18 +125,4 @@ class Results (val metric: Metric) {
fun isEmpty(): Boolean{ fun isEmpty(): Boolean{
return results.isEmpty() return results.isEmpty()
} }
fun getYDimensionValue(experimentKey: Pair<Int, Int>): Int{
if(metric.value == "demand"){
return experimentKey.second
}
return experimentKey.first
}
fun getXDimensionValue(experimentKey: Pair<Int, Int>): Int{
if(metric.value == "demand"){
return experimentKey.first
}
return experimentKey.second
}
} }
...@@ -63,7 +63,7 @@ internal class LowerBoundRestrictionTest { ...@@ -63,7 +63,7 @@ internal class LowerBoundRestrictionTest {
results.setResult(10000, 1, false) results.setResult(10000, 1, false)
results.setResult(20000, 2, true) results.setResult(20000, 2, true)
val minRequiredInstances = results.getMinRequiredYDimensionValue(20000) val minRequiredInstances = results.getOptYDimensionValue(20000)
assertNotNull(minRequiredInstances) assertNotNull(minRequiredInstances)
assertEquals(2, minRequiredInstances!!) assertEquals(2, minRequiredInstances!!)
...@@ -79,7 +79,7 @@ internal class LowerBoundRestrictionTest { ...@@ -79,7 +79,7 @@ internal class LowerBoundRestrictionTest {
results.setResult(10000, 1, false) results.setResult(10000, 1, false)
results.setResult(20000, 2, false) results.setResult(20000, 2, false)
val minRequiredInstances = results.getMinRequiredYDimensionValue(20000) val minRequiredInstances = results.getOptYDimensionValue(20000)
assertNotNull(minRequiredInstances) assertNotNull(minRequiredInstances)
assertEquals(2, minRequiredInstances!!) assertEquals(2, minRequiredInstances!!)
......
...@@ -11,60 +11,99 @@ import theodolite.strategies.Metric ...@@ -11,60 +11,99 @@ import theodolite.strategies.Metric
internal class ResultsTest { internal class ResultsTest {
@Test @Test
fun testMinRequiredInstancesWhenSuccessful() { fun testMinRequiredInstancesWhenSuccessfulDemand() {
val results = Results(Metric.from("demand")) val results = Results(Metric.from("demand"))
results.setResult(10000, 1, true) results.setResult(Pair(10000, 1), true)
results.setResult(10000, 2, true) results.setResult(Pair(10000, 2), true)
results.setResult(20000, 1, false) results.setResult(Pair(20000, 1), false)
results.setResult(20000, 2, true) results.setResult(Pair(20000, 2), true)
val minRequiredInstances = results.getMinRequiredYDimensionValue(20000) val minRequiredInstances = results.getOptYDimensionValue(20000)
assertNotNull(minRequiredInstances) assertNotNull(minRequiredInstances)
assertEquals(2, minRequiredInstances!!) assertEquals(2, minRequiredInstances)
} }
@Test @Test
@Disabled @Disabled
// TODO necessary?
fun testMinRequiredInstancesWhenNotSuccessful() { fun testMinRequiredInstancesWhenNotSuccessful() {
// This test is currently not implemented this way, but might later be the desired behavior. // This test is currently not implemented this way, but might later be the desired behavior.
val results = Results(Metric.from("demand")) val results = Results(Metric.from("demand"))
results.setResult(10000, 1, true) results.setResult(Pair(10000, 1), true)
results.setResult(10000, 2, true) results.setResult(Pair(10000, 2), true)
results.setResult(20000, 1, false) results.setResult(Pair(20000, 1), false)
results.setResult(20000, 2, false) results.setResult(Pair(20000, 2), false)
val minRequiredInstances = results.getMinRequiredYDimensionValue(20000) val minRequiredInstances = results.getOptYDimensionValue(20000)
assertNotNull(minRequiredInstances) assertNotNull(minRequiredInstances)
assertEquals(2, minRequiredInstances!!) assertEquals(2, minRequiredInstances!!)
} }
private fun Results.setResult(load: Int, resource: Int, successful: Boolean) {
this.setResult(Pair(load, resource), successful)
}
@Test @Test
fun testGetMaxBenchmarkedLoadWhenAllSuccessful() { fun testGetMaxBenchmarkedLoadWhenAllSuccessfulDemand() {
val results = Results(Metric.from("demand")) val results = Results(Metric.from("demand"))
results.setResult(10000, 1, true) results.setResult(Pair(10000, 1), true)
results.setResult(10000, 2, true) results.setResult(Pair(10000, 2), true)
val test1 = results.getMaxBenchmarkedXDimensionValue(100000)!! val test1 = results.getMaxBenchmarkedXDimensionValue(100000)
assertNotNull(test1)
assertEquals(10000, test1) assertEquals(10000, test1)
} }
@Test @Test
fun testGetMaxBenchmarkedLoadWhenLargestNotSuccessful() { fun testGetMaxBenchmarkedLoadWhenLargestNotSuccessfulDemand() {
val results = Results(Metric.from("demand")) val results = Results(Metric.from("demand"))
results.setResult(10000, 1, true) results.setResult(Pair(10000, 1), true)
results.setResult(10000, 2, true) results.setResult(Pair(10000, 2), true)
results.setResult(20000, 1, false) results.setResult(Pair(20000, 1), false)
val test2 = results.getMaxBenchmarkedXDimensionValue(100000)!! val test2 = results.getMaxBenchmarkedXDimensionValue(100000)
assertNotNull(test2)
assertEquals(20000, test2) assertEquals(20000, test2)
} }
@Test
fun testMaxRequiredInstancesWhenSuccessfulCapacity() {
val results = Results(Metric.from("capacity"))
results.setResult(Pair(10000, 1), true)
results.setResult(Pair(20000, 1), false)
results.setResult(Pair(10000, 2), true)
results.setResult(Pair(20000, 2), true)
val maxRequiredInstances = results.getOptYDimensionValue(2)
assertNotNull(maxRequiredInstances)
assertEquals(20000, maxRequiredInstances)
}
@Test
fun testGetMaxBenchmarkedLoadWhenAllSuccessfulCapacity() {
val results = Results(Metric.from("capacity"))
results.setResult(Pair(10000, 1), true)
results.setResult(Pair(10000, 2), true)
val test1 = results.getMaxBenchmarkedXDimensionValue(5)
assertNotNull(test1)
assertEquals(2, test1)
}
@Test
fun testGetMaxBenchmarkedLoadWhenLargestNotSuccessfulCapacity() {
val results = Results(Metric.from("capacity"))
results.setResult(Pair(10000, 1), true)
results.setResult(Pair(20000, 1), true)
results.setResult(Pair(10000, 2), false)
val test2 = results.getMaxBenchmarkedXDimensionValue(5)
assertNotNull(test2)
assertEquals(2, test2)
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment