Merge "Log energy consumer result attribution data" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-02-04 23:07:39 +00:00
committed by Android (Google) Code Review
6 changed files with 155 additions and 26 deletions

View File

@@ -191,6 +191,14 @@ message EnergyConsumerProto {
optional string name = 4;
}
message EnergyConsumerAttributionProto {
/** Android ID / Linux UID, the accumulated energy should be attributed to. */
optional int32 uid = 1;
/** Accumulated energy since boot in microwatt-seconds (uWs) for this AID. */
optional int64 energy_uws = 2;
}
/**
* Energy consumer result:
* An estimate of energy consumption since boot for the subsystem identified
@@ -205,6 +213,9 @@ message EnergyConsumerResultProto {
/** Accumulated energy since device boot in microwatt-seconds (uWs) */
optional int64 energy_uws = 3;
/** Optional attribution per UID for this EnergyConsumer. */
repeated EnergyConsumerAttributionProto attribution = 4;
}
/**

View File

@@ -53,8 +53,9 @@ import java.io.IOException;
public final class PowerStatsLogger extends Handler {
private static final String TAG = PowerStatsLogger.class.getSimpleName();
private static final boolean DEBUG = false;
protected static final int MSG_LOG_TO_DATA_STORAGE_TIMER = 0;
protected static final int MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP = 1;
protected static final int MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP = 0;
protected static final int MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY = 1;
protected static final int MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY = 2;
private final PowerStatsDataStorage mPowerStatsMeterStorage;
private final PowerStatsDataStorage mPowerStatsModelStorage;
@@ -64,8 +65,8 @@ public final class PowerStatsLogger extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOG_TO_DATA_STORAGE_TIMER:
if (DEBUG) Slog.d(TAG, "Logging to data storage on timer");
case MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY:
if (DEBUG) Slog.d(TAG, "Logging to data storage on high frequency timer");
// Log power meter data.
EnergyMeasurement[] energyMeasurements =
@@ -74,12 +75,23 @@ public final class PowerStatsLogger extends Handler {
EnergyMeasurementUtils.getProtoBytes(energyMeasurements));
if (DEBUG) EnergyMeasurementUtils.print(energyMeasurements);
// Log power model data.
EnergyConsumerResult[] energyConsumerResults =
// Log power model data without attribution data.
EnergyConsumerResult[] ecrNoAttribution =
mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
mPowerStatsModelStorage.write(
EnergyConsumerResultUtils.getProtoBytes(energyConsumerResults));
if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResults);
EnergyConsumerResultUtils.getProtoBytes(ecrNoAttribution, false));
if (DEBUG) EnergyConsumerResultUtils.print(ecrNoAttribution);
break;
case MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY:
if (DEBUG) Slog.d(TAG, "Logging to data storage on low frequency timer");
// Log power model data with attribution data.
EnergyConsumerResult[] ecrAttribution =
mPowerStatsHALWrapper.getEnergyConsumed(new int[0]);
mPowerStatsModelStorage.write(
EnergyConsumerResultUtils.getProtoBytes(ecrAttribution, true));
if (DEBUG) EnergyConsumerResultUtils.print(ecrAttribution);
break;
case MSG_LOG_TO_DATA_STORAGE_BATTERY_DROP:
@@ -163,7 +175,7 @@ public final class PowerStatsLogger extends Handler {
// deserialize, then re-serialize. This is computationally inefficient.
EnergyConsumerResult[] energyConsumerResult =
EnergyConsumerResultUtils.unpackProtoMessage(data);
EnergyConsumerResultUtils.packProtoMessage(energyConsumerResult, pos);
EnergyConsumerResultUtils.packProtoMessage(energyConsumerResult, pos, true);
if (DEBUG) EnergyConsumerResultUtils.print(energyConsumerResult);
} catch (IOException e) {
Slog.e(TAG, "Failed to write energy model data to incident report.");

View File

@@ -18,6 +18,7 @@ package com.android.server.powerstats;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
@@ -433,23 +434,40 @@ public class ProtoStreamUtils {
}
static class EnergyConsumerResultUtils {
public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult) {
public static byte[] getProtoBytes(EnergyConsumerResult[] energyConsumerResult,
boolean includeAttribution) {
ProtoOutputStream pos = new ProtoOutputStream();
packProtoMessage(energyConsumerResult, pos);
packProtoMessage(energyConsumerResult, pos, includeAttribution);
return pos.getBytes();
}
public static void packProtoMessage(EnergyConsumerResult[] energyConsumerResult,
ProtoOutputStream pos) {
ProtoOutputStream pos, boolean includeAttribution) {
if (energyConsumerResult == null) return;
for (int i = 0; i < energyConsumerResult.length; i++) {
long token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
long ecrToken = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
pos.write(EnergyConsumerResultProto.ID, energyConsumerResult[i].id);
pos.write(EnergyConsumerResultProto.TIMESTAMP_MS,
energyConsumerResult[i].timestampMs);
pos.write(EnergyConsumerResultProto.ENERGY_UWS, energyConsumerResult[i].energyUWs);
pos.end(token);
if (includeAttribution) {
final int attributionLength = energyConsumerResult[i].attribution.length;
for (int j = 0; j < attributionLength; j++) {
final EnergyConsumerAttribution energyConsumerAttribution =
energyConsumerResult[i].attribution[j];
final long ecaToken = pos.start(EnergyConsumerResultProto.ATTRIBUTION);
pos.write(EnergyConsumerAttributionProto.UID,
energyConsumerAttribution.uid);
pos.write(EnergyConsumerAttributionProto.ENERGY_UWS,
energyConsumerAttribution.energyUWs);
pos.end(ecaToken);
}
}
pos.end(ecrToken);
}
}
@@ -480,9 +498,45 @@ public class ProtoStreamUtils {
}
}
private static EnergyConsumerAttribution unpackEnergyConsumerAttributionProto(
ProtoInputStream pis) throws IOException {
final EnergyConsumerAttribution energyConsumerAttribution =
new EnergyConsumerAttribution();
while (true) {
try {
switch (pis.nextField()) {
case (int) EnergyConsumerAttributionProto.UID:
energyConsumerAttribution.uid =
pis.readInt(EnergyConsumerAttributionProto.UID);
break;
case (int) EnergyConsumerAttributionProto.ENERGY_UWS:
energyConsumerAttribution.energyUWs =
pis.readLong(EnergyConsumerAttributionProto.ENERGY_UWS);
break;
case ProtoInputStream.NO_MORE_FIELDS:
return energyConsumerAttribution;
default:
Slog.e(TAG, "Unhandled field in EnergyConsumerAttributionProto: "
+ ProtoUtils.currentFieldToString(pis));
break;
}
} catch (WireTypeMismatchException wtme) {
Slog.e(TAG, "Wire Type mismatch in EnergyConsumerAttributionProto: "
+ ProtoUtils.currentFieldToString(pis));
}
}
}
private static EnergyConsumerResult unpackEnergyConsumerResultProto(ProtoInputStream pis)
throws IOException {
EnergyConsumerResult energyConsumerResult = new EnergyConsumerResult();
final List<EnergyConsumerAttribution> energyConsumerAttributionList =
new ArrayList<EnergyConsumerAttribution>();
while (true) {
try {
@@ -501,7 +555,18 @@ public class ProtoStreamUtils {
pis.readLong(EnergyConsumerResultProto.ENERGY_UWS);
break;
case (int) EnergyConsumerResultProto.ATTRIBUTION:
final long token = pis.start(EnergyConsumerResultProto.ATTRIBUTION);
energyConsumerAttributionList.add(
unpackEnergyConsumerAttributionProto(pis));
pis.end(token);
break;
case ProtoInputStream.NO_MORE_FIELDS:
energyConsumerResult.attribution =
energyConsumerAttributionList.toArray(
new EnergyConsumerAttribution[
energyConsumerAttributionList.size()]);
return energyConsumerResult;
default:
@@ -520,9 +585,16 @@ public class ProtoStreamUtils {
if (energyConsumerResult == null) return;
for (int i = 0; i < energyConsumerResult.length; i++) {
Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].id
+ ", Timestamp (ms): " + energyConsumerResult[i].timestampMs
+ ", Energy (uWs): " + energyConsumerResult[i].energyUWs);
final EnergyConsumerResult result = energyConsumerResult[i];
Slog.d(TAG, "EnergyConsumerId: " + result.id
+ ", Timestamp (ms): " + result.timestampMs
+ ", Energy (uWs): " + result.energyUWs);
final int attributionLength = result.attribution.length;
for (int j = 0; j < attributionLength; j++) {
final EnergyConsumerAttribution attribution = result.attribution[j];
Slog.d(TAG, " UID: " + attribution.uid
+ " Energy (uWs): " + attribution.energyUWs);
}
}
}
}

View File

@@ -29,18 +29,30 @@ public final class TimerTrigger extends PowerStatsLogTrigger {
private static final String TAG = TimerTrigger.class.getSimpleName();
private static final boolean DEBUG = false;
// TODO(b/166689029): Make configurable through global settings.
private static final long LOG_PERIOD_MS = 120 * 1000;
private static final long LOG_PERIOD_MS_LOW_FREQUENCY = 60 * 60 * 1000; // 1 hour
private static final long LOG_PERIOD_MS_HIGH_FREQUENCY = 2 * 60 * 1000; // 2 minutes
private final Handler mHandler;
private Runnable mLogData = new Runnable() {
private Runnable mLogDataLowFrequency = new Runnable() {
@Override
public void run() {
// Do not wake the device for these messages. Opportunistically log rail data every
// LOG_PERIOD_MS.
mHandler.postDelayed(mLogData, LOG_PERIOD_MS);
if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data");
logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
// LOG_PERIOD_MS_LOW_FREQUENCY.
mHandler.postDelayed(mLogDataLowFrequency, LOG_PERIOD_MS_LOW_FREQUENCY);
if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data low frequency");
logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
}
};
private Runnable mLogDataHighFrequency = new Runnable() {
@Override
public void run() {
// Do not wake the device for these messages. Opportunistically log rail data every
// LOG_PERIOD_MS_HIGH_FREQUENCY.
mHandler.postDelayed(mLogDataHighFrequency, LOG_PERIOD_MS_HIGH_FREQUENCY);
if (DEBUG) Slog.d(TAG, "Received delayed message. Log rail data high frequency");
logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
}
};
@@ -50,7 +62,8 @@ public final class TimerTrigger extends PowerStatsLogTrigger {
mHandler = mContext.getMainThreadHandler();
if (triggerEnabled) {
mLogData.run();
mLogDataLowFrequency.run();
mLogDataHighFrequency.run();
}
}
}

View File

@@ -22,6 +22,7 @@ import static org.junit.Assert.fail;
import android.content.Context;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
@@ -73,6 +74,7 @@ public class PowerStatsServiceTest {
private static final String ENERGY_CONSUMER_NAME = "energyconsumer";
private static final int ENERGY_METER_COUNT = 8;
private static final int ENERGY_CONSUMER_COUNT = 2;
private static final int ENERGY_CONSUMER_ATTRIBUTION_COUNT = 5;
private static final int POWER_ENTITY_COUNT = 3;
private static final int STATE_INFO_COUNT = 5;
private static final int STATE_RESIDENCY_COUNT = 4;
@@ -204,6 +206,13 @@ public class PowerStatsServiceTest {
energyConsumedList[i].id = i;
energyConsumedList[i].timestampMs = i;
energyConsumedList[i].energyUWs = i;
energyConsumedList[i].attribution =
new EnergyConsumerAttribution[ENERGY_CONSUMER_ATTRIBUTION_COUNT];
for (int j = 0; j < energyConsumedList[i].attribution.length; j++) {
energyConsumedList[i].attribution[j] = new EnergyConsumerAttribution();
energyConsumedList[i].attribution[j].uid = j;
energyConsumedList[i].attribution[j].energyUWs = j;
}
}
return energyConsumedList;
}
@@ -250,7 +259,7 @@ public class PowerStatsServiceTest {
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
// Write data to on-device storage.
mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_HIGH_FREQUENCY);
// The above call puts a message on a handler. Wait for
// it to be processed.
@@ -293,7 +302,7 @@ public class PowerStatsServiceTest {
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
// Write data to on-device storage.
mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_TIMER);
mTimerTrigger.logPowerStatsData(PowerStatsLogger.MSG_LOG_TO_DATA_STORAGE_LOW_FREQUENCY);
// The above call puts a message on a handler. Wait for
// it to be processed.
@@ -324,6 +333,12 @@ public class PowerStatsServiceTest {
assertTrue(pssProto.energyConsumerResult[i].id == i);
assertTrue(pssProto.energyConsumerResult[i].timestampMs == i);
assertTrue(pssProto.energyConsumerResult[i].energyUws == i);
assertTrue(pssProto.energyConsumerResult[i].attribution.length
== ENERGY_CONSUMER_ATTRIBUTION_COUNT);
for (int j = 0; j < pssProto.energyConsumerResult[i].attribution.length; j++) {
assertTrue(pssProto.energyConsumerResult[i].attribution[j].uid == j);
assertTrue(pssProto.energyConsumerResult[i].attribution[j].energyUws == j);
}
}
}

View File

@@ -86,6 +86,12 @@ public class PowerStatsServiceProtoParser {
csvRow += energyConsumerResult.getId() + ","
+ energyConsumerResult.getTimestampMs() + ","
+ energyConsumerResult.getEnergyUws() + ",";
for (int k = 0; k < energyConsumerResult.getAttributionCount(); k++) {
final EnergyConsumerAttributionProto energyConsumerAttribution =
energyConsumerResult.getAttribution(k);
csvRow += energyConsumerAttribution.getUid() + ","
+ energyConsumerAttribution.getEnergyUws() + ",";
}
}
System.out.println(csvRow);
}