Skip to content

Commit

Permalink
Prefer interning combos/components/bands over basic features.
Browse files Browse the repository at this point in the history
This optimization saves memory up to 90% for 5k capabilities or 60% for 1k capabilities.
  • Loading branch information
handymenny committed Aug 2, 2024
1 parent a3cec4c commit b55c0eb
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ object HelpMessage {
const val CUSTOM_CSS = "Inject custom css in Web UI"
const val CUSTOM_JS = "Inject custom js in Web UI"
const val LIBRARY_CACHE =
"Number of items to cache, each items occupies ~0.15MB of RAM. 0 = disabled, -1 = unlimited."
"Number of items to cache, each items occupies ~4-80KB of RAM. 0 = disabled, -1 = unlimited."
}
29 changes: 15 additions & 14 deletions src/main/java/it/smartphonecombo/uecapabilityparser/util/Intern.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package it.smartphonecombo.uecapabilityparser.util

import it.smartphonecombo.uecapabilityparser.model.EmptyMimo
import it.smartphonecombo.uecapabilityparser.model.Mimo
import it.smartphonecombo.uecapabilityparser.model.bandwidth.Bandwidth
import it.smartphonecombo.uecapabilityparser.model.bandwidth.EmptyBandwidth
import it.smartphonecombo.uecapabilityparser.model.modulation.EmptyModulation
import it.smartphonecombo.uecapabilityparser.model.modulation.Modulation
import it.smartphonecombo.uecapabilityparser.model.band.IBandDetails
import it.smartphonecombo.uecapabilityparser.model.combo.ICombo
import it.smartphonecombo.uecapabilityparser.model.component.IComponent

open class InternMap<T>(maxCapacity: Int) {
@Transient private val lock = Any()
Expand All @@ -24,6 +21,10 @@ open class InternMap<T>(maxCapacity: Int) {

fun intern(value: T): T = internalMap[value] ?: put(value)

fun contains(value: T): Boolean = internalMap.contains(value)

fun size() = internalMap.size

companion object {
private fun computeInitialCapacity(maxCapacity: Int): Int {
// A value that ensures no re-hash is maxCapacity / 0.75 + 1
Expand All @@ -35,16 +36,16 @@ open class InternMap<T>(maxCapacity: Int) {
}
}

object MimoInternMap : InternMap<Mimo>(100)
private object IBandDetailsInternMap : InternMap<IBandDetails>(1000)

private object IComponentInternMap : InternMap<IComponent>(10000)

object ModulationInternMap : InternMap<Modulation>(100)
private object IComboInternMap : InternMap<ICombo>(100000)

object BandwidthInternMap : InternMap<Bandwidth>(100)
internal fun IBandDetails.intern() = IBandDetailsInternMap.intern(this)

internal fun Mimo.intern(): Mimo = if (this == EmptyMimo) this else MimoInternMap.intern(this)
internal fun IComponent.intern() = IComponentInternMap.intern(this)

internal fun Modulation.intern() =
if (this == EmptyModulation) this else ModulationInternMap.intern(this)
internal fun ICombo.intern() = IComboInternMap.intern(this)

internal fun Bandwidth.intern() =
if (this == EmptyBandwidth) this else BandwidthInternMap.intern(this)
internal fun ICombo.alreadyInterned() = IComboInternMap.contains(this)
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
package it.smartphonecombo.uecapabilityparser.util

import it.smartphonecombo.uecapabilityparser.extension.trimToSize
import it.smartphonecombo.uecapabilityparser.extension.typedList
import it.smartphonecombo.uecapabilityparser.model.Capabilities
import it.smartphonecombo.uecapabilityparser.model.band.IBandDetails
import it.smartphonecombo.uecapabilityparser.model.combo.ComboEnDc
import it.smartphonecombo.uecapabilityparser.model.combo.ComboLte
import it.smartphonecombo.uecapabilityparser.model.combo.ComboNr
import it.smartphonecombo.uecapabilityparser.model.combo.ComboNrDc
import it.smartphonecombo.uecapabilityparser.model.combo.ICombo
import it.smartphonecombo.uecapabilityparser.model.component.ComponentNr
import it.smartphonecombo.uecapabilityparser.model.component.IComponent

internal fun Capabilities.optimize() {
lteBands.forEach { it.optimize() }
nrBands.forEach { it.optimize() }
lteCombos.forEach { it.optimize() }
nrCombos.forEach { it.optimize() }
nrDcCombos.forEach { it.optimize() }
enDcCombos.forEach { it.optimize() }
}
// bands
lteBands = lteBands.map(IBandDetails::intern).typedList()
nrBands = nrBands.map(IBandDetails::intern).typedList()

internal fun IBandDetails.optimize() {
mimoDL = mimoDL.intern()
mimoUL = mimoUL.intern()
modDL = modDL.intern()
modUL = modUL.intern()
// combos
lteCombos = lteCombos.map(ICombo::optimizeAndIntern).typedList()
nrCombos = nrCombos.map(ICombo::optimizeAndIntern).typedList()
nrDcCombos = nrDcCombos.map(ICombo::optimizeAndIntern).typedList()
enDcCombos = enDcCombos.map(ICombo::optimizeAndIntern).typedList()
}

internal fun ICombo.optimize() {
masterComponents.trimToSize()
masterComponents.forEach { it.optimize() }
secondaryComponents.trimToSize()
secondaryComponents.forEach { it.optimize() }
private fun ICombo.optimizeAndIntern(): ICombo {
val res = if (alreadyInterned()) this else optimized()
return res.intern()
}

internal fun IComponent.optimize() {
mimoDL = mimoDL.intern()
mimoUL = mimoUL.intern()
modDL = modDL.intern()
modUL = modUL.intern()
if (this is ComponentNr) {
maxBandwidthDl = maxBandwidthDl.intern()
maxBandwidthUl = maxBandwidthUl.intern()
private fun ICombo.optimized(): ICombo {
val masterComponentsOpt = masterComponents.map(IComponent::intern)
val secondaryComponentsOpt = secondaryComponents.map(IComponent::intern)

return when (this) {
is ComboLte -> copy(masterComponents = masterComponentsOpt.typedList())
is ComboNr -> copy(masterComponents = masterComponentsOpt.typedList())
is ComboNrDc ->
copy(
masterComponents = masterComponentsOpt.typedList(),
secondaryComponents = secondaryComponentsOpt.typedList(),
)
is ComboEnDc ->
copy(
masterComponents = masterComponentsOpt.typedList(),
secondaryComponents = secondaryComponentsOpt.typedList(),
)
}
}

0 comments on commit b55c0eb

Please sign in to comment.