diff --git a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt index 7efeea05d64471751cd5b3b08f21dbabccae0a76..44d6928d60c8a1fdac14dc18e641f85545edb3a8 100644 --- a/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt +++ b/theodolite/src/main/kotlin/theodolite/strategies/searchstrategy/InitialGuessSearchStrategy.kt @@ -8,7 +8,8 @@ import theodolite.util.Resource private val logger = KotlinLogging.logger {} /** - * Linear-search-like implementation for determining the smallest suitable number of instances. + * Search strategy implementation for determining the smallest suitable number of instances, which takes the + * resource demand of the previous load into account as a starting point for the search. * * @param benchmarkExecutor Benchmark executor which runs the individual benchmarks. */ @@ -16,18 +17,28 @@ class InitialGuessSearchStrategy(benchmarkExecutor: BenchmarkExecutor) : SearchS override fun findSuitableResource(load: LoadDimension, resources: List<Resource>, lastLowestResource: Resource?): Resource? { - if (lastLowestResource != null) { + var lastLowestResourceToUse = lastLowestResource + + // This Search strategy needs a resource demand to start the search with, + // if this is not provided it will be set to the first resource of the given resource-list + if(lastLowestResource == null && resources.isNotEmpty()){ + lastLowestResourceToUse = resources[0] + } + + if (lastLowestResourceToUse != null) { val resourcesToCheck: List<Resource> - val startIndex: Int = resources.indexOf(lastLowestResource) + val startIndex: Int = resources.indexOf(lastLowestResourceToUse) - logger.info { "Running experiment with load '${load.get()}' and resources '${lastLowestResource.get()}'" } + logger.info { "Running experiment with load '${load.get()}' and resources '${lastLowestResourceToUse.get()}'" } - if (this.benchmarkExecutor.runExperiment(load, lastLowestResource)) { + // If the first experiment passes, starting downward linear search + // otherwise starting upward linear search + if (this.benchmarkExecutor.runExperiment(load, lastLowestResourceToUse)) { resourcesToCheck = resources.subList(0, startIndex).reversed() - if(resourcesToCheck.isEmpty()) return lastLowestResource + if (resourcesToCheck.isEmpty()) return lastLowestResourceToUse - var currentMin : Resource = lastLowestResource + var currentMin: Resource = lastLowestResourceToUse for (res in resourcesToCheck) { logger.info { "Running experiment with load '${load.get()}' and resources '${res.get()}'" } diff --git a/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt b/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt index 1581730eb16d02187c47d0fe50b7d10e694049de..f90b96ee148a900aedf2925566f8383c379a68c9 100644 --- a/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt +++ b/theodolite/src/test/kotlin/theodolite/InitialGuessSearchStrategyTest.kt @@ -94,4 +94,45 @@ class InitialGuessSearchStrategyTest { assertEquals(actual, expected) } + + @Test + fun testEnd2EndInitialGuessSearchFirstNotDoable() { + val mockResults = arrayOf( + arrayOf(false, false, false, false, false, false, false), + arrayOf(false, false, true, true, true, true, true), + arrayOf(false, false, false, true, true, true, true), + arrayOf(true, true, true, true, true, true, true), + arrayOf(false, false, false, false, true, true, true), + arrayOf(false, false, false, false, false, false, true), + arrayOf(false, false, false, false, false, false, false) + ) + val mockLoads: List<LoadDimension> = (0..6).map { number -> LoadDimension(number, emptyList()) } + val mockResources: List<Resource> = (0..6).map { number -> Resource(number, emptyList()) } + val results = Results() + val benchmark = TestBenchmark() + val sloChecker: BenchmarkExecution.Slo = BenchmarkExecution.Slo() + val benchmarkExecutor = TestBenchmarkExecutorImpl(mockResults, benchmark, results, listOf(sloChecker), 0, 0, 5) + val strategy = InitialGuessSearchStrategy(benchmarkExecutor) + + 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) + if(returnVal != null) { + logger.info { "returnVal '${returnVal.get()}'" } + } + else { + logger.info { "returnVal is null." } + } + + actual.add(returnVal) + currentResource = returnVal + } + + assertEquals(actual, expected) + } } \ No newline at end of file