Skip to content
Closed
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
4 changes: 2 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import _root_.mdoc.MdocPlugin
// ===== Build‑wide Settings =====
ThisBuild / organization := "net.ghoula"
ThisBuild / versionScheme := Some("early-semver")
ThisBuild / scalaVersion := "3.7.1"
ThisBuild / scalaVersion := "3.7.2"
ThisBuild / semanticdbEnabled := true
ThisBuild / semanticdbVersion := scalafixSemanticdb.revision

Expand Down Expand Up @@ -37,7 +37,7 @@ ThisBuild / scalacOptions ++= Seq(
"-Wunused:imports",
"-no-indent"
)
ThisBuild / javacOptions ++= Seq("--release", "17")
ThisBuild / javacOptions ++= Seq("--release", "21")

// ===== Project Definitions =====
lazy val root = (project in file("."))
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.11.3
sbt.version=1.11.4
50 changes: 24 additions & 26 deletions valar-benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,49 +11,47 @@ The benchmark suite covers:

## Benchmark Results

Based on the latest run (JDK 21.0.7, OpenJDK 64-Bit Server VM):

| Benchmark | Mode | Score | Error | Units |
|----------------------|------|------------|-------------|-------|
| `syncSimpleValid` | avgt | 44.628 | ± 6.746 | ns/op |
| `syncSimpleInvalid` | avgt | 149.155 | ± 7.124 | ns/op |
| `syncNestedValid` | avgt | 108.968 | ± 7.300 | ns/op |
| `syncNestedInvalid` | avgt | 449.783 | ± 18.373 | ns/op |
| `asyncSimpleValid` | avgt | 13,212.036 | ± 1,114.597 | ns/op |
| `asyncSimpleInvalid` | avgt | 13,465.022 | ± 214.379 | ns/op |
| `asyncNestedValid` | avgt | 14,513.056 | ± 1,023.942 | ns/op |
| `asyncNestedInvalid` | avgt | 15,432.503 | ± 2,592.103 | ns/op |
Based on the latest run (JDK 21.0.8, OpenJDK 64-Bit Server VM):

| Benchmark | Mode | Score | Error | Units |
|----------------------|------|------------|--------------|-------|
| `syncSimpleValid` | avgt | 60.858 | ± 0.743 | ns/op |
| `syncSimpleInvalid` | avgt | 171.782 | ± 1.806 | ns/op |
| `syncNestedValid` | avgt | 115.872 | ± 3.227 | ns/op |
| `syncNestedInvalid` | avgt | 431.439 | ± 10.251 | ns/op |
| `asyncSimpleValid` | avgt | 17,656.897 | ± 444.704 | ns/op |
| `asyncSimpleInvalid` | avgt | 17,704.613 | ± 254.509 | ns/op |
| `asyncNestedValid` | avgt | 21,292.686 | ± 542.063 | ns/op |
| `asyncNestedInvalid` | avgt | 26,748.345 | ± 10,286.717 | ns/op |

## Performance Analysis

### 🚀 Synchronous Performance is Excellent
### Synchronous Validation Performance

The validation for simple, valid objects completes in **~45 nanoseconds**. This is incredibly fast and proves that for the "happy path," the library adds negligible overhead. The slightly higher numbers for invalid and nested cases (~150–450 ns) are also excellent and are expected, as they account for:
The validation for simple, valid objects completes in **~61 nanoseconds**. Invalid and nested cases show higher execution times (~172–431 ns), which can be attributed to:

- Creation of `ValidationError` objects for invalid cases
- Recursive validation calls for nested structures
- Error accumulation logic

**Key takeaway**: Synchronous validation is extremely fast with minimal overhead.
### Asynchronous Validation Performance

### ⚡ Asynchronous Performance is As Expected

The async benchmarks show results in the **~13–16 microsecond range** (13,00016,000 ns). This is excellent and exactly what we should expect. The "cost" here is not from our validation logic but from the inherent overhead of:
The async benchmarks show results in the **~18–27 microsecond range** (18,000–27,000 ns). The overhead observed includes:

- Creating `Future` instances
- Managing the `ExecutionContext`
- The `Await.result` call in the benchmark (blocking on async results)

**Key takeaway**: Our async logic is efficient and correctly builds on Scala's non-blocking primitives without introducing performance bottlenecks.

### Summary

- **Sync validation**: Negligible overhead, perfect for high-throughput scenarios
- **Async validation**: Adds only the expected Future abstraction overhead
- **Valid vs Invalid**: Invalid cases show expected slight overhead due to error object creation
- **Simple vs Nested**: Nested validation scales linearly with complexity
The benchmark results show the following patterns:

- **Sync validation**: Execution times range from 61ns for simple valid cases to 431ns for nested invalid cases
- **Async validation**: Execution times range from 17.7μs to 26.7μs across different scenarios
- **Valid vs Invalid**: Invalid cases consistently show higher execution times due to error object creation
- **Simple vs Nested**: Nested validation shows increased execution time proportional to structural complexity

The results confirm that Valar introduces no significant performance penalties beyond what's inherent to the chosen execution model (sync vs. async).
These measurements represent the current performance characteristics under the specified test conditions.

## Running Benchmarks

Expand Down Expand Up @@ -129,7 +127,7 @@ To add new benchmarks:

## Dependencies
- JMH 1.37
- Scala 3.7.1
- Scala 3.7.2
- OpenJDK 21+

## Notes
Expand Down