Repository: JetBrains/compose-multiplatform
File: benchmarks/multiplatform/benchmarks/src/commonMain/kotlin/MeasureComposable.kt (Kotlin)

Code before:
                repeat(frameCount) {
                    scene.mimicSkikoRender(surface, it * nanosPerFrame, width, height)
                    surface.flushAndSubmit(false)
                    gpuTime += measureTime {
                        graphicsContext?.awaitGPUCompletion()
                    }
                }
            }
            renderTime -= gpuTime
        }

        val frames = MutableList(frameCount) {
            BenchmarkFrame(Duration.INFINITE, Duration.INFINITE)
        }

        if (Args.isModeEnabled(Mode.FRAMES)) {

            var nextVSync = Duration.ZERO
            var missedFrames = 0;

            runGC()

            val start = markNow()

            repeat(frameCount) {
                val frameStart = markNow()

                scene.mimicSkikoRender(surface, it * nextVSync.inWholeNanoseconds, width, height)
                surface.flushAndSubmit(false)

                val cpuTime = frameStart.elapsedNow()

                graphicsContext?.awaitGPUCompletion()

                val frameTime = frameStart.elapsedNow()

                frames[it] = BenchmarkFrame(cpuTime, frameTime - cpuTime)

                missedFrames += (frameTime.inWholeNanoseconds / nanosPerFrame).toInt()

                nextVSync = ((it + 1 + missedFrames) * nanosPerFrame).nanoseconds

                val timeUntilNextVSync = nextVSync - start.elapsedNow()

                if (timeUntilNextVSync > Duration.ZERO) {
                    // Emulate waiting for next vsync
                    preciseDelay(timeUntilNextVSync)
                }
            }
        }


Review comment (suggestion):
From https://github.com/JetBrains/compose-multiplatform/pull/5216#discussion_r1930973719:

> We mark frameStart from nextVSync intentionally to catch possible GC. Consider revert this


Code after:
                repeat(frameCount) {
                    scene.mimicSkikoRender(surface, it * nanosPerFrame, width, height)
                    surface.flushAndSubmit(false)
                    gpuTime += measureTime {
                        graphicsContext?.awaitGPUCompletion()
                    }
                }
            }
            renderTime -= gpuTime
        }

        val frames = MutableList(frameCount) {
            BenchmarkFrame(Duration.INFINITE, Duration.INFINITE)
        }

        if (Args.isModeEnabled(Mode.FRAMES)) {

            var nextVSync = Duration.ZERO
            var missedFrames = 0;

            runGC()

            val start = markNow()

            repeat(frameCount) {
                val frameStart = start + nextVSync

                scene.mimicSkikoRender(surface, it * nextVSync.inWholeNanoseconds, width, height)
                surface.flushAndSubmit(false)

                val cpuTime = frameStart.elapsedNow()

                graphicsContext?.awaitGPUCompletion()

                val frameTime = frameStart.elapsedNow()

                frames[it] = BenchmarkFrame(cpuTime, frameTime - cpuTime)

                missedFrames += (frameTime.inWholeNanoseconds / nanosPerFrame).toInt()

                nextVSync = ((it + 1 + missedFrames) * nanosPerFrame).nanoseconds

                val timeUntilNextVSync = nextVSync - start.elapsedNow()

                if (timeUntilNextVSync > Duration.ZERO) {
                    // Emulate waiting for next vsync
                    preciseDelay(timeUntilNextVSync)
                }
            }
        }