Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use kotlin.time API (for Koin 4.x) #1955

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.koin.benchmark.PerfLimit
import org.koin.benchmark.PerfRunner.runAll
import org.koin.sample.android.R
import kotlin.coroutines.CoroutineContext
import kotlin.time.Duration.Companion.milliseconds

class MainActivity : AppCompatActivity(), CoroutineScope {

Expand All @@ -19,7 +20,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
title = "Android First Perfs"

runBlocking {
val limits = PerfLimit(10.8, 0.185)
val limits = PerfLimit(10.8.milliseconds, 0.185.milliseconds)

println("Perf Tolerance: $limits")

Expand All @@ -29,8 +30,8 @@ class MainActivity : AppCompatActivity(), CoroutineScope {

val textWidget = findViewById<TextView>(R.id.text)
var textReport = """
Start time: $startTime - max ${results.worstMaxStartTime} ms
Exec time: $execTime - max ${results.worstExecTime} ms
Start time: $startTime - max ${results.worstMaxStartTime}
Exec time: $execTime - max ${results.worstExecTime}
""".trimIndent()

if (!results.isOk) textReport += "\nTest Failed!"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@ package org.koin.benchmark
import junit.framework.TestCase.assertTrue
import kotlinx.coroutines.runBlocking
import org.junit.Test
import kotlin.time.Duration.Companion.milliseconds

class TestPerfRunner {

/**
* Avg start time: 13.06
* Avg execution time: 0.158
* Avg start time: 13.06 ms
* Avg execution time: 0.158 ms
*/
// @Test
fun main() = runBlocking {
val limits = PerfLimit(17.0, 0.175)
val limits = PerfLimit(17.milliseconds, 0.175.milliseconds)

println("Perf Tolerance: $limits")

val results = PerfRunner.runAll(this)
results.applyLimits(limits)

assertTrue("Should start under ${results.worstMaxStartTime} ms", results.isStartOk)
assertTrue("Should exec under ${results.worstExecTime} ms", results.isExecOk)
assertTrue("Should start under ${results.worstMaxStartTime}", results.isStartOk)
assertTrue("Should exec under ${results.worstExecTime}", results.isExecOk)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koin.core.context.startKoin
import org.koin.core.logger.Level
import org.koin.core.time.measureDuration
import kotlin.time.measureTime

class CoffeeApp : KoinComponent {
val maker: CoffeeMaker by inject()
Expand All @@ -17,8 +17,8 @@ fun main() {
}

val coffeeShop = CoffeeApp()
val duration = measureDuration {
val duration = measureTime {
coffeeShop.maker.brew()
}
println("Got Coffee in $duration ms")
println("Got Coffee in $duration")
}
39 changes: 18 additions & 21 deletions examples/jvm-perfs/src/main/kotlin/org/koin/benchmark/PerfRunner.kt
Original file line number Diff line number Diff line change
@@ -1,47 +1,46 @@
package org.koin.benchmark

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.koin.core.Koin
import org.koin.core.annotation.KoinExperimentalAPI
import org.koin.core.time.measureDurationForResult
import org.koin.dsl.koinApplication
import kotlin.math.roundToInt
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.measureTime
import kotlin.time.measureTimedValue

object PerfRunner {

suspend fun runAll(scope: CoroutineScope): PerfResult {
val results = (1..10).map { i -> withContext(scope.coroutineContext) { runScenario(i) } }
val avgStart = (results.sumOf { it.first } / results.size).round(100)
val avgExec = (results.sumOf { it.second } / results.size).round(1000)
val avgStart = results.map { it.first.inWholeMilliseconds }.average().milliseconds
val avgExec = results.map { it.second.inWholeMilliseconds }.average().milliseconds

println("Avg start: $avgStart ms")
println("Avg execution: $avgExec ms")
return PerfResult(avgStart,avgExec)
println("Avg start: $avgStart")
println("Avg execution: $avgExec")
return PerfResult(avgStart, avgExec)
}

@OptIn(KoinExperimentalAPI::class)
fun runScenario(index: Int): Pair<Double, Double> {
val (app, duration) = measureDurationForResult {
fun runScenario(index: Int): Pair<Duration, Duration> {
val (app, duration) = measureTimedValue {
koinApplication {
modules(
perfModule400()
)
}
}
println("Perf[$index] start in $duration ms")
println("Perf[$index] start in $duration")

val koin: Koin = app.koin

// runBlocking {
// koin.awaitAllStartJobs()
// }

val (_, executionDuration) = measureDurationForResult {
val executionDuration = measureTime {
koinScenario(koin)
}
println("Perf[$index] run in $executionDuration ms")
println("Perf[$index] run in $executionDuration")
app.close()
return Pair(duration, executionDuration)
}
Expand All @@ -54,13 +53,11 @@ object PerfRunner {
}
}

fun Double.round(digits : Int) : Double = (this * digits).roundToInt() / digits.toDouble()
data class PerfLimit(val startTime: Duration, val execTime: Duration)

data class PerfLimit(val startTime : Double, val execTime : Double)

data class PerfResult(val startTime : Double, val execTime : Double) {
var worstMaxStartTime = 0.0
var worstExecTime = 0.0
data class PerfResult(val startTime: Duration, val execTime: Duration) {
var worstMaxStartTime = Duration.ZERO
var worstExecTime = Duration.ZERO
var isStartOk = false
var isExecOk = false
var isOk = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import org.koin.core.context.GlobalContext.startKoin
import org.koin.core.context.GlobalContext.stopKoin
import org.koin.core.context.waitKoinStart
import org.koin.core.logger.*
import org.koin.core.time.Timer
import org.koin.dsl.koinApplication
import org.koin.mp.KoinPlatform
import kotlin.test.Test
import kotlin.time.measureTime
import kotlin.time.measureTimedValue

class PerfsTest {

Expand All @@ -24,30 +25,32 @@ class PerfsTest {
}

private fun runPerfs(log: Logger = EmptyLogger(), isLazy: Boolean = false) {
val timerStart = Timer.start()
val app = koinApplication {
if (isLazy) {
lazyModules(perfModule400())
} else {
modules(perfModule400().value)
val (app, startKoinAppDuration) = measureTimedValue {
koinApplication {
if (isLazy) {
lazyModules(perfModule400())
} else {
modules(perfModule400().value)
}
}
}
timerStart.stop()
println("perf400 - start in ${timerStart.getTimeInMillis()}")

println("perf400 - start in $startKoinAppDuration")

val koin = app.koin

if (isLazy) {
koin.waitAllStartJobs()
}

val timerRun = Timer.start()
koin.get<Perfs.A27>()
koin.get<Perfs.B31>()
koin.get<Perfs.C12>()
koin.get<Perfs.D42>()
timerRun.stop()
println("perf400 - executed in ${timerRun.getTimeInMillis()}")
val getDepsDuration = measureTime {
koin.get<Perfs.A27>()
koin.get<Perfs.B31>()
koin.get<Perfs.C12>()
koin.get<Perfs.D42>()
}

println("perf400 - executed in $getDepsDuration")

app.close()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ import org.koin.core.registry.PropertyRegistry
import org.koin.core.registry.ScopeRegistry
import org.koin.core.scope.Scope
import org.koin.core.scope.ScopeID
import org.koin.core.time.measureDuration
import org.koin.mp.KoinPlatformTools
import org.koin.mp.generateId
import kotlin.reflect.KClass
import kotlin.time.measureTime

/**
* Koin
Expand Down Expand Up @@ -327,9 +327,9 @@ class Koin {
*/
fun createEagerInstances() {
logger.debug("Create eager instances ...")
val duration = measureDuration {
val duration = measureTime {
instanceRegistry.createAllEagerInstances()
}
logger.debug("Created eager instances in $duration ms")
logger.debug("Created eager instances in $duration")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import org.koin.core.logger.Level
import org.koin.core.logger.Logger
import org.koin.core.module.KoinApplicationDslMarker
import org.koin.core.module.Module
import org.koin.core.time.measureDuration
import org.koin.mp.KoinPlatformTools
import kotlin.time.measureTime

/**
* Koin Application
Expand Down Expand Up @@ -58,9 +58,9 @@ class KoinApplication private constructor() {
*/
fun modules(modules: List<Module>): KoinApplication {
if (koin.logger.isAt(Level.INFO)) {
val duration = measureDuration { loadModules(modules) }
val duration = measureTime { loadModules(modules) }
val count = koin.instanceRegistry.size()
koin.logger.display(Level.INFO, "Started $count definitions in $duration ms")
koin.logger.display(Level.INFO, "Started $count definitions in $duration")
} else {
loadModules(modules)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@ import org.koin.core.module.KoinDslMarker
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.parameter.ParametersHolder
import org.koin.core.qualifier.Qualifier
import org.koin.core.time.Timer
import org.koin.ext.getFullName
import org.koin.mp.KoinPlatformTimeTools
import org.koin.mp.KoinPlatformTools
import org.koin.mp.Lockable
import org.koin.mp.ThreadLocal
import kotlin.reflect.KClass
import kotlin.time.measureTimedValue

@Suppress("UNCHECKED_CAST")
@OptIn(KoinInternalApi::class)
Expand Down Expand Up @@ -201,12 +200,11 @@ class Scope(
val scopeId = if (isRoot) "" else "- scope:'$id"
_koin.logger.display(Level.DEBUG, "|- '${clazz.getFullName()}'$qualifierString $scopeId...")

val start = KoinPlatformTimeTools.getTimeInNanoSeconds()
val instance = resolveInstance<T>(qualifier, clazz, parameters)
val stop = KoinPlatformTimeTools.getTimeInNanoSeconds()
val duration = (stop - start) / Timer.NANO_TO_MILLI
val (instance, duration) = measureTimedValue {
resolveInstance<T>(qualifier, clazz, parameters)
}

_koin.logger.display(Level.DEBUG, "|- '${clazz.getFullName()}' in $duration ms")
_koin.logger.display(Level.DEBUG, "|- '${clazz.getFullName()}' in $duration")
instance
} else {
resolveInstance(qualifier, clazz, parameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import org.koin.mp.KoinPlatformTimeTools
* @param code - code to execute
* @return Time in milliseconds
*/
@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated("Use measureTime() from kotlin.time instead.")
inline fun measureDuration(code: () -> Unit): TimeInMillis {
return measureTimedValue(code).second
}
Expand All @@ -38,16 +40,19 @@ inline fun measureDuration(code: () -> Unit): TimeInMillis {
* @param code - code to execute
* @return Pair Value & Time in milliseconds
*/
@Deprecated("Use measureTimedValue() from kotlin.time instead.")
inline fun <T> measureDurationForResult(code: () -> T): Pair<T, TimeInMillis> {
val (value, duration) = measureTimedValue(code)
return Pair(value, duration)
}

@Deprecated("Use measureTimedValue() from kotlin.time instead.")
inline fun <T> measureTimedValue(code: () -> T): Pair<T, TimeInMillis> {
val start = KoinPlatformTimeTools.getTimeInNanoSeconds()
val value = code()
val stop = KoinPlatformTimeTools.getTimeInNanoSeconds()
return Pair(value, (stop - start) / Timer.NANO_TO_MILLI)
}

@Deprecated("Use kotlin.time.Duration instead.")
typealias TimeInMillis = Double
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import kotlin.time.Duration.Companion.ZERO
import kotlin.time.DurationUnit
import kotlin.time.toDuration

@Deprecated("Use TimeSource.Monotonic instead.")
class Timer {

val start: Duration = KoinPlatformTimeTools.getTimeInNanoSeconds().toDuration(DurationUnit.NANOSECONDS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
*/
package org.koin.mp

expect object KoinPlatformTimeTools {
fun getTimeInNanoSeconds(): Long
}
import kotlin.time.TimeSource

@Deprecated("Use kotlin.time instead.")
object KoinPlatformTimeTools {

@Suppress("DeprecatedCallableAddReplaceWith")
@Deprecated("Use TimeSource.Monotonic.markNow() instead.")
fun getTimeInNanoSeconds(): Long =
TimeSource.Monotonic.markNow().elapsedNow().inWholeNanoseconds
}
Loading