Merge "Calculate and account for memory power use"
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index f0cc390..370f7f9 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -30,6 +30,7 @@
import android.telephony.SignalStrength;
import android.text.format.DateFormat;
import android.util.ArrayMap;
+import android.util.LongSparseArray;
import android.util.MutableBoolean;
import android.util.Pair;
import android.util.Printer;
@@ -2450,6 +2451,8 @@
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
+ public abstract LongSparseArray<? extends Timer> getKernelMemoryStats();
+
public abstract void writeToParcelWithoutUids(Parcel out, int flags);
private final static void formatTimeRaw(StringBuilder out, long seconds) {
@@ -4116,6 +4119,17 @@
}
}
+ final LongSparseArray<? extends Timer> mMemoryStats = getKernelMemoryStats();
+ pw.println("Memory Stats");
+ for (int i = 0; i < mMemoryStats.size(); i++) {
+ sb.setLength(0);
+ sb.append("Bandwidth ");
+ sb.append(mMemoryStats.keyAt(i));
+ sb.append(" Time ");
+ sb.append(mMemoryStats.valueAt(i).getTotalTimeLocked(rawRealtime, which));
+ pw.println(sb.toString());
+ }
+
for (int iu=0; iu<NU; iu++) {
final int uid = uidStats.keyAt(iu);
if (reqUid >= 0 && uid != reqUid && uid != Process.SYSTEM_UID) {
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index d92e596..5ea9475 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -88,7 +88,8 @@
USER,
UNACCOUNTED,
OVERCOUNTED,
- CAMERA
+ CAMERA,
+ MEMORY
}
public BatterySipper(DrainType drainType, Uid uid, double value) {
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 27ffb8b..1ae5c66 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -125,6 +125,7 @@
PowerCalculator mSensorPowerCalculator;
PowerCalculator mCameraPowerCalculator;
PowerCalculator mFlashlightPowerCalculator;
+ PowerCalculator mMemoryPowerCalculator;
boolean mHasWifiPowerReporting = false;
boolean mHasBluetoothPowerReporting = false;
@@ -342,6 +343,11 @@
}
mCpuPowerCalculator.reset();
+ if (mMemoryPowerCalculator == null) {
+ mMemoryPowerCalculator = new MemoryPowerCalculator(mPowerProfile);
+ }
+ mMemoryPowerCalculator.reset();
+
if (mWakelockPowerCalculator == null) {
mWakelockPowerCalculator = new WakelockPowerCalculator(mPowerProfile);
}
@@ -672,12 +678,23 @@
}
}
+ private void addMemoryUsage() {
+ BatterySipper memory = new BatterySipper(DrainType.MEMORY, null, 0);
+ mMemoryPowerCalculator.calculateRemaining(memory, mStats, mRawRealtimeUs, mRawUptimeUs,
+ mStatsType);
+ memory.sumPower();
+ if (memory.totalPowerMah > 0) {
+ mUsageList.add(memory);
+ }
+ }
+
private void processMiscUsage() {
addUserUsage();
addPhoneUsage();
addScreenUsage();
addWiFiUsage();
addBluetoothUsage();
+ addMemoryUsage();
addIdleUsage(); // Not including cellular idle power
// Don't compute radio usage if it's a wifi-only device
if (!mWifiOnly) {
diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java
new file mode 100644
index 0000000..efd3ab5
--- /dev/null
+++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java
@@ -0,0 +1,54 @@
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+public class MemoryPowerCalculator extends PowerCalculator {
+
+ public static final String TAG = "MemoryPowerCalculator";
+ private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+ private final double[] powerAverages;
+
+ public MemoryPowerCalculator(PowerProfile profile) {
+ int numBuckets = profile.getNumElements(PowerProfile.POWER_MEMORY);
+ powerAverages = new double[numBuckets];
+ for (int i = 0; i < numBuckets; i++) {
+ powerAverages[i] = profile.getAveragePower(PowerProfile.POWER_MEMORY, i);
+ if (powerAverages[i] == 0 && DEBUG) {
+ Log.d(TAG, "Problem with PowerProfile. Received 0 value in MemoryPowerCalculator");
+ }
+ }
+ }
+
+ @Override
+ public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+ long rawUptimeUs, int statsType) {}
+
+ @Override
+ public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+ long rawUptimeUs, int statsType) {
+ double totalMah = 0;
+ long totalTimeMs = 0;
+ LongSparseArray<? extends BatteryStats.Timer> timers = stats.getKernelMemoryStats();
+ for (int i = 0; i < timers.size() && i < powerAverages.length; i++) {
+ double mAatRail = powerAverages[(int) timers.keyAt(i)];
+ long timeMs = timers.valueAt(i).getTotalTimeLocked(rawRealtimeUs, statsType);
+ double mAm = (mAatRail * timeMs) / (1000*60);
+ if(DEBUG) {
+ Log.d(TAG, "Calculating mAh for bucket " + timers.keyAt(i) + " while unplugged");
+ Log.d(TAG, "Converted power profile number from "
+ + powerAverages[(int) timers.keyAt(i)] + " into " + mAatRail);
+ Log.d(TAG, "Calculated mAm " + mAm);
+ }
+ totalMah += mAm/60;
+ totalTimeMs += timeMs;
+ }
+ app.usagePowerMah = totalMah;
+ app.usageTimeMs = totalTimeMs;
+ if (DEBUG) {
+ Log.d(TAG, String.format("Calculated total mAh for memory %f while unplugged %d ",
+ totalMah, totalTimeMs));
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index ad14a20..51cf2ea 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -171,6 +171,11 @@
public static final String POWER_FLASHLIGHT = "camera.flashlight";
/**
+ * Power consumption when DDR is being used.
+ */
+ public static final String POWER_MEMORY = "memory.bandwidths";
+
+ /**
* Average power consumption when the camera is on over all standard use cases.
*
* TODO: Add more fine-grained camera power metrics.
@@ -365,6 +370,24 @@
}
/**
+ * Returns the number of memory bandwidth buckets defined in power_profile.xml, or a
+ * default value if the subsystem has no recorded value.
+ * @return the number of memory bandwidth buckets.
+ */
+ public int getNumElements(String key) {
+ if (sPowerMap.containsKey(key)) {
+ Object data = sPowerMap.get(key);
+ if (data instanceof Double[]) {
+ final Double[] values = (Double[]) data;
+ return values.length;
+ } else {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ /**
* Returns the average current in mA consumed by the subsystem, or the given
* default value if the subsystem has no recorded value.
* @param type the subsystem type
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ff13125..67cac47 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1516,6 +1516,7 @@
mStats.updateCpuTimeLocked();
mStats.updateKernelWakelocksLocked();
+ mStats.updateKernelMemoryBandwidthLocked();
if (wifiInfo != null) {
if (wifiInfo.isValid()) {