Skip to content

Commit

Permalink
benchmark results added
Browse files Browse the repository at this point in the history
th2 gradle plugin updated
  • Loading branch information
lumber1000 committed Sep 17, 2024
1 parent d8604e5 commit 5951ab7
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 37 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ default value: `true`. If `true`, decodes all values to strings instead of typed
#### decodeComponentsToNestedMaps
default value: `true`. If `true`, decodes `components` to nested maps instead of unwrap component's map to message's main map.

## Performance
Component benchmark results available [here](docs/benchmarks/jmh-benchmark.md).

## Release notes
### 0.1.0
+ Dirty mode added.
Expand Down
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id "application"
id "com.exactpro.th2.gradle.component" version "0.1.1"
id "com.exactpro.th2.gradle.component" version "0.1.2"
id "org.jetbrains.kotlin.jvm" version "$kotlin_version"
id "org.jetbrains.kotlin.kapt" version "$kotlin_version"
id "me.champeau.jmh" version "0.7.2"
Expand Down Expand Up @@ -95,11 +95,11 @@ dependencies {
jmh "org.openjdk.jmh:jmh-generator-annprocess:$jmhVersion"
jmh "org.openjdk.jmh:jmh-generator-bytecode:$jmhVersion"

testImplementation "org.junit.jupiter:junit-jupiter"
testImplementation "org.junit.jupiter:junit-jupiter:5.11.0"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit5"
testImplementation "org.assertj:assertj-core:3.26.3"
}

test.useJUnitPlatform()
application.mainClass = "com.exactpro.th2.codec.MainKt"
dependencyCheck.suppressionFile = file('suppressions.xml')
dependencyCheck.suppressionFile = "suppressions.xml"
84 changes: 84 additions & 0 deletions docs/benchmarks/jmh-benchmark.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# JMH benchmark

encode the following FIX message:

```kotlin
ParsedMessage(
MessageId("test_alias", Direction.OUTGOING, 0L, Instant.now(), emptyList()),
EventId("test_id", "test_book", "test_scope", Instant.now()),
"ExecutionReport",
mutableMapOf("encode-mode" to "dirty"),
PROTOCOL,
mutableMapOf(
"header" to mutableMapOf(
"MsgSeqNum" to 10947,
"SenderCompID" to "SENDER",
"SendingTime" to LocalDateTime.parse("2023-04-19T10:36:07.415088"),
"TargetCompID" to "RECEIVER",
"BeginString" to "FIXT.1.1",
"BodyLength" to 295,
"MsgType" to "8"
),
"ExecID" to "495504662",
"ClOrdID" to "zSuNbrBIZyVljs",
"OrigClOrdID" to "zSuNbrBIZyVljs",
"OrderID" to "49415882",
"ExecType" to '0',
"OrdStatus" to '0',
"LeavesQty" to BigDecimal(500),
"CumQty" to BigDecimal(500),
"SecurityID" to "NWDR",
"SecurityIDSource" to "8",
"TradingParty" to mutableMapOf(
"NoPartyIDs" to mutableListOf(
mutableMapOf(
"PartyID" to "NGALL1FX01",
"PartyIDSource" to 'D',
"PartyRole" to 76
),
mutableMapOf(
"PartyID" to "0",
"PartyIDSource" to 'P',
"PartyRole" to 3
)
)
),
"Account" to "test",
"OrdType" to 'A',
"TimeInForce" to '0',
"Side" to 'B',
"Symbol" to "ABC",
"OrderQty" to BigDecimal(500),
"Price" to BigDecimal(1000),
"Unknown" to "500",
"TransactTime" to LocalDateTime.parse("2018-02-05T10:38:08.000008"),
"trailer" to mutableMapOf(
"CheckSum" to "191"
)
)
)
```

decode the same FIX message:

8=FIXT.1.19=29535=849=SENDER56=RECEIVER34=1094752=20230419-10:36:07.41508817=49550466211=zSuNbrBIZyVljs41=zSuNbrBIZyVljs37=49415882150=039=0151=50014=50048=NWDR22=8453=2448=NGALL1FX01447=D452=76448=0447=P452=31=test40=A59=054=B55=ABC38=50044=100047=50060=20180205-10:38:08.00000810=191

Testing is carried out in two formats of parsed messages: String values and Typed values.

## benchmark results for version 0.1.0-dev

dirty mode:

Benchmark Mode Cnt Score Error Units
FixNgCodecBenchmark.encodeFixMessageString thrpt 25 178479.225 ± 2851.079 ops/s
FixNgCodecBenchmark.encodeFixMessageTyped thrpt 25 263077.629 ± 3967.905 ops/s
FixNgCodecBenchmark.parseFixMessageString thrpt 25 173370.305 ± 1878.013 ops/s
FixNgCodecBenchmark.parseFixMessageTyped thrpt 25 186232.291 ± 1295.186 ops/s

strict mode:

Benchmark Mode Cnt Score Error Units
FixNgCodecBenchmark.encodeFixMessageString thrpt 25 179523.040 ± 3084.493 ops/s
FixNgCodecBenchmark.encodeFixMessageTyped thrpt 25 265769.868 ± 3893.223 ops/s
FixNgCodecBenchmark.parseFixMessageString thrpt 25 165978.593 ± 6474.860 ops/s
FixNgCodecBenchmark.parseFixMessageTyped thrpt 25 186475.155 ± 1548.224 ops/s
103 changes: 69 additions & 34 deletions src/jmh/kotlin/com/exactpro/th2/codec/fixng/FixNgCodecBenchmark.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,31 @@ import org.openjdk.jmh.annotations.Mode
import org.openjdk.jmh.annotations.Scope
import org.openjdk.jmh.annotations.Setup
import org.openjdk.jmh.annotations.State
import java.math.BigDecimal
import java.time.Instant
import java.time.LocalDateTime

@State(Scope.Benchmark)
open class BenchmarkState {
lateinit var codec: IPipelineCodec
lateinit var rawBody: ByteBuf
lateinit var codecTyped: IPipelineCodec
lateinit var codecString: IPipelineCodec
private lateinit var rawBody: ByteBuf
lateinit var rawGroup: MessageGroup
lateinit var parsedGroup: MessageGroup
lateinit var parsedGroupTyped: MessageGroup
lateinit var parsedGroupString: MessageGroup

@Setup(Level.Trial)
fun setup() {
val dictionary: IDictionaryStructure = FixNgCodecTest::class.java.classLoader
.getResourceAsStream("dictionary-benchmark.xml")
.use(XmlDictionaryStructureLoader()::load)

codec = FixNgCodec(dictionary, FixNgCodecSettings(dictionary = "", decodeValuesToStrings = true))
codecTyped = FixNgCodec(dictionary, FixNgCodecSettings(dictionary = "", decodeValuesToStrings = false))
codecString = FixNgCodec(dictionary, FixNgCodecSettings(dictionary = "", decodeValuesToStrings = true))
rawBody = Unpooled.wrappedBuffer(MSG_CORRECT.toByteArray(Charsets.US_ASCII))
rawGroup = MessageGroup(listOf(RawMessage(id = parsedMessage.id, eventId = parsedMessage.eventId, body = rawBody)))
parsedGroup = MessageGroup(listOf(parsedMessage))
rawGroup = MessageGroup(listOf(RawMessage(id = parsedMessageTyped.id, eventId = parsedMessageTyped.eventId, body = rawBody, metadata = mutableMapOf("encode-mode" to "dirty"))))
parsedGroupTyped = MessageGroup(listOf(parsedMessageTyped))
parsedGroupString = MessageGroup(listOf(parsedMessageString))
}

@Setup(Level.Invocation)
Expand All @@ -64,20 +70,21 @@ open class BenchmarkState {

companion object {
private const val MSG_CORRECT = "8=FIXT.1.1\u00019=295\u000135=8\u000149=SENDER\u000156=RECEIVER\u000134=10947\u000152=20230419-10:36:07.415088\u000117=495504662\u000111=zSuNbrBIZyVljs\u000141=zSuNbrBIZyVljs\u000137=49415882\u0001150=0\u000139=0\u0001151=500\u000114=500\u000148=NWDR\u000122=8\u0001453=2\u0001448=NGALL1FX01\u0001447=D\u0001452=76\u0001448=0\u0001447=P\u0001452=3\u00011=test\u000140=A\u000159=0\u000154=B\u000155=ABC\u000138=500\u000144=1000\u000147=500\u000160=20180205-10:38:08.000008\u000110=191\u0001"
private val parsedMessage = ParsedMessage(

private val parsedMessageTyped = ParsedMessage(
MessageId("test_alias", Direction.OUTGOING, 0L, Instant.now(), emptyList()),
EventId("test_id", "test_book", "test_scope", Instant.now()),
"ExecutionReport",
mapOf("encode-mode" to "dirty"),
mutableMapOf("encode-mode" to "dirty"),
PROTOCOL,
mapOf(
"header" to mapOf(
"MsgSeqNum" to "10947",
mutableMapOf(
"header" to mutableMapOf(
"MsgSeqNum" to 10947,
"SenderCompID" to "SENDER",
"SendingTime" to "2023-04-19T10:36:07.415088",
"SendingTime" to LocalDateTime.parse("2023-04-19T10:36:07.415088"),
"TargetCompID" to "RECEIVER",
"BeginString" to "FIXT.1.1",
"BodyLength" to "295",
"BodyLength" to 295,
"MsgType" to "8"
),
"ExecID" to "495504662",
Expand All @@ -86,52 +93,80 @@ open class BenchmarkState {
"OrderID" to "49415882",
"ExecType" to '0',
"OrdStatus" to '0',
"LeavesQty" to "500",
"CumQty" to "500",
"LeavesQty" to BigDecimal(500),
"CumQty" to BigDecimal(500),
"SecurityID" to "NWDR",
"SecurityIDSource" to "8",
"TradingParty" to mapOf(
"NoPartyIDs" to listOf(
mapOf(
"TradingParty" to mutableMapOf(
"NoPartyIDs" to mutableListOf(
mutableMapOf(
"PartyID" to "NGALL1FX01",
"PartyIDSource" to "D",
"PartyRole" to "76"
"PartyIDSource" to 'D',
"PartyRole" to 76
),
mapOf(
mutableMapOf(
"PartyID" to "0",
"PartyIDSource" to "P",
"PartyRole" to "3"
"PartyIDSource" to 'P',
"PartyRole" to 3
)
)
),
"Account" to "test",
"OrdType" to "A",
"TimeInForce" to "0",
"Side" to "B",
"OrdType" to 'A',
"TimeInForce" to '0',
"Side" to 'B',
"Symbol" to "ABC",
"OrderQty" to "500",
"Price" to "1000",
"OrderQty" to BigDecimal(500),
"Price" to BigDecimal(1000),
"Unknown" to "500",
"TransactTime" to "2018-02-05T10:38:08.000008",
"trailer" to mapOf(
"TransactTime" to LocalDateTime.parse("2018-02-05T10:38:08.000008"),
"trailer" to mutableMapOf(
"CheckSum" to "191"
)
)
)

@Suppress("UNCHECKED_CAST")
private val parsedMessageString = ParsedMessage(
MessageId("test_alias", Direction.OUTGOING, 0L, Instant.now(), emptyList()),
EventId("test_id", "test_book", "test_scope", Instant.now()),
"ExecutionReport",
mutableMapOf(/*"encode-mode" to "dirty"*/),
PROTOCOL,
convertValuesToString(parsedMessageTyped.body) as MutableMap<String, Any>
)

private fun convertValuesToString(value: Any?): Any = when (value) {
is Map<*, *> -> value.mapValues { convertValuesToString(it.value) }
is List<*> -> value.map(::convertValuesToString)
else -> value.toString()
}
}
}

open class FixNgCodecBenchmark {
@Benchmark
@BenchmarkMode(Mode.Throughput)
fun encodeFixMessage(state: BenchmarkState) {
state.codec.encode(state.parsedGroup, context)
fun encodeFixMessageTyped(state: BenchmarkState) {
state.codecTyped.encode(state.parsedGroupTyped, context)
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
fun parseFixMessageTyped(state: BenchmarkState) {
state.codecTyped.decode(state.rawGroup, context)
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
fun encodeFixMessageString(state: BenchmarkState) {
state.codecString.encode(state.parsedGroupString, context)
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
fun parseFixMessage(state: BenchmarkState) {
state.codec.decode(state.rawGroup, context)
fun parseFixMessageString(state: BenchmarkState) {
state.codecString.decode(state.rawGroup, context)
}

companion object {
Expand Down

0 comments on commit 5951ab7

Please sign in to comment.