Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
8b18aff
Add JMH benchmarks for datetime format creation and performance evalu…
DmitryNekrasov Nov 12, 2025
d4a2bdd
Introduce `ConcatenatedListView` for efficient list concatenation in …
DmitryNekrasov Nov 12, 2025
e03b0a9
Remove redundant type parameter `<T>` in `ParserStructure.simplify` m…
DmitryNekrasov Nov 12, 2025
0eadd92
Add unconditionalModifications after each step of simplification
DmitryNekrasov Nov 18, 2025
7cb14e0
Rename `unconditionalModificationsForTails` to `unconditionalModifica…
DmitryNekrasov Nov 18, 2025
823e65a
Refactor `ParserStructure` logic to use `buildList` for streamlined l…
DmitryNekrasov Nov 18, 2025
e3d88b2
Refactor `ParserStructure` instantiation to improve formatting and re…
DmitryNekrasov Nov 18, 2025
f07556f
Reorder `unconditionalModifications` placement in `ParserStructure`.
DmitryNekrasov Nov 18, 2025
3a3ba54
Passes all tests and it has benchmarc score increase on Python dateti…
DmitryNekrasov Nov 18, 2025
6b753bd
Refactor `ParserStructure` logic to extract `mergeOperations` for cle…
DmitryNekrasov Nov 18, 2025
67630d9
Refactor `ParserStructure.concat` logic to simplify `mergeOperations`…
DmitryNekrasov Nov 18, 2025
459dd76
Add missing newline
DmitryNekrasov Nov 18, 2025
ed9db86
Rename `operations` to `mergedOperations`.
DmitryNekrasov Nov 18, 2025
9a9a628
Simplify the ` mergedTails ` condition.
DmitryNekrasov Nov 19, 2025
d923b96
Reorder and simplify `unconditionalModifications` handling in `Parser…
DmitryNekrasov Nov 19, 2025
f5db9de
Refactor `ParserStructure` logic to streamline `mergedOperations` con…
DmitryNekrasov Nov 19, 2025
2907804
Fix typo in comment: "number consumers" → "number of consumers".
DmitryNekrasov Nov 19, 2025
6b10288
Refactor `mergedOperations` construction to reuse `operationsToMerge`…
DmitryNekrasov Nov 19, 2025
d371115
Refactor `PythonDateTimeFormatBenchmark` into `CommonFormats`, update…
DmitryNekrasov Nov 19, 2025
1d2a7e2
Add benchmark for building four-digit UTC offset format
DmitryNekrasov Nov 19, 2025
c674a83
Add benchmark for building RFC 1123 DateTime format
DmitryNekrasov Nov 19, 2025
502b0c3
Add benchmark for building ISO DateTime with offset format
DmitryNekrasov Nov 19, 2025
ba37c51
Refactor RFC 1123 and UTC offset format benchmarks to use inline form…
DmitryNekrasov Nov 19, 2025
41d338a
Remove `ConcatenatedListView` as it is no longer in use.
DmitryNekrasov Nov 19, 2025
5af9c09
Remove `SerialFormatBenchmark` as it is no longer in use.
DmitryNekrasov Nov 19, 2025
6470c77
Update `ParallelFormatBenchmark` warmup and measurement parameters.
DmitryNekrasov Nov 19, 2025
292ea76
Update copyright year range in `Parser.kt` header.
DmitryNekrasov Nov 19, 2025
de419dd
Optimize concatenation of flat parsers.
DmitryNekrasov Nov 20, 2025
b9b0a4b
Refactor `Parser` to streamline handling of accumulated operations.
DmitryNekrasov Nov 20, 2025
2ed069e
Add `SerialFormatBenchmark` for evaluating large format serialization…
DmitryNekrasov Nov 20, 2025
991a1fb
Refactor `Parser` to replace `drop(1)` with an explicit loop for merg…
DmitryNekrasov Nov 21, 2025
ed4720b
Refactor `Parser` to apply `unconditionalModifications` after process…
DmitryNekrasov Nov 21, 2025
8e37066
Fix typo in comment within `Parser.kt`
DmitryNekrasov Nov 27, 2025
c7c1350
Document `mergeOperations` function with detailed explanation of para…
DmitryNekrasov Nov 27, 2025
859bc18
Fix the comment regarding unconditional modifications in `Parser.kt`.
DmitryNekrasov Nov 27, 2025
83e5763
Document `simplifyAndAppend` function with detailed explanation of be…
DmitryNekrasov Nov 27, 2025
97b820f
Improve comments in `Parser` for better clarity on reverse order proc…
DmitryNekrasov Nov 27, 2025
8eddac6
Document `concat` extension function in `Parser.kt` with details on b…
DmitryNekrasov Nov 27, 2025
5c46bc3
Fix typos and clarify comments in `Parser.kt` regarding invariants an…
DmitryNekrasov Nov 27, 2025
873a49e
Add validation check for non-empty operations in `mergeOperations` of…
DmitryNekrasov Nov 27, 2025
0976016
Refactor `concat` function in `Parser.kt`, simplifying comments
DmitryNekrasov Nov 28, 2025
313432c
Add `ParserStructureConcatenationTest` to verify `concat` behavior an…
DmitryNekrasov Dec 3, 2025
f05b0bf
Remove unnecessary validation check for non-empty operations in `merg…
DmitryNekrasov Dec 3, 2025
b4b080d
Add test case for `concat` to verify operation flattening and nesting…
DmitryNekrasov Dec 3, 2025
72e8b12
Refactor tests in `ParserStructureConcatenationTest` to use `assertTr…
DmitryNekrasov Dec 3, 2025
ae9a10c
Remove redundant comments regarding invariants in `concat` function o…
DmitryNekrasov Dec 3, 2025
4f3ac20
Add test for `concat` to verify distribution of `UnconditionalModific…
DmitryNekrasov Dec 3, 2025
bbf5bc5
Fix a bug
DmitryNekrasov Dec 3, 2025
3c88d25
Refactor `ParserStructureConcatenationTest` to inline parser creation…
DmitryNekrasov Dec 3, 2025
75e00b0
Add test for `concat` to verify distribution of `NumberSpanParserOper…
DmitryNekrasov Dec 3, 2025
87640fe
Refactor comment
DmitryNekrasov Dec 3, 2025
aaf58ec
Refactor `Parser.kt` to replace `if-else` with `when` for operation h…
DmitryNekrasov Dec 3, 2025
56b5b4d
Add some optimization for unconditionalModifications promotion
DmitryNekrasov Dec 4, 2025
0c14518
Fix typo in comment of `ParserStructureConcatenationTest` test case.
DmitryNekrasov Dec 4, 2025
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
167 changes: 167 additions & 0 deletions benchmarks/src/jmh/kotlin/CommonFormats.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright 2019-2025 JetBrains s.r.o. and contributors.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

@file:Suppress("unused")

package kotlinx.datetime

import kotlinx.datetime.format.*
import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole
import java.util.concurrent.*

@Warmup(iterations = 20, time = 2)
@Measurement(iterations = 30, time = 2)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Fork(2)
open class CommonFormats {

@Benchmark
fun buildPythonDateTimeFormat(blackhole: Blackhole) {
val v = LocalDateTime.Format {
year()
char('-')
monthNumber()
char('-')
day()
char(' ')
hour()
char(':')
minute()
optional {
char(':')
second()
optional {
char('.')
secondFraction()
}
}
}
blackhole.consume(v)
}

@Benchmark
fun buildIsoDateTimeFormat(blackhole: Blackhole) {
val format = LocalDateTime.Format {
date(LocalDate.Format {
year()
char('-')
monthNumber()
char('-')
day()
})
alternativeParsing({ char('t') }) { char('T') }
time(LocalTime.Format {
hour()
char(':')
minute()
alternativeParsing({}) {
char(':')
second()
optional {
char('.')
secondFraction(1, 9)
}
}
})
}
blackhole.consume(format)
}

@Benchmark
fun buildFourDigitsUtcOffsetFormat(blackhole: Blackhole) {
val format = UtcOffset.Format {
offsetHours()
offsetMinutesOfHour()
}
blackhole.consume(format)
}

@Benchmark
fun buildRfc1123DateTimeFormat(blackhole: Blackhole) {
val format = DateTimeComponents.Format {
alternativeParsing({
// the day of week may be missing
}) {
dayOfWeek(DayOfWeekNames.ENGLISH_ABBREVIATED)
chars(", ")
}
day(Padding.NONE)
char(' ')
monthName(MonthNames.ENGLISH_ABBREVIATED)
char(' ')
year()
char(' ')
hour()
char(':')
minute()
optional {
char(':')
second()
}
chars(" ")
alternativeParsing({
chars("UT")
}, {
chars("Z")
}) {
optional("GMT") {
offset(UtcOffset.Format {
offsetHours()
offsetMinutesOfHour()
})
}
}
}
blackhole.consume(format)
}

@Benchmark
fun buildIsoDateTimeOffsetFormat(blackhole: Blackhole) {
val format = DateTimeComponents.Format {
date(LocalDate.Format {
year()
char('-')
monthNumber()
char('-')
day()
})
alternativeParsing({
char('t')
}) {
char('T')
}
hour()
char(':')
minute()
char(':')
second()
optional {
char('.')
secondFraction(1, 9)
}
alternativeParsing({
offsetHours()
}) {
offset(UtcOffset.Format {
alternativeParsing({ chars("z") }) {
optional("Z") {
offsetHours()
char(':')
offsetMinutesOfHour()
optional {
char(':')
offsetSecondsOfMinute()
}
}
}
})
}
}
blackhole.consume(format)
}
}
88 changes: 88 additions & 0 deletions benchmarks/src/jmh/kotlin/ParallelFormatBenchmark.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2019-2025 JetBrains s.r.o. and contributors.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

@file:Suppress("unused")

package kotlinx.datetime

import kotlinx.datetime.format.alternativeParsing
import kotlinx.datetime.format.char
import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole
import java.util.concurrent.TimeUnit

@Warmup(iterations = 10, time = 2)
@Measurement(iterations = 20, time = 2)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Fork(1)
open class ParallelFormatBenchmark {

@Param("2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12")
var n = 0

@Benchmark
fun formatCreationWithAlternativeParsing(blackhole: Blackhole) {
val format = LocalDateTime.Format {
repeat(n) {
alternativeParsing(
{ monthNumber() },
{ day() },
primaryFormat = { hour() }
)
char('@')
minute()
char('#')
second()
}
}
blackhole.consume(format)
}

@Benchmark
fun formatCreationWithNestedAlternativeParsing(blackhole: Blackhole) {
val format = LocalDateTime.Format {
repeat(n) { index ->
alternativeParsing(
{ monthNumber(); char('-'); day() },
{ day(); char('/'); monthNumber() },
primaryFormat = { year(); char('-'); monthNumber(); char('-'); day() }
)

if (index and 1 == 0) {
alternativeParsing(
{
alternativeParsing(
{ hour(); char(':'); minute() },
{ minute(); char(':'); second() },
primaryFormat = { hour(); char(':'); minute(); char(':'); second() }
)
},
primaryFormat = {
year(); char('-'); monthNumber(); char('-'); day()
char('T')
hour(); char(':'); minute(); char(':'); second()
}
)
}

char('|')
if (index % 3 == 0) {
char('|')
}

if (index and 2 == 0) {
alternativeParsing(
{ char('Z') },
{ char('+'); hour(); char(':'); minute() },
primaryFormat = { char('-'); hour(); char(':'); minute() }
)
}
}
}
blackhole.consume(format)
}
}
45 changes: 45 additions & 0 deletions benchmarks/src/jmh/kotlin/SerialFormatBenchmark.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2019-2025 JetBrains s.r.o. and contributors.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

@file:Suppress("unused")

package kotlinx.datetime

import kotlinx.datetime.format.char
import org.openjdk.jmh.annotations.*
import org.openjdk.jmh.infra.Blackhole
import java.util.concurrent.TimeUnit

@Warmup(iterations = 10, time = 2)
@Measurement(iterations = 20, time = 2)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Fork(1)
open class SerialFormatBenchmark {

@Param("1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024")
var n = 0

@Benchmark
fun largeSerialFormat(blackhole: Blackhole) {
val format = LocalDateTime.Format {
repeat(n) {
char('^')
monthNumber()
char('&')
day()
char('!')
hour()
char('$')
minute()
char('#')
second()
char('@')
}
}
blackhole.consume(format)
}
}
Loading