Skip to content

Commit 2611e9c

Browse files
committed
Add a profiling mode to see what parts take up time
1 parent 44347dd commit 2611e9c

File tree

5 files changed

+69
-1
lines changed

5 files changed

+69
-1
lines changed

interfaces/src/main/kotlin/com/noxcrew/interfaces/interfaces/InterfaceProperties.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public open class InterfaceProperties<P : Pane> {
3232
/** The timeout to apply to all coroutines for this menu. */
3333
public var defaultTimeout: Duration = 2.5.seconds
3434

35+
/** Enables debug logs for time spent on various actions. */
36+
public var debugRenderingTime: Boolean = false
37+
3538
// --- CACHING / EFFICIENCY ---
3639
/** Whether to redraw the title when re-opening a menu. */
3740
public var redrawTitleOnReopen: Boolean = true
@@ -108,13 +111,15 @@ public open class InterfaceProperties<P : Pane> {
108111
/** Sets all values to their simple defaults. This is the default type! */
109112
public fun useSimpleDefaults() {
110113
redrawTitleOnReopen = true
114+
alwaysReloadProperties = true
111115
defaultRefreshMode = RefreshMode.ALWAYS
112116
defaultBlockMode = BlockingMode.ALWAYS
113117
}
114118

115119
/** Sets all values to support efficient caching of components and minimize automatic refreshes. */
116120
public fun useCachingDefaults() {
117121
redrawTitleOnReopen = false
122+
alwaysReloadProperties = false
118123
defaultRefreshMode = RefreshMode.INITIAL
119124
defaultBlockMode = BlockingMode.INITIAL
120125
}

interfaces/src/main/kotlin/com/noxcrew/interfaces/menu/PlayerInventoryMenu.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,40 @@ import com.noxcrew.interfaces.exception.StandardInterfacesExceptionHandler
77
import com.noxcrew.interfaces.interfaces.PlayerInterface
88
import com.noxcrew.interfaces.interfaces.PlayerInterfaceBuilder
99
import com.noxcrew.interfaces.interfaces.buildPlayerInterface
10+
import com.noxcrew.interfaces.utilities.InterfacesProfiler
1011
import com.noxcrew.interfaces.view.InterfaceView
1112
import com.noxcrew.interfaces.view.PlayerInterfaceView
1213
import org.bukkit.entity.Player
14+
import java.time.Instant
1315

1416
/** The base for a menu that is applied on a player's whole inventory. */
1517
public abstract class PlayerInventoryMenu : BaseInventoryMenu {
1618
/** The exception handler to use for this menu. */
1719
public open val exceptionHandler: InterfacesExceptionHandler = StandardInterfacesExceptionHandler()
1820

21+
/** Enables debug logs for time spent on various actions. */
22+
public open val debugRenderingTime: Boolean = false
23+
1924
/** Configures the GUI for the given [player]. */
2025
protected abstract suspend fun PlayerInterfaceBuilder.configure(player: Player)
2126

2227
/** Builds the menu. */
2328
protected open suspend fun buildMenu(player: Player): PlayerInterface = buildPlayerInterface {
2429
this@buildPlayerInterface.exceptionHandler = this@PlayerInventoryMenu.exceptionHandler
30+
this@buildPlayerInterface.debugRenderingTime = this@PlayerInventoryMenu.debugRenderingTime
2531
configure(player)
2632
}
2733

2834
override suspend fun open(player: Player, parent: InterfaceView?, reload: Boolean): PlayerInterfaceView? {
35+
val start = Instant.now()
2936
val menu = exceptionHandler.execute(
3037
InterfacesExceptionContext(
3138
player,
3239
InterfacesOperation.BUILDING_PLAYER,
3340
null,
3441
),
3542
) { buildMenu(player) } ?: return null
43+
if (debugRenderingTime) InterfacesProfiler.logAbstract("building menu", start)
3644
return open(player, parent, menu, reload) as PlayerInterfaceView?
3745
}
3846
}

interfaces/src/main/kotlin/com/noxcrew/interfaces/menu/SimpleInventoryMenu.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,27 @@ import com.noxcrew.interfaces.exception.StandardInterfacesExceptionHandler
77
import com.noxcrew.interfaces.interfaces.Interface
88
import com.noxcrew.interfaces.interfaces.InterfaceBuilder
99
import com.noxcrew.interfaces.pane.Pane
10+
import com.noxcrew.interfaces.utilities.InterfacesProfiler
1011
import com.noxcrew.interfaces.view.InterfaceView
1112
import org.bukkit.entity.Player
13+
import java.time.Instant
1214

1315
/** The base for a simple built menu. */
1416
public abstract class SimpleInventoryMenu<B : InterfaceBuilder<out Pane, *>> : BaseInventoryMenu {
1517
/** The exception handler to use for this menu. */
1618
public open val exceptionHandler: InterfacesExceptionHandler = StandardInterfacesExceptionHandler()
1719

20+
/** Enables debug logs for time spent on various actions. */
21+
public open val debugRenderingTime: Boolean = false
22+
1823
/** Builds the interface for this type using [configure]. */
1924
protected abstract suspend fun build(player: Player, configure: suspend B.() -> Unit): Interface<*, *>
2025

2126
/** Configures the GUI for the given [player]. */
2227
protected abstract suspend fun B.configure(player: Player)
2328

2429
override suspend fun open(player: Player, parent: InterfaceView?, reload: Boolean): InterfaceView? {
30+
val start = Instant.now()
2531
val menu = exceptionHandler.execute(
2632
InterfacesExceptionContext(
2733
player,
@@ -31,10 +37,11 @@ public abstract class SimpleInventoryMenu<B : InterfaceBuilder<out Pane, *>> : B
3137
) {
3238
build(player) {
3339
this@build.exceptionHandler = this@SimpleInventoryMenu.exceptionHandler
40+
this@build.debugRenderingTime = this@SimpleInventoryMenu.debugRenderingTime
3441
configure(player)
3542
}
3643
} ?: return null
37-
44+
if (debugRenderingTime) InterfacesProfiler.logAbstract("building menu", start)
3845
return open(player, parent, menu, reload)
3946
}
4047
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.noxcrew.interfaces.utilities
2+
3+
import com.noxcrew.interfaces.view.AbstractInterfaceView
4+
import org.slf4j.LoggerFactory
5+
import java.time.Duration
6+
import java.time.Instant
7+
import java.util.WeakHashMap
8+
import kotlin.time.toKotlinDuration
9+
10+
/** Assists in profiling interfaces. */
11+
public object InterfacesProfiler {
12+
private val logger = LoggerFactory.getLogger(InterfacesProfiler::class.java)
13+
14+
private val lastTimes = WeakHashMap<AbstractInterfaceView<*, *, *>, Instant>()
15+
16+
/** Logs the given [action] for [view]. */
17+
public fun log(view: AbstractInterfaceView<*, *, *>, action: String) {
18+
if (!view.builder.debugRenderingTime) return
19+
20+
val lastTime = lastTimes[view]
21+
val message = StringBuilder()
22+
message.append("Action `$action` has run for ${view.player.name}")
23+
if (lastTime != null) {
24+
val timeSinceLast = Duration.between(lastTime, Instant.now())
25+
message.append(", took ${timeSinceLast.toKotlinDuration()}")
26+
}
27+
logger.info(message.toString())
28+
lastTimes[view] = Instant.now()
29+
}
30+
31+
/** Logs a general action that started at [start]. */
32+
public fun logAbstract(action: String, start: Instant) {
33+
val timeSinceLast = Duration.between(start, Instant.now())
34+
logger.info("Action `$action` has run, took ${timeSinceLast.toKotlinDuration()}")
35+
}
36+
}

interfaces/src/main/kotlin/com/noxcrew/interfaces/view/AbstractInterfaceView.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.noxcrew.interfaces.transform.BlockingMode
2525
import com.noxcrew.interfaces.transform.RefreshMode
2626
import com.noxcrew.interfaces.utilities.CollapsablePaneMap
2727
import com.noxcrew.interfaces.utilities.InterfacesCoroutineDetails
28+
import com.noxcrew.interfaces.utilities.InterfacesProfiler
2829
import kotlinx.coroutines.CoroutineScope
2930
import kotlinx.coroutines.Job
3031
import kotlinx.coroutines.SupervisorJob
@@ -159,6 +160,9 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
159160
get() = if (::pane.isInitialized) pane else null
160161

161162
init {
163+
// Log to the profiler
164+
InterfacesProfiler.log(this, "interface being constructed")
165+
162166
// Determine for each trigger what transforms it updates
163167
val triggers = HashMultimap.create<Trigger, AppliedTransform<P>>()
164168
for (transform in builder.transforms) {
@@ -355,6 +359,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
355359
private suspend fun triggerProperties() {
356360
try {
357361
queueAllTriggers.set(true)
362+
InterfacesProfiler.log(this, "starting to trigger properties")
358363
execute(
359364
InterfacesExceptionContext(
360365
player,
@@ -394,6 +399,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
394399
}
395400

396401
// Either draw the entire interface or just re-render it
402+
InterfacesProfiler.log(this, "starting rendering")
397403
if (firstPaint) {
398404
queuedTransforms.clear()
399405
redrawComplete()
@@ -426,6 +432,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
426432
}
427433

428434
// Await to acquire the mutex before we start rendering
435+
InterfacesProfiler.log(this, "starting re-rendering loop")
429436
paneMutex.lock()
430437
try {
431438
execute(
@@ -518,6 +525,8 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
518525

519526
/** Processes all pending transforms. */
520527
private suspend fun processTransforms() {
528+
InterfacesProfiler.log(this, "starting transform processing")
529+
521530
while (pendingTransforms.isNotEmpty()) {
522531
// Go through all pending transforms one at a time until
523532
// we're fully done with all of them. Other threads may
@@ -548,6 +557,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
548557
} finally {
549558
paneMutex.unlock()
550559
}
560+
InterfacesProfiler.log(this, "finished rendering transform")
551561
}
552562
}
553563

@@ -801,6 +811,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
801811
// Draw the contents of the inventory synchronously because
802812
// we don't want it to happen in between ticks and show
803813
// a half-finished inventory.
814+
InterfacesProfiler.log(this, "ready to render sync")
804815
InterfacesListeners.INSTANCE.runSync {
805816
executeSync(
806817
InterfacesExceptionContext(
@@ -824,6 +835,7 @@ public abstract class AbstractInterfaceView<I : InterfacesInventory, T : Interfa
824835
val isOpen = isOpen()
825836
drawPaneToInventory(drawNormalInventory = true, drawPlayerInventory = isOpen)
826837
callback(createdInventory)
838+
InterfacesProfiler.log(this, "finished rendering to inventory")
827839

828840
if (this is PlayerInterfaceView) {
829841
// If this is a player inventory we can't update the inventory without

0 commit comments

Comments
 (0)