Skip to content
Snippets Groups Projects
Commit 6f88b8c2 authored by Benedikt Wetzel's avatar Benedikt Wetzel
Browse files

Load executionID from file

parent a10e11de
No related branches found
No related tags found
4 merge requests!159Re-implementation of Theodolite with Kotlin/Quarkus,!157Update Graal Image in CI pipeline,!138Load execution ID from file,!83WIP: Re-implementation of Theodolite with Kotlin/Quarkus
......@@ -2,6 +2,7 @@ package theodolite.evaluation
import mu.KotlinLogging
import theodolite.benchmark.BenchmarkExecution
import theodolite.util.IOHandler
import theodolite.util.LoadDimension
import theodolite.util.Resource
import java.text.Normalizer
......@@ -44,15 +45,14 @@ class AnalysisExecutor(
query = "sum by(group)(kafka_consumergroup_group_lag >= 0)"
)
var resultsFolder: String = System.getenv("RESULTS_FOLDER")
if (resultsFolder.isNotEmpty()){
resultsFolder += "/"
}
val ioHandler = IOHandler()
val resultsFolder: String = ioHandler.getResultFolderURL()
val fileURL = "${resultsFolder}exp${executionId}_${load.get()}_${res.get()}_${slo.sloType.toSlug()}"
ioHandler.writeToCSVFile(
fileURL = fileURL,
data = prometheusData.getResultAsList(),
columns = listOf("group", "timestamp", "value"))
CsvExporter().toCsv(
name = "${resultsFolder}exp${executionId}_${load.get()}_${res.get()}_${slo.sloType.toSlug()}",
prom = prometheusData
)
val sloChecker = SloCheckerFactory().create(
sloType = slo.sloType,
externalSlopeURL = slo.externalSloUrl,
......
package theodolite.evaluation
import mu.KotlinLogging
import theodolite.util.PrometheusResponse
import java.io.File
import java.io.PrintWriter
import java.util.*
private val logger = KotlinLogging.logger {}
/**
* Used to document the data received from prometheus for additional offline analysis.
*/
class CsvExporter {
/**
* Uses the [PrintWriter] to transform a [PrometheusResponse] to a CSV file.
* @param name of the file.
* @param prom Response that is documented.
*
*/
fun toCsv(name: String, prom: PrometheusResponse) {
val responseArray = promResponseToList(prom)
val csvOutputFile = File("$name.csv")
PrintWriter(csvOutputFile).use { pw ->
pw.println(listOf("group", "timestamp", "value").joinToString(separator=","))
responseArray.forEach {
pw.println(it.joinToString(separator=","))
}
}
logger.info { "Wrote CSV file: $name to ${csvOutputFile.absolutePath}." }
}
/**
* Converts a [PrometheusResponse] into a [List] of [List]s of [String]s
*/
private fun promResponseToList(prom: PrometheusResponse): List<List<String>> {
val name = prom.data?.result?.get(0)?.metric?.group.toString()
val values = prom.data?.result?.get(0)?.values
val dataList = mutableListOf<List<String>>()
if (values != null) {
for (maybeValuePair in values) {
val valuePair = maybeValuePair as List<*>
val timestamp = (valuePair[0] as Double).toLong().toString()
val value = valuePair[1].toString()
dataList.add(listOf(name, timestamp, value))
}
}
return Collections.unmodifiableList(dataList)
}
}
......@@ -7,10 +7,7 @@ import theodolite.benchmark.KubernetesBenchmark
import theodolite.patcher.PatcherDefinitionFactory
import theodolite.strategies.StrategyFactory
import theodolite.strategies.searchstrategy.CompositeStrategy
import theodolite.util.Config
import theodolite.util.LoadDimension
import theodolite.util.Resource
import theodolite.util.Results
import theodolite.util.*
import java.io.File
import java.io.PrintWriter
import java.lang.IllegalArgumentException
......@@ -102,34 +99,17 @@ class TheodoliteExecutor(
return this.kubernetesBenchmark
}
private fun getResultFolderString(): String {
var resultsFolder: String = System.getenv("RESULTS_FOLDER") ?: ""
val createResultsFolder = System.getenv("CREATE_RESULTS_FOLDER") ?: "false"
if (resultsFolder != ""){
logger.info { "RESULT_FOLDER: $resultsFolder" }
val directory = File(resultsFolder)
if (!directory.exists()) {
logger.error { "Folder $resultsFolder does not exist" }
if (createResultsFolder.toBoolean()) {
directory.mkdirs()
} else {
throw IllegalArgumentException("Result folder not found")
}
}
resultsFolder += "/"
}
return resultsFolder
}
/**
* Run all experiments which are specified in the corresponding
* execution and benchmark objects.
*/
fun run() {
val resultsFolder = getResultFolderString()
storeAsFile(this.config, "$resultsFolder${this.config.executionId}-execution-configuration")
storeAsFile(kubernetesBenchmark, "$resultsFolder${this.config.executionId}-benchmark-configuration")
val ioHandler = IOHandler()
val resultsFolder = ioHandler.getResultFolderURL()
this.config.executionId = getAndIncrementExecutionID(resultsFolder+"expID.txt")
ioHandler.writeToJSONFile(this.config, "$resultsFolder${this.config.executionId}-execution-configuration")
ioHandler.writeToJSONFile(kubernetesBenchmark, "$resultsFolder${this.config.executionId}-benchmark-configuration")
val config = buildConfig()
// execute benchmarks for each load
......@@ -138,14 +118,17 @@ class TheodoliteExecutor(
config.compositeStrategy.findSuitableResource(load, config.resources)
}
}
storeAsFile(config.compositeStrategy.benchmarkExecutor.results, "$resultsFolder${this.config.executionId}-result")
ioHandler.writeToJSONFile(config.compositeStrategy.benchmarkExecutor.results, "$resultsFolder${this.config.executionId}-result")
}
private fun <T> storeAsFile(saveObject: T, filename: String) {
val gson = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create()
PrintWriter(filename).use { pw ->
pw.println(gson.toJson(saveObject))
}
private fun getAndIncrementExecutionID(fileURL: String): Int {
val ioHandler = IOHandler()
var executionID = 0
if (File(fileURL).exists()) {
executionID = ioHandler.readFileAsString(fileURL).toInt() + 1
}
ioHandler.writeStringToTextFile(fileURL, (executionID).toString())
return executionID
}
}
......@@ -37,7 +37,6 @@ class TheodoliteController(
val executionsQueue: ConcurrentLinkedDeque<BenchmarkExecution> = ConcurrentLinkedDeque()
val benchmarks: ConcurrentHashMap<String, KubernetesBenchmark> = ConcurrentHashMap()
var isUpdated = AtomicBoolean(false)
var executionID = AtomicInteger(0)
/**
* Runs the TheodoliteController forever.
......@@ -91,7 +90,6 @@ class TheodoliteController(
*/
@Synchronized
fun runExecution(execution: BenchmarkExecution, benchmark: KubernetesBenchmark) {
execution.executionId = executionID.getAndSet(executionID.get() + 1)
isUpdated.set(false)
benchmark.path = path
logger.info { "Start execution ${execution.name} with benchmark ${benchmark.name}." }
......
package theodolite.util
import com.google.gson.GsonBuilder
import mu.KotlinLogging
import java.io.File
import java.io.PrintWriter
import java.lang.IllegalArgumentException
private val logger = KotlinLogging.logger {}
/**
* The IOHandler handles most common I/O operations within the Theodolite framework
*/
class IOHandler {
/**
* The location in which Theodolite store result and configuration file are depends on
* the values of the environment variables `RESULT_FOLDER` and `CREATE_RESULTS_FOLDER`
*
* @return the URL of the result folder
*/
fun getResultFolderURL(): String {
var resultsFolder: String = System.getenv("RESULTS_FOLDER") ?: ""
val createResultsFolder = System.getenv("CREATE_RESULTS_FOLDER") ?: "false"
if (resultsFolder != ""){
logger.info { "RESULT_FOLDER: $resultsFolder" }
val directory = File(resultsFolder)
if (!directory.exists()) {
logger.error { "Folder $resultsFolder does not exist" }
if (createResultsFolder.toBoolean()) {
directory.mkdirs()
} else {
throw IllegalArgumentException("Result folder not found")
}
}
resultsFolder += "/"
}
return resultsFolder
}
/**
* Read a file as String
*
* @param fileURL the URL of the file
* @return The content of the file as String
*/
fun readFileAsString(fileURL: String): String {
return File(fileURL).inputStream().readBytes().toString(Charsets.UTF_8).trim()
}
/**
* Creates a JSON string of the given object and store them to file
*
* @param T class of the object to save
* @param objectToSave object which should be saved as file
* @param fileURL the URL of the file
*/
fun <T> writeToJSONFile(objectToSave: T, fileURL: String) {
val gson = GsonBuilder().enableComplexMapKeySerialization().setPrettyPrinting().create()
writeStringToTextFile(fileURL, gson.toJson(objectToSave))
}
/**
* Write to CSV file
*
* @param fileURL the URL of the file
* @param data the data to write in the file, as list of list, each subList corresponds to a row in the CSV file
* @param columns columns of the CSV file
*/
fun writeToCSVFile(fileURL: String, data: List<List<String>>, columns: List<String>) {
val outputFile = File("$fileURL.csv")
PrintWriter(outputFile).use { pw ->
pw.println(columns.joinToString(separator=","))
data.forEach {
pw.println(it.joinToString(separator=","))
}
}
logger.info { "Wrote CSV file: $fileURL to ${outputFile.absolutePath}." }
}
/**
* Write to text file
*
* @param fileURL the URL of the file
* @param data the data to write in the file as String
*/
fun writeStringToTextFile(fileURL: String, data: String) {
val outputFile = File("$fileURL")
outputFile.printWriter().use {
it.println(data)
}
logger.info { "Wrote txt file: $fileURL to ${outputFile.absolutePath}." }
}
}
\ No newline at end of file
package theodolite.util
import io.quarkus.runtime.annotations.RegisterForReflection
import java.util.*
/**
* This class corresponds to the JSON response format of a Prometheus
......@@ -17,6 +18,27 @@ data class PrometheusResponse(
*/
var data: PromData? = null
)
{
/**
* Return the data of the PrometheusResponse as [List] of [List]s of [String]s
* The format of the returned list is: `[[ group, timestamp, value ], [ group, timestamp, value ], ... ]`
*/
fun getResultAsList(): List<List<String>> {
val group = data?.result?.get(0)?.metric?.group.toString()
val values = data?.result?.get(0)?.values
val result = mutableListOf<List<String>>()
if (values != null) {
for (value in values) {
val valueList = value as List<*>
val timestamp = (valueList[0] as Double).toLong().toString()
val value = valueList[1].toString()
result.add(listOf(group, timestamp, value))
}
}
return Collections.unmodifiableList(result)
}
}
/**
* Description of Prometheus data.
......@@ -56,4 +78,5 @@ data class PromResult(
@RegisterForReflection
data class PromMetric(
var group: String? = null
)
\ No newline at end of file
)
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