summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-09-28 16:21:09 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2022-10-03 17:35:59 +0200
commit4010d0cfb49bb8a0ffdb2c3ac26fc0c8417a0bbf (patch)
tree9f287e56e503a2b98472790c1a3373149af53d85
parentc453e27abe54221f76648bc91edadb2efcd1ec07 (diff)
feat(exp/faas): Add provisioners for FaaS service
This change adds a new module `opendc-experiments-faas` that provides provisioner implementations for experiments to use for setting up the FaaS service of OpenDC.
-rw-r--r--opendc-experiments/opendc-experiments-faas/build.gradle.kts (renamed from opendc-faas/opendc-faas-workload/build.gradle.kts)3
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSServiceProvisioningStep.kt71
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSSteps.kt51
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionSample.kt (renamed from opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionSample.kt)2
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionTrace.kt (renamed from opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionTrace.kt)2
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionTraceWorkload.kt (renamed from opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionTraceWorkload.kt)2
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/ServerlessTraceReader.kt (renamed from opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/ServerlessTraceReader.kt)2
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/TraceHelpers.kt71
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt (renamed from opendc-faas/opendc-faas-workload/src/test/kotlin/org/opendc/faas/workload/FaaSServiceHelperTest.kt)53
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/ServerlessTraceReaderTest.kt (renamed from opendc-faas/opendc-faas-workload/src/test/kotlin/org/opendc/faas/workload/ServerlessTraceReaderTest.kt)2
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/test/resources/trace/1.csv (renamed from opendc-faas/opendc-faas-workload/src/test/resources/trace/1.csv)0
-rw-r--r--opendc-experiments/opendc-experiments-faas/src/test/resources/trace/10.csv (renamed from opendc-faas/opendc-faas-workload/src/test/resources/trace/10.csv)0
-rw-r--r--opendc-faas/opendc-faas-service/src/main/kotlin/org/opendc/faas/service/deployer/FunctionDeployer.kt2
-rw-r--r--opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/SimFunctionDeployer.kt16
-rw-r--r--opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/workload/SimMetaFaaSWorkloadMapper.kt34
-rw-r--r--opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt5
-rw-r--r--opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FaaSServiceHelper.kt153
-rw-r--r--settings.gradle.kts2
18 files changed, 281 insertions, 190 deletions
diff --git a/opendc-faas/opendc-faas-workload/build.gradle.kts b/opendc-experiments/opendc-experiments-faas/build.gradle.kts
index 37c74d7e..8230c74d 100644
--- a/opendc-faas/opendc-faas-workload/build.gradle.kts
+++ b/opendc-experiments/opendc-experiments-faas/build.gradle.kts
@@ -25,9 +25,12 @@ description = "Support library for simulating FaaS workloads with OpenDC"
/* Build configuration */
plugins {
`kotlin-library-conventions`
+ `testing-conventions`
+ `jacoco-conventions`
}
dependencies {
+ api(projects.opendcExperiments.opendcExperimentsBase)
api(projects.opendcFaas.opendcFaasSimulator)
implementation(libs.kotlin.logging)
diff --git a/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSServiceProvisioningStep.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSServiceProvisioningStep.kt
new file mode 100644
index 00000000..d977042e
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSServiceProvisioningStep.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.experiments.faas
+
+import org.opendc.experiments.provisioner.ProvisioningContext
+import org.opendc.experiments.provisioner.ProvisioningStep
+import org.opendc.faas.service.FaaSService
+import org.opendc.faas.service.autoscaler.FunctionTerminationPolicy
+import org.opendc.faas.service.router.RoutingPolicy
+import org.opendc.faas.simulator.SimFunctionDeployer
+import org.opendc.faas.simulator.delay.ColdStartModel
+import org.opendc.faas.simulator.delay.StochasticDelayInjector
+import org.opendc.faas.simulator.delay.ZeroDelayInjector
+import org.opendc.simulator.compute.model.MachineModel
+import java.util.*
+
+/**
+ * A [ProvisioningStep] implementation for a [FaaSService].
+ *
+ * @param serviceDomain The domain name under which to register the compute service.
+ * @param routingPolicy The routing policy to use.
+ * @param terminationPolicy The function termination policy to use.
+ * @param machineModel The [MachineModel] that models the physical machine on which the functions run.
+ * @param coldStartModel The cold start models to test.
+ */
+public class FaaSServiceProvisioningStep internal constructor(
+ private val serviceDomain: String,
+ private val routingPolicy: (ProvisioningContext) -> RoutingPolicy,
+ private val terminationPolicy: (ProvisioningContext) -> FunctionTerminationPolicy,
+ private val machineModel: MachineModel,
+ private val coldStartModel: ColdStartModel?
+) : ProvisioningStep {
+ override fun apply(ctx: ProvisioningContext): AutoCloseable {
+ val delayInjector = if (coldStartModel != null)
+ StochasticDelayInjector(coldStartModel, Random(ctx.seeder.nextLong()))
+ else
+ ZeroDelayInjector
+ val deployer = SimFunctionDeployer(ctx.coroutineContext, ctx.clock, machineModel, delayInjector)
+ val service = FaaSService(
+ ctx.coroutineContext,
+ ctx.clock,
+ deployer,
+ routingPolicy(ctx),
+ terminationPolicy(ctx)
+ )
+
+ ctx.registry.register(serviceDomain, FaaSService::class.java, service)
+
+ return AutoCloseable { service.close() }
+ }
+}
diff --git a/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSSteps.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSSteps.kt
new file mode 100644
index 00000000..40e5627b
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FaaSSteps.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+@file:JvmName("FaaSSteps")
+package org.opendc.experiments.faas
+
+import org.opendc.experiments.provisioner.ProvisioningContext
+import org.opendc.experiments.provisioner.ProvisioningStep
+import org.opendc.faas.service.FaaSService
+import org.opendc.faas.service.autoscaler.FunctionTerminationPolicy
+import org.opendc.faas.service.router.RoutingPolicy
+import org.opendc.faas.simulator.delay.ColdStartModel
+import org.opendc.simulator.compute.model.MachineModel
+
+/**
+ * Return a [ProvisioningStep] that sets up a [FaaSService].
+ *
+ * @param serviceDomain The domain name under which to register the compute service.
+ * @param routingPolicy The routing policy to use.
+ * @param terminationPolicy The function termination policy to use.
+ * @param machineModel The [MachineModel] that models the physical machine on which the functions run.
+ * @param coldStartModel The cold start models to test.
+ */
+public fun setupFaaSService(
+ serviceDomain: String,
+ routingPolicy: (ProvisioningContext) -> RoutingPolicy,
+ terminationPolicy: (ProvisioningContext) -> FunctionTerminationPolicy,
+ machineModel: MachineModel,
+ coldStartModel: ColdStartModel? = null
+): ProvisioningStep {
+ return FaaSServiceProvisioningStep(serviceDomain, routingPolicy, terminationPolicy, machineModel, coldStartModel)
+}
diff --git a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionSample.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionSample.kt
index 418f895d..4ce2b136 100644
--- a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionSample.kt
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionSample.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.faas.workload
+package org.opendc.experiments.faas
/**
* A sample of a single function.
diff --git a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionTrace.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionTrace.kt
index 712267e5..5268811c 100644
--- a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionTrace.kt
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionTrace.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.faas.workload
+package org.opendc.experiments.faas
/**
* A trace for a single function
diff --git a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionTraceWorkload.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionTraceWorkload.kt
index cdb800c3..90e76dac 100644
--- a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FunctionTraceWorkload.kt
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/FunctionTraceWorkload.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.faas.workload
+package org.opendc.experiments.faas
import org.opendc.faas.simulator.workload.SimFaaSWorkload
import org.opendc.simulator.compute.workload.SimTrace
diff --git a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/ServerlessTraceReader.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/ServerlessTraceReader.kt
index 3694cf30..7b6b3ef7 100644
--- a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/ServerlessTraceReader.kt
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/ServerlessTraceReader.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.faas.workload
+package org.opendc.experiments.faas
import com.fasterxml.jackson.core.JsonToken
import com.fasterxml.jackson.dataformat.csv.CsvFactory
diff --git a/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/TraceHelpers.kt b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/TraceHelpers.kt
new file mode 100644
index 00000000..cf278606
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-faas/src/main/kotlin/org/opendc/experiments/faas/TraceHelpers.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+@file:JvmName("TraceHelpers")
+package org.opendc.experiments.faas
+
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import org.opendc.faas.service.FaaSService
+import java.time.Clock
+import kotlin.math.max
+
+/**
+ * Run a simulation of the [FaaSService] by replaying the workload trace given by [trace].
+ *
+ * @param clock A [Clock] instance tracking simulation time.
+ * @param trace The trace to simulate.
+ */
+public suspend fun FaaSService.replay(clock: Clock, trace: List<FunctionTrace>) {
+ val client = newClient()
+ try {
+ coroutineScope {
+ for (entry in trace) {
+ launch {
+ val workload = FunctionTraceWorkload(entry)
+ val function = client.newFunction(entry.id, entry.maxMemory.toLong(), meta = mapOf("workload" to workload))
+
+ var offset = Long.MIN_VALUE
+
+ for (sample in entry.samples) {
+ if (sample.invocations == 0) {
+ continue
+ }
+
+ if (offset < 0) {
+ offset = sample.timestamp - clock.millis()
+ }
+
+ delay(max(0, (sample.timestamp - offset) - clock.millis()))
+
+ repeat(sample.invocations) {
+ function.invoke()
+ }
+ }
+ }
+ }
+ }
+ } finally {
+ client.close()
+ }
+}
diff --git a/opendc-faas/opendc-faas-workload/src/test/kotlin/org/opendc/faas/workload/FaaSServiceHelperTest.kt b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt
index dbe024c0..98328d3e 100644
--- a/opendc-faas/opendc-faas-workload/src/test/kotlin/org/opendc/faas/workload/FaaSServiceHelperTest.kt
+++ b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/FaaSExperiment.kt
@@ -20,11 +20,13 @@
* SOFTWARE.
*/
-package org.opendc.faas.workload
+package org.opendc.experiments.faas
+import org.junit.jupiter.api.Assertions.assertAll
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertAll
+import org.opendc.experiments.provisioner.Provisioner
+import org.opendc.faas.service.FaaSService
import org.opendc.faas.service.autoscaler.FunctionTerminationPolicyFixed
import org.opendc.faas.service.router.RandomRoutingPolicy
import org.opendc.faas.simulator.delay.ColdStartModel
@@ -37,37 +39,40 @@ import java.io.File
import java.time.Duration
/**
- * Integration test suite for the [FaaSServiceHelper] class.
+ * Integration test to demonstrate a FaaS experiment.
*/
-class FaaSServiceHelperTest {
+class FaaSExperiment {
/**
* Smoke test that simulates a small trace.
*/
@Test
fun testSmoke() = runBlockingSimulation {
- val trace = ServerlessTraceReader().parse(File("src/test/resources/trace"))
- val runner = FaaSServiceHelper(
- coroutineContext,
- clock,
- createMachineModel(),
- RandomRoutingPolicy(),
- FunctionTerminationPolicyFixed(coroutineContext, clock, timeout = Duration.ofMinutes(10)),
- coldStartModel = ColdStartModel.GOOGLE
- )
+ val faasService = "faas.opendc.org"
- try {
- runner.run(trace)
- } finally {
- runner.close()
- }
+ Provisioner(coroutineContext, clock, seed = 0L).use { provisioner ->
+ provisioner.runStep(
+ setupFaaSService(
+ faasService,
+ { RandomRoutingPolicy() },
+ { FunctionTerminationPolicyFixed(it.coroutineContext, it.clock, timeout = Duration.ofMinutes(10)) },
+ createMachineModel(),
+ coldStartModel = ColdStartModel.GOOGLE
+ )
+ )
- val stats = runner.service.getSchedulerStats()
+ val service = provisioner.registry.resolve(faasService, FaaSService::class.java)!!
- assertAll(
- { assertEquals(14, stats.totalInvocations) },
- { assertEquals(2, stats.timelyInvocations) },
- { assertEquals(12, stats.delayedInvocations) },
- )
+ val trace = ServerlessTraceReader().parse(File("src/test/resources/trace"))
+ service.replay(clock, trace)
+
+ val stats = service.getSchedulerStats()
+
+ assertAll(
+ { assertEquals(14, stats.totalInvocations) },
+ { assertEquals(2, stats.timelyInvocations) },
+ { assertEquals(12, stats.delayedInvocations) },
+ )
+ }
}
/**
diff --git a/opendc-faas/opendc-faas-workload/src/test/kotlin/org/opendc/faas/workload/ServerlessTraceReaderTest.kt b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/ServerlessTraceReaderTest.kt
index e835d4d9..54071791 100644
--- a/opendc-faas/opendc-faas-workload/src/test/kotlin/org/opendc/faas/workload/ServerlessTraceReaderTest.kt
+++ b/opendc-experiments/opendc-experiments-faas/src/test/kotlin/org/opendc/experiments/faas/ServerlessTraceReaderTest.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.faas.workload
+package org.opendc.experiments.faas
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
diff --git a/opendc-faas/opendc-faas-workload/src/test/resources/trace/1.csv b/opendc-experiments/opendc-experiments-faas/src/test/resources/trace/1.csv
index 03a10d07..03a10d07 100644
--- a/opendc-faas/opendc-faas-workload/src/test/resources/trace/1.csv
+++ b/opendc-experiments/opendc-experiments-faas/src/test/resources/trace/1.csv
diff --git a/opendc-faas/opendc-faas-workload/src/test/resources/trace/10.csv b/opendc-experiments/opendc-experiments-faas/src/test/resources/trace/10.csv
index 0046b0e5..0046b0e5 100644
--- a/opendc-faas/opendc-faas-workload/src/test/resources/trace/10.csv
+++ b/opendc-experiments/opendc-experiments-faas/src/test/resources/trace/10.csv
diff --git a/opendc-faas/opendc-faas-service/src/main/kotlin/org/opendc/faas/service/deployer/FunctionDeployer.kt b/opendc-faas/opendc-faas-service/src/main/kotlin/org/opendc/faas/service/deployer/FunctionDeployer.kt
index 049f1cc7..18d16d06 100644
--- a/opendc-faas/opendc-faas-service/src/main/kotlin/org/opendc/faas/service/deployer/FunctionDeployer.kt
+++ b/opendc-faas/opendc-faas-service/src/main/kotlin/org/opendc/faas/service/deployer/FunctionDeployer.kt
@@ -28,7 +28,7 @@ import org.opendc.faas.service.FunctionObject
* A [FunctionDeployer] is responsible for ensuring that an instance of an arbitrary function, a [FunctionInstance],
* is deployed.
*
- * The function deployer should combines the configuration stored in the function registry, the parameters supplied by
+ * The function deployer should combine the configuration stored in the function registry, the parameters supplied by
* the requester, and other factors into a decision of how the function should be deployed, including how many and
* what kind of resources it should receive.
*
diff --git a/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/SimFunctionDeployer.kt b/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/SimFunctionDeployer.kt
index a3d0d34e..22131b13 100644
--- a/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/SimFunctionDeployer.kt
+++ b/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/SimFunctionDeployer.kt
@@ -31,6 +31,7 @@ import org.opendc.faas.service.deployer.FunctionInstanceListener
import org.opendc.faas.service.deployer.FunctionInstanceState
import org.opendc.faas.simulator.delay.DelayInjector
import org.opendc.faas.simulator.workload.SimFaaSWorkloadMapper
+import org.opendc.faas.simulator.workload.SimMetaFaaSWorkloadMapper
import org.opendc.simulator.compute.SimBareMetalMachine
import org.opendc.simulator.compute.SimMachine
import org.opendc.simulator.compute.model.MachineModel
@@ -41,6 +42,7 @@ import org.opendc.simulator.flow.FlowEngine
import java.time.Clock
import java.util.ArrayDeque
import kotlin.coroutines.Continuation
+import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
@@ -48,12 +50,16 @@ import kotlin.coroutines.resumeWithException
* A [FunctionDeployer] that uses that simulates the [FunctionInstance]s.
*/
public class SimFunctionDeployer(
+ context: CoroutineContext,
private val clock: Clock,
- private val scope: CoroutineScope,
private val model: MachineModel,
private val delayInjector: DelayInjector,
- private val mapper: SimFaaSWorkloadMapper
-) : FunctionDeployer {
+ private val mapper: SimFaaSWorkloadMapper = SimMetaFaaSWorkloadMapper()
+) : FunctionDeployer, AutoCloseable {
+ /**
+ * The [CoroutineScope] of this deployer.
+ */
+ private val scope = CoroutineScope(context + Job())
override fun deploy(function: FunctionObject, listener: FunctionInstanceListener): Instance {
val instance = Instance(function, listener)
@@ -172,6 +178,10 @@ public class SimFunctionDeployer(
}
}
+ override fun close() {
+ scope.cancel()
+ }
+
/**
* A function invocation request.
*/
diff --git a/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/workload/SimMetaFaaSWorkloadMapper.kt b/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/workload/SimMetaFaaSWorkloadMapper.kt
new file mode 100644
index 00000000..8da8bd19
--- /dev/null
+++ b/opendc-faas/opendc-faas-simulator/src/main/kotlin/org/opendc/faas/simulator/workload/SimMetaFaaSWorkloadMapper.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.faas.simulator.workload
+
+import org.opendc.faas.service.FunctionObject
+
+/**
+ * A [SimFaaSWorkloadMapper] that maps a [FunctionObject] to a workload via the meta-data.
+ */
+public class SimMetaFaaSWorkloadMapper(private val key: String = "workload") : SimFaaSWorkloadMapper {
+ override fun createWorkload(function: FunctionObject): SimFaaSWorkload {
+ return requireNotNull(function.meta[key]) as SimFaaSWorkload
+ }
+}
diff --git a/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt b/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt
index d528558c..5b730089 100644
--- a/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt
+++ b/opendc-faas/opendc-faas-simulator/src/test/kotlin/org/opendc/faas/simulator/SimFaaSServiceTest.kt
@@ -24,7 +24,6 @@ package org.opendc.faas.simulator
import io.mockk.coVerify
import io.mockk.spyk
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.yield
import org.junit.jupiter.api.Assertions.assertEquals
@@ -50,7 +49,6 @@ import java.util.*
/**
* A test suite for the [FaaSService] implementation under simulated conditions.
*/
-@OptIn(ExperimentalCoroutinesApi::class)
internal class SimFaaSServiceTest {
private lateinit var machineModel: MachineModel
@@ -75,7 +73,7 @@ internal class SimFaaSServiceTest {
})
val delayInjector = StochasticDelayInjector(ColdStartModel.GOOGLE, random)
- val deployer = SimFunctionDeployer(clock, this, machineModel, delayInjector) { workload }
+ val deployer = SimFunctionDeployer(coroutineContext, clock, machineModel, delayInjector) { workload }
val service = FaaSService(
coroutineContext,
clock,
@@ -91,6 +89,7 @@ internal class SimFaaSServiceTest {
delay(2000)
service.close()
+ deployer.close()
yield()
diff --git a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FaaSServiceHelper.kt b/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FaaSServiceHelper.kt
deleted file mode 100644
index ede6ac54..00000000
--- a/opendc-faas/opendc-faas-workload/src/main/kotlin/org/opendc/faas/workload/FaaSServiceHelper.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.faas.workload
-
-import kotlinx.coroutines.*
-import mu.KotlinLogging
-import org.opendc.faas.api.FaaSFunction
-import org.opendc.faas.service.FaaSService
-import org.opendc.faas.service.FunctionObject
-import org.opendc.faas.service.autoscaler.FunctionTerminationPolicy
-import org.opendc.faas.service.deployer.FunctionDeployer
-import org.opendc.faas.service.deployer.FunctionInstance
-import org.opendc.faas.service.deployer.FunctionInstanceListener
-import org.opendc.faas.service.router.RoutingPolicy
-import org.opendc.faas.simulator.SimFunctionDeployer
-import org.opendc.faas.simulator.delay.ColdStartModel
-import org.opendc.faas.simulator.delay.StochasticDelayInjector
-import org.opendc.faas.simulator.delay.ZeroDelayInjector
-import org.opendc.simulator.compute.model.MachineModel
-import java.time.Clock
-import java.util.*
-import kotlin.coroutines.CoroutineContext
-import kotlin.math.max
-
-/**
- * Helper class to simulate FaaS-based workloads in OpenDC.
- *
- * @param context A [CoroutineContext] to run the simulation in.
- * @param clock A [Clock] instance tracking simulation time.
- * @param machineModel The [MachineModel] that models the physical machine on which the functions run.
- * @param routingPolicy The routing policy to use.
- * @param terminationPolicy The function termination policy to use.
- * @param coldStartModel The cold start models to test.
- * @param seed The seed of the simulation.
- */
-public class FaaSServiceHelper(
- private val context: CoroutineContext,
- private val clock: Clock,
- private val machineModel: MachineModel,
- private val routingPolicy: RoutingPolicy,
- private val terminationPolicy: FunctionTerminationPolicy,
- private val coldStartModel: ColdStartModel? = null,
-) : AutoCloseable {
- /**
- * The scope of this helper.
- */
- private val scope = CoroutineScope(context + Job())
-
- /**
- * The logger for this class.
- */
- private val logger = KotlinLogging.logger {}
-
- /**
- * The simulated function deployer.
- */
- private val deployer = object : FunctionDeployer {
- override fun deploy(function: FunctionObject, listener: FunctionInstanceListener): FunctionInstance {
- val deployer = checkNotNull(_deployer)
- return deployer.deploy(function, listener)
- }
- }
- private var _deployer: SimFunctionDeployer? = null
-
- /**
- * The [FaaSService] created by the helper.
- */
- public val service: FaaSService = FaaSService(
- context,
- clock,
- deployer,
- routingPolicy,
- terminationPolicy
- )
-
- /**
- * Run a simulation of the [FaaSService] by replaying the workload trace given by [trace].
- *
- * @param trace The trace to simulate.
- * @param seed The seed for the simulation.
- * @param functions The functions that have been created by the runner.
- */
- public suspend fun run(trace: List<FunctionTrace>, seed: Long = 0, functions: MutableList<FaaSFunction>? = null) {
- // Set up the simulated deployer
- val delayInjector = if (coldStartModel != null)
- StochasticDelayInjector(coldStartModel, Random(seed))
- else
- ZeroDelayInjector
- val traceById = trace.associateBy { it.id }
- _deployer = SimFunctionDeployer(clock, scope, machineModel, delayInjector) {
- FunctionTraceWorkload(traceById.getValue(it.name))
- }
-
- val client = service.newClient()
- try {
- coroutineScope {
- for (entry in trace) {
- launch {
- val function = client.newFunction(entry.id, entry.maxMemory.toLong())
- functions?.add(function)
-
- var offset = Long.MIN_VALUE
-
- for (sample in entry.samples) {
- if (sample.invocations == 0) {
- continue
- }
-
- if (offset < 0) {
- offset = sample.timestamp - clock.millis()
- }
-
- delay(max(0, (sample.timestamp - offset) - clock.millis()))
-
- logger.info { "Invoking function ${entry.id} ${sample.invocations} times [${sample.timestamp}]" }
-
- repeat(sample.invocations) {
- function.invoke()
- }
- }
- }
- }
- }
- } finally {
- client.close()
- }
- }
-
- override fun close() {
- service.close()
- scope.cancel()
- }
-}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 92b1eaf3..0aeee160 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -31,10 +31,10 @@ include(":opendc-workflow:opendc-workflow-service")
include(":opendc-faas:opendc-faas-api")
include(":opendc-faas:opendc-faas-service")
include(":opendc-faas:opendc-faas-simulator")
-include(":opendc-faas:opendc-faas-workload")
include(":opendc-experiments:opendc-experiments-base")
include(":opendc-experiments:opendc-experiments-compute")
include(":opendc-experiments:opendc-experiments-workflow")
+include(":opendc-experiments:opendc-experiments-faas")
include(":opendc-experiments:opendc-experiments-capelin")
include(":opendc-experiments:opendc-experiments-tf20")
include(":opendc-web:opendc-web-proto")