Merge pull request #2070 from justmara/fix/tdd-cache

TDD calculation cache optimization
This commit is contained in:
Milos Kozak 2022-10-06 13:29:50 +02:00 committed by GitHub
commit bfb0e1f6a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 47 deletions

View file

@ -43,7 +43,7 @@ class ProfileFunctionImplementation @Inject constructor(
private val deviceStatusData: DeviceStatusData private val deviceStatusData: DeviceStatusData
) : ProfileFunction { ) : ProfileFunction {
val cache = LongSparseArray<Profile>() val cache = HashMap<Long,Profile?>()
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
@ -54,10 +54,10 @@ class ProfileFunctionImplementation @Inject constructor(
.subscribe( .subscribe(
{ {
synchronized(cache) { synchronized(cache) {
for (index in cache.size() - 1 downTo 0) { for (key in cache.keys) {
if (cache.keyAt(index) > it.startDate) { if (key > it.startDate) {
aapsLogger.debug(LTag.AUTOSENS, "Removing from profileCache: " + dateUtil.dateAndTimeAndSecondsString(cache.keyAt(index))) aapsLogger.debug(LTag.AUTOSENS, "Removing from profileCache: " + dateUtil.dateAndTimeAndSecondsString(key))
cache.removeAt(index) cache.remove(key)
} else { } else {
break break
} }
@ -98,14 +98,17 @@ class ProfileFunctionImplementation @Inject constructor(
val rounded = time - time % 1000 val rounded = time - time % 1000
// Clear cache after longer use // Clear cache after longer use
synchronized(cache) { synchronized(cache) {
if (cache.size() > 30000) { if (cache.keys.size > 30000) {
cache.clear() cache.clear()
aapsLogger.debug("Profile cache cleared") aapsLogger.debug("Profile cache cleared")
} }
val cached = cache[rounded] if (cache.containsKey(rounded)) {
if (cached != null) return cached //aapsLogger.debug(LTag.PROFILE, "Profile cache HIT for $rounded")
return cache[rounded]
}
} }
// aapsLogger.debug("getProfile called for $time") // aapsLogger.debug("getProfile called for $time")
//aapsLogger.debug(LTag.PROFILE, "Profile cache MISS for $rounded")
val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet() val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()
if (ps is ValueWrapper.Existing) { if (ps is ValueWrapper.Existing) {
val sealed = ProfileSealed.EPS(ps.value) val sealed = ProfileSealed.EPS(ps.value)
@ -130,6 +133,9 @@ class ProfileFunctionImplementation @Inject constructor(
} }
} }
synchronized(cache) {
cache.put(rounded, null)
}
return null return null
} }

View file

@ -41,6 +41,7 @@ class TddCalculator @Inject constructor(
fun calculate(days: Long): LongSparseArray<TotalDailyDose> { fun calculate(days: Long): LongSparseArray<TotalDailyDose> {
var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
val endTime = MidnightTime.calc(dateUtil.now()) val endTime = MidnightTime.calc(dateUtil.now())
val stepSize = T.hours(24).msecs()
val result = LongSparseArray<TotalDailyDose>() val result = LongSparseArray<TotalDailyDose>()
// Try to load cached values // Try to load cached values
@ -48,47 +49,17 @@ class TddCalculator @Inject constructor(
val tdd = repository.getCalculatedTotalDailyDose(startTime).blockingGet() val tdd = repository.getCalculatedTotalDailyDose(startTime).blockingGet()
if (tdd is ValueWrapper.Existing) result.put(startTime, tdd.value) if (tdd is ValueWrapper.Existing) result.put(startTime, tdd.value)
else break else break
startTime += T.hours(24).msecs() startTime += stepSize
} }
if (endTime > startTime) { if (endTime > startTime) {
repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() for (midnight in startTime until endTime step stepSize) {
.filter { it.type != Bolus.Type.PRIMING } val tdd = calculate(midnight, midnight + stepSize)
.forEach { t ->
val midnight = MidnightTime.calc(t.timestamp)
val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight)
tdd.bolusAmount += t.amount
result.put(midnight, tdd)
}
repository.getCarbsDataFromTimeToTimeExpanded(startTime, endTime, true).blockingGet().forEach { t ->
val midnight = MidnightTime.calc(t.timestamp)
val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight)
tdd.carbs += t.amount
result.put(midnight, tdd)
}
val calculationStep = T.mins(5).msecs()
val tempBasals = iobCobCalculator.getTempBasalIncludingConvertedExtendedForRange(startTime, endTime, calculationStep)
for (t in startTime until endTime step calculationStep) {
val midnight = MidnightTime.calc(t)
val tdd = result[midnight] ?: TotalDailyDose(timestamp = midnight)
val tbr = tempBasals[t]
val profile = profileFunction.getProfile(t) ?: continue
val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t)
tdd.basalAmount += absoluteRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble()
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
// they are not included in TBRs
val eb = iobCobCalculator.getExtendedBolus(t)
val absoluteEbRate = eb?.rate ?: 0.0
tdd.bolusAmount += absoluteEbRate / T.mins(60).msecs().toDouble() * calculationStep.toDouble()
}
result.put(midnight, tdd) result.put(midnight, tdd)
} }
} }
for (i in 0 until result.size()) { for (i in 0 until result.size()) {
val tdd = result.valueAt(i) val tdd = result.valueAt(i)
tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount
if (tdd.interfaceIDs.pumpType != InterfaceIDs.PumpType.CACHE) { if (tdd.interfaceIDs.pumpType != InterfaceIDs.PumpType.CACHE) {
tdd.interfaceIDs.pumpType = InterfaceIDs.PumpType.CACHE tdd.interfaceIDs.pumpType = InterfaceIDs.PumpType.CACHE
aapsLogger.debug(LTag.CORE, "Storing TDD $tdd") aapsLogger.debug(LTag.CORE, "Storing TDD $tdd")
@ -99,7 +70,7 @@ class TddCalculator @Inject constructor(
} }
fun calculateToday(): TotalDailyDose { fun calculateToday(): TotalDailyDose {
var startTime = MidnightTime.calc(dateUtil.now()) val startTime = MidnightTime.calc(dateUtil.now())
val endTime = dateUtil.now() val endTime = dateUtil.now()
return calculate(startTime, endTime) return calculate(startTime, endTime)
} }
@ -111,7 +82,9 @@ class TddCalculator @Inject constructor(
} }
fun calculate(startTime: Long, endTime: Long): TotalDailyDose { fun calculate(startTime: Long, endTime: Long): TotalDailyDose {
val tdd = TotalDailyDose(timestamp = startTime) val startTimeAligned = startTime - startTime % (5 * 60 * 1000)
val endTimeAligned = endTime - endTime % (5 * 60 * 1000)
val tdd = TotalDailyDose(timestamp = startTimeAligned)
repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet()
.filter { it.type != Bolus.Type.PRIMING } .filter { it.type != Bolus.Type.PRIMING }
.forEach { t -> .forEach { t ->
@ -121,14 +94,14 @@ class TddCalculator @Inject constructor(
tdd.carbs += t.amount tdd.carbs += t.amount
} }
val calculationStep = T.mins(5).msecs() val calculationStep = T.mins(5).msecs()
for (t in startTime until endTime step calculationStep) { for (t in startTimeAligned until endTimeAligned step calculationStep) {
val tbr = iobCobCalculator.getTempBasalIncludingConvertedExtended(t)
val profile = profileFunction.getProfile(t) ?: continue val profile = profileFunction.getProfile(t) ?: continue
val absoluteRate = tbr?.convertedToAbsolute(t, profile) ?: profile.getBasal(t) val tbr = iobCobCalculator.getBasalData(profile, t)
val absoluteRate = tbr.tempBasalAbsolute
tdd.basalAmount += absoluteRate / 60.0 * 5.0 tdd.basalAmount += absoluteRate / 60.0 * 5.0
if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) {
// they are not included in TBRs
val eb = iobCobCalculator.getExtendedBolus(t) val eb = iobCobCalculator.getExtendedBolus(t)
val absoluteEbRate = eb?.rate ?: 0.0 val absoluteEbRate = eb?.rate ?: 0.0
tdd.bolusAmount += absoluteEbRate / 60.0 * 5.0 tdd.bolusAmount += absoluteEbRate / 60.0 * 5.0