Skip to content

Commit

Permalink
Improve benchmarks (#14)
Browse files Browse the repository at this point in the history
* Refactor

* WIP: Improve benchmarks

* WIP: Benchmarks

* Fix DI

* Prepare benchmarks

* Remove upload step
  • Loading branch information
ILIYANGERMANOV authored Dec 15, 2024
1 parent 63d5b26 commit 60ac327
Show file tree
Hide file tree
Showing 14 changed files with 423 additions and 60 deletions.
8 changes: 1 addition & 7 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,4 @@ jobs:
distribution: 'temurin'

- name: Run benchmarks
run: ./gradlew :benchmark:benchmark

- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: benchmark/build/reports/benchmark/
run: ./gradlew :benchmark:benchmark
102 changes: 86 additions & 16 deletions benchmark/src/main/kotlin/ivy/di/benchmark/DiBenchmark.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
package ivy.di.benchmark

import ivy.di.Di
import ivy.di.benchmark.fixtures.android.*
import ivy.di.benchmark.fixtures.*
import ivy.di.benchmark.fixtures.modules.*
import ivy.di.benchmark.fixtures.modules.ivy.AndroidGraphIvyDi
import ivy.di.benchmark.fixtures.modules.ivy.BeGraphIvyDi
import ivy.di.benchmark.fixtures.modules.ivy.CommonGraphIvyDi
import ivy.di.benchmark.fixtures.modules.ivy.ComplexGraphIvyDi
import ivy.di.benchmark.fixtures.modules.koin.AndroidGraphKoin
import ivy.di.benchmark.fixtures.modules.koin.BeGraphKoin
import ivy.di.benchmark.fixtures.modules.koin.CommonGraphKoin
import ivy.di.benchmark.fixtures.modules.koin.ComplexGraphKoin
import kotlinx.benchmark.*
import org.koin.core.context.startKoin
import org.koin.core.context.stopKoin
import org.koin.java.KoinJavaComponent.getKoin
import org.openjdk.jmh.annotations.Level
import java.util.concurrent.TimeUnit

@Suppress("unused")
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
class DiComparisonBenchmark {

private val diGetIterations = 100
private val smallGraphGets = 20
private val mediumGraphGets = 50
private val complexGraphGets = 200

@TearDown(Level.Invocation)
fun cleanup() {
Expand All @@ -35,28 +47,86 @@ class DiComparisonBenchmark {
}

@Benchmark
fun androidCommonIvyDi() {
Di.init(AndroidCommonModuleIvyDi)
repeat(diGetIterations) {
Di.get<ArticlesViewModel>()
Di.get<AuthorViewModel>()
fun smallGraphIvyDI() {
Di.init(CommonGraphIvyDi, AndroidGraphIvyDi)
repeat(smallGraphGets) {
Di.get<App>()
Di.get<AppHolder>()
Di.get<AppAppHolder>()
}
}

@Benchmark
fun androidCommonKoin() {
fun smallGraphKoin() {
startKoin {
modules(AndroidCommonModuleKoin)
modules(CommonGraphKoin, AndroidGraphKoin)
}
repeat(diGetIterations) {
getKoin().get<ArticlesViewModel>()
getKoin().get<AuthorViewModel>()
repeat(smallGraphGets) {
getKoin().get<App>()
getKoin().get<AppHolder>()
getKoin().get<AppAppHolder>()
}
}

@Benchmark
fun mediumGraphIvyDI() {
Di.init(CommonGraphIvyDi, AndroidGraphIvyDi, BeGraphIvyDi)
repeat(mediumGraphGets) {
Di.get<App>()
Di.get<ServerApp>()
}
}

@Benchmark
fun mediumGraphKoin() {
startKoin {
modules(CommonGraphKoin, AndroidGraphKoin, BeGraphKoin)
}
repeat(mediumGraphGets) {
getKoin().get<App>()
getKoin().get<ServerApp>()
}
}

@Benchmark
fun complexGraphIvyDI() {
Di.init(
CommonGraphIvyDi,
AndroidGraphIvyDi,
BeGraphIvyDi,
ComplexGraphIvyDi,
)
repeat(complexGraphGets) {
Di.get<MultiHolderFinal>()
}
}

@Benchmark
fun complexGraphKoin() {
startKoin {
modules(
CommonGraphKoin,
AndroidGraphKoin,
BeGraphKoin,
ComplexGraphKoin,
)
}
repeat(complexGraphGets) {
getKoin().get<MultiHolderFinal>()
}
}
}

fun main() {
println("Testing correctness...")
DiComparisonBenchmark().apply {
cleanup()
smallGraphIvyDI()
smallGraphKoin()

cleanup()
mediumGraphIvyDI()
mediumGraphKoin()

cleanup()
complexGraphIvyDI()
complexGraphKoin()
}
println("Correctness ensured.")
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
@file:Suppress("unused")

package ivy.di.benchmark.fixtures.android

interface DispatchersProvider
class AndroidDispatchersProvider : DispatchersProvider
package ivy.di.benchmark.fixtures

class Context
interface Logger
class AndroidLogger : Logger

class HttpClient
class LocalStorage

class SessionManager(val localStorage: LocalStorage, val logger: Logger)
Expand Down Expand Up @@ -81,16 +75,4 @@ class App(
val authorScreen: AuthorScreen,
val articlesScreen: ArticlesScreen,
val logger: Logger,
)

class AppHolder(
val app: App,
val context: Context,
val logger: Logger,
)

// Complicate the DI graph
class AppAppHolder(
val app: App,
val appHolder: AppHolder,
)
53 changes: 53 additions & 0 deletions benchmark/src/main/kotlin/ivy/di/benchmark/fixtures/BeGraph.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ivy.di.benchmark.fixtures

class AwsUrlProvider : UrlProvider
interface UrlProvider

interface Environment
class RealEnvironment : Environment

class ServerConfig(
val urlProvider: UrlProvider
)

class KtorApp
class RateLimiter(val ktorApp: KtorApp)

class Database(
val config: ServerConfig,
val logger: Logger,
)

class AuthRepository(val database: Database)
class GoogleLoginUseCase(val database: Database, val httpClient: HttpClient)
class AuthService(
val repository: AuthRepository,
val googleLoginUseCase: GoogleLoginUseCase,
)
class AuthApi(
val authService: AuthService,
val logger: Logger,
val rateLimiter: RateLimiter
)

class CarsRepository(
val database: Database,
val logger: Logger,
)
class CarsService(
val authService: AuthService,
val repository: CarsRepository,
)
class CarsApi(val service: CarsService)

class Apis(
val rateLimiter: RateLimiter,
val authApi: AuthApi,
val carsApi: CarsApi,
)
class ServerApp(
val serverConfig: ServerConfig,
val ktorApp: KtorApp,
val logger: Logger,
val apis: Apis,
)
18 changes: 18 additions & 0 deletions benchmark/src/main/kotlin/ivy/di/benchmark/fixtures/CommonGraph.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ivy.di.benchmark.fixtures


interface DispatchersProvider
class RealDispatchersProvider : DispatchersProvider

interface Logger
class LoggerImpl : Logger

interface Serialization
class Json
class KotlinXSerialization(val json: Json) : Serialization

class HttpClient(
val serialization: Serialization,
val logger: Logger,
val dispatchersProvider: DispatchersProvider,
)
106 changes: 106 additions & 0 deletions benchmark/src/main/kotlin/ivy/di/benchmark/fixtures/ComplexGraph.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package ivy.di.benchmark.fixtures

class Holder1(
val app: App,
val serverApp: ServerApp,
)

class Holder2(
val app: App,
val serverApp: ServerApp,
val holder1: Holder1,
)

class Holder3(
val holder1: Holder1,
val holder2: Holder2,
)

class Holder4(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
)

class Holder5(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
val holder4: Holder4,
)

class Holder6(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
val holder4: Holder4,
val holder5: Holder5,
)

class Holder7(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
val holder4: Holder4,
val holder5: Holder5,
val holder6: Holder6,
)

class Holder8(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
val holder4: Holder4,
val holder5: Holder5,
val holder6: Holder6,
val holder7: Holder7,
)

class Holder9(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
val holder4: Holder4,
val holder5: Holder5,
val holder6: Holder6,
val holder7: Holder7,
val holder8: Holder8,
)

class Holder10(
val holder1: Holder1,
val holder2: Holder2,
val holder3: Holder3,
val holder4: Holder4,
val holder5: Holder5,
val holder6: Holder6,
val holder7: Holder7,
val holder8: Holder8,
val holder9: Holder9,
)

interface MultiHolder
class MultiHolderImpl(
val holderA: Holder10,
val holderB: Holder10,
val holderC: Holder10,
val holderD: Holder10,
val holderE: Holder10,
val holderF: Holder10,
val holderG: Holder10,
val holderH: Holder10,
val holderI: Holder10,
val holderJ: Holder10,
val holderK: Holder10,
val holderL: Holder10,
val holderM: Holder10,
val holderN: Holder10,
) : MultiHolder

class MultiHolderFinal(
val holder1: MultiHolder,
val holder2: MultiHolder,
val holder3: MultiHolder,
val holder4: MultiHolder,
val holder5: MultiHolder,
)
Loading

0 comments on commit 60ac327

Please sign in to comment.