Skip to content
Snippets Groups Projects
Commit 5470d9d0 authored by Marcel Samir Becker's avatar Marcel Samir Becker Committed by Sören Henning
Browse files

Using result object for InitialGuessSearchStrategy implementation

parent dd3b6173
Branches
Tags
1 merge request!210Add "Initial Guess" Search Strategy
Showing
with 58 additions and 48 deletions
......@@ -13,12 +13,7 @@ private val logger = KotlinLogging.logger {}
* @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
*/
class BinarySearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>,
lastLowestResource: Resource?): Resource? {
if (lastLowestResource != null) {
logger.info { "Running LinearSearch with a set lastLowestResource value doesn't make sense." }
}
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
val result = binarySearch(load, resources, 0, resources.size - 1)
if (result == -1) {
......
......@@ -20,8 +20,7 @@ class CompositeStrategy(
val restrictionStrategies: Set<RestrictionStrategy>
) : SearchStrategy(benchmarkExecutor) {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>,
lastLowestResource: Resource?): Resource? {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
var restrictedResources = resources.toList()
for (strategy in this.restrictionStrategies) {
restrictedResources = restrictedResources.intersect(strategy.apply(load, resources)).toList()
......
......@@ -17,11 +17,7 @@ private val logger = KotlinLogging.logger {}
*/
class FullSearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>,
lastLowestResource: Resource?): Resource? {
if (lastLowestResource != null) {
logger.info { "Running LinearSearch with a set lastLowestResource value doesn't make sense." }
}
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
var minimalSuitableResources: Resource? = null
for (res in resources) {
......
......@@ -2,6 +2,7 @@ package theodolite.strategies.searchstrategy
import io.quarkus.runtime.annotations.RegisterForReflection
import theodolite.util.Resource
import theodolite.util.Results
/**
* Base class for the implementation of Guess strategies. Guess strategies are strategies to determine the resource
......
......@@ -4,6 +4,7 @@ import mu.KotlinLogging
import theodolite.execution.BenchmarkExecutor
import theodolite.util.LoadDimension
import theodolite.util.Resource
import theodolite.util.Results
private val logger = KotlinLogging.logger {}
......@@ -14,31 +15,51 @@ private val logger = KotlinLogging.logger {}
* @param benchmarkExecutor Benchmark executor which runs the individual benchmarks.
* @param guessStrategy Strategy that provides us with a guess for the first resource amount.
*/
class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStrategy: GuessStrategy) : SearchStrategy(benchmarkExecutor, guessStrategy) {
class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor, guessStrategy: GuessStrategy, results: Results) :
SearchStrategy(benchmarkExecutor, guessStrategy, results) {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>, lastLowestResource: Resource?): Resource? {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
if(resources.isEmpty()) {
logger.info { "You need to specify resources to be checked for the InitialGuessSearchStrategy to work." }
return null
}
if(guessStrategy == null){
logger.info { "Your InitialGuessSearchStrategy doesn't have a GuessStrategy. This is not supported." }
return null
}
var lastLowestResourceToUse = this.guessStrategy.firstGuess(resources, lastLowestResource)
if(results == null){
logger.info { "The results need to be initialized." }
return null
}
var lastLowestResource : Resource? = null
// Getting the lastLowestResource from results and calling firstGuess() with it
if (!results.isEmpty()) {
val maxLoad: LoadDimension? = this.results.getMaxBenchmarkedLoad(load)
lastLowestResource = this.results.getMinRequiredInstances(maxLoad)
if (lastLowestResource.get() == Int.MAX_VALUE) lastLowestResource = null
}
lastLowestResource = this.guessStrategy.firstGuess(resources, lastLowestResource)
if (lastLowestResourceToUse != null) {
if (lastLowestResource != null) {
val resourcesToCheck: List<Resource>
val startIndex: Int = resources.indexOf(lastLowestResourceToUse)
val startIndex: Int = resources.indexOf(lastLowestResource)
logger.info { "Running experiment with load '${load.get()}' and resources '${lastLowestResourceToUse.get()}'" }
logger.info { "Running experiment with load '${load.get()}' and resources '${lastLowestResource.get()}'" }
// If the first experiment passes, starting downward linear search
// otherwise starting upward linear search
if (this.benchmarkExecutor.runExperiment(load, lastLowestResourceToUse)) {
if (this.benchmarkExecutor.runExperiment(load, lastLowestResource)) {
resourcesToCheck = resources.subList(0, startIndex).reversed()
if (resourcesToCheck.isEmpty()) return lastLowestResourceToUse
if (resourcesToCheck.isEmpty()) return lastLowestResource
var currentMin: Resource = lastLowestResourceToUse
var currentMin: Resource = lastLowestResource
for (res in resourcesToCheck) {
logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" }
......
......@@ -14,11 +14,7 @@ private val logger = KotlinLogging.logger {}
*/
class LinearSearch(benchmarkExecutor: BenchmarkExecutor) : SearchStrategy(benchmarkExecutor) {
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>,
lastLowestResource: Resource?): Resource? {
if (lastLowestResource != null) {
logger.info { "Running LinearSearch with a set lastLowestResource value doesn't make sense." }
}
override fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource? {
for (res in resources) {
......
......@@ -4,6 +4,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection
import theodolite.execution.BenchmarkExecutor
import theodolite.util.LoadDimension
import theodolite.util.Resource
import theodolite.util.Results
/**
* Base class for the implementation for SearchStrategies. SearchStrategies determine the smallest suitable number of instances.
......@@ -12,7 +13,8 @@ import theodolite.util.Resource
* @param guessStrategy Guess strategy for the initial resource amount in case the InitialGuessStrategy is selected.
*/
@RegisterForReflection
abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor, val guessStrategy: GuessStrategy? = null) {
abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor, val guessStrategy: GuessStrategy? = null,
val results: Results? = null) {
/**
* Find smallest suitable resource from the specified resource list for the given load.
*
......@@ -22,5 +24,5 @@ abstract class SearchStrategy(val benchmarkExecutor: BenchmarkExecutor, val gues
*
* @return suitable resource for the specified load, or null if no suitable resource exists.
*/
abstract fun findSuitableResource(load: LoadDimension, resources: List<Resource>, lastLowestResource: Resource? = null): Resource?
abstract fun findSuitableResource(load: LoadDimension, resources: List<Resource>): Resource?
}
......@@ -3,7 +3,7 @@ package theodolite.util
import io.quarkus.runtime.annotations.RegisterForReflection
/**
* Central class that saves the state of a execution of Theodolite. For an execution, it is used to save the result of
* Central class that saves the state of an execution of Theodolite. For an execution, it is used to save the result of
* individual experiments. Further, it is used by the RestrictionStrategy to
* perform the [theodolite.strategies.restriction.RestrictionStrategy].
*/
......@@ -44,16 +44,16 @@ class Results {
* If no experiments have been marked as either successful or unsuccessful
* yet, a Resource with the constant value Int.MIN_VALUE is returned.
*/
fun getMinRequiredInstances(load: LoadDimension?): Resource? {
fun getMinRequiredInstances(load: LoadDimension?): Resource {
if (this.results.isEmpty()) {
return Resource(Int.MIN_VALUE, emptyList())
}
var minRequiredInstances: Resource? = Resource(Int.MAX_VALUE, emptyList())
var minRequiredInstances = Resource(Int.MAX_VALUE, emptyList())
for (experiment in results) {
// Get all successful experiments for requested load
if (experiment.key.first == load && experiment.value) {
if (minRequiredInstances == null || experiment.key.second.get() < minRequiredInstances.get()) {
if (experiment.key.second.get() < minRequiredInstances.get()) {
// Found new smallest resources
minRequiredInstances = experiment.key.second
}
......@@ -83,4 +83,13 @@ class Results {
}
return maxBenchmarkedLoad
}
/**
* Checks whether the results are empty.
*
* @return true if [results] is empty.
*/
fun isEmpty(): Boolean{
return results.isEmpty()
}
}
......@@ -34,24 +34,21 @@ class InitialGuessSearchStrategyTest {
val guessStrategy = PrevResourceMinGuess()
val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy)
val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy, results)
val actual: ArrayList<Resource?> = ArrayList()
val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 3, 4, 6).map { x -> Resource(x, emptyList()) })
expected.add(null)
var currentResource : Resource? = mockResources[0]
for (load in mockLoads) {
val returnVal : Resource? = strategy.findSuitableResource(load, mockResources, currentResource)
val returnVal : Resource? = strategy.findSuitableResource(load, mockResources)
if(returnVal != null) {
logger.info { "returnVal '${returnVal.get()}'" }
}
else {
logger.info { "returnVal is null." }
}
actual.add(returnVal)
currentResource = returnVal
}
assertEquals(actual, expected)
......@@ -75,24 +72,21 @@ class InitialGuessSearchStrategyTest {
val guessStrategy = PrevResourceMinGuess()
val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy)
val strategy = InitialGuessSearchStrategy(benchmarkExecutor,guessStrategy, results)
val actual: ArrayList<Resource?> = ArrayList()
val expected: ArrayList<Resource?> = ArrayList(listOf(0, 2, 2, 1, 4, 6).map { x -> Resource(x, emptyList()) })
expected.add(null)
var currentResource : Resource? = mockResources[0]
for (load in mockLoads) {
val returnVal : Resource? = strategy.findSuitableResource(load, mockResources, currentResource)
val returnVal : Resource? = strategy.findSuitableResource(load, mockResources)
if(returnVal != null) {
logger.info { "returnVal '${returnVal.get()}'" }
}
else {
logger.info { "returnVal is null." }
}
actual.add(returnVal)
currentResource = returnVal
}
assertEquals(actual, expected)
......@@ -116,25 +110,22 @@ class InitialGuessSearchStrategyTest {
val guessStrategy = PrevResourceMinGuess()
val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo()
val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5)
val strategy = InitialGuessSearchStrategy(benchmarkExecutor, guessStrategy)
val strategy = InitialGuessSearchStrategy(benchmarkExecutor, guessStrategy, results)
val actual: ArrayList<Resource?> = ArrayList()
var expected: ArrayList<Resource?> = ArrayList(listOf(2, 3, 0, 4, 6).map { x -> Resource(x, emptyList()) })
expected.add(null)
expected = ArrayList(listOf(null) + expected)
var currentResource : Resource? = mockResources[0]
for (load in mockLoads) {
val returnVal : Resource? = strategy.findSuitableResource(load, mockResources, currentResource)
val returnVal : Resource? = strategy.findSuitableResource(load, mockResources)
if(returnVal != null) {
logger.info { "returnVal '${returnVal.get()}'" }
}
else {
logger.info { "returnVal is null." }
}
actual.add(returnVal)
currentResource = returnVal
}
assertEquals(actual, expected)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment