From 3a37d5e42d908d5586ccb633da1bcdc1e9bf0ca7 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Fri, 25 Jul 2025 14:29:14 -0400 Subject: [PATCH] Fixes the benchmark testing cases --- .../benchmark/BaseLargeCacheBenchmark.kt | 63 +++++ .../quartz/benchmark/EventBenchmark.kt | 5 +- .../benchmark/GiftWrapReceivingBenchmark.kt | 102 ++++----- .../benchmark/GiftWrapSigningBenchmark.kt | 216 ++++++++---------- .../quartz/benchmark/HintIndexerBenchmark.kt | 2 + .../quartz/benchmark/LargeCacheBenchmark.kt | 44 +--- 6 files changed, 207 insertions(+), 225 deletions(-) create mode 100644 benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt new file mode 100644 index 000000000..bcf917ec0 --- /dev/null +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/BaseLargeCacheBenchmark.kt @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.benchmark + +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.fasterxml.jackson.module.kotlin.readValue +import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper +import com.vitorpamplona.quartz.utils.LargeCache +import org.junit.Assert.assertTrue +import java.util.function.Consumer +import java.util.zip.GZIPInputStream + +open class BaseLargeCacheBenchmark { + fun getEventDB(): List { + // This file includes duplicates + val fullDBInputStream = getInstrumentation().context.assets.open("nostr_vitor_startup_data.json") + + return JsonMapper.mapper.readValue>( + GZIPInputStream(fullDBInputStream), + ) + } + + fun getLargeCache(db: List): LargeCache { + val cache = LargeCache() + + db.forEach { + cache.getOrCreate(it.id) { key -> + it + } + } + + return cache + } + + fun hasId(event: Event) { + assertTrue(event.id.isNotEmpty()) + } + + val consumer = + Consumer { + hasId(it) + } +} diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt index 0820f4560..d7489336b 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/EventBenchmark.kt @@ -28,6 +28,7 @@ import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper import com.vitorpamplona.quartz.nip01Core.verify import com.vitorpamplona.quartz.nip01Core.verifyId import com.vitorpamplona.quartz.nip01Core.verifySignature +import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent import com.vitorpamplona.quartz.utils.TimeUtils import junit.framework.TestCase.assertTrue import org.junit.Rule @@ -90,7 +91,7 @@ class EventBenchmark { val now = TimeUtils.now() val tags = arrayOf(arrayOf("")) benchmarkRule.measureRepeated { - EventFactory.create("id", "pubkey", now, 1, tags, "content", "sig") + EventFactory.create("id", "pubkey", now, 1, tags, "content", "sig") } } @@ -99,7 +100,7 @@ class EventBenchmark { val now = TimeUtils.now() val tags = arrayOf(arrayOf("")) benchmarkRule.measureRepeated { - EventFactory.create("id", "pubkey", now, 30818, tags, "content", "sig") + EventFactory.create("id", "pubkey", now, 30818, tags, "content", "sig") } } } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt index 897b46224..3472b7794 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapReceivingBenchmark.kt @@ -40,12 +40,10 @@ import com.vitorpamplona.quartz.nip59Giftwrap.rumors.Rumor import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent import junit.framework.TestCase.assertNotNull -import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit /** * Benchmark, which will execute on an Android device. @@ -60,78 +58,56 @@ class GiftWrapReceivingBenchmark { fun createWrap( sender: NostrSigner, receiver: NostrSigner, - ): GiftWrapEvent { - val countDownLatch = CountDownLatch(1) - var wrap: GiftWrapEvent? = null - - sender.sign( - ChatMessageEvent.build( - msg = "Hi there! This is a test message", - to = - listOf( - PTag(receiver.pubKey), + ): GiftWrapEvent = + runBlocking { + GiftWrapEvent.create( + event = + SealedRumorEvent.create( + event = + sender.sign( + ChatMessageEvent.build( + msg = "Hi there! This is a test message", + to = listOf(PTag(receiver.pubKey)), + ) { + changeSubject("Party Tonight") + zapraiser(10000) + contentWarning("nsfw") + }, + ), + encryptTo = receiver.pubKey, + signer = sender, ), - ) { - changeSubject("Party Tonight") - zapraiser(10000) - contentWarning("nsfw") - }, - ) { - SealedRumorEvent.create( - event = it, - encryptTo = receiver.pubKey, - signer = sender, - ) { - GiftWrapEvent.create( - event = it, - recipientPubKey = receiver.pubKey, - ) { - wrap = it - countDownLatch.countDown() - } - } + recipientPubKey = receiver.pubKey, + ) } - assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) - - return wrap!! - } - fun createSeal( sender: NostrSigner, receiver: NostrSigner, - ): SealedRumorEvent { - val countDownLatch = CountDownLatch(1) - var seal: SealedRumorEvent? = null + ): SealedRumorEvent = + runBlocking { + val msg = + sender.sign( + ChatMessageEvent.build( + msg = "Hi there! This is a test message", + to = + listOf( + PTag(receiver.pubKey), + ), + ) { + changeSubject("Party Tonight") + zapraiser(10000) + contentWarning("nsfw") + }, + ) - sender.sign( - ChatMessageEvent.build( - msg = "Hi there! This is a test message", - to = - listOf( - PTag(receiver.pubKey), - ), - ) { - changeSubject("Party Tonight") - zapraiser(10000) - contentWarning("nsfw") - }, - ) { SealedRumorEvent.create( - event = it, + event = msg, encryptTo = receiver.pubKey, signer = sender, - ) { - seal = it - countDownLatch.countDown() - } + ) } - assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) - - return seal!! - } - @Test fun parseWrapFromString() { val sender = NostrSignerInternal(KeyPair()) diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapSigningBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapSigningBenchmark.kt index 9e1a770c1..3c310d28d 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapSigningBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/GiftWrapSigningBenchmark.kt @@ -32,12 +32,10 @@ import com.vitorpamplona.quartz.nip36SensitiveContent.contentWarning import com.vitorpamplona.quartz.nip57Zaps.zapraiser.zapraiser import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent -import junit.framework.TestCase.assertTrue +import kotlinx.coroutines.runBlocking import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import java.util.concurrent.CountDownLatch -import java.util.concurrent.TimeUnit /** * Benchmark, which will execute on an Android device. @@ -55,25 +53,21 @@ class GiftWrapSigningBenchmark { val receiver = NostrSignerInternal(KeyPair()) benchmarkRule.measureRepeated { - val countDownLatch = CountDownLatch(1) - - sender.sign( - ChatMessageEvent.build( - msg = "Hi there! This is a test message", - to = - listOf( - PTag(receiver.pubKey), - ), - ) { - changeSubject("Party Tonight") - zapraiser(10000) - contentWarning("nsfw") - }, - ) { - countDownLatch.countDown() + runBlocking { + sender.sign( + ChatMessageEvent.build( + msg = "Hi there! This is a test message", + to = + listOf( + PTag(receiver.pubKey), + ), + ) { + changeSubject("Party Tonight") + zapraiser(10000) + contentWarning("nsfw") + }, + ) } - - assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) } } @@ -82,40 +76,31 @@ class GiftWrapSigningBenchmark { val sender = NostrSignerInternal(KeyPair()) val receiver = NostrSignerInternal(KeyPair()) - val countDownLatch = CountDownLatch(1) - - var msg: ChatMessageEvent? = null - - sender.sign( - ChatMessageEvent.build( - msg = "Hi there! This is a test message", - to = - listOf( - PTag(receiver.pubKey), - ), - ) { - changeSubject("Party Tonight") - zapraiser(10000) - contentWarning("nsfw") - }, - ) { - msg = it - countDownLatch.countDown() - } - - assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) - - benchmarkRule.measureRepeated { - val countDownLatch2 = CountDownLatch(1) - SealedRumorEvent.create( - event = msg!!, - encryptTo = receiver.pubKey, - signer = sender, - ) { - countDownLatch2.countDown() + val msg = + runBlocking { + sender.sign( + ChatMessageEvent.build( + msg = "Hi there! This is a test message", + to = + listOf( + PTag(receiver.pubKey), + ), + ) { + changeSubject("Party Tonight") + zapraiser(10000) + contentWarning("nsfw") + }, + ) } - assertTrue(countDownLatch2.await(1, TimeUnit.SECONDS)) + benchmarkRule.measureRepeated { + runBlocking { + SealedRumorEvent.create( + event = msg, + encryptTo = receiver.pubKey, + signer = sender, + ) + } } } @@ -124,44 +109,39 @@ class GiftWrapSigningBenchmark { val sender = NostrSignerInternal(KeyPair()) val receiver = NostrSignerInternal(KeyPair()) - val countDownLatch = CountDownLatch(1) - - var seal: SealedRumorEvent? = null - - sender.sign( - ChatMessageEvent.build( - msg = "Hi there! This is a test message", - to = - listOf( - PTag(receiver.pubKey), - ), - ) { - changeSubject("Party Tonight") - zapraiser(10000) - contentWarning("nsfw") - }, - ) { - SealedRumorEvent.create( - event = it, - encryptTo = receiver.pubKey, - signer = sender, - ) { - seal = it - countDownLatch.countDown() + val msg = + runBlocking { + sender.sign( + ChatMessageEvent.build( + msg = "Hi there! This is a test message", + to = + listOf( + PTag(receiver.pubKey), + ), + ) { + changeSubject("Party Tonight") + zapraiser(10000) + contentWarning("nsfw") + }, + ) } - } - assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) + val seal = + runBlocking { + SealedRumorEvent.create( + event = msg, + encryptTo = receiver.pubKey, + signer = sender, + ) + } benchmarkRule.measureRepeated { - val countDownLatch2 = CountDownLatch(1) - GiftWrapEvent.create( - event = seal!!, - recipientPubKey = receiver.pubKey, - ) { - countDownLatch2.countDown() + runBlocking { + GiftWrapEvent.create( + event = seal!!, + recipientPubKey = receiver.pubKey, + ) } - assertTrue(countDownLatch2.await(1, TimeUnit.SECONDS)) } } @@ -170,40 +150,40 @@ class GiftWrapSigningBenchmark { val sender = NostrSignerInternal(KeyPair()) val receiver = NostrSignerInternal(KeyPair()) - val countDownLatch = CountDownLatch(1) - - var wrap: GiftWrapEvent? = null - - sender.sign( - ChatMessageEvent.build( - msg = "Hi there! This is a test message", - to = - listOf( - PTag(receiver.pubKey), - ), - ) { - changeSubject("Party Tonight") - zapraiser(10000) - contentWarning("nsfw") - }, - ) { - SealedRumorEvent.create( - event = it, - encryptTo = receiver.pubKey, - signer = sender, - ) { - GiftWrapEvent.create( - event = it, - recipientPubKey = receiver.pubKey, - ) { - wrap = it - countDownLatch.countDown() - } + val msg = + runBlocking { + sender.sign( + ChatMessageEvent.build( + msg = "Hi there! This is a test message", + to = + listOf( + PTag(receiver.pubKey), + ), + ) { + changeSubject("Party Tonight") + zapraiser(10000) + contentWarning("nsfw") + }, + ) } - } - assertTrue(countDownLatch.await(1, TimeUnit.SECONDS)) + val seal = + runBlocking { + SealedRumorEvent.create( + event = msg, + encryptTo = receiver.pubKey, + signer = sender, + ) + } - benchmarkRule.measureRepeated { wrap!!.toJson() } + val wrap = + runBlocking { + GiftWrapEvent.create( + event = seal, + recipientPubKey = receiver.pubKey, + ) + } + + benchmarkRule.measureRepeated { wrap.toJson() } } } diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt index 0b8150e21..80c16fdfe 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/HintIndexerBenchmark.kt @@ -27,6 +27,7 @@ import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.toHexKey import com.vitorpamplona.quartz.nip01Core.hints.HintIndexer +import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.utils.RandomInstance import org.junit.Rule import org.junit.Test @@ -52,6 +53,7 @@ class HintIndexerBenchmark { .readBytes() .toString(Charset.forName("utf-8")) .split("\n") + .mapNotNull(RelayUrlNormalizer::normalizeOrNull) } @Test diff --git a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeCacheBenchmark.kt b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeCacheBenchmark.kt index a64b13d84..325c72329 100644 --- a/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeCacheBenchmark.kt +++ b/benchmark/src/androidTest/java/com/vitorpamplona/quartz/benchmark/LargeCacheBenchmark.kt @@ -23,54 +23,14 @@ package com.vitorpamplona.quartz.benchmark import androidx.benchmark.junit4.BenchmarkRule import androidx.benchmark.junit4.measureRepeated import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation -import com.fasterxml.jackson.module.kotlin.readValue -import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.jackson.JsonMapper -import com.vitorpamplona.quartz.utils.LargeCache -import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import java.util.Arrays -import java.util.function.Consumer -import java.util.zip.GZIPInputStream - -open class BaseLargeCacheBenchmark { - fun getEventDB(): List { - // This file includes duplicates - val fullDBInputStream = getInstrumentation().context.assets.open("nostr_vitor_startup_data.json") - - return JsonMapper.mapper.readValue>( - GZIPInputStream(fullDBInputStream), - ) - } - - fun getLargeCache(db: List): LargeCache { - val cache = LargeCache() - - db.forEach { - cache.getOrCreate(it.id) { key -> - it - } - } - - return cache - } - - fun hasId(event: Event) { - assertTrue(event.id.isNotEmpty()) - } - - val consumer = - Consumer { - hasId(it) - } -} +import kotlin.collections.distinctBy @RunWith(AndroidJUnit4::class) -class LargeCacheForEachBenchmark : BaseLargeCacheBenchmark() { +class LargeCacheBenchmark : BaseLargeCacheBenchmark() { @get:Rule val benchmarkRule = BenchmarkRule() // 191,353 ns 0 allocs Trace EMULATOR_LargeCacheForEachBenchmark.benchForEachConsumerList