Skip to content

Commit 89d1031

Browse files
Added an initial version of benchmarking to OpenDC
1 parent e9a1b60 commit 89d1031

36 files changed

+813
-112
lines changed

.github/workflows/build.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
branches: [ master ]
88
merge_group:
99

10+
permissions:
11+
contents: write # Required to push to the repository
12+
pages: write
13+
1014
jobs:
1115
build:
1216
name: Build (Java ${{ matrix.java }} - ${{ matrix.os }})
@@ -84,3 +88,43 @@ jobs:
8488
uses: docker/build-push-action@v6
8589
with:
8690
file: opendc-web/opendc-web-runner/Dockerfile
91+
benchmark:
92+
name: Benchmark
93+
runs-on: ubuntu-22.04
94+
steps:
95+
- name: Checkout repository
96+
uses: actions/checkout@v4
97+
- name: Validate Gradle wrapper
98+
uses: gradle/actions/wrapper-validation@v3
99+
- name: Set up JDK
100+
uses: actions/setup-java@v4
101+
with:
102+
distribution: 'zulu'
103+
java-version: 21
104+
- name: Run benchmark
105+
uses: gradle/actions/setup-gradle@v3
106+
with:
107+
arguments: jmh
108+
- name: Combine JMH benchmark results
109+
run: |
110+
mkdir -p combined-results
111+
echo "[]" > combined-results/results.json
112+
find . -name "results.json" -exec cat {} + > all-results.tmp.json
113+
jq -s 'add' all-results.tmp.json > combined-results/results.json
114+
rm all-results.tmp.json
115+
- name: Store benchmark results
116+
uses: benchmark-action/github-action-benchmark@v1
117+
with:
118+
name: OpenDC benchmarks
119+
tool: 'jmh'
120+
output-file-path: combined-results/results.json
121+
# Access token to deploy GitHub Pages branch
122+
github-token: ${{ secrets.GITHUB_TOKEN }}
123+
124+
comment-on-alert: true
125+
alert-comment-cc-users: '@DanteNiewenhuis'
126+
127+
# Push and deploy GitHub pages branch automatically
128+
auto-push: true
129+
summary-always: true
130+
benchmark-data-dir-path: site/dev/benchmarks

buildSrc/src/main/kotlin/benchmark-conventions.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@ configure<AllOpenExtension> {
3434
}
3535

3636
jmh {
37-
jmhVersion.set("1.35")
37+
jmhVersion.set("1.37")
3838

3939
profilers.add("stack")
4040
profilers.add("gc")
4141

4242
includeTests.set(false) // Do not include tests by default
43+
44+
resultFormat = "JSON"
4345
}
4446

4547
tasks.named("jmh", JMHTask::class) {

buildSrc/src/main/kotlin/testing-conventions.gradle.kts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,9 @@ dependencies {
4242
testRuntimeOnly(versionCatalog["junit.jupiter.engine"])
4343
}
4444

45-
tasks.register<Test>("testsOn18") {
45+
tasks.register<Test>("testsOn21") {
4646
javaLauncher.set(javaToolchains.launcherFor {
47-
languageVersion.set(JavaLanguageVersion.of(18))
48-
})
49-
50-
useJUnitPlatform()
51-
52-
minHeapSize = "512m"
53-
maxHeapSize = "1024m"
54-
jvmArgs = listOf("-XX:MaxMetaspaceSize=512m")
55-
}
56-
57-
tasks.register<Test>("testsOn19") {
58-
javaLauncher.set(javaToolchains.launcherFor {
59-
languageVersion.set(JavaLanguageVersion.of(19))
47+
languageVersion.set(JavaLanguageVersion.of(21))
6048
})
6149

6250
useJUnitPlatform()

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jackson = "2.16.1"
1010
jandex-gradle = "1.1.0"
1111
java = "21"
1212
jline = "3.25.1"
13-
jmh-gradle = "0.7.0"
13+
jmh-gradle = "0.7.3"
1414
jakarta = "3.0.2"
1515
junit-jupiter = "5.10.2"
1616
kotlin = "1.9.22"

opendc-experiments/opendc-experiments-base/build.gradle.kts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import me.champeau.jmh.JMHTask
2+
import org.gradle.kotlin.dsl.assign
3+
import org.gradle.kotlin.dsl.named
4+
15
/*
26
* Copyright (c) 2022 AtLarge Research
37
*
@@ -27,6 +31,7 @@ plugins {
2731
`kotlin-library-conventions`
2832
`testing-conventions`
2933
`jacoco-conventions`
34+
`benchmark-conventions`
3035
distribution
3136
kotlin("plugin.serialization") version "1.9.22"
3237
}
@@ -58,6 +63,17 @@ val createScenarioApp by tasks.creating(CreateStartScripts::class) {
5863
outputDir = layout.buildDirectory.dir("scripts").get().asFile
5964
}
6065

66+
//tasks.named("jmh", JMHTask::class) {
67+
// outputs.upToDateWhen { false } // XXX Do not cache the output of this task
68+
// jvmArgs = listOf("-Djmh.outputFormat=json", "-Djmh.output=/reports/jmh/results-${project.name}.json")
69+
// testRuntimeClasspath.setFrom() // XXX Clear test runtime classpath to eliminate duplicate dependencies on classpath
70+
//}
71+
72+
//jmh {
73+
// resultFormat = "JSON" // <--- Key: This sets the output format
74+
// resultsFile = file("$buildDir/reports/jmh/results-${project.name}.json") // <--- Sets the output file
75+
//}
76+
6177
// Create custom Scenario distribution
6278
distributions {
6379
main {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2025 AtLarge Research
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package org.opendc.experiments.base
24+
25+
import org.opendc.compute.workload.Task
26+
import org.opendc.simulator.compute.workload.trace.TraceFragment
27+
import org.openjdk.jmh.annotations.Benchmark
28+
import org.openjdk.jmh.annotations.BenchmarkMode
29+
import org.openjdk.jmh.annotations.Fork
30+
import org.openjdk.jmh.annotations.Level
31+
import org.openjdk.jmh.annotations.Measurement
32+
import org.openjdk.jmh.annotations.Mode
33+
import org.openjdk.jmh.annotations.OutputTimeUnit
34+
import org.openjdk.jmh.annotations.Scope
35+
import org.openjdk.jmh.annotations.Setup
36+
import org.openjdk.jmh.annotations.State
37+
import org.openjdk.jmh.annotations.Warmup
38+
import java.util.ArrayList
39+
import java.util.concurrent.TimeUnit
40+
41+
@BenchmarkMode(Mode.AverageTime) // or Mode.AverageTime
42+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
43+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.MILLISECONDS)
44+
@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.MILLISECONDS)
45+
@State(Scope.Thread)
46+
@Fork(1)
47+
class BasicBenchmark {
48+
private lateinit var list: MutableList<Int>
49+
50+
@Setup(Level.Iteration)
51+
fun setUp() {
52+
list = mutableListOf()
53+
}
54+
55+
/**
56+
* FlowDistributor test 13: 1000 tasks. This tests the performance
57+
* In this test, two tasks are scheduled, and they can both fit.
58+
* However, task 0 increases its demand which overloads the FlowDistributor.
59+
* This test shows how the FlowDistributor handles transition from fitting to overloading when multiple tasks are running.
60+
* We check if both the host and the Tasks show the correct cpu usage and demand during the two fragments.
61+
*/
62+
@Benchmark
63+
fun benchmarkFlowDistributor1() {
64+
val workload: ArrayList<Task> =
65+
arrayListOf<Task>().apply {
66+
repeat(1000) {
67+
this.add(
68+
createBenchmarkTask(
69+
name = "0",
70+
fragments =
71+
arrayListOf(TraceFragment(10 * 60 * 1000, 2000.0, 1)),
72+
),
73+
)
74+
}
75+
}
76+
val topology = createTopology("single_1_2000.json")
77+
78+
val monitor = runBenchmark(topology, workload)
79+
}
80+
}

0 commit comments

Comments
 (0)