diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2021-10-25 16:16:13 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-25 16:16:13 +0200 |
| commit | a41cd2504f15f3e3e49eb533faca390911cc5110 (patch) | |
| tree | f35e7e5c65e2985cf34ad7689526d5b5c0815230 | |
| parent | aa9b32f8cd1467e9718959f400f6777e5d71737d (diff) | |
| parent | fe8cd32c3f79d2a6c898a1c8809792e35440a539 (diff) | |
merge: Address several regressions in simulator
This pull request addresses several regressions that have been introduced in the past few pull requests.
- Fix queue resizing logic
- Change clock resolution from milliseconds to nanoseconds in `OtelClockAdapter`
- Compute energy usage in absence of convergence
- Fix duplicate classpath entries
- Fix release workflow
**Breaking API Changes**
- `OtelClockAdapter` now exports time in nanoseconds as the method contract describes.
8 files changed, 53 insertions, 11 deletions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c525eb97..c1f2864c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,9 +24,9 @@ jobs: run: chmod +x gradlew - uses: actions/cache@v2 with: - path:| - ~/.gradle/caches - ~/.gradle/wrapper + path: | + ~/.gradle/caches + ~/.gradle/wrapper key: ${{ runner.os }}-${{ matrix.java }}-gradle-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-${{ matrix.java }}-gradle- diff --git a/buildSrc/src/main/kotlin/benchmark-conventions.gradle.kts b/buildSrc/src/main/kotlin/benchmark-conventions.gradle.kts index 65608e8f..7d8775c6 100644 --- a/buildSrc/src/main/kotlin/benchmark-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/benchmark-conventions.gradle.kts @@ -20,6 +20,7 @@ * SOFTWARE. */ +import me.champeau.jmh.JMHTask import org.jetbrains.kotlin.allopen.gradle.* plugins { @@ -37,4 +38,19 @@ jmh { profilers.add("stack") profilers.add("gc") + + includeTests.set(false) // Do not include tests by default +} + +tasks.named("jmh", JMHTask::class) { + outputs.upToDateWhen { false } // XXX Do not cache the output of this task + + testRuntimeClasspath.setFrom() // XXX Clear test runtime classpath to eliminate duplicate dependencies on classpath +} + +dependencies { + constraints { + val libs = Libs(project) + jmh(libs["commons.math3"]) // XXX Force JMH to use the same commons-math3 version as OpenDC + } } diff --git a/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt b/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt index e34c5bdc..94e92c1b 100644 --- a/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt +++ b/opendc-experiments/opendc-experiments-capelin/src/test/kotlin/org/opendc/experiments/capelin/CapelinIntegrationTest.kt @@ -120,7 +120,7 @@ class CapelinIntegrationTest { { assertEquals(67006560, this@CapelinIntegrationTest.exporter.activeTime) { "Incorrect active time" } }, { assertEquals(3159377, this@CapelinIntegrationTest.exporter.stealTime) { "Incorrect steal time" } }, { assertEquals(0, this@CapelinIntegrationTest.exporter.lostTime) { "Incorrect lost time" } }, - { assertEquals(5.840212485920686E9, this@CapelinIntegrationTest.exporter.energyUsage, 0.01) { "Incorrect power draw" } }, + { assertEquals(5.840862926294953E9, this@CapelinIntegrationTest.exporter.energyUsage, 0.01) { "Incorrect power draw" } }, ) } @@ -164,7 +164,7 @@ class CapelinIntegrationTest { { assertEquals(9740289, this@CapelinIntegrationTest.exporter.activeTime) { "Active time incorrect" } }, { assertEquals(0, this@CapelinIntegrationTest.exporter.stealTime) { "Steal time incorrect" } }, { assertEquals(0, this@CapelinIntegrationTest.exporter.lostTime) { "Lost time incorrect" } }, - { assertEquals(7.0099453912813E8, this@CapelinIntegrationTest.exporter.energyUsage, 0.01) { "Incorrect power draw" } } + { assertEquals(7.010642279990053E8, this@CapelinIntegrationTest.exporter.energyUsage, 0.01) { "Incorrect power draw" } } ) } diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt index 9140d31b..5df03d45 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt +++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt @@ -60,8 +60,12 @@ public class SimBareMetalMachine( * The total energy usage of the machine (without PSU loss) in Joules. */ public val energyUsage: Double - get() = _energyUsage + get() { + computeEnergyUsage(engine.clock.millis()) + return _energyUsage + } private var _energyUsage = 0.0 + private var _energyLastComputation = 0L /** * The processing units of the machine. @@ -86,13 +90,25 @@ public class SimBareMetalMachine( val duration = max(0, now - lastConverge) if (duration > 0) { // Compute the power and energy usage of the machine - _energyUsage += _powerUsage * (duration / 1000.0) + computeEnergyUsage(now) _powerUsage = powerDriverLogic.computePower() } } init { psu.connect(powerDriverLogic) + _powerUsage = powerDriverLogic.computePower() + } + + /** + * Helper method to compute total energy usage. + */ + private fun computeEnergyUsage(now: Long) { + val duration = max(0, now - _energyLastComputation) + _energyLastComputation = now + + // Compute the energy usage of the machine + _energyUsage += _powerUsage * (duration / 1000.0) } /** diff --git a/opendc-simulator/opendc-simulator-flow/build.gradle.kts b/opendc-simulator/opendc-simulator-flow/build.gradle.kts index 05e21c3c..f5b67851 100644 --- a/opendc-simulator/opendc-simulator-flow/build.gradle.kts +++ b/opendc-simulator/opendc-simulator-flow/build.gradle.kts @@ -36,4 +36,6 @@ dependencies { testImplementation(projects.opendcSimulator.opendcSimulatorCore) testImplementation(libs.slf4j.simple) + + jmhImplementation(projects.opendcSimulator.opendcSimulatorCore) } diff --git a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowDeque.kt b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowDeque.kt index c6cba4b7..94232954 100644 --- a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowDeque.kt +++ b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowDeque.kt @@ -25,7 +25,10 @@ package org.opendc.simulator.flow.internal import java.util.* /** - * A specialized [ArrayDeque] for [FlowConsumerContextImpl] implementations. + * A specialized [ArrayDeque] that tracks the [FlowConsumerContextImpl] instances that have updated in an interpreter + * cycle. + * + * By using a specialized class, we reduce the overhead caused by type-erasure. */ internal class FlowDeque(initialCapacity: Int = 256) { /** @@ -106,7 +109,7 @@ internal class FlowDeque(initialCapacity: Int = 256) { val a = arrayOfNulls<FlowConsumerContextImpl>(newCapacity) - _elements.copyInto(a, 0, p, r) + _elements.copyInto(a, 0, p, n) _elements.copyInto(a, r, 0, p) _elements = a diff --git a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowTimerQueue.kt b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowTimerQueue.kt index 22a390e6..47061a91 100644 --- a/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowTimerQueue.kt +++ b/opendc-simulator/opendc-simulator-flow/src/main/kotlin/org/opendc/simulator/flow/internal/FlowTimerQueue.kt @@ -24,6 +24,9 @@ package org.opendc.simulator.flow.internal /** * Specialized priority queue for flow timers. + * + * By using a specialized priority queue, we reduce the overhead caused by the default priority queue implementation + * being generic. */ internal class FlowTimerQueue(initialCapacity: Int = 256) { /** @@ -46,9 +49,11 @@ internal class FlowTimerQueue(initialCapacity: Int = 256) { */ fun add(ctx: FlowConsumerContextImpl, deadline: Long) { val i = size - val deadlines = _deadlines + var deadlines = _deadlines if (i >= deadlines.size) { grow() + // Re-fetch the resized array + deadlines = _deadlines } siftUp(deadlines, _pending, i, ctx, deadline) diff --git a/opendc-telemetry/opendc-telemetry-sdk/src/main/kotlin/org/opendc/telemetry/sdk/OtelClockAdapter.kt b/opendc-telemetry/opendc-telemetry-sdk/src/main/kotlin/org/opendc/telemetry/sdk/OtelClockAdapter.kt index 86f6647e..cd191652 100644 --- a/opendc-telemetry/opendc-telemetry-sdk/src/main/kotlin/org/opendc/telemetry/sdk/OtelClockAdapter.kt +++ b/opendc-telemetry/opendc-telemetry-sdk/src/main/kotlin/org/opendc/telemetry/sdk/OtelClockAdapter.kt @@ -28,7 +28,7 @@ import io.opentelemetry.sdk.common.Clock * An adapter class that bridges a [java.time.Clock] to a [Clock] */ public class OtelClockAdapter(private val clock: java.time.Clock) : Clock { - override fun now(): Long = clock.millis() + override fun now(): Long = nanoTime() override fun nanoTime(): Long = clock.millis() * 1_000_000L } |
