From 4c1bfce6c5f1102a6eac4e0ab421fa8181a38722 Mon Sep 17 00:00:00 2001 From: Sergey Zorchenko Date: Sun, 11 Sep 2022 14:34:19 +0300 Subject: [PATCH 1/2] TDD calc cache optimization --- .../ProfileFunctionImplementation.kt | 22 ++++++++++++------- .../androidaps/utils/stats/TddCalculator.kt | 14 +++++++----- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt index b851e40b22..4bbb6f8efe 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ProfileFunctionImplementation.kt @@ -43,7 +43,7 @@ class ProfileFunctionImplementation @Inject constructor( private val deviceStatusData: DeviceStatusData ) : ProfileFunction { - val cache = LongSparseArray() + val cache = HashMap() private val disposable = CompositeDisposable() @@ -54,10 +54,10 @@ class ProfileFunctionImplementation @Inject constructor( .subscribe( { synchronized(cache) { - for (index in cache.size() - 1 downTo 0) { - if (cache.keyAt(index) > it.startDate) { - aapsLogger.debug(LTag.AUTOSENS, "Removing from profileCache: " + dateUtil.dateAndTimeAndSecondsString(cache.keyAt(index))) - cache.removeAt(index) + for (key in cache.keys) { + if (key > it.startDate) { + aapsLogger.debug(LTag.AUTOSENS, "Removing from profileCache: " + dateUtil.dateAndTimeAndSecondsString(key)) + cache.remove(key) } else { break } @@ -98,14 +98,17 @@ class ProfileFunctionImplementation @Inject constructor( val rounded = time - time % 1000 // Clear cache after longer use synchronized(cache) { - if (cache.size() > 30000) { + if (cache.keys.size > 30000) { cache.clear() aapsLogger.debug("Profile cache cleared") } - val cached = cache[rounded] - if (cached != null) return cached + if (cache.containsKey(rounded)) { + //aapsLogger.debug(LTag.PROFILE, "Profile cache HIT for $rounded") + return cache[rounded] + } } // aapsLogger.debug("getProfile called for $time") + //aapsLogger.debug(LTag.PROFILE, "Profile cache MISS for $rounded") val ps = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet() if (ps is ValueWrapper.Existing) { val sealed = ProfileSealed.EPS(ps.value) @@ -130,6 +133,9 @@ class ProfileFunctionImplementation @Inject constructor( } } + synchronized(cache) { + cache.put(rounded, null) + } return null } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt index f9b7ba509a..02c505525e 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt @@ -99,7 +99,7 @@ class TddCalculator @Inject constructor( } fun calculateToday(): TotalDailyDose { - var startTime = MidnightTime.calc(dateUtil.now()) + val startTime = MidnightTime.calc(dateUtil.now()) val endTime = dateUtil.now() return calculate(startTime, endTime) } @@ -111,7 +111,9 @@ class TddCalculator @Inject constructor( } 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() .filter { it.type != Bolus.Type.PRIMING } .forEach { t -> @@ -121,14 +123,14 @@ class TddCalculator @Inject constructor( tdd.carbs += t.amount } val calculationStep = T.mins(5).msecs() - for (t in startTime until endTime step calculationStep) { - val tbr = iobCobCalculator.getTempBasalIncludingConvertedExtended(t) + for (t in startTimeAligned until endTimeAligned step calculationStep) { + 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 if (!activePlugin.activePump.isFakingTempsByExtendedBoluses) { - // they are not included in TBRs val eb = iobCobCalculator.getExtendedBolus(t) val absoluteEbRate = eb?.rate ?: 0.0 tdd.bolusAmount += absoluteEbRate / 60.0 * 5.0 From bf873e304e5332628897465119d9836ef0780232 Mon Sep 17 00:00:00 2001 From: Sergey Zorchenko Date: Mon, 12 Sep 2022 13:33:15 +0300 Subject: [PATCH 2/2] daily TDD calculation now uses unified flow to benefit from caches --- .../androidaps/utils/stats/TddCalculator.kt | 37 ++----------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt index 02c505525e..009671e58a 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/stats/TddCalculator.kt @@ -41,6 +41,7 @@ class TddCalculator @Inject constructor( fun calculate(days: Long): LongSparseArray { var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) val endTime = MidnightTime.calc(dateUtil.now()) + val stepSize = T.hours(24).msecs() val result = LongSparseArray() // Try to load cached values @@ -48,47 +49,17 @@ class TddCalculator @Inject constructor( val tdd = repository.getCalculatedTotalDailyDose(startTime).blockingGet() if (tdd is ValueWrapper.Existing) result.put(startTime, tdd.value) else break - startTime += T.hours(24).msecs() + startTime += stepSize } if (endTime > startTime) { - repository.getBolusesDataFromTimeToTime(startTime, endTime, true).blockingGet() - .filter { it.type != Bolus.Type.PRIMING } - .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() - } + for (midnight in startTime until endTime step stepSize) { + val tdd = calculate(midnight, midnight + stepSize) result.put(midnight, tdd) } } for (i in 0 until result.size()) { val tdd = result.valueAt(i) - tdd.totalAmount = tdd.bolusAmount + tdd.basalAmount if (tdd.interfaceIDs.pumpType != InterfaceIDs.PumpType.CACHE) { tdd.interfaceIDs.pumpType = InterfaceIDs.PumpType.CACHE aapsLogger.debug(LTag.CORE, "Storing TDD $tdd")