diff options
10 files changed, 68 insertions, 23 deletions
diff --git a/opendc-experiments/opendc-experiments-energy21/build.gradle.kts b/opendc-experiments/opendc-experiments-energy21/build.gradle.kts index 618c525e..7d5fc98d 100644 --- a/opendc-experiments/opendc-experiments-energy21/build.gradle.kts +++ b/opendc-experiments/opendc-experiments-energy21/build.gradle.kts @@ -27,12 +27,6 @@ plugins { `kotlin-library-conventions` `experiment-conventions` `testing-conventions` - application -} - -application { - mainClass.set("org.opendc.harness.runner.cli.ConsoleRunnerKt") - applicationDefaultJvmArgs = listOf("-Xms2500M") } dependencies { diff --git a/opendc-experiments/opendc-experiments-energy21/src/main/kotlin/org/opendc/experiments/energy21/EnergyExperiment.kt b/opendc-experiments/opendc-experiments-energy21/src/main/kotlin/org/opendc/experiments/energy21/EnergyExperiment.kt index bb6dcd3a..772c9bcc 100644 --- a/opendc-experiments/opendc-experiments-energy21/src/main/kotlin/org/opendc/experiments/energy21/EnergyExperiment.kt +++ b/opendc-experiments/opendc-experiments-energy21/src/main/kotlin/org/opendc/experiments/energy21/EnergyExperiment.kt @@ -26,7 +26,6 @@ import io.opentelemetry.api.metrics.MeterProvider import io.opentelemetry.sdk.metrics.SdkMeterProvider import io.opentelemetry.sdk.metrics.export.MetricProducer import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.coroutineScope import mu.KotlinLogging @@ -85,9 +84,7 @@ public class EnergyExperiment : Experiment("Energy Modeling 2021") { */ private val powerModel by anyOf(PowerModelType.LINEAR, PowerModelType.CUBIC, PowerModelType.INTERPOLATION) - @OptIn(ExperimentalCoroutinesApi::class) override fun doRun(repeat: Int): Unit = runBlockingSimulation { - val chan = Channel<Unit>(Channel.CONFLATED) val allocationPolicy = FilterScheduler( filters = listOf(ComputeFilter(), ComputeCapabilitiesFilter()), diff --git a/opendc-harness/opendc-harness-cli/build.gradle.kts b/opendc-harness/opendc-harness-cli/build.gradle.kts index 26f02f55..3e169e2a 100644 --- a/opendc-harness/opendc-harness-cli/build.gradle.kts +++ b/opendc-harness/opendc-harness-cli/build.gradle.kts @@ -25,6 +25,12 @@ description = "Command line interface of OpenDC Harness" /* Build configuration */ plugins { `kotlin-library-conventions` + application +} + +application { + applicationName = "opendc-harness" + mainClass.set("org.opendc.harness.runner.cli.ConsoleRunnerKt") } dependencies { diff --git a/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt b/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt index c59e623c..82adb2fd 100644 --- a/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt +++ b/opendc-harness/opendc-harness-cli/src/main/kotlin/org/opendc/harness/runner/cli/ConsoleRunner.kt @@ -23,16 +23,23 @@ package org.opendc.harness.runner.cli import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.arguments.multiple +import com.github.ajalt.clikt.parameters.arguments.unique import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.multiple import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.options.unique +import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.int import mu.KotlinLogging +import org.junit.platform.commons.util.ClassLoaderUtils import org.opendc.harness.engine.ExperimentEngineLauncher import org.opendc.harness.engine.discovery.DiscoveryProvider import org.opendc.harness.engine.discovery.DiscoveryRequest import org.opendc.harness.engine.discovery.DiscoverySelector import org.opendc.harness.engine.scheduler.ThreadPoolExperimentScheduler +import java.net.URLClassLoader /** * The logger for this experiment runner. @@ -53,23 +60,38 @@ public class ConsoleRunner : CliktCommand(name = "opendc-harness") { /** * The selected experiments to run by name. */ - private val experiments by option("-e", "--experiments", help = "Names of experiments to explore") - .multiple(emptyList()) + private val experiments by argument(help = "Experiments to explore") + .multiple() + .unique() /** * The maximum number of worker threads to use. */ private val parallelism by option("-p", "--parallelism", help = "Maximum number of concurrent simulation runs") .int() - .default(Runtime.getRuntime().availableProcessors()) + .default(Runtime.getRuntime().availableProcessors() - 1) + + /** + * Additional classpath entries to load. + */ + private val additionalClasspathEntries by option("--class-path", help = "Additional classpath entries to load") + .file(mustExist = true) + .multiple() + .unique() override fun run() { logger.info { "Starting OpenDC Console Experiment Runner" } - val discovery = DiscoveryProvider.createComposite() + val classLoader = createClassLoader() + // TODO: Add way to specify class loader for scheduler + Thread.currentThread().contextClassLoader = classLoader + + val discovery = DiscoveryProvider.createComposite(classLoader) val experiments = discovery.discover( DiscoveryRequest( - selectors = experiments.map { DiscoverySelector.Name(it) } + selectors = experiments.flatMap { + listOf(DiscoverySelector.Name(it), DiscoverySelector.Meta("class.name", it)) + } ) ) @@ -91,6 +113,30 @@ public class ConsoleRunner : CliktCommand(name = "opendc-harness") { logger.info { "Finished all experiments. Exiting." } } + + /** + * Create a [ClassLoader] that is used to load the + */ + private fun createClassLoader(): ClassLoader { + val parent = ClassLoaderUtils.getDefaultClassLoader() + + if (additionalClasspathEntries.isNotEmpty()) { + val urls = additionalClasspathEntries.flatMap { file -> + if (file.isDirectory) { + file.walk() + .filter { it.extension == "jar" } + .map { it.toURI().toURL() } + .toList() + } else { + listOf(file.toURI().toURL()) + } + } + + return URLClassLoader.newInstance(urls.toTypedArray(), parent) + } + + return parent + } } /** diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt index 204de3fc..c4b420c5 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/discovery/DiscoveryProvider.kt @@ -40,7 +40,7 @@ public interface DiscoveryProvider { /** * Factory method for creating a new [Discovery] instance. */ - public fun create(): Discovery + public fun create(classLoader: ClassLoader): Discovery public companion object { /** @@ -58,8 +58,8 @@ public interface DiscoveryProvider { /** * Obtain a composite [Discovery] that combines the results of all available providers. */ - public fun createComposite(): Discovery { - return CompositeDiscovery(providers) + public fun createComposite(classLoader: ClassLoader): Discovery { + return CompositeDiscovery(classLoader, providers) } } } diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt index 8ebc485a..726125a8 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/CompositeDiscovery.kt @@ -32,11 +32,11 @@ import org.opendc.harness.engine.discovery.DiscoveryRequest /** * A composite [Discovery] instance that combines the results of multiple delegate instances. */ -internal class CompositeDiscovery(providers: Iterable<DiscoveryProvider>) : Discovery { +internal class CompositeDiscovery(classLoader: ClassLoader, providers: Iterable<DiscoveryProvider>) : Discovery { /** * The [Discovery] instances to delegate to. */ - private val delegates = providers.map { it.create() } + private val delegates = providers.map { it.create(classLoader) } @OptIn(FlowPreview::class) override fun discover(request: DiscoveryRequest): Flow<ExperimentDefinition> { diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt index 20708230..3fa3fe35 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscovery.kt @@ -36,7 +36,7 @@ import org.opendc.harness.engine.discovery.DiscoverySelector /** * A [Discovery] implementation that discovers [Experiment] instances on the classpath. */ -internal class DslDiscovery : Discovery { +internal class DslDiscovery(private val classLoader: ClassLoader) : Discovery { /* * Lazily memoize the results of the classpath scan. */ @@ -84,6 +84,7 @@ internal class DslDiscovery : Discovery { */ private fun scan(): ScanResult { return ClassGraph() + .addClassLoader(classLoader) .enableClassInfo() .enableExternalClasses() .ignoreClassVisibility() diff --git a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt index 987bc889..6a9bd599 100644 --- a/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt +++ b/opendc-harness/opendc-harness-engine/src/main/kotlin/org/opendc/harness/engine/internal/DslDiscoveryProvider.kt @@ -32,5 +32,5 @@ import org.opendc.harness.engine.discovery.DiscoveryProvider public class DslDiscoveryProvider : DiscoveryProvider { override val id: String = "dsl" - override fun create(): Discovery = DslDiscovery() + override fun create(classLoader: ClassLoader): Discovery = DslDiscovery(classLoader) } diff --git a/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt b/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt index 6f2989db..6955f7c5 100644 --- a/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt +++ b/opendc-harness/opendc-harness-engine/src/test/kotlin/org/opendc/harness/EngineTest.kt @@ -50,7 +50,7 @@ internal class EngineTest { @Test fun discovery() { runBlocking { - val discovery = DiscoveryProvider.findById("dsl")?.create() + val discovery = DiscoveryProvider.findById("dsl")?.create(Thread.currentThread().contextClassLoader) assertNotNull(discovery) val res = mutableListOf<ExperimentDefinition>() discovery?.discover(DiscoveryRequest())?.toList(res) diff --git a/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt b/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt index ab7367b8..7fc97f6d 100644 --- a/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt +++ b/opendc-harness/opendc-harness-junit5/src/main/kotlin/org/opendc/harness/runner/junit5/OpenDCTestEngine.kt @@ -25,6 +25,7 @@ package org.opendc.harness.runner.junit5 import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import mu.KotlinLogging +import org.junit.platform.commons.util.ClassLoaderUtils import org.junit.platform.engine.* import org.junit.platform.engine.discovery.ClassNameFilter import org.junit.platform.engine.discovery.ClassSelector @@ -63,7 +64,7 @@ public class OpenDCTestEngine : TestEngine { val classNames = request.getSelectorsByType(ClassSelector::class.java).map { DiscoverySelector.Meta("class.name", it.className) } val classNameFilters = request.getFiltersByType(ClassNameFilter::class.java).map { DiscoveryFilter.Name(it.toPredicate()) } - val discovery = DiscoveryProvider.createComposite() + val discovery = DiscoveryProvider.createComposite(ClassLoaderUtils.getDefaultClassLoader()) val definitions = discovery.discover(DiscoveryRequest(classNames, classNameFilters)) return ExperimentEngineDescriptor(uniqueId, definitions) |
