You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
3.8 KiB
142 lines
3.8 KiB
import androidx.compose.runtime.mutableStateListOf |
|
import androidx.compose.runtime.mutableStateOf |
|
import kotlinx.browser.window |
|
import kotlinx.coroutines.flow.Flow |
|
import kotlinx.coroutines.flow.flow |
|
import kotlinx.coroutines.flow.toList |
|
import org.w3c.dom.get |
|
import kotlin.test.Test |
|
import kotlin.test.assertEquals |
|
import kotlin.time.Duration |
|
import kotlin.time.DurationUnit |
|
import kotlin.time.ExperimentalTime |
|
import kotlin.time.measureTime |
|
|
|
@OptIn(ExperimentalTime::class) |
|
class BenchmarkTests { |
|
|
|
private fun flowRepeat(count: Int, calculate: suspend () -> Duration): Flow<Duration> { |
|
return flow { |
|
repeat(count) { |
|
emit(calculate()) |
|
} |
|
} |
|
} |
|
|
|
private fun runBenchmark( |
|
name: String, |
|
repeat: Int = 5, |
|
run: suspend TestScope.() -> Duration |
|
) = runTest { |
|
val durations = flowRepeat(count = repeat) { |
|
run() |
|
}.toList() |
|
|
|
val avgMs = durations.map { it.toInt(DurationUnit.MILLISECONDS) }.average().toInt() |
|
|
|
val browserName = window.navigator.userAgent.toLowerCase().let { |
|
when { |
|
it.contains("chrome") -> "chrome" |
|
it.contains("firefox") -> "firefox" |
|
else -> "unknown_browser" |
|
} |
|
} |
|
|
|
println("#$name[$browserName]:$avgMs;") |
|
} |
|
|
|
suspend private fun TestScope.addNItems(n: Int): Duration { |
|
val addItemsCount = mutableStateOf(0) |
|
|
|
val composition = composition { |
|
AddItems(addItemsCount.value) |
|
} |
|
|
|
assertEquals(0, root.childElementCount) |
|
|
|
val duration = measureTime { |
|
addItemsCount.value = n |
|
waitForAnimationFrame() |
|
} |
|
|
|
assertEquals(n, root.childElementCount) |
|
composition.dispose() |
|
|
|
return duration |
|
} |
|
|
|
@Test // add1kItems overrides default `repeat` value (was - 5, now - 3) to avoid getting swallowed on CI |
|
fun add1kItems() = runBenchmark(name = "add1000Items", repeat = 3) { |
|
addNItems(1000) |
|
} |
|
|
|
@Test |
|
fun add100Items() = runBenchmark("add100Items") { |
|
addNItems(100) |
|
} |
|
|
|
@Test |
|
fun add200Items() = runBenchmark("add200Items") { |
|
addNItems(200) |
|
} |
|
|
|
@Test |
|
fun add500Items() = runBenchmark("add500Items") { |
|
addNItems(500) |
|
} |
|
|
|
@Test |
|
fun remove1000Items() = runBenchmark("remove1000Items") { |
|
val addItemsCount = mutableStateOf(1000) |
|
|
|
val composition = composition { |
|
AddItems(addItemsCount.value) |
|
} |
|
|
|
assertEquals(1000, root.childElementCount) |
|
|
|
val duration = measureTime { |
|
addItemsCount.value = 0 |
|
waitForAnimationFrame() |
|
} |
|
|
|
assertEquals(0, root.childElementCount) |
|
composition.dispose() |
|
|
|
duration |
|
} |
|
|
|
@Test |
|
fun changeEvery10thItem() = runBenchmark("changeEvery10thItem") { |
|
val items = mutableStateListOf<String>() |
|
items.addAll(generateSequence(0) { it + 1 }.map { it.toString() }.take(1000)) |
|
|
|
val composition = composition { |
|
AddItems(items) |
|
} |
|
|
|
assertEquals(1000, root.childElementCount) |
|
assertEquals("1", root.children[1]!!.firstChild!!.textContent) |
|
assertEquals("10", root.children[10]!!.firstChild!!.textContent) |
|
|
|
val duration = measureTime { |
|
repeat(items.size) { |
|
if (it % 10 == 0) items[it] = "${items[it]}-$it" |
|
} |
|
waitForAnimationFrame() |
|
} |
|
|
|
repeat(items.size) { |
|
if (it % 10 == 0) items[it] = "${items[it]}-$it" |
|
} |
|
waitForAnimationFrame() |
|
|
|
assertEquals(1000, root.childElementCount) |
|
assertEquals("1", root.children[1]!!.firstChild!!.textContent) |
|
assertEquals("10-10", root.children[10]!!.firstChild!!.textContent) |
|
|
|
composition.dispose() |
|
|
|
duration |
|
} |
|
} |