Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,21 @@ lazy val termflowSample = (project in file("modules/termflow-sample"))
publish / skip := true
)

// JMH microbenchmark module. Deliberately NOT added to root.aggregate(...) so
// it is excluded from `ciCheck` (scalafmtCheckAll/scalafixAll/test follow
// project aggregation). It is built only by explicit `sbt "bench/..."`
// invocations and the dedicated bench CI workflow. The val MUST stay named
// `bench` so `sbt "bench/Jmh/run"` works verbatim.
lazy val bench = (project in file("modules/termflow-bench"))
.enablePlugins(JmhPlugin)
.dependsOn(termflowScreen, termflowApp, termflowWidgets, termflowSample, termflowTestkit)
.settings(
name := "termflow-bench",
commonSettings,
publish / skip := true,
coverageEnabled := false
)

addCommandAlias("ciCheck", ";scalafmtCheckAll;scalafixAll --check;test")
// `coverage`/`coverageReport` are sbt-scoverage *commands* — they
// can't be invoked with the `project/key` selector syntax. The pattern
Expand Down
32 changes: 32 additions & 0 deletions modules/termflow-bench/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# termflow-bench

JMH microbenchmarks for TermFlow (Scala 3 only).

## Not part of `ciCheck`

This module is **deliberately excluded** from `root.aggregate(...)` in
`build.sbt`. Because sbt's `scalafmtCheckAll`, `scalafixAll --check`, and `test`
all follow project aggregation, that means `ciCheck`
(`;scalafmtCheckAll;scalafixAll --check;test`) does **not** compile, test,
format-check, or scalafix-lint anything here.

The module is built only by:

- explicit `sbt "bench/..."` invocations, and
- the dedicated bench CI workflow.

Keep the code consistent with the repo's `.scalafmt.conf` anyway — run
`sbt "bench/scalafmt"` locally before committing.

## Running

```bash
# Quick smoke run (1 iteration, 1 warmup, 1 fork)
sbt "bench/Jmh/run -i 1 -wi 1 -f1"

# A specific benchmark
sbt "bench/Jmh/run -i 1 -wi 1 -f1 NoOpBench"
```

JMH benchmarks are **main** sources (`src/main/scala/termflow/bench/`), not test
sources.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package termflow.bench

import java.util.concurrent.TimeUnit

import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole

/**
* Trivial smoke benchmark proving the JMH harness compiles and runs.
*
* It does no TermFlow work; it only sums a small range of ints into a
* [[Blackhole]] so the JIT cannot elide the loop. Real benchmarks land in
* sibling classes; this one exists so `sbt "bench/Jmh/run"` has something to
* execute from day one.
*/
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
class NoOpBench:

@Benchmark
def sumInts(bh: Blackhole): Unit =
var total = 0
var i = 0
while i < 1000 do
total += i
i += 1
bh.consume(total)
1 change: 1 addition & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.11.0")
addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.12")
addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7")
Loading