Repository: JetBrains/compose-multiplatform
File: benchmarks/multiplatform/benchmarks/src/wasmJsMain/kotlin/main.wasmJs.kt (Kotlin)

Code before:
import kotlinx.browser.window
import kotlinx.coroutines.*
import org.w3c.dom.url.URLSearchParams
import kotlin.js.Promise

val jsOne = 1.toJsNumber()

fun main(args: Array<String>) {
    if (isD8env().toBoolean()) {
        mainD8(args)
    } else {
        mainBrowser()
    }
}

@OptIn(ExperimentalComposeUiApi::class)
fun mainBrowser() {
    val urlParams = URLSearchParams(window.location.search.toJsString())
    var i = 0
    val args = generateSequence { urlParams.get("arg${i++}") }.toList().toTypedArray()

    Config.setGlobalFromArgs(args)

    val composeRoot = document.getElementById("root")!!
    if (Config.isModeEnabled(Mode.REAL)) {
        val frameRate = 120 // can we get this from device?
        ComposeViewport(composeRoot) {
            BenchmarkRunner(getBenchmarks(), frameRate, onExit = { composeRoot.remove() })
        }
    } else {
        composeRoot.remove()
        println("Wait for the benchmarks to complete...\n")
        MainScope().launch {
            if (Config.saveStats() && !BenchmarksSaveServerClient.isServerAlive()) {
                println("No benchmark server found.")
                return@launch
            }
            runBenchmarks()
            println("Completed!")
            if (Config.saveStats()) {
                GlobalScope.launch {
                    BenchmarksSaveServerClient.stopServer()
                }
            }
        }
    }
}


// Currently, the initialization can't be adjusted to avoid calling the fun main, but
// we don't want use the default fun main, because Jetstream3 requires running the workloads separately / independently of each other.

Review comment (suggestion):
Unfortunately, there is no direct API.
But we can get it by running `requestAnimationFrame` for 1-2 seconds - https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame and then take the average.

Code after:
import kotlinx.browser.window
import kotlinx.coroutines.*
import org.w3c.dom.url.URLSearchParams
import kotlin.js.Promise

val jsOne = 1.toJsNumber()

fun main(args: Array<String>) {
    if (isD8env().toBoolean()) {
        mainD8(args)
    } else {
        mainBrowser()
    }
}

@OptIn(ExperimentalComposeUiApi::class)
fun mainBrowser() {
    val urlParams = URLSearchParams(window.location.search.toJsString())
    var i = 0
    val args = generateSequence { urlParams.get("arg${i++}") }.toList().toTypedArray()

    Config.setGlobalFromArgs(args)

    val composeRoot = document.getElementById("root")!!
    if (Config.isModeEnabled(Mode.REAL)) {
        val frameRate = 120 // can we get this from device?
        ComposeViewport(composeRoot) {
            BenchmarkRunner(getBenchmarks(), frameRate, onExit = { composeRoot.remove() })
        }
    } else {
        composeRoot.remove()
        println("Wait for the benchmarks to complete...\n")
        MainScope().launch {
            if (Config.saveStats() && !BenchmarksSaveServerClient.isServerAlive()) {
                println("No benchmark server found.")
                return@launch
            }
            awaitSkikoWasm()

            runBenchmarks()
            println("Completed!")
            if (Config.saveStats()) {
                GlobalScope.launch {
                    BenchmarksSaveServerClient.stopServer()
                }
            }
        }
    }
}

private suspend fun awaitSkikoWasm() {