Loading packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/KairosNetwork.kt +37 −3 Original line number Diff line number Diff line Loading @@ -229,17 +229,51 @@ class RootKairosNetwork internal constructor(private val network: Network, private val scope: CoroutineScope, job: Job) : Job by job, KairosNetwork by LocalNetwork(network, scope, lazyOf(emptyEvents)) /** Constructs a new [RootKairosNetwork] in the given [CoroutineScope]. */ /** Constructs a new [RootKairosNetwork] in the given [CoroutineScope] and [CoalescingPolicy]. */ @ExperimentalKairosApi fun CoroutineScope.launchKairosNetwork( context: CoroutineContext = EmptyCoroutineContext context: CoroutineContext = EmptyCoroutineContext, coalescingPolicy: CoalescingPolicy = CoalescingPolicy.Normal, ): RootKairosNetwork { val scope = childScope(context) val network = Network(scope) val network = Network(scope, coalescingPolicy) scope.launch(CoroutineName("launchKairosNetwork scheduler")) { network.runInputScheduler() } return RootKairosNetwork(network, scope, scope.coroutineContext.job) } /** Constructs a new [RootKairosNetwork] in the given [CoroutineScope] and [CoalescingPolicy]. */ fun KairosNetwork( scope: CoroutineScope, coalescingPolicy: CoalescingPolicy = CoalescingPolicy.Normal, ): RootKairosNetwork = scope.launchKairosNetwork(coalescingPolicy = coalescingPolicy) /** Configures how multiple input events are processed by the network. */ enum class CoalescingPolicy { /** * Each input event is processed in its own transaction. This policy has the least overhead but * can cause backpressure if the network becomes flooded with inputs. */ None, /** * Input events are processed as they appear. Compared to [Eager], this policy will not * internally [yield][kotlinx.coroutines.yield] to allow more inputs to be processed before * starting a transaction. This means that if there is a race between an input and a transaction * occurring, it is beholden to the * [CoroutineDispatcher][kotlinx.coroutines.CoroutineDispatcher] to determine the ordering. * * Note that any input events which miss being included in a transaction will be immediately * scheduled for a subsequent transaction. */ Normal, /** * Input events are processed eagerly. Compared to [Normal], this policy will internally * [yield][kotlinx.coroutines.yield] to allow for as many input events to be processed as * possible. This can be useful for noisy networks where many inputs can be handled * simultaneously, potentially improving throughput. */ Eager, } @ExperimentalKairosApi interface HasNetwork : KairosScope { /** Loading packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Network.kt +18 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.kairos.internal import com.android.systemui.kairos.CoalescingPolicy import com.android.systemui.kairos.State import com.android.systemui.kairos.internal.util.HeteroMap import com.android.systemui.kairos.internal.util.logDuration Loading @@ -40,7 +41,8 @@ import kotlinx.coroutines.yield private val nextNetworkId = AtomicLong() internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { internal class Network(val coroutineScope: CoroutineScope, val coalescingPolicy: CoalescingPolicy) : NetworkScope { override val networkId: Any = nextNetworkId.getAndIncrement() Loading Loading @@ -103,11 +105,22 @@ internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { for (first in inputScheduleChan) { // Drain and conflate all transaction requests into a single transaction actions.add(first) when (coalescingPolicy) { CoalescingPolicy.None -> {} CoalescingPolicy.Normal -> { while (true) { val func = inputScheduleChan.tryReceive().getOrNull() ?: break actions.add(func) } } CoalescingPolicy.Eager -> { while (true) { yield() val func = inputScheduleChan.tryReceive().getOrNull() ?: break actions.add(func) } } } transactionMutex.withLock { val e = epoch val duration = measureTime { Loading Loading
packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/KairosNetwork.kt +37 −3 Original line number Diff line number Diff line Loading @@ -229,17 +229,51 @@ class RootKairosNetwork internal constructor(private val network: Network, private val scope: CoroutineScope, job: Job) : Job by job, KairosNetwork by LocalNetwork(network, scope, lazyOf(emptyEvents)) /** Constructs a new [RootKairosNetwork] in the given [CoroutineScope]. */ /** Constructs a new [RootKairosNetwork] in the given [CoroutineScope] and [CoalescingPolicy]. */ @ExperimentalKairosApi fun CoroutineScope.launchKairosNetwork( context: CoroutineContext = EmptyCoroutineContext context: CoroutineContext = EmptyCoroutineContext, coalescingPolicy: CoalescingPolicy = CoalescingPolicy.Normal, ): RootKairosNetwork { val scope = childScope(context) val network = Network(scope) val network = Network(scope, coalescingPolicy) scope.launch(CoroutineName("launchKairosNetwork scheduler")) { network.runInputScheduler() } return RootKairosNetwork(network, scope, scope.coroutineContext.job) } /** Constructs a new [RootKairosNetwork] in the given [CoroutineScope] and [CoalescingPolicy]. */ fun KairosNetwork( scope: CoroutineScope, coalescingPolicy: CoalescingPolicy = CoalescingPolicy.Normal, ): RootKairosNetwork = scope.launchKairosNetwork(coalescingPolicy = coalescingPolicy) /** Configures how multiple input events are processed by the network. */ enum class CoalescingPolicy { /** * Each input event is processed in its own transaction. This policy has the least overhead but * can cause backpressure if the network becomes flooded with inputs. */ None, /** * Input events are processed as they appear. Compared to [Eager], this policy will not * internally [yield][kotlinx.coroutines.yield] to allow more inputs to be processed before * starting a transaction. This means that if there is a race between an input and a transaction * occurring, it is beholden to the * [CoroutineDispatcher][kotlinx.coroutines.CoroutineDispatcher] to determine the ordering. * * Note that any input events which miss being included in a transaction will be immediately * scheduled for a subsequent transaction. */ Normal, /** * Input events are processed eagerly. Compared to [Normal], this policy will internally * [yield][kotlinx.coroutines.yield] to allow for as many input events to be processed as * possible. This can be useful for noisy networks where many inputs can be handled * simultaneously, potentially improving throughput. */ Eager, } @ExperimentalKairosApi interface HasNetwork : KairosScope { /** Loading
packages/SystemUI/utils/kairos/src/com/android/systemui/kairos/internal/Network.kt +18 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.kairos.internal import com.android.systemui.kairos.CoalescingPolicy import com.android.systemui.kairos.State import com.android.systemui.kairos.internal.util.HeteroMap import com.android.systemui.kairos.internal.util.logDuration Loading @@ -40,7 +41,8 @@ import kotlinx.coroutines.yield private val nextNetworkId = AtomicLong() internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { internal class Network(val coroutineScope: CoroutineScope, val coalescingPolicy: CoalescingPolicy) : NetworkScope { override val networkId: Any = nextNetworkId.getAndIncrement() Loading Loading @@ -103,11 +105,22 @@ internal class Network(val coroutineScope: CoroutineScope) : NetworkScope { for (first in inputScheduleChan) { // Drain and conflate all transaction requests into a single transaction actions.add(first) when (coalescingPolicy) { CoalescingPolicy.None -> {} CoalescingPolicy.Normal -> { while (true) { val func = inputScheduleChan.tryReceive().getOrNull() ?: break actions.add(func) } } CoalescingPolicy.Eager -> { while (true) { yield() val func = inputScheduleChan.tryReceive().getOrNull() ?: break actions.add(func) } } } transactionMutex.withLock { val e = epoch val duration = measureTime { Loading