diff options
| -rw-r--r-- | gradle/libs.versions.toml | 2 | ||||
| -rw-r--r-- | opendc-trace/opendc-trace-tools/build.gradle.kts | 8 | ||||
| -rw-r--r-- | opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/ConvertCommand.kt (renamed from opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceConverter.kt) | 12 | ||||
| -rw-r--r-- | opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/QueryCommand.kt | 159 | ||||
| -rw-r--r-- | opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceTools.kt | 44 |
5 files changed, 215 insertions, 10 deletions
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 458ac973..a5c0f184 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ gradle-node = "3.2.1" hadoop = "3.3.1" jackson = "2.13.2" jandex-gradle = "0.12.0" +jline = "3.21.0" jmh-gradle = "0.6.6" jakarta-validation = "2.0.2" junit-jupiter = "5.8.2" @@ -104,6 +105,7 @@ restassured-kotlin = { module = "io.rest-assured:kotlin-extensions" } # Calcite (SQL) calcite-core = { module = "org.apache.calcite:calcite-core", version.ref = "calcite" } +jline = { module = "org.jline:jline", version.ref = "jline" } # Other classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" } diff --git a/opendc-trace/opendc-trace-tools/build.gradle.kts b/opendc-trace/opendc-trace-tools/build.gradle.kts index 0c1e179e..e98fb932 100644 --- a/opendc-trace/opendc-trace-tools/build.gradle.kts +++ b/opendc-trace/opendc-trace-tools/build.gradle.kts @@ -29,16 +29,22 @@ plugins { } application { - mainClass.set("org.opendc.trace.tools.TraceConverter") + mainClass.set("org.opendc.trace.tools.TraceTools") } dependencies { implementation(projects.opendcTrace.opendcTraceApi) + implementation(projects.opendcTrace.opendcTraceCalcite) implementation(libs.kotlin.logging) implementation(libs.clikt) + implementation(libs.jline) runtimeOnly(projects.opendcTrace.opendcTraceOpendc) runtimeOnly(projects.opendcTrace.opendcTraceBitbrains) runtimeOnly(projects.opendcTrace.opendcTraceAzure) + runtimeOnly(projects.opendcTrace.opendcTraceGwf) + runtimeOnly(projects.opendcTrace.opendcTraceSwf) + runtimeOnly(projects.opendcTrace.opendcTraceWfformat) + runtimeOnly(projects.opendcTrace.opendcTraceWtf) runtimeOnly(libs.log4j.slf4j) } diff --git a/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceConverter.kt b/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/ConvertCommand.kt index c71035d4..970de0f4 100644 --- a/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceConverter.kt +++ b/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/ConvertCommand.kt @@ -20,7 +20,6 @@ * SOFTWARE. */ -@file:JvmName("TraceConverter") package org.opendc.trace.tools import com.github.ajalt.clikt.core.CliktCommand @@ -44,14 +43,9 @@ import kotlin.math.max import kotlin.math.min /** - * A script to convert a trace in text format into a Parquet trace. + * A [CliktCommand] that can convert between workload trace formats. */ -fun main(args: Array<String>): Unit = TraceConverterCli().main(args) - -/** - * Represents the command for converting traces - */ -internal class TraceConverterCli : CliktCommand(name = "trace-converter") { +internal class ConvertCommand : CliktCommand(name = "convert", help = "Convert between workload trace formats") { /** * The logger instance for the converter. */ @@ -73,7 +67,7 @@ internal class TraceConverterCli : CliktCommand(name = "trace-converter") { /** * The input format of the trace. */ - private val inputFormat by option("-f", "--input-format", help = "format of output trace") + private val inputFormat by option("-f", "--input-format", help = "format of input trace") .required() /** diff --git a/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/QueryCommand.kt b/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/QueryCommand.kt new file mode 100644 index 00000000..b0f95de2 --- /dev/null +++ b/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/QueryCommand.kt @@ -0,0 +1,159 @@ +/* + * 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.trace.tools + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.options.required +import com.github.ajalt.clikt.parameters.types.file +import org.apache.calcite.jdbc.CalciteConnection +import org.jline.builtins.Styles +import org.jline.console.Printer +import org.jline.console.impl.DefaultPrinter +import org.jline.terminal.Terminal +import org.jline.terminal.TerminalBuilder +import org.jline.utils.AttributedStringBuilder +import org.opendc.trace.Trace +import org.opendc.trace.calcite.TraceSchema +import java.nio.charset.StandardCharsets +import java.sql.DriverManager +import java.sql.ResultSet +import java.sql.ResultSetMetaData +import java.util.* + +/** + * A [CliktCommand] that allows users to query workload traces using SQL. + */ +internal class QueryCommand : CliktCommand(name = "query", help = "Query workload traces") { + /** + * The trace to open. + */ + private val input by option("-i", "--input") + .file(mustExist = true) + .required() + + /** + * The input format of the trace. + */ + private val inputFormat by option("-f", "--format", help = "format of the trace") + .required() + + /** + * The query to execute. + */ + private val query by argument() + + /** + * Access to the terminal. + */ + private val terminal = TerminalBuilder.builder() + .system(false) + .streams(System.`in`, System.out) + .encoding(StandardCharsets.UTF_8) + .build() + + /** + * Helper class to print results to console. + */ + private val printer = QueryPrinter(terminal) + + override fun run() { + val inputTrace = Trace.open(input, format = inputFormat) + val info = Properties().apply { this["lex"] = "JAVA" } + val connection = DriverManager.getConnection("jdbc:calcite:", info).unwrap(CalciteConnection::class.java) + connection.rootSchema.add("trace", TraceSchema(inputTrace)) + connection.schema = "trace" + + val stmt = connection.createStatement() + stmt.executeQuery(query) + + val start = System.currentTimeMillis() + val hasResults = stmt.execute(query) + + try { + if (hasResults) { + do { + stmt.resultSet.use { rs -> + val count: Int = printResults(rs) + val duration = (System.currentTimeMillis() - start) / 1000.0 + printer.println("$count rows selected (${"%.3f".format(duration)} seconds)") + } + } while (stmt.moreResults) + } else { + val count: Int = stmt.updateCount + val duration = (System.currentTimeMillis() - start) / 1000.0 + + printer.println("$count rows affected (${"%0.3f".format(duration)} seconds)") + } + } finally { + stmt.close() + connection.close() + } + } + + /** + * Helper function to print the results to console. + */ + private fun printResults(rs: ResultSet): Int { + var count = 0 + val meta: ResultSetMetaData = rs.metaData + + val options = mapOf( + Printer.COLUMNS to List(meta.columnCount) { meta.getColumnName(it + 1) }, + Printer.BORDER to "|", + ) + val data = mutableListOf<Map<String, Any>>() + + while (rs.next()) { + val row = mutableMapOf<String, Any>() + for (i in 1..meta.columnCount) { + row[meta.getColumnName(i)] = rs.getObject(i) + } + data.add(row) + + count++ + } + + printer.println(options, data) + + return count + } + + /** + * Helper class to print the results of the query. + */ + private class QueryPrinter(private val terminal: Terminal) : DefaultPrinter(null) { + override fun terminal(): Terminal = terminal + + override fun highlightAndPrint(options: MutableMap<String, Any>, exception: Throwable) { + if (options.getOrDefault("exception", "stack") == "stack") { + exception.printStackTrace() + } else { + val asb = AttributedStringBuilder() + asb.append(exception.message, Styles.prntStyle().resolve(".em")) + asb.toAttributedString().println(terminal()) + } + } + } +} diff --git a/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceTools.kt b/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceTools.kt new file mode 100644 index 00000000..b480484b --- /dev/null +++ b/opendc-trace/opendc-trace-tools/src/main/kotlin/org/opendc/trace/tools/TraceTools.kt @@ -0,0 +1,44 @@ +/* + * 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("TraceTools") +package org.opendc.trace.tools + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.core.subcommands + +/** + * A script for querying and manipulating workload traces supported by OpenDC. + */ +fun main(args: Array<String>): Unit = TraceToolsCli().main(args) + +/** + * The primary [CliktCommand] for the trace tools offered by OpenDC. + */ +class TraceToolsCli : CliktCommand(name = "trace-tools") { + init { + subcommands(QueryCommand()) + subcommands(ConvertCommand()) + } + + override fun run() {} +} |
