summaryrefslogtreecommitdiff
path: root/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org')
-rw-r--r--opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/ServerlessExperiment.kt137
-rw-r--r--opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionSample.kt44
-rw-r--r--opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTrace.kt28
-rw-r--r--opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTraceWorkload.kt34
-rw-r--r--opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/ServerlessTraceReader.kt107
5 files changed, 350 insertions, 0 deletions
diff --git a/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/ServerlessExperiment.kt b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/ServerlessExperiment.kt
new file mode 100644
index 00000000..67b5ea54
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/ServerlessExperiment.kt
@@ -0,0 +1,137 @@
+/*
+ * 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.experiments.serverless
+
+import io.opentelemetry.api.metrics.MeterProvider
+import io.opentelemetry.sdk.metrics.SdkMeterProvider
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import mu.KotlinLogging
+import org.opendc.experiments.serverless.trace.FunctionTraceWorkload
+import org.opendc.experiments.serverless.trace.ServerlessTraceReader
+import org.opendc.harness.dsl.Experiment
+import org.opendc.harness.dsl.anyOf
+import org.opendc.serverless.service.ServerlessService
+import org.opendc.serverless.service.router.RandomRoutingPolicy
+import org.opendc.serverless.simulator.SimFunctionDeployer
+import org.opendc.serverless.simulator.delay.ColdStartModel
+import org.opendc.serverless.simulator.delay.StochasticDelayInjector
+import org.opendc.simulator.compute.SimMachineModel
+import org.opendc.simulator.compute.model.MemoryUnit
+import org.opendc.simulator.compute.model.ProcessingNode
+import org.opendc.simulator.compute.model.ProcessingUnit
+import org.opendc.simulator.core.runBlockingSimulation
+import org.opendc.telemetry.sdk.toOtelClock
+import java.io.File
+import java.util.*
+import kotlin.math.max
+
+/**
+ * A reproduction of the experiments of Soufiane Jounaid's BSc Computer Science thesis:
+ * OpenDC Serverless: Design, Implementation and Evaluation of a FaaS Platform Simulator.
+ */
+public class ServerlessExperiment : Experiment("Serverless") {
+ /**
+ * The logger for this portfolio instance.
+ */
+ private val logger = KotlinLogging.logger {}
+
+ /**
+ * The path to where the traces are located.
+ */
+ private val tracePath by anyOf(File("../../input/traces/serverless"))
+
+ /**
+ * The path to where the output results should be written.
+ */
+ private val outputPath by anyOf(File("output/"))
+
+ /**
+ * The routing policy to test.
+ */
+ private val routingPolicy by anyOf(RandomRoutingPolicy())
+
+ /**
+ * The cold start models to test.
+ */
+ private val coldStartModel by anyOf(ColdStartModel.LAMBDA, ColdStartModel.AZURE, ColdStartModel.GOOGLE)
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ override fun doRun(repeat: Int): Unit = runBlockingSimulation {
+ val meterProvider: MeterProvider = SdkMeterProvider
+ .builder()
+ .setClock(clock.toOtelClock())
+ .build()
+
+ val trace = ServerlessTraceReader().parse(tracePath)
+ val traceById = trace.associateBy { it.id }
+ val delayInjector = StochasticDelayInjector(coldStartModel, Random())
+ val deployer = SimFunctionDeployer(clock, this, createMachineModel(), delayInjector) { FunctionTraceWorkload(traceById.getValue(it.name)) }
+ val service = ServerlessService(coroutineContext, clock, meterProvider.get("opendc-serverless"), deployer, routingPolicy)
+ val client = service.newClient()
+
+ coroutineScope {
+ for (entry in trace) {
+ launch {
+ val function = client.newFunction(entry.id, entry.maxMemory.toLong())
+ 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()
+ }
+ }
+ }
+ }
+ }
+
+ client.close()
+ service.close()
+ }
+
+ /**
+ * Construct the machine model to test with.
+ */
+ private fun createMachineModel(): SimMachineModel {
+ val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2)
+
+ return SimMachineModel(
+ cpus = List(cpuNode.coreCount) { ProcessingUnit(cpuNode, it, 1000.0) },
+ memory = List(4) { MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000) }
+ )
+ }
+}
diff --git a/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionSample.kt b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionSample.kt
new file mode 100644
index 00000000..492f44b9
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionSample.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.experiments.serverless.trace
+
+/**
+ * A sample of a single function.
+ *
+ * @param timestamp The timestamp of the function.
+ * @param duration The average execution time of the function.
+ * @param invocations The number of invocations.
+ * @param provisionedCpu The provisioned CPU for this function in MHz.
+ * @param provisionedMem The amount of memory provisioned for this function in MB.
+ * @param cpuUsage The actual CPU usage in MHz.
+ * @param memUsage The actual memory usage in MB.
+ */
+public data class FunctionSample(
+ val timestamp: Long,
+ val duration: Long,
+ val invocations: Int,
+ val provisionedCpu: Int,
+ val provisionedMem: Int,
+ val cpuUsage: Double,
+ val memUsage: Double
+)
diff --git a/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTrace.kt b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTrace.kt
new file mode 100644
index 00000000..4fea6b96
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTrace.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.experiments.serverless.trace
+
+/**
+ * A trace for a single function
+ */
+public data class FunctionTrace(val id: String, val maxMemory: Int, val samples: List<FunctionSample>)
diff --git a/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTraceWorkload.kt b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTraceWorkload.kt
new file mode 100644
index 00000000..7d824857
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/FunctionTraceWorkload.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.experiments.serverless.trace
+
+import org.opendc.serverless.simulator.workload.SimServerlessWorkload
+import org.opendc.simulator.compute.workload.SimTraceWorkload
+import org.opendc.simulator.compute.workload.SimWorkload
+
+/**
+ * A [SimServerlessWorkload] for a [FunctionTrace].
+ */
+public class FunctionTraceWorkload(trace: FunctionTrace) : SimServerlessWorkload, SimWorkload by SimTraceWorkload(trace.samples.asSequence().map { SimTraceWorkload.Fragment(it.duration, it.cpuUsage, 1) }) {
+ override suspend fun invoke() {}
+}
diff --git a/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/ServerlessTraceReader.kt b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/ServerlessTraceReader.kt
new file mode 100644
index 00000000..6dc35c59
--- /dev/null
+++ b/opendc-experiments/opendc-experiments-serverless20/src/main/kotlin/org/opendc/experiments/serverless/trace/ServerlessTraceReader.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.experiments.serverless.trace
+
+import mu.KotlinLogging
+import java.io.File
+import kotlin.math.max
+
+/**
+ * A trace reader for the serverless workload trace used in the OpenDC Serverless thesis.
+ */
+public class ServerlessTraceReader {
+ /**
+ * The logger for this portfolio instance.
+ */
+ private val logger = KotlinLogging.logger {}
+
+ /**
+ * Parse the traces at the specified [path].
+ */
+ public fun parse(path: File): List<FunctionTrace> {
+ return if (path.isFile) {
+ listOf(parseSingle(path))
+ } else {
+ path.walk()
+ .filterNot { it.isDirectory }
+ .map { file ->
+ logger.info { "Parsing $file" }
+ parseSingle(file)
+ }
+ .toList()
+ }
+ }
+
+ /**
+ * Parse a single trace.
+ */
+ private fun parseSingle(path: File): FunctionTrace {
+ val samples = mutableListOf<FunctionSample>()
+ val id = path.nameWithoutExtension
+ var idx = 0
+
+ var timestampCol = 0
+ var invocationsCol = 0
+ var execTimeCol = 0
+ var provCpuCol = 0
+ var provMemCol = 0
+ var cpuUsageCol = 0
+ var memoryUsageCol = 0
+ var maxMemory = 0
+
+ path.forEachLine { line ->
+ if (line.startsWith("#") && line.isNotBlank()) {
+ return@forEachLine
+ }
+
+ val values = line.split(",")
+
+ /* Header parsing */
+ if (idx++ == 0) {
+ val header = values.mapIndexed { col, name -> Pair(name.trim(), col) }.toMap()
+ timestampCol = header["Timestamp [ms]"]!!
+ invocationsCol = header["Invocations"]!!
+ execTimeCol = header["Avg Exec time per Invocation"]!!
+ provCpuCol = header["Provisioned CPU [Mhz]"]!!
+ provMemCol = header["Provisioned Memory [mb]"]!!
+ cpuUsageCol = header["Avg cpu usage per Invocation [Mhz]"]!!
+ memoryUsageCol = header["Avg mem usage per Invocation [mb]"]!!
+ return@forEachLine
+ }
+
+ val timestamp = values[timestampCol].trim().toLong()
+ val invocations = values[invocationsCol].trim().toInt()
+ val execTime = values[execTimeCol].trim().toLong()
+ val provisionedCpu = values[provCpuCol].trim().toInt()
+ val provisionedMemory = values[provMemCol].trim().toInt()
+ val cpuUsage = values[cpuUsageCol].trim().toDouble()
+ val memoryUsage = values[memoryUsageCol].trim().toDouble()
+
+ maxMemory = max(maxMemory, provisionedMemory)
+
+ samples.add(FunctionSample(timestamp, execTime, invocations, provisionedCpu, provisionedMemory, cpuUsage, memoryUsage))
+ }
+
+ return FunctionTrace(id, maxMemory, samples)
+ }
+}