Merge "Log energy consumer result attribution data" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
208c4707e8
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user