From 721bb4473356b8f47db2b8c8f248a64d2a5023bd Mon Sep 17 00:00:00 2001 From: Thierry Strudel Date: Wed, 17 Feb 2021 11:25:26 -0800 Subject: [PATCH] PowerStats: adjust time since boot to epoch before writing to disk Data stored to disk are extracted into an incident report for timeseries visualization which shows walltime and may span multiple reboot sessions so storing walltime is better suited than relative time since device boot. Bug: 179712445 Tests: atest FrameworksServicesTests:PowerStatsServiceTest Signed-off-by: Thierry Strudel Change-Id: I5ae8e2fe22f1ab9ea960e5be8fef4e9fb1cc10f0 --- .../android/server/powerstatsservice.proto | 6 ++--- .../server/powerstats/PowerStatsLogger.java | 22 ++++++++++++++++ .../server/powerstats/ProtoStreamUtils.java | 26 +++++++++++++++++++ .../powerstats/PowerStatsServiceTest.java | 9 ++++--- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/core/proto/android/server/powerstatsservice.proto b/core/proto/android/server/powerstatsservice.proto index 4b1ee02a6c303..f64e146f87b70 100644 --- a/core/proto/android/server/powerstatsservice.proto +++ b/core/proto/android/server/powerstatsservice.proto @@ -144,7 +144,7 @@ message StateResidencyProto { */ optional int64 total_state_entry_count = 3; /** - * Last time this state was entered. Time in milliseconds since boot + * Last time this state was entered. Walltime in milliseconds since Unix epoch. */ optional int64 last_entry_timestamp_ms = 4; } @@ -208,7 +208,7 @@ message EnergyConsumerResultProto { /** Unique index identifying the energy consumer. */ optional int32 id = 1; - /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */ + /** Walltime in milliseconds since Unix epoch */ optional int64 timestamp_ms = 2; /** Accumulated energy since device boot in microwatt-seconds (uWs) */ @@ -247,7 +247,7 @@ message EnergyMeasurementProto { */ optional int32 id = 1; - /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */ + /** Walltime in milliseconds since Unix epoch */ optional int64 timestamp_ms = 2; /** Accumulated energy since device boot in microwatt-seconds (uWs) */ diff --git a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java index c4f29ea692182..ef0079e0c01fc 100644 --- a/services/core/java/com/android/server/powerstats/PowerStatsLogger.java +++ b/services/core/java/com/android/server/powerstats/PowerStatsLogger.java @@ -16,6 +16,8 @@ package com.android.server.powerstats; +import static java.lang.System.currentTimeMillis; + import android.content.Context; import android.hardware.power.stats.Channel; import android.hardware.power.stats.EnergyConsumer; @@ -26,11 +28,14 @@ import android.hardware.power.stats.StateResidencyResult; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.SystemClock; import android.util.AtomicFile; import android.util.Slog; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.VisibleForTesting; + import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper; import com.android.server.powerstats.ProtoStreamUtils.ChannelUtils; import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerResultUtils; @@ -61,6 +66,8 @@ public final class PowerStatsLogger extends Handler { protected static final int MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY = 1; protected static final int MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY = 2; + // TODO(b/181240441): Add a listener to update the Wall clock baseline when changed + private final long mStartWallTime; private final PowerStatsDataStorage mPowerStatsMeterStorage; private final PowerStatsDataStorage mPowerStatsModelStorage; private final PowerStatsDataStorage mPowerStatsResidencyStorage; @@ -79,6 +86,8 @@ public final class PowerStatsLogger extends Handler { // Log power meter data. EnergyMeasurement[] energyMeasurements = mPowerStatsHALWrapper.readEnergyMeter(new int[0]); + EnergyMeasurementUtils.adjustTimeSinceBootToEpoch(energyMeasurements, + mStartWallTime); mPowerStatsMeterStorage.write( EnergyMeasurementUtils.getProtoBytes(energyMeasurements)); if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements); @@ -86,6 +95,8 @@ public final class PowerStatsLogger extends Handler { // Log power model data without attribution data. EnergyConsumerResult[] ecrNoAttribution = mPowerStatsHALWrapper.getEnergyConsumed(new int[0]); + EnergyConsumerResultUtils.adjustTimeSinceBootToEpoch(ecrNoAttribution, + mStartWallTime); mPowerStatsModelStorage.write( EnergyConsumerResultUtils.getProtoBytes(ecrNoAttribution, false)); if (DEBUG) EnergyConsumerResultUtils.print(ecrNoAttribution); @@ -97,6 +108,8 @@ public final class PowerStatsLogger extends Handler { // Log power model data with attribution data. EnergyConsumerResult[] ecrAttribution = mPowerStatsHALWrapper.getEnergyConsumed(new int[0]); + EnergyConsumerResultUtils.adjustTimeSinceBootToEpoch(ecrAttribution, + mStartWallTime); mPowerStatsModelStorage.write( EnergyConsumerResultUtils.getProtoBytes(ecrAttribution, true)); if (DEBUG) EnergyConsumerResultUtils.print(ecrAttribution); @@ -108,6 +121,8 @@ public final class PowerStatsLogger extends Handler { // Log state residency data. StateResidencyResult[] stateResidencyResults = mPowerStatsHALWrapper.getStateResidency(new int[0]); + StateResidencyResultUtils.adjustTimeSinceBootToEpoch(stateResidencyResults, + mStartWallTime); mPowerStatsResidencyStorage.write( StateResidencyResultUtils.getProtoBytes(stateResidencyResults)); if (DEBUG) StateResidencyResultUtils.print(stateResidencyResults); @@ -293,12 +308,19 @@ public final class PowerStatsLogger extends Handler { return mDeleteResidencyDataOnBoot; } + @VisibleForTesting + public long getStartWallTime() { + return mStartWallTime; + } + public PowerStatsLogger(Context context, File dataStoragePath, String meterFilename, String meterCacheFilename, String modelFilename, String modelCacheFilename, String residencyFilename, String residencyCacheFilename, IPowerStatsHALWrapper powerStatsHALWrapper) { super(Looper.getMainLooper()); + mStartWallTime = currentTimeMillis() - SystemClock.elapsedRealtime(); + if (DEBUG) Slog.d(TAG, "mStartWallTime: " + mStartWallTime); mPowerStatsHALWrapper = powerStatsHALWrapper; mDataStoragePath = dataStoragePath; diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java index 11b22a574476e..746a09882f930 100644 --- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java +++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java @@ -109,6 +109,18 @@ public class ProtoStreamUtils { } static class StateResidencyResultUtils { + public static void adjustTimeSinceBootToEpoch(StateResidencyResult[] stateResidencyResult, + long startWallTime) { + for (int i = 0; i < stateResidencyResult.length; i++) { + final int stateLength = stateResidencyResult[i].stateResidencyData.length; + for (int j = 0; j < stateLength; j++) { + final StateResidency stateResidencyData = + stateResidencyResult[i].stateResidencyData[j]; + stateResidencyData.lastEntryTimestampMs += startWallTime; + } + } + } + public static byte[] getProtoBytes(StateResidencyResult[] stateResidencyResult) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(stateResidencyResult, pos); @@ -306,6 +318,13 @@ public class ProtoStreamUtils { } static class EnergyMeasurementUtils { + public static void adjustTimeSinceBootToEpoch(EnergyMeasurement[] energyMeasurement, + long startWallTime) { + for (int i = 0; i < energyMeasurement.length; i++) { + energyMeasurement[i].timestampMs += startWallTime; + } + } + public static byte[] getProtoBytes(EnergyMeasurement[] energyMeasurement) { ProtoOutputStream pos = new ProtoOutputStream(); packProtoMessage(energyMeasurement, pos); @@ -518,6 +537,13 @@ public class ProtoStreamUtils { } static class EnergyConsumerResultUtils { + public static void adjustTimeSinceBootToEpoch(EnergyConsumerResult[] energyConsumerResult, + long startWallTime) { + for (int i = 0; i < energyConsumerResult.length; i++) { + energyConsumerResult[i].timestampMs += startWallTime; + } + } + public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult, boolean includeAttribution) { ProtoOutputStream pos = new ProtoOutputStream(); diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java index ddbe81c81d6da..26b34fdd4e043 100644 --- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java @@ -318,7 +318,8 @@ public class PowerStatsServiceTest { assertTrue(pssProto.energyMeasurement.length == ENERGY_METER_COUNT); for (int i = 0; i < pssProto.energyMeasurement.length; i++) { assertTrue(pssProto.energyMeasurement[i].id == i); - assertTrue(pssProto.energyMeasurement[i].timestampMs == i); + assertTrue(pssProto.energyMeasurement[i].timestampMs == + i + mPowerStatsLogger.getStartWallTime()); assertTrue(pssProto.energyMeasurement[i].durationMs == i); assertTrue(pssProto.energyMeasurement[i].energyUws == i); } @@ -359,7 +360,8 @@ public class PowerStatsServiceTest { assertTrue(pssProto.energyConsumerResult.length == ENERGY_CONSUMER_COUNT); for (int i = 0; i < pssProto.energyConsumerResult.length; i++) { assertTrue(pssProto.energyConsumerResult[i].id == i); - assertTrue(pssProto.energyConsumerResult[i].timestampMs == i); + assertTrue(pssProto.energyConsumerResult[i].timestampMs == + i + mPowerStatsLogger.getStartWallTime()); assertTrue(pssProto.energyConsumerResult[i].energyUws == i); assertTrue(pssProto.energyConsumerResult[i].attribution.length == ENERGY_CONSUMER_ATTRIBUTION_COUNT); @@ -420,7 +422,8 @@ public class PowerStatsServiceTest { assertTrue(stateResidency.id == j); assertTrue(stateResidency.totalTimeInStateMs == j); assertTrue(stateResidency.totalStateEntryCount == j); - assertTrue(stateResidency.lastEntryTimestampMs == j); + assertTrue(stateResidency.lastEntryTimestampMs == + j + mPowerStatsLogger.getStartWallTime()); } } }